1 1.4 andvar /* $NetBSD: gpioirq.c,v 1.4 2024/02/10 09:21:52 andvar Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.2 brad * Copyright (c) 2016, 2023 Brad Spencer <brad (at) anduin.eldar.org> 5 1.1 thorpej * 6 1.1 thorpej * Permission to use, copy, modify, and distribute this software for any 7 1.1 thorpej * purpose with or without fee is hereby granted, provided that the above 8 1.1 thorpej * copyright notice and this permission notice appear in all copies. 9 1.1 thorpej * 10 1.1 thorpej * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 thorpej * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 thorpej * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 thorpej * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 thorpej * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 1.1 thorpej * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 1.1 thorpej * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 thorpej */ 18 1.1 thorpej 19 1.1 thorpej #include <sys/cdefs.h> 20 1.4 andvar __KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.4 2024/02/10 09:21:52 andvar Exp $"); 21 1.1 thorpej 22 1.1 thorpej /* 23 1.2 brad * GPIO driver that uses interrupts and can send that fact to userland. 24 1.1 thorpej */ 25 1.1 thorpej 26 1.1 thorpej #include <sys/param.h> 27 1.1 thorpej #include <sys/systm.h> 28 1.1 thorpej #include <sys/device.h> 29 1.2 brad #include <sys/device_impl.h> 30 1.1 thorpej #include <sys/gpio.h> 31 1.1 thorpej #include <sys/module.h> 32 1.2 brad #include <sys/conf.h> 33 1.2 brad #include <sys/proc.h> 34 1.2 brad #include <sys/pool.h> 35 1.2 brad #include <sys/kmem.h> 36 1.2 brad #include <sys/condvar.h> 37 1.3 brad #include <sys/vnode.h> 38 1.3 brad #include <sys/select.h> 39 1.3 brad #include <sys/poll.h> 40 1.1 thorpej 41 1.1 thorpej #include <dev/gpio/gpiovar.h> 42 1.1 thorpej 43 1.2 brad #define GPIOIRQ_NPINS 64 44 1.2 brad 45 1.2 brad struct gpioirq_iv { 46 1.2 brad char sc_intrstr[128]; 47 1.2 brad void * sc_ih; 48 1.2 brad int i_thispin_index; 49 1.2 brad uint8_t i_thispin_num; 50 1.2 brad uint8_t i_parentunit; 51 1.2 brad struct gpioirq_softc *sc; 52 1.2 brad }; 53 1.1 thorpej 54 1.1 thorpej struct gpioirq_softc { 55 1.1 thorpej device_t sc_dev; 56 1.2 brad device_t sc_parentdev; 57 1.1 thorpej void * sc_gpio; 58 1.1 thorpej struct gpio_pinmap sc_map; 59 1.1 thorpej int _map[GPIOIRQ_NPINS]; 60 1.2 brad struct gpioirq_iv sc_intrs[GPIOIRQ_NPINS]; 61 1.2 brad int sc_npins; 62 1.1 thorpej kmutex_t sc_lock; 63 1.2 brad kmutex_t sc_read_mutex; 64 1.2 brad kmutex_t sc_dying_mutex; 65 1.1 thorpej bool sc_verbose; 66 1.1 thorpej bool sc_functional; 67 1.2 brad bool sc_opened; 68 1.2 brad bool sc_dying; 69 1.2 brad kcondvar_t sc_condreadready; 70 1.2 brad kcondvar_t sc_cond_dying; 71 1.2 brad pool_cache_t sc_readpool; 72 1.2 brad char *sc_readpoolname; 73 1.3 brad struct selinfo sc_rsel; 74 1.2 brad SIMPLEQ_HEAD(,gpioirq_read_q) sc_read_queue; 75 1.2 brad }; 76 1.2 brad 77 1.2 brad struct gpioirq_read_q { 78 1.2 brad int parentunit; 79 1.2 brad int thepin; 80 1.2 brad int theval; 81 1.2 brad SIMPLEQ_ENTRY(gpioirq_read_q) read_q; 82 1.1 thorpej }; 83 1.1 thorpej 84 1.1 thorpej #define GPIOIRQ_FLAGS_IRQMODE GPIO_INTR_MODE_MASK 85 1.1 thorpej #define GPIOIRQ_FLAGS_VERBOSE 0x1000 86 1.1 thorpej 87 1.1 thorpej static int gpioirq_match(device_t, cfdata_t, void *); 88 1.1 thorpej static void gpioirq_attach(device_t, device_t, void *); 89 1.1 thorpej static int gpioirq_detach(device_t, int); 90 1.1 thorpej static int gpioirq_activate(device_t, enum devact); 91 1.1 thorpej static int gpioirq_intr(void *); 92 1.2 brad static uint8_t gpioirq_index_to_pin_num(struct gpioirq_softc *, int); 93 1.2 brad static uint8_t gpioirq_parent_unit(struct gpioirq_softc *); 94 1.1 thorpej 95 1.1 thorpej CFATTACH_DECL_NEW(gpioirq, sizeof(struct gpioirq_softc), 96 1.1 thorpej gpioirq_match, gpioirq_attach, 97 1.1 thorpej gpioirq_detach, gpioirq_activate); 98 1.1 thorpej 99 1.1 thorpej extern struct cfdriver gpioirq_cd; 100 1.1 thorpej 101 1.2 brad static dev_type_open(gpioirq_open); 102 1.2 brad static dev_type_read(gpioirq_read); 103 1.2 brad static dev_type_close(gpioirq_close); 104 1.3 brad static dev_type_poll(gpioirq_poll); 105 1.2 brad const struct cdevsw gpioirq_cdevsw = { 106 1.2 brad .d_open = gpioirq_open, 107 1.2 brad .d_close = gpioirq_close, 108 1.2 brad .d_read = gpioirq_read, 109 1.2 brad .d_write = nowrite, 110 1.2 brad .d_ioctl = noioctl, 111 1.2 brad .d_stop = nostop, 112 1.2 brad .d_tty = notty, 113 1.3 brad .d_poll = gpioirq_poll, 114 1.2 brad .d_mmap = nommap, 115 1.2 brad .d_kqfilter = nokqfilter, 116 1.2 brad .d_discard = nodiscard, 117 1.2 brad .d_flag = D_OTHER 118 1.2 brad }; 119 1.2 brad 120 1.2 brad static uint8_t 121 1.2 brad gpioirq_index_to_pin_num(struct gpioirq_softc *sc, int index) 122 1.2 brad { 123 1.2 brad return (uint8_t)gpio_pin_to_pin_num(sc->sc_gpio, &sc->sc_map, index); 124 1.2 brad } 125 1.2 brad 126 1.2 brad static uint8_t 127 1.2 brad gpioirq_parent_unit(struct gpioirq_softc *sc) 128 1.2 brad { 129 1.2 brad device_t parent = sc->sc_parentdev; 130 1.2 brad 131 1.2 brad return (uint8_t)parent->dv_unit; 132 1.2 brad } 133 1.2 brad 134 1.1 thorpej static int 135 1.1 thorpej gpioirq_match(device_t parent, cfdata_t cf, void *aux) 136 1.1 thorpej { 137 1.1 thorpej struct gpio_attach_args *ga = aux; 138 1.1 thorpej 139 1.1 thorpej if (strcmp(ga->ga_dvname, cf->cf_name)) 140 1.1 thorpej return (0); 141 1.2 brad 142 1.1 thorpej if (ga->ga_offset == -1) 143 1.1 thorpej return (0); 144 1.1 thorpej 145 1.1 thorpej return (1); 146 1.1 thorpej } 147 1.1 thorpej 148 1.1 thorpej static void 149 1.1 thorpej gpioirq_attach(device_t parent, device_t self, void *aux) 150 1.1 thorpej { 151 1.1 thorpej struct gpioirq_softc *sc = device_private(self); 152 1.1 thorpej struct gpio_attach_args *ga = aux; 153 1.2 brad int mask = ga->ga_mask; 154 1.1 thorpej int irqmode, flags; 155 1.1 thorpej 156 1.1 thorpej sc->sc_dev = self; 157 1.2 brad sc->sc_parentdev = parent; 158 1.2 brad sc->sc_opened = false; 159 1.2 brad sc->sc_dying = false; 160 1.2 brad sc->sc_readpoolname = NULL; 161 1.1 thorpej 162 1.1 thorpej /* Map pins */ 163 1.1 thorpej sc->sc_gpio = ga->ga_gpio; 164 1.1 thorpej sc->sc_map.pm_map = sc->_map; 165 1.1 thorpej 166 1.4 andvar /* Determine our pin configuration. */ 167 1.2 brad sc->sc_npins = gpio_npins(mask); 168 1.2 brad if (sc->sc_npins == 0) { 169 1.2 brad sc->sc_npins = 1; 170 1.2 brad mask = 0x1; 171 1.2 brad } 172 1.2 brad 173 1.2 brad /* XXX - exit if more than allowed number of pins */ 174 1.2 brad 175 1.1 thorpej if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, 176 1.2 brad mask, &sc->sc_map)) { 177 1.1 thorpej aprint_error(": can't map pins\n"); 178 1.1 thorpej return; 179 1.1 thorpej } 180 1.1 thorpej 181 1.1 thorpej aprint_normal("\n"); 182 1.1 thorpej 183 1.1 thorpej if (ga->ga_flags & GPIOIRQ_FLAGS_VERBOSE) 184 1.1 thorpej sc->sc_verbose = true; 185 1.1 thorpej 186 1.1 thorpej irqmode = ga->ga_flags & GPIOIRQ_FLAGS_IRQMODE; 187 1.1 thorpej 188 1.1 thorpej mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); 189 1.2 brad mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_VM); 190 1.2 brad mutex_init(&sc->sc_read_mutex, MUTEX_DEFAULT, IPL_VM); 191 1.2 brad cv_init(&sc->sc_cond_dying, "girqdie"); 192 1.2 brad cv_init(&sc->sc_condreadready,"girqrr"); 193 1.2 brad sc->sc_readpoolname = kmem_asprintf("girqread%d",device_unit(self)); 194 1.2 brad sc->sc_readpool = pool_cache_init(sizeof(struct gpioirq_read_q),0,0,0,sc->sc_readpoolname,NULL,IPL_VM,NULL,NULL,NULL); 195 1.2 brad pool_cache_sethiwat(sc->sc_readpool,100); 196 1.2 brad SIMPLEQ_INIT(&sc->sc_read_queue); 197 1.3 brad selinit(&sc->sc_rsel); 198 1.2 brad 199 1.2 brad for(int apin = 0; apin < sc->sc_npins; apin++) { 200 1.2 brad if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, apin, irqmode, 201 1.2 brad sc->sc_intrs[apin].sc_intrstr, sizeof(sc->sc_intrs[apin].sc_intrstr))) { 202 1.2 brad aprint_error_dev(self, "failed to decode interrupt\n"); 203 1.2 brad return; 204 1.2 brad } 205 1.2 brad 206 1.2 brad if (!gpio_pin_irqmode_issupported(sc->sc_gpio, &sc->sc_map, apin, 207 1.2 brad irqmode)) { 208 1.2 brad aprint_error_dev(self, 209 1.2 brad "irqmode not supported: %s\n", sc->sc_intrs[apin].sc_intrstr); 210 1.2 brad gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 211 1.2 brad return; 212 1.2 brad } 213 1.2 brad 214 1.2 brad flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, apin); 215 1.2 brad flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) | 216 1.2 brad GPIO_PIN_INPUT; 217 1.2 brad if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, apin, flags)) { 218 1.2 brad aprint_error_dev(sc->sc_dev, "pin not capable of input\n"); 219 1.2 brad gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 220 1.2 brad return; 221 1.2 brad } 222 1.2 brad 223 1.2 brad /* These are static for each pin, so just stuff them in here, 224 1.2 brad * so they don't need to be looked up again. 225 1.2 brad */ 226 1.2 brad sc->sc_intrs[apin].i_thispin_index = apin; 227 1.2 brad sc->sc_intrs[apin].i_thispin_num = gpioirq_index_to_pin_num(sc,apin); 228 1.2 brad sc->sc_intrs[apin].i_parentunit = gpioirq_parent_unit(sc); 229 1.2 brad sc->sc_intrs[apin].sc = sc; 230 1.2 brad 231 1.2 brad sc->sc_intrs[apin].sc_ih = gpio_intr_establish(sc->sc_gpio, &sc->sc_map, apin, IPL_VM, 232 1.2 brad irqmode | GPIO_INTR_MPSAFE, 233 1.2 brad gpioirq_intr, &sc->sc_intrs[apin]); 234 1.2 brad if (sc->sc_intrs[apin].sc_ih == NULL) { 235 1.2 brad aprint_error_dev(self, 236 1.2 brad "unable to establish interrupt on %s\n", sc->sc_intrs[apin].sc_intrstr); 237 1.2 brad gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 238 1.2 brad return; 239 1.2 brad } 240 1.2 brad aprint_normal_dev(self, "interrupting on %s\n", sc->sc_intrs[apin].sc_intrstr); 241 1.1 thorpej } 242 1.1 thorpej 243 1.1 thorpej sc->sc_functional = true; 244 1.1 thorpej } 245 1.1 thorpej 246 1.1 thorpej int 247 1.1 thorpej gpioirq_intr(void *arg) 248 1.1 thorpej { 249 1.2 brad struct gpioirq_iv *is = arg; 250 1.2 brad struct gpioirq_softc *sc = is->sc; 251 1.2 brad struct gpioirq_read_q *q; 252 1.1 thorpej int val; 253 1.1 thorpej 254 1.1 thorpej mutex_enter(&sc->sc_lock); 255 1.1 thorpej 256 1.2 brad val = gpio_pin_read(sc->sc_gpio, &sc->sc_map, is->i_thispin_index); 257 1.1 thorpej 258 1.1 thorpej if (sc->sc_verbose) 259 1.1 thorpej printf("%s: interrupt on %s --> %d\n", 260 1.2 brad device_xname(sc->sc_dev), sc->sc_intrs[is->i_thispin_index].sc_intrstr, val); 261 1.1 thorpej 262 1.1 thorpej mutex_exit(&sc->sc_lock); 263 1.1 thorpej 264 1.2 brad if (sc->sc_opened) { 265 1.2 brad mutex_enter(&sc->sc_read_mutex); 266 1.2 brad q = pool_cache_get(sc->sc_readpool,PR_NOWAIT); 267 1.2 brad if (q != NULL) { 268 1.2 brad q->thepin = is->i_thispin_num; 269 1.2 brad q->parentunit = is->i_parentunit; 270 1.2 brad q->theval = val; 271 1.2 brad SIMPLEQ_INSERT_TAIL(&sc->sc_read_queue,q,read_q); 272 1.3 brad selnotify(&sc->sc_rsel, POLLIN|POLLRDNORM, NOTE_SUBMIT); 273 1.2 brad cv_signal(&sc->sc_condreadready); 274 1.2 brad } else { 275 1.2 brad aprint_error("Could not allocate memory for read pool\n"); 276 1.2 brad } 277 1.2 brad mutex_exit(&sc->sc_read_mutex); 278 1.2 brad } 279 1.2 brad 280 1.1 thorpej return (1); 281 1.1 thorpej } 282 1.1 thorpej 283 1.2 brad static int 284 1.2 brad gpioirq_open(dev_t dev, int flags, int fmt, struct lwp *l) 285 1.2 brad { 286 1.2 brad struct gpioirq_softc *sc; 287 1.2 brad 288 1.2 brad sc = device_lookup_private(&gpioirq_cd, minor(dev)); 289 1.2 brad if (!sc) 290 1.2 brad return (ENXIO); 291 1.2 brad 292 1.2 brad if (sc->sc_opened) 293 1.2 brad return (EBUSY); 294 1.2 brad 295 1.2 brad mutex_enter(&sc->sc_lock); 296 1.2 brad sc->sc_opened = true; 297 1.2 brad mutex_exit(&sc->sc_lock); 298 1.2 brad 299 1.2 brad return (0); 300 1.2 brad } 301 1.2 brad 302 1.2 brad static int 303 1.2 brad gpioirq_read(dev_t dev, struct uio *uio, int flags) 304 1.2 brad { 305 1.2 brad struct gpioirq_softc *sc; 306 1.2 brad struct gpioirq_read_q *chp; 307 1.2 brad int error = 0,any; 308 1.2 brad uint8_t obuf[3]; 309 1.2 brad 310 1.2 brad sc = device_lookup_private(&gpioirq_cd, minor(dev)); 311 1.2 brad if (!sc) 312 1.2 brad return (ENXIO); 313 1.2 brad 314 1.3 brad if (sc->sc_dying) { 315 1.3 brad return EIO; 316 1.3 brad } 317 1.3 brad 318 1.2 brad while (uio->uio_resid > 0) { 319 1.2 brad any = 0; 320 1.2 brad error = 0; 321 1.2 brad mutex_enter(&sc->sc_read_mutex); 322 1.2 brad 323 1.2 brad while (any == 0) { 324 1.2 brad chp = SIMPLEQ_FIRST(&sc->sc_read_queue); 325 1.2 brad if (chp != NULL) { 326 1.2 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); 327 1.2 brad any = 1; 328 1.2 brad break; 329 1.2 brad } else { 330 1.3 brad if (flags & IO_NDELAY) { 331 1.3 brad error = EWOULDBLOCK; 332 1.3 brad } else { 333 1.3 brad error = cv_wait_sig(&sc->sc_condreadready,&sc->sc_read_mutex); 334 1.3 brad } 335 1.2 brad if (sc->sc_dying) 336 1.2 brad error = EIO; 337 1.2 brad if (error == 0) 338 1.2 brad continue; 339 1.2 brad break; 340 1.2 brad } 341 1.2 brad } 342 1.2 brad 343 1.2 brad if (any == 1 && error == 0) { 344 1.2 brad obuf[0] = (uint8_t)chp->parentunit; 345 1.2 brad obuf[1] = (uint8_t)chp->thepin; 346 1.2 brad obuf[2] = (uint8_t)chp->theval; 347 1.2 brad pool_cache_put(sc->sc_readpool,chp); 348 1.2 brad mutex_exit(&sc->sc_read_mutex); 349 1.2 brad if ((error = uiomove(&obuf[0], 3, uio)) != 0) { 350 1.2 brad break; 351 1.2 brad } 352 1.2 brad } else { 353 1.2 brad mutex_exit(&sc->sc_read_mutex); 354 1.2 brad if (error) { 355 1.2 brad break; 356 1.2 brad } 357 1.2 brad } 358 1.2 brad } 359 1.2 brad 360 1.2 brad if (sc->sc_dying) { 361 1.2 brad mutex_enter(&sc->sc_dying_mutex); 362 1.2 brad cv_signal(&sc->sc_cond_dying); 363 1.2 brad mutex_exit(&sc->sc_dying_mutex); 364 1.2 brad } 365 1.2 brad return error; 366 1.2 brad } 367 1.2 brad 368 1.2 brad static int 369 1.2 brad gpioirq_close(dev_t dev, int flags, int fmt, struct lwp *l) 370 1.2 brad { 371 1.2 brad struct gpioirq_softc *sc; 372 1.2 brad struct gpioirq_read_q *q; 373 1.2 brad 374 1.2 brad sc = device_lookup_private(&gpioirq_cd, minor(dev)); 375 1.2 brad 376 1.3 brad if (sc->sc_dying) { 377 1.3 brad return(0); 378 1.3 brad } 379 1.3 brad 380 1.2 brad mutex_enter(&sc->sc_lock); 381 1.2 brad while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) { 382 1.2 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); 383 1.2 brad pool_cache_put(sc->sc_readpool,q); 384 1.2 brad } 385 1.2 brad sc->sc_opened = false; 386 1.2 brad mutex_exit(&sc->sc_lock); 387 1.2 brad 388 1.2 brad return(0); 389 1.2 brad } 390 1.2 brad 391 1.3 brad static int 392 1.3 brad gpioirq_poll(dev_t dev, int events, struct lwp *l) 393 1.3 brad { 394 1.3 brad struct gpioirq_softc *sc; 395 1.3 brad int revents = 0; 396 1.3 brad 397 1.3 brad sc = device_lookup_private(&gpioirq_cd, minor(dev)); 398 1.3 brad 399 1.3 brad mutex_enter(&sc->sc_read_mutex); 400 1.3 brad if (sc->sc_dying) { 401 1.3 brad mutex_exit(&sc->sc_read_mutex); 402 1.3 brad return POLLHUP; 403 1.3 brad } 404 1.3 brad 405 1.3 brad if ((events & (POLLIN | POLLRDNORM)) != 0) { 406 1.3 brad if (!SIMPLEQ_EMPTY(&sc->sc_read_queue)) 407 1.3 brad revents |= events & (POLLIN | POLLRDNORM); 408 1.3 brad else 409 1.3 brad selrecord(l, &sc->sc_rsel); 410 1.3 brad } 411 1.3 brad 412 1.3 brad mutex_exit(&sc->sc_read_mutex); 413 1.3 brad return revents; 414 1.3 brad } 415 1.3 brad 416 1.1 thorpej int 417 1.1 thorpej gpioirq_detach(device_t self, int flags) 418 1.1 thorpej { 419 1.1 thorpej struct gpioirq_softc *sc = device_private(self); 420 1.2 brad struct gpioirq_read_q *q; 421 1.1 thorpej 422 1.1 thorpej /* Clear the handler and disable the interrupt. */ 423 1.2 brad for(int apin = 0;apin < sc->sc_npins;apin++) { 424 1.2 brad gpio_intr_disestablish(sc->sc_gpio, sc->sc_intrs[apin].sc_ih); 425 1.2 brad } 426 1.1 thorpej 427 1.1 thorpej /* Release the pin. */ 428 1.1 thorpej gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 429 1.1 thorpej 430 1.2 brad sc->sc_dying = true; 431 1.2 brad 432 1.2 brad if (sc->sc_opened) { 433 1.2 brad mutex_enter(&sc->sc_dying_mutex); 434 1.2 brad mutex_enter(&sc->sc_read_mutex); 435 1.2 brad cv_signal(&sc->sc_condreadready); 436 1.2 brad mutex_exit(&sc->sc_read_mutex); 437 1.2 brad /* In the worst case this will time out after 5 seconds. 438 1.2 brad * It really should not take that long for the drain / whatever 439 1.2 brad * to happen 440 1.2 brad */ 441 1.2 brad cv_timedwait_sig(&sc->sc_cond_dying, 442 1.2 brad &sc->sc_dying_mutex, mstohz(5000)); 443 1.2 brad mutex_exit(&sc->sc_dying_mutex); 444 1.2 brad cv_destroy(&sc->sc_condreadready); 445 1.2 brad cv_destroy(&sc->sc_cond_dying); 446 1.2 brad } 447 1.2 brad 448 1.2 brad /* Drain any read pools */ 449 1.2 brad while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) { 450 1.2 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); 451 1.2 brad pool_cache_put(sc->sc_readpool,q); 452 1.2 brad } 453 1.2 brad 454 1.2 brad if (sc->sc_readpoolname != NULL) { 455 1.2 brad kmem_free(sc->sc_readpoolname,strlen(sc->sc_readpoolname) + 1); 456 1.2 brad } 457 1.2 brad 458 1.2 brad mutex_destroy(&sc->sc_read_mutex); 459 1.2 brad mutex_destroy(&sc->sc_lock); 460 1.3 brad seldestroy(&sc->sc_rsel); 461 1.2 brad 462 1.1 thorpej return (0); 463 1.1 thorpej } 464 1.1 thorpej 465 1.1 thorpej int 466 1.1 thorpej gpioirq_activate(device_t self, enum devact act) 467 1.1 thorpej { 468 1.1 thorpej 469 1.2 brad struct gpioirq_softc *sc = device_private(self); 470 1.2 brad 471 1.1 thorpej switch (act) { 472 1.1 thorpej case DVACT_DEACTIVATE: 473 1.2 brad sc->sc_dying = true; 474 1.1 thorpej return (0); 475 1.1 thorpej default: 476 1.1 thorpej return (EOPNOTSUPP); 477 1.1 thorpej } 478 1.1 thorpej } 479 1.1 thorpej 480 1.1 thorpej MODULE(MODULE_CLASS_DRIVER, gpioirq, "gpio"); 481 1.1 thorpej 482 1.1 thorpej #ifdef _MODULE 483 1.1 thorpej #include "ioconf.c" 484 1.1 thorpej #endif 485 1.1 thorpej 486 1.1 thorpej static int 487 1.1 thorpej gpioirq_modcmd(modcmd_t cmd, void *opaque) 488 1.1 thorpej { 489 1.1 thorpej int error = 0; 490 1.2 brad #ifdef _MODULE 491 1.2 brad int bmaj = -1, cmaj = -1; 492 1.2 brad #endif 493 1.1 thorpej 494 1.1 thorpej switch (cmd) { 495 1.1 thorpej case MODULE_CMD_INIT: 496 1.1 thorpej #ifdef _MODULE 497 1.1 thorpej error = config_init_component(cfdriver_ioconf_gpioirq, 498 1.1 thorpej cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); 499 1.2 brad if (error) { 500 1.1 thorpej aprint_error("%s: unable to init component\n", 501 1.1 thorpej gpioirq_cd.cd_name); 502 1.2 brad return (error); 503 1.2 brad } 504 1.2 brad 505 1.2 brad error = devsw_attach("gpioirq", NULL, &bmaj, 506 1.2 brad &gpioirq_cdevsw, &cmaj); 507 1.2 brad if (error) { 508 1.2 brad aprint_error("%s: unable to attach devsw\n", 509 1.2 brad gpioirq_cd.cd_name); 510 1.2 brad config_fini_component(cfdriver_ioconf_gpioirq, 511 1.2 brad cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); 512 1.2 brad } 513 1.1 thorpej #endif 514 1.2 brad return (error); 515 1.1 thorpej case MODULE_CMD_FINI: 516 1.1 thorpej #ifdef _MODULE 517 1.2 brad devsw_detach(NULL, &gpioirq_cdevsw); 518 1.1 thorpej config_fini_component(cfdriver_ioconf_gpioirq, 519 1.1 thorpej cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); 520 1.1 thorpej #endif 521 1.2 brad return (0); 522 1.1 thorpej default: 523 1.2 brad return (ENOTTY); 524 1.1 thorpej } 525 1.1 thorpej } 526