Home | History | Annotate | Line # | Download | only in gpio
gpiosim.c revision 1.23.6.1
      1 /* $NetBSD: gpiosim.c,v 1.23.6.1 2023/11/26 12:13:19 bouyer Exp $ */
      2 /*      $OpenBSD: gpiosim.c,v 1.1 2008/11/23 18:46:49 mbalmer Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2007 - 2011, 2013 Marc Balmer <marc (at) msys.ch>
      6  * All rights reserved.
      7  *
      8  * Permission to use, copy, modify, and distribute this software for any
      9  * purpose with or without fee is hereby granted, provided that the above
     10  * copyright notice and this permission notice appear in all copies.
     11  *
     12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
     17  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     18  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19  */
     20 
     21 /* 64 bit wide GPIO simulator  */
     22 
     23 #include <sys/param.h>
     24 #include <sys/systm.h>
     25 #include <sys/device.h>
     26 #include <sys/gpio.h>
     27 #include <sys/malloc.h>
     28 #include <sys/module.h>
     29 #include <sys/sysctl.h>
     30 #include <sys/ioccom.h>
     31 #include <dev/gpio/gpiovar.h>
     32 #include <sys/callout.h>
     33 #include <sys/workqueue.h>
     34 
     35 #include "gpiosim.h"
     36 #include "ioconf.h"
     37 
     38 #define	GPIOSIM_NPINS	64
     39 
     40 struct gpiosim_irq {
     41 	int (*sc_gpio_irqfunc)(void *);
     42 	void *sc_gpio_irqarg;
     43 	int sc_gpio_irqmode;
     44 	bool sc_gpio_irqtriggered;
     45 };
     46 
     47 struct gpiosim_softc {
     48 	device_t		sc_dev;
     49 	device_t		sc_gdev;	/* gpio that attaches here */
     50 	uint64_t		sc_state;
     51 	struct gpio_chipset_tag	sc_gpio_gc;
     52 	gpio_pin_t		sc_gpio_pins[GPIOSIM_NPINS];
     53         struct gpiosim_irq      sc_gpio_irqs[GPIOSIM_NPINS];
     54 
     55 	struct sysctllog	*sc_log;
     56         struct workqueue        *sc_wq;
     57         callout_t               sc_co;
     58         bool                    sc_co_init;
     59 	bool			sc_co_running;
     60         int                     sc_ms;
     61         kmutex_t 		sc_intr_mutex;
     62 };
     63 
     64 static int	gpiosim_match(device_t, cfdata_t, void *);
     65 static void	gpiosim_attach(device_t, device_t, void *);
     66 static int	gpiosim_detach(device_t, int);
     67 static int	gpiosim_sysctl(SYSCTLFN_PROTO);
     68 static int	gpiosim_ms_sysctl(SYSCTLFN_PROTO);
     69 
     70 static int	gpiosim_pin_read(void *, int);
     71 static void	gpiosim_pin_write(void *, int, int);
     72 static void	gpiosim_pin_ctl(void *, int, int);
     73 
     74 static void *   gpiosim_intr_establish(void *, int, int, int,
     75     int (*)(void *), void *);
     76 static void     gpiosim_intr_disestablish(void *, void *);
     77 static bool     gpiosim_gpio_intrstr(void *, int, int, char *, size_t);
     78 
     79 void            gpiosim_wq(struct work *,void *);
     80 void            gpiosim_co(void *);
     81 
     82 CFATTACH_DECL_NEW(gpiosim, sizeof(struct gpiosim_softc), gpiosim_match,
     83     gpiosim_attach, gpiosim_detach, NULL);
     84 
     85 int gpiosim_work;
     86 
     87 #ifndef GPIOSIM_MS
     88 #define GPIOSIM_MS 1000
     89 #endif
     90 
     91 static int
     92 gpiosim_match(device_t parent, cfdata_t match, void *aux)
     93 {
     94 	return 1;
     95 }
     96 
     97 void
     98 gpiosimattach(int num __unused)
     99 {
    100 	cfdata_t cf;
    101 	int n, err;
    102 
    103 	err = config_cfattach_attach(gpiosim_cd.cd_name, &gpiosim_ca);
    104 	if (err)
    105 		printf("%s: unable to register cfattach\n", gpiosim_cd.cd_name);
    106 
    107 	for (n = 0; n < NGPIOSIM; n++) {
    108 		cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
    109 		cf->cf_name = "gpiosim";
    110 		cf->cf_atname = "gpiosim";
    111 		cf->cf_unit = n;
    112 		cf->cf_fstate = FSTATE_NOTFOUND;
    113 		config_attach_pseudo(cf);
    114 	}
    115 }
    116 
    117 static void
    118 gpiosim_attach(device_t parent, device_t self, void *aux)
    119 {
    120 	struct gpiosim_softc *sc = device_private(self);
    121 	struct gpiobus_attach_args gba;
    122 	const struct sysctlnode *node;
    123 	int i;
    124 	int error = 0;
    125 
    126 	sc->sc_dev = self;
    127 
    128 	printf("%s", device_xname(sc->sc_dev));
    129 
    130 	/* initialize pin array */
    131 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    132 		sc->sc_gpio_pins[i].pin_num = i;
    133 		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
    134 		    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
    135 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
    136 		    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
    137 
    138 		/* Set up what interrupt types are allowed */
    139 		sc->sc_gpio_pins[i].pin_intrcaps =
    140 		    GPIO_INTR_POS_EDGE |
    141 		    GPIO_INTR_NEG_EDGE |
    142 		    GPIO_INTR_DOUBLE_EDGE |
    143 		    GPIO_INTR_HIGH_LEVEL |
    144 		    GPIO_INTR_LOW_LEVEL |
    145 		    GPIO_INTR_MPSAFE;
    146 		sc->sc_gpio_irqs[i].sc_gpio_irqfunc = NULL;
    147 		sc->sc_gpio_irqs[i].sc_gpio_irqarg = NULL;
    148 		sc->sc_gpio_irqs[i].sc_gpio_irqmode = 0;
    149 		sc->sc_gpio_irqs[i].sc_gpio_irqtriggered = false;
    150 
    151 		/* read initial state */
    152 		sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT;}
    153 
    154 	sc->sc_state = 0;
    155 	sc->sc_ms = GPIOSIM_MS;
    156 	sc->sc_co_init = false;
    157 
    158 	mutex_init(&sc->sc_intr_mutex, MUTEX_DEFAULT, IPL_VM);
    159 
    160 	/* create controller tag */
    161 	sc->sc_gpio_gc.gp_cookie = sc;
    162 	sc->sc_gpio_gc.gp_pin_read = gpiosim_pin_read;
    163 	sc->sc_gpio_gc.gp_pin_write = gpiosim_pin_write;
    164 	sc->sc_gpio_gc.gp_pin_ctl = gpiosim_pin_ctl;
    165         sc->sc_gpio_gc.gp_intr_establish = gpiosim_intr_establish;
    166         sc->sc_gpio_gc.gp_intr_disestablish = gpiosim_intr_disestablish;
    167 	sc->sc_gpio_gc.gp_intr_str = gpiosim_gpio_intrstr;
    168 
    169 	/* gba.gba_name = "gpio"; */
    170 	gba.gba_gc = &sc->sc_gpio_gc;
    171 	gba.gba_pins = sc->sc_gpio_pins;
    172 	gba.gba_npins = GPIOSIM_NPINS;
    173 
    174 	if (!pmf_device_register(self, NULL, NULL))
    175 		aprint_error_dev(self, "couldn't establish power handler\n");
    176 
    177         sysctl_createv(&sc->sc_log, 0, NULL, &node,
    178             0,
    179             CTLTYPE_NODE, device_xname(sc->sc_dev),
    180             SYSCTL_DESCR("GPIO simulator"),
    181             NULL, 0, NULL, 0,
    182             CTL_HW, CTL_CREATE, CTL_EOL);
    183 
    184         if (node == NULL) {
    185 		aprint_error(": can't create sysctl node\n");
    186                 return;
    187 	}
    188 
    189         sysctl_createv(&sc->sc_log, 0, &node, NULL,
    190             CTLFLAG_READWRITE,
    191             CTLTYPE_QUAD, "value",
    192             SYSCTL_DESCR("Current GPIO simulator value"),
    193             gpiosim_sysctl, 0, (void *)sc, 0,
    194 	    CTL_CREATE, CTL_EOL);
    195 
    196         sysctl_createv(&sc->sc_log, 0, &node, NULL,
    197             CTLFLAG_READWRITE,
    198             CTLTYPE_INT, "ms",
    199             SYSCTL_DESCR("Number of ms for level interrupts"),
    200             gpiosim_ms_sysctl, 0, &sc->sc_ms, 0,
    201 	    CTL_CREATE, CTL_EOL);
    202 
    203 	error = workqueue_create(&sc->sc_wq,"gsimwq",gpiosim_wq,sc,PRI_NONE,IPL_VM,WQ_MPSAFE);
    204 	if (error != 0) {
    205 		aprint_error(": can't create workqueue for interrupts\n");
    206                 return;
    207 	}
    208 
    209 	callout_init(&sc->sc_co,CALLOUT_MPSAFE);
    210 	callout_setfunc(&sc->sc_co,gpiosim_co, sc);
    211 	sc->sc_co_running = false;
    212 	sc->sc_co_init = true;
    213 
    214 	aprint_normal(": simulating %d pins\n", GPIOSIM_NPINS);
    215 	sc->sc_gdev = config_found(self, &gba, gpiobus_print, CFARGS_NONE);
    216 }
    217 
    218 static int
    219 gpiosim_detach(device_t self, int flags)
    220 {
    221 	struct gpiosim_softc *sc = device_private(self);
    222 
    223 	/* Detach the gpio driver that attached here */
    224 	if (sc->sc_gdev != NULL)
    225 		config_detach(sc->sc_gdev, 0);
    226 
    227 	pmf_device_deregister(self);
    228 
    229 	if (sc->sc_log != NULL) {
    230 		sysctl_teardown(&sc->sc_log);
    231 		sc->sc_log = NULL;
    232 	}
    233 
    234 	/* Destroy the workqueue, hope that it is empty */
    235 	if (sc->sc_wq != NULL) {
    236 		workqueue_destroy(sc->sc_wq);
    237 	}
    238 
    239 	sc->sc_co_running = false;
    240 
    241 	/* Destroy any callouts */
    242 	if (sc->sc_co_init) {
    243 		callout_halt(&sc->sc_co,NULL);
    244 		callout_destroy(&sc->sc_co);
    245 	}
    246 	return 0;
    247 }
    248 
    249 static int
    250 gpiosim_sysctl(SYSCTLFN_ARGS)
    251 {
    252 	struct sysctlnode node;
    253 	struct gpiosim_softc *sc;
    254 	uint64_t val, error;
    255 	uint64_t previous_val;
    256 	int i;
    257 	struct gpiosim_irq *irq;
    258 	int t = 0;
    259 
    260 	node = *rnode;
    261 	sc = node.sysctl_data;
    262 
    263 	node.sysctl_data = &val;
    264 
    265 	val = sc->sc_state;
    266 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    267 	if (error || newp == NULL)
    268 		return error;
    269 
    270 	mutex_enter(&sc->sc_intr_mutex);
    271 	previous_val = sc->sc_state;
    272 	sc->sc_state = val;
    273 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    274 		irq = &sc->sc_gpio_irqs[i];
    275 		/* Simulate edge interrupts ... */
    276 		if ((previous_val & (1LL << i)) == 0 && (sc->sc_state & (1LL << i)) &&
    277 		    irq->sc_gpio_irqfunc != NULL &&
    278 		    (irq->sc_gpio_irqmode & (GPIO_INTR_POS_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    279 			irq->sc_gpio_irqtriggered = true;
    280 			t++;
    281 		}
    282 		if ((previous_val & (1LL << i)) && (sc->sc_state & (1LL << i)) == 0 &&
    283 		    irq->sc_gpio_irqfunc != NULL &&
    284 		    (irq->sc_gpio_irqmode & (GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    285 			irq->sc_gpio_irqtriggered = true;
    286 			t++;
    287 		}
    288 		/* Simulate level interrupts ... */
    289 		if ((sc->sc_state & (1LL << i)) && irq->sc_gpio_irqfunc != NULL &&
    290 		    (irq->sc_gpio_irqmode & GPIO_INTR_HIGH_LEVEL)) {
    291 			irq->sc_gpio_irqtriggered = true;
    292 		}
    293 		if ((sc->sc_state & (1LL << i)) == 0 && irq->sc_gpio_irqfunc != NULL &&
    294 		    (irq->sc_gpio_irqmode & GPIO_INTR_LOW_LEVEL)) {
    295 			irq->sc_gpio_irqtriggered = true;
    296 		}
    297 		if ((sc->sc_state & (1LL << i)) && irq->sc_gpio_irqfunc != NULL &&
    298 		    (irq->sc_gpio_irqmode & GPIO_INTR_LOW_LEVEL)) {
    299 			irq->sc_gpio_irqtriggered = false;
    300 		}
    301 		if ((sc->sc_state & (1LL << i)) == 0 && irq->sc_gpio_irqfunc != NULL &&
    302 		    (irq->sc_gpio_irqmode & GPIO_INTR_HIGH_LEVEL)) {
    303 			irq->sc_gpio_irqtriggered = false;
    304 		}
    305 	}
    306 	mutex_exit(&sc->sc_intr_mutex);
    307 
    308 	if (t > 0) {
    309 		workqueue_enqueue(sc->sc_wq,(struct work *)&gpiosim_work,NULL);
    310 	}
    311 
    312 	return 0;
    313 }
    314 
    315 int
    316 gpiosim_ms_sysctl(SYSCTLFN_ARGS)
    317 {
    318 	int error, t;
    319 	struct sysctlnode node;
    320 
    321 	node = *rnode;
    322 	t = *(int*)rnode->sysctl_data;
    323 	node.sysctl_data = &t;
    324 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    325 	if (error || newp == NULL)
    326 		return (error);
    327 
    328 	if (t < 1)
    329 		return (EINVAL);
    330 
    331 	*(int*)rnode->sysctl_data = t;
    332 
    333 	return (0);
    334 }
    335 
    336 /* Interrupts though the read and write path are not simulated,
    337  * that is, an interrupt on the setting of an output or an
    338  * interrupt on a pin read.  It is not at all clear that it makes
    339  * any sense to do any of that, although real hardware in some cases
    340  * might trigger an interrupt on an output pin.
    341  */
    342 
    343 static int
    344 gpiosim_pin_read(void *arg, int pin)
    345 {
    346 	struct gpiosim_softc *sc = arg;
    347 
    348 	if (sc->sc_state & (1LL << pin))
    349 		return GPIO_PIN_HIGH;
    350 	else
    351 		return GPIO_PIN_LOW;
    352 }
    353 
    354 static void
    355 gpiosim_pin_write(void *arg, int pin, int value)
    356 {
    357 	struct gpiosim_softc *sc = arg;
    358 
    359 	if (value == 0)
    360 		sc->sc_state &= ~(1LL << pin);
    361 	else
    362 		sc->sc_state |= (1LL << pin);
    363 }
    364 
    365 static void
    366 gpiosim_pin_ctl(void *arg, int pin, int flags)
    367 {
    368 	struct gpiosim_softc *sc = arg;
    369 
    370 	sc->sc_gpio_pins[pin].pin_flags = flags;
    371 }
    372 
    373 static void *
    374 gpiosim_intr_establish(void *vsc, int pin, int ipl, int irqmode,
    375     int (*func)(void *), void *arg)
    376 {
    377 	struct gpiosim_softc * const sc = vsc;
    378 	struct gpiosim_irq *irq;
    379 
    380 	mutex_enter(&sc->sc_intr_mutex);
    381 	irq = &sc->sc_gpio_irqs[pin];
    382 	irq->sc_gpio_irqfunc = func;
    383 	irq->sc_gpio_irqmode = irqmode;
    384 	irq->sc_gpio_irqarg = arg;
    385 
    386 	/* The first level interrupt starts the callout if it is not running */
    387 	if (((irqmode & GPIO_INTR_HIGH_LEVEL) ||
    388 	    (irqmode & GPIO_INTR_LOW_LEVEL)) &&
    389 	    (sc->sc_co_running == false)) {
    390 		callout_schedule(&sc->sc_co,mstohz(sc->sc_ms));
    391 		sc->sc_co_running = true;
    392 	}
    393 
    394 	/* Level interrupts can start as soon as a IRQ handler is installed */
    395 	if (((irqmode & GPIO_INTR_HIGH_LEVEL) && (sc->sc_state & (1LL << pin))) ||
    396 	    ((irqmode & GPIO_INTR_LOW_LEVEL) && ((sc->sc_state & (1LL << pin)) == 0))) {
    397 		irq->sc_gpio_irqtriggered = true;
    398 	}
    399 
    400 	mutex_exit(&sc->sc_intr_mutex);
    401 
    402 	return(irq);
    403 }
    404 
    405 static void
    406 gpiosim_intr_disestablish(void *vsc, void *ih)
    407 {
    408 	struct gpiosim_softc * const sc = vsc;
    409 	struct gpiosim_irq *irq = ih;
    410 	struct gpiosim_irq *lirq;
    411 	int i;
    412 	bool has_level = false;
    413 
    414 	mutex_enter(&sc->sc_intr_mutex);
    415 	irq->sc_gpio_irqfunc = NULL;
    416 	irq->sc_gpio_irqmode = 0;
    417 	irq->sc_gpio_irqarg = NULL;
    418 	irq->sc_gpio_irqtriggered = false;
    419 
    420 	/* Check for any level interrupts and stop the callout
    421 	 * if there are none.
    422 	 */
    423 	for (i = 0;i < GPIOSIM_NPINS; i++) {
    424 		lirq = &sc->sc_gpio_irqs[i];
    425 		if (lirq->sc_gpio_irqmode & (GPIO_INTR_HIGH_LEVEL | GPIO_INTR_LOW_LEVEL)) {
    426 			has_level = true;
    427 			break;
    428 		}
    429 	}
    430 	if (has_level == false) {
    431 		sc->sc_co_running = false;
    432 	}
    433 	mutex_exit(&sc->sc_intr_mutex);
    434 }
    435 
    436 static bool
    437 gpiosim_gpio_intrstr(void *vsc, int pin, int irqmode, char *buf, size_t buflen)
    438 {
    439 
    440         if (pin < 0 || pin >= GPIOSIM_NPINS)
    441                 return (false);
    442 
    443         snprintf(buf, buflen, "GPIO %d", pin);
    444 
    445         return (true);
    446 }
    447 
    448 /* The workqueue handles edge the simulation of edge interrupts */
    449 void
    450 gpiosim_wq(struct work *wk, void *arg)
    451 {
    452 	struct gpiosim_softc *sc = arg;
    453 	struct gpiosim_irq *irq;
    454 	int i;
    455 
    456 	mutex_enter(&sc->sc_intr_mutex);
    457 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    458 		irq = &sc->sc_gpio_irqs[i];
    459 		if (irq->sc_gpio_irqtriggered &&
    460 		    irq->sc_gpio_irqfunc != NULL &&
    461 		    (irq->sc_gpio_irqmode & (GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    462 			(*irq->sc_gpio_irqfunc)(irq->sc_gpio_irqarg);
    463 			irq->sc_gpio_irqtriggered = false;
    464 		}
    465 	}
    466 	mutex_exit(&sc->sc_intr_mutex);
    467 }
    468 
    469 /* This runs as long as there are level interrupts to simulate */
    470 void
    471 gpiosim_co(void *arg)
    472 {
    473 	struct gpiosim_softc *sc = arg;
    474 	struct gpiosim_irq *irq;
    475 	int i;
    476 
    477 	mutex_enter(&sc->sc_intr_mutex);
    478 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    479 		irq = &sc->sc_gpio_irqs[i];
    480 		if (irq->sc_gpio_irqtriggered &&
    481 		    irq->sc_gpio_irqfunc != NULL &&
    482 		    (irq->sc_gpio_irqmode & (GPIO_INTR_HIGH_LEVEL | GPIO_INTR_LOW_LEVEL))) {
    483 			(*irq->sc_gpio_irqfunc)(irq->sc_gpio_irqarg);
    484 		}
    485 	}
    486 	mutex_exit(&sc->sc_intr_mutex);
    487 
    488 	if (sc->sc_co_running == true) {
    489 		callout_schedule(&sc->sc_co,mstohz(sc->sc_ms));
    490 	}
    491 }
    492 
    493 
    494 MODULE(MODULE_CLASS_DRIVER, gpiosim, "gpio");
    495 
    496 #ifdef _MODULE
    497 static const struct cfiattrdata gpiobus_iattrdata = {
    498 	"gpiobus", 0, { { NULL, NULL, 0 },}
    499 };
    500 static const struct cfiattrdata *const gpiosim_attrs[] = {
    501 	&gpiobus_iattrdata, NULL
    502 };
    503 CFDRIVER_DECL(gpiosim, DV_DULL, gpiosim_attrs);
    504 extern struct cfattach gpiosim_ca;
    505 static int gpiosimloc[] = {
    506 	-1,
    507 	-1,
    508 	-1
    509 };
    510 static struct cfdata gpiosim_cfdata[] = {
    511 	{
    512 		.cf_name = "gpiosim",
    513 		.cf_atname = "gpiosim",
    514 		.cf_unit = 0,
    515 		.cf_fstate = FSTATE_STAR,
    516 		.cf_loc = gpiosimloc,
    517 		.cf_flags = 0,
    518 		.cf_pspec = NULL,
    519 	},
    520 	{ NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
    521 };
    522 #endif
    523 
    524 static int
    525 gpiosim_modcmd(modcmd_t cmd, void *opaque)
    526 {
    527 #ifdef _MODULE
    528 	int error = 0;
    529 #endif
    530 	switch (cmd) {
    531 	case MODULE_CMD_INIT:
    532 #ifdef _MODULE
    533 		error = config_cfdriver_attach(&gpiosim_cd);
    534 		if (error)
    535 			return error;
    536 
    537 		error = config_cfattach_attach(gpiosim_cd.cd_name,
    538 		    &gpiosim_ca);
    539 		if (error) {
    540 			config_cfdriver_detach(&gpiosim_cd);
    541 			aprint_error("%s: unable to register cfattach\n",
    542 			    gpiosim_cd.cd_name);
    543 			return error;
    544 		}
    545 		error = config_cfdata_attach(gpiosim_cfdata, 1);
    546 		if (error) {
    547 			config_cfattach_detach(gpiosim_cd.cd_name,
    548 			    &gpiosim_ca);
    549 			config_cfdriver_detach(&gpiosim_cd);
    550 			aprint_error("%s: unable to register cfdata\n",
    551 			    gpiosim_cd.cd_name);
    552 			return error;
    553 		}
    554 		config_attach_pseudo(gpiosim_cfdata);
    555 #endif
    556 		return 0;
    557 	case MODULE_CMD_FINI:
    558 #ifdef _MODULE
    559 		error = config_cfdata_detach(gpiosim_cfdata);
    560 		if (error)
    561 			return error;
    562 
    563 		config_cfattach_detach(gpiosim_cd.cd_name, &gpiosim_ca);
    564 		config_cfdriver_detach(&gpiosim_cd);
    565 #endif
    566 		return 0;
    567 	case MODULE_CMD_AUTOUNLOAD:
    568 		/* no auto-unload */
    569 		return EBUSY;
    570 	default:
    571 		return ENOTTY;
    572 	}
    573 }
    574