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