xref: /dragonfly/sys/dev/misc/gpio/gpio.c (revision fcf6efefc03a35111797b109fa4994034ebe39ba)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
36  * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50 /*
51  * XXX: consumer_detach stuff.
52  * XXX: userland stuff.
53  */
54 
55 #include <sys/param.h>
56 #include <sys/conf.h>
57 #include <sys/kernel.h>
58 #include <sys/systm.h>
59 #include <sys/limits.h>
60 #include <sys/thread.h>
61 #include <sys/malloc.h>
62 #include <sys/ctype.h>
63 #include <sys/sbuf.h>
64 #include <sys/queue.h>
65 #include <sys/uio.h>
66 #include <sys/lock.h>
67 #include <dev/misc/gpio/gpio.h>
68 #include <sys/devfs.h>
69 
70 struct gpio_driver {
71           char      *name;
72           struct devfs_bitmap unit_bitmap;
73           LIST_ENTRY(gpio_driver)       link;
74 };
75 
76 static LIST_HEAD(, gpio_consumer) gpio_conslist = LIST_HEAD_INITIALIZER(&gpio_conslist);
77 static LIST_HEAD(, gpio_driver) gpio_driverlist = LIST_HEAD_INITIALIZER(&gpio_driverlist);
78 DEVFS_DEFINE_CLONE_BITMAP(gpio);
79 static struct lock gpio_lock;
80 static struct lock gpiodev_lock;
81 
82 void
gpio_consumer_register(struct gpio_consumer * gcp)83 gpio_consumer_register(struct gpio_consumer *gcp)
84 {
85           lockmgr(&gpio_lock, LK_EXCLUSIVE);
86           LIST_INSERT_HEAD(&gpio_conslist, gcp, link);
87           lockmgr(&gpio_lock, LK_RELEASE);
88 }
89 
90 void
gpio_consumer_unregister(struct gpio_consumer * gcp)91 gpio_consumer_unregister(struct gpio_consumer *gcp)
92 {
93           lockmgr(&gpio_lock, LK_EXCLUSIVE);
94           LIST_REMOVE(gcp, link);
95           lockmgr(&gpio_lock, LK_RELEASE);
96 }
97 
98 int
gpio_consumer_attach(const char * consumer,void * arg,struct gpio * gp,int pin,u_int32_t mask)99 gpio_consumer_attach(const char *consumer, void *arg, struct gpio *gp,
100               int pin, u_int32_t mask)
101 {
102           struct gpio_consumer *gcp;
103           int error = -1;
104           int locked = 0;
105 
106           /* Check if it is locked already. if not, we acquire the lock */
107           if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
108                     lockmgr(&gpio_lock, LK_EXCLUSIVE);
109                     locked = 1;
110           }
111 
112           LIST_FOREACH(gcp, &gpio_conslist, link) {
113                     if (strcmp(gcp->consumer_name, consumer) != 0)
114                               continue;
115 
116                     if (gcp->consumer_attach)
117                               error = gcp->consumer_attach(gp, arg, pin, mask);
118                     if (error) {
119                               kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
120                                   "(consumer error %d)\n", consumer, gp->driver_name,
121                                   gp->driver_unit, pin, error);
122                               goto end;
123                     }
124 
125                     kprintf("gpio: Attached consumer %s to gpio %s%d pin %d\n",
126                         consumer, gp->driver_name, gp->driver_unit, pin);
127                     goto end;
128           }
129 
130           kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
131               "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
132 
133 end:
134           /* If we acquired the lock, we also get rid of it */
135           if (locked)
136                     lockmgr(&gpio_lock, LK_RELEASE);
137           return error;
138 }
139 
140 int
gpio_consumer_detach(const char * consumer,struct gpio * gp,int pin)141 gpio_consumer_detach(const char *consumer, struct gpio *gp,
142                     int pin)
143 {
144           struct gpio_consumer *gcp;
145           int error = -1;
146           int locked = 0;
147 
148           /* Check if it is locked already. if not, we acquire the lock */
149           if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
150                     lockmgr(&gpio_lock, LK_EXCLUSIVE);
151                     locked = 1;
152           }
153 
154           LIST_FOREACH(gcp, &gpio_conslist, link) {
155                     if (strcmp(gcp->consumer_name, consumer) != 0)
156                               continue;
157 
158                     if (gcp->consumer_detach)
159                               error = gcp->consumer_detach(gp, NULL, pin);
160                     if (error) {
161                               kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
162                                   "(consumer error %d)\n", consumer, gp->driver_name,
163                                   gp->driver_unit, pin, error);
164                               goto end;
165                     }
166 
167                     kprintf("gpio: Detached consumer %s from gpio %s%d pin %d\n",
168                         consumer, gp->driver_name, gp->driver_unit, pin);
169                     goto end;
170           }
171 
172           kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
173               "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
174 
175 end:
176           /* If we acquired the lock, we also get rid of it */
177           if (locked)
178                     lockmgr(&gpio_lock, LK_RELEASE);
179           return error;
180 }
181 
182 struct gpio_mapping *
gpio_map(struct gpio * gp,int * map,int offset,u_int32_t mask)183 gpio_map(struct gpio *gp, int *map, int offset, u_int32_t mask)
184 {
185           struct gpio_mapping *gmp;
186           int npins, pin, i;
187           int locked = 0;
188 
189           npins = gpio_npins(mask);
190           if (npins > gp->npins)
191                     return NULL;
192           if (npins == 0)
193                     return NULL;
194 
195           /* Check if it is locked already. if not, we acquire the lock */
196           if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
197                     lockmgr(&gpio_lock, LK_EXCLUSIVE);
198                     locked = 1;
199           }
200 
201           gmp = kmalloc(sizeof(struct gpio_mapping), M_TEMP, M_WAITOK);
202           gmp->gp = gp;
203           if (map) {
204                     gmp->map = map;
205                     gmp->map_alloced = 0;
206           } else {
207                     gmp->map = kmalloc(sizeof(int) * npins, M_TEMP, M_WAITOK);
208                     gmp->map_alloced = 1;
209           }
210 
211           for (npins = 0, i = 0; i < 32; i++)
212                     if (mask & (1 << i)) {
213                               pin = offset + i;
214                               if (pin < 0 || pin >= gp->npins ||
215                                         gp->pins[pin].pin_mapped || gp->pins[pin].pin_opened) {
216                                         if (map == NULL)
217                                                   kfree(gmp->map, M_TEMP);
218                                         kfree(gmp, M_TEMP);
219                                         /* If we acquired the lock, we also get rid of it */
220                                         if (locked)
221                                                   lockmgr(&gpio_lock, LK_RELEASE);
222                                         return NULL;
223                               }
224                               gp->pins[pin].pin_mapped = 1;
225                               gmp->map[npins++] = pin;
226                     }
227           gmp->size = npins;
228 
229           /* If we acquired the lock, we also get rid of it */
230           if (locked)
231                     lockmgr(&gpio_lock, LK_RELEASE);
232 
233           return gmp;
234 }
235 
236 void
gpio_unmap(struct gpio_mapping * gmp)237 gpio_unmap(struct gpio_mapping *gmp)
238 {
239           int pin, i;
240           int locked = 0;
241 
242           /* Check if it is locked already. if not, we acquire the lock */
243           if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
244                     lockmgr(&gpio_lock, LK_EXCLUSIVE);
245                     locked = 1;
246           }
247 
248           for (i = 0; i < gmp->size; i++) {
249                     pin = gmp->map[i];
250                     gmp->gp->pins[pin].pin_mapped = 0;
251           }
252 
253           if (gmp->map_alloced)
254                     kfree(gmp->map, M_TEMP);
255           kfree(gmp, M_TEMP);
256 
257           /* If we acquired the lock, we also get rid of it */
258           if (locked)
259                     lockmgr(&gpio_lock, LK_RELEASE);
260 }
261 
262 int
gpio_npins(u_int32_t mask)263 gpio_npins(u_int32_t mask)
264 {
265           int npins, i;
266 
267           for (npins = 0, i = 0; i < 32; i++)
268                     if (mask & (1 << i))
269                               npins++;
270 
271           return (npins);
272 }
273 
274 int
gpio_pin_read(struct gpio * gp,struct gpio_mapping * map,int pin)275 gpio_pin_read(struct gpio *gp, struct gpio_mapping *map, int pin)
276 {
277           return gp->pin_read(gp->arg, map->map[pin]);
278 }
279 
280 void
gpio_pin_write(struct gpio * gp,struct gpio_mapping * map,int pin,int data)281 gpio_pin_write(struct gpio *gp, struct gpio_mapping *map, int pin, int data)
282 {
283           gp->pin_write(gp->arg, map->map[pin], data);
284 }
285 
286 void
gpio_pin_ctl(struct gpio * gp,struct gpio_mapping * map,int pin,int flags)287 gpio_pin_ctl(struct gpio *gp, struct gpio_mapping *map, int pin, int flags)
288 {
289           gp->pin_ctl(gp->arg, map->map[pin], flags);
290 }
291 
292 int
gpio_pin_caps(struct gpio * gp,struct gpio_mapping * map,int pin)293 gpio_pin_caps(struct gpio *gp, struct gpio_mapping *map, int pin)
294 {
295           return (gp->pins[map->map[pin]].pin_caps);
296 }
297 
298 static int
gpio_open(struct dev_open_args * ap)299 gpio_open(struct dev_open_args *ap)
300 {
301           gpio_pin_t          *pin;
302           cdev_t    dev;
303 
304           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
305           dev = ap->a_head.a_dev;
306           pin = dev->si_drv2;
307 
308           if (pin->pin_opened || pin->pin_mapped) {
309                     lockmgr(&gpiodev_lock, LK_RELEASE);
310                     return EBUSY;
311           }
312 
313           pin->pin_opened = 1;
314           lockmgr(&gpiodev_lock, LK_RELEASE);
315 
316           return 0;
317 }
318 
319 static int
gpio_close(struct dev_close_args * ap)320 gpio_close(struct dev_close_args *ap)
321 {
322           gpio_pin_t          *pin;
323           cdev_t    dev;
324 
325           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
326           dev = ap->a_head.a_dev;
327           pin = dev->si_drv2;
328 
329           if (pin->pin_opened)
330                     pin->pin_opened = 0;
331           lockmgr(&gpiodev_lock, LK_RELEASE);
332 
333           return 0;
334 }
335 
336 static int
gpio_write(struct dev_write_args * ap)337 gpio_write(struct dev_write_args *ap)
338 {
339           struct gpio         *gp;
340           gpio_pin_t          *pin;
341           cdev_t              dev;
342           int                 error;
343           int                 data = 0;
344 
345           dev = ap->a_head.a_dev;
346           gp = dev->si_drv1;
347           pin = dev->si_drv2;
348 
349           if (ap->a_uio->uio_resid > sizeof(int))
350                     return EINVAL;
351 
352           error = uiomove((void *)&data, ap->a_uio->uio_resid, ap->a_uio);
353           if (error)
354                     return error;
355 
356           if (data != GPIO_PIN_LOW && data != GPIO_PIN_HIGH)
357                     return EINVAL;
358 
359           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
360           gp->pin_write(gp->arg, pin->pin_num, data);
361           pin->pin_state = data;
362           lockmgr(&gpiodev_lock, LK_RELEASE);
363 
364           return 0;
365 }
366 
367 static int
gpio_read(struct dev_read_args * ap)368 gpio_read(struct dev_read_args *ap)
369 {
370           struct gpio         *gp;
371           gpio_pin_t          *pin;
372           cdev_t              dev;
373           int                 error;
374           int                 data = 0;
375 
376           dev = ap->a_head.a_dev;
377           gp = dev->si_drv1;
378           pin = dev->si_drv2;
379 
380           if (ap->a_uio->uio_resid < sizeof(char))
381                     return EINVAL;
382 
383           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
384           data = gp->pin_read(gp->arg, pin->pin_num);
385           lockmgr(&gpiodev_lock, LK_RELEASE);
386 
387           error = uiomove((void *)&data,
388               (ap->a_uio->uio_resid > sizeof(int))?(sizeof(int)):(ap->a_uio->uio_resid),
389                     ap->a_uio);
390 
391           return error;
392 }
393 
394 static int
gpio_ioctl(struct dev_ioctl_args * ap)395 gpio_ioctl(struct dev_ioctl_args *ap)
396 {
397           struct gpio_pin_set_args *gpsa;
398           struct gpio         *gp;
399           gpio_pin_t          *pin;
400           cdev_t              dev;
401           int                 error;
402 
403           dev = ap->a_head.a_dev;
404           gpsa = (struct gpio_pin_set_args *)ap->a_data;
405           gp = dev->si_drv1;
406           pin = dev->si_drv2;
407           error = 0;
408 
409           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
410 
411           switch(ap->a_cmd) {
412           case GPIOPINSET:
413                     if (pin->pin_opened || pin->pin_mapped) {
414                               error = EBUSY;
415                               break;
416                     }
417 
418                     gpsa->caps = pin->pin_caps;
419                     gpsa->flags = pin->pin_flags;
420 
421                     if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
422                               error = ENODEV;
423                               break;
424                     }
425 
426                     if (gpsa->flags > 0) {
427                               gp->pin_ctl(gp->arg, pin->pin_num, gpsa->flags);
428                               pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
429                     }
430                     break;
431 
432           case GPIOPINUNSET:
433                     error = EINVAL;
434                     break;
435 
436           default:
437                     error = EINVAL;
438                     break;
439           }
440           lockmgr(&gpiodev_lock, LK_RELEASE);
441 
442           return error;
443 }
444 
445 static int
gpio_master_ioctl(struct dev_ioctl_args * ap)446 gpio_master_ioctl(struct dev_ioctl_args *ap)
447 {
448           struct gpio_pin_set_args *gpsa;
449           struct gpio_info    *gpi;
450           struct gpio_attach_args       *gpaa;
451           struct gpio         *gp;
452           cdev_t              dev;
453           gpio_pin_t          *pin;
454           int                 error = 0;
455 
456           dev = ap->a_head.a_dev;
457           gp = dev->si_drv1;
458 
459           lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
460 
461           switch(ap->a_cmd) {
462           case GPIOINFO:
463                     gpi = (struct gpio_info *)ap->a_data;
464                     gpi->npins = gp->npins;
465                     if (gpi->pins != NULL) {
466                               error = copyout(gp->pins, gpi->pins,
467                                   sizeof(struct gpio_pin)*gp->npins);
468                     }
469                     break;
470 
471           case GPIOATTACH:
472                     gpaa = (struct gpio_attach_args *)ap->a_data;
473                     error = gpio_consumer_attach(gpaa->consumer_name,
474                         (gpaa->arg_type == GPIO_TYPE_INT)?
475                         ((void *)gpaa->consumer_arg.lint):
476                         (gpaa->consumer_arg.string),
477                         gp, gpaa->pin_offset, gpaa->pin_mask);
478                     break;
479 
480           case GPIODETACH:
481                     gpaa = (struct gpio_attach_args *)ap->a_data;
482                     error = gpio_consumer_detach(gpaa->consumer_name, gp,
483                         gpaa->pin_offset);
484                     break;
485 
486           case GPIOPINSET:
487                     gpsa = (struct gpio_pin_set_args *)ap->a_data;
488                     if (gpsa->pin < 0 || gpsa->pin >= gp->npins) {
489                               error = EINVAL;
490                               break;
491                     }
492 
493                     pin = &gp->pins[gpsa->pin];
494 
495                     if (pin->pin_opened || pin->pin_mapped) {
496                               error = EBUSY;
497                               break;
498                     }
499 
500                     gpsa->caps = pin->pin_caps;
501                     gpsa->flags = pin->pin_flags;
502 
503                     if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
504                               error = ENODEV;
505                               break;
506                     }
507 
508                     if (gpsa->flags > 0) {
509                               gp->pin_ctl(gp->arg, gpsa->pin, gpsa->flags);
510                               pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
511                     }
512                     break;
513 
514           case GPIOPINUNSET:
515                     gpsa = (struct gpio_pin_set_args *)ap->a_data;
516                     error = EINVAL;
517                     break;
518 
519           default:
520                     error = EINVAL;
521                     break;
522           }
523           lockmgr(&gpiodev_lock, LK_RELEASE);
524 
525           return error;
526 }
527 
528 static struct dev_ops gpio_ops = {
529           { "gpio", 0, D_MPSAFE },
530           .d_open  =          gpio_open,
531           .d_close =          gpio_close,
532           .d_write =          gpio_write,
533           .d_read  =          gpio_read,
534           .d_ioctl =          gpio_ioctl,
535 };
536 
537 static struct dev_ops gpio_master_ops = {
538           { "gpio", 0, D_MPSAFE },
539           .d_ioctl =          gpio_master_ioctl,
540 };
541 
542 void
gpio_register(struct gpio * gp)543 gpio_register(struct gpio *gp)
544 {
545           struct gpio_driver *gpd;
546           int i, unit, master_unit = -1;
547 
548           KKASSERT(gp->npins > 0);
549           KKASSERT(gp->pins);
550 
551           lockmgr(&gpio_lock, LK_EXCLUSIVE);
552           LIST_FOREACH(gpd, &gpio_driverlist, link) {
553                     if (strcmp(gpd->name, gp->driver_name) != 0)
554                               continue;
555 
556                     master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
557                     break;
558           }
559           if (master_unit == -1) {
560                     gpd = kmalloc(sizeof(struct gpio_driver),
561                         M_TEMP, M_WAITOK | M_ZERO);
562                     gpd->name = kstrdup(gp->driver_name, M_TEMP);
563                     devfs_clone_bitmap_init(&gpd->unit_bitmap);
564                     master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
565                     LIST_INSERT_HEAD(&gpio_driverlist, gpd, link);
566           }
567           lockmgr(&gpio_lock, LK_RELEASE);
568 
569           gp->driver_unit = master_unit;
570           kprintf("gpio: GPIO driver %s%d registered, npins = %d\n",
571               gp->driver_name, master_unit, gp->npins);
572 
573           unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
574           gp->master_dev = make_dev(&gpio_master_ops, unit, UID_ROOT, GID_WHEEL, 0600,
575               "gpio/%s%d/master", gp->driver_name, master_unit);
576           gp->master_dev->si_drv1 = gp;
577 
578           for (i = 0; i < gp->npins; i++) {
579                     unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
580                     gp->pins[i].dev = make_dev(&gpio_ops, unit, UID_ROOT, GID_WHEEL, 0600,
581                         "gpio/%s%d/%d", gp->driver_name, master_unit, gp->pins[i].pin_num);
582                     gp->pins[i].dev->si_drv1 = gp;
583                     gp->pins[i].dev->si_drv2 = &gp->pins[i];
584           }
585 }
586 
587 void
gpio_unregister(struct gpio * gp)588 gpio_unregister(struct gpio *gp)
589 {
590           struct gpio_driver *gpd;
591           int i;
592 
593           KKASSERT(gp->npins > 0);
594           KKASSERT(gp->pins);
595 
596           for (i = 0; i < gp->npins; i++) {
597                     devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio),
598                         minor(gp->pins[i].dev));
599                     destroy_dev(gp->pins[i].dev);
600           }
601 
602           destroy_dev(gp->master_dev);
603 
604           lockmgr(&gpio_lock, LK_EXCLUSIVE);
605           LIST_FOREACH(gpd, &gpio_driverlist, link) {
606                     if (strcmp(gpd->name, gp->driver_name) != 0)
607                               continue;
608 
609                     devfs_clone_bitmap_put(&gpd->unit_bitmap, gp->driver_unit);
610                     LIST_REMOVE(gpd, link);
611                     break;
612           }
613           lockmgr(&gpio_lock, LK_RELEASE);
614 
615           kprintf("gpio: GPIO driver %s%d unregistered\n",
616               gp->driver_name, gp->driver_unit);
617 }
618 
619 static void
gpio_drvinit(void * unused)620 gpio_drvinit(void *unused)
621 {
622           lockinit(&gpio_lock, "gpio_lock", 0, 0);
623           lockinit(&gpiodev_lock, "gpiodev_lock", 0, 0);
624           devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(gpio));
625 }
626 
627 SYSINIT(gpio, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, gpio_drvinit, NULL);
628