Home | History | Annotate | Line # | Download | only in gpio
gpiosim.c revision 1.25
      1 /* $NetBSD: gpiosim.c,v 1.25 2023/11/08 23:46:54 brad 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 	int error;
    223 
    224 	/* Detach the gpio driver that attached here */
    225 	error = config_detach_children(self, flags);
    226 	if (error)
    227 		return error;
    228 
    229 	pmf_device_deregister(self);
    230 
    231 	if (sc->sc_log != NULL) {
    232 		sysctl_teardown(&sc->sc_log);
    233 		sc->sc_log = NULL;
    234 	}
    235 
    236 	/* Destroy the workqueue, hope that it is empty */
    237 	if (sc->sc_wq != NULL) {
    238 		workqueue_destroy(sc->sc_wq);
    239 	}
    240 
    241 	sc->sc_co_running = false;
    242 
    243 	/* Destroy any callouts */
    244 	if (sc->sc_co_init) {
    245 		callout_halt(&sc->sc_co,NULL);
    246 		callout_destroy(&sc->sc_co);
    247 	}
    248 	return 0;
    249 }
    250 
    251 static int
    252 gpiosim_sysctl(SYSCTLFN_ARGS)
    253 {
    254 	struct sysctlnode node;
    255 	struct gpiosim_softc *sc;
    256 	uint64_t val, error;
    257 	uint64_t previous_val;
    258 	int i;
    259 	struct gpiosim_irq *irq;
    260 	int t = 0;
    261 
    262 	node = *rnode;
    263 	sc = node.sysctl_data;
    264 
    265 	node.sysctl_data = &val;
    266 
    267 	val = sc->sc_state;
    268 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    269 	if (error || newp == NULL)
    270 		return error;
    271 
    272 	mutex_enter(&sc->sc_intr_mutex);
    273 	previous_val = sc->sc_state;
    274 	sc->sc_state = val;
    275 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    276 		irq = &sc->sc_gpio_irqs[i];
    277 		/* Simulate edge interrupts ... */
    278 		if ((previous_val & (1LL << i)) == 0 && (sc->sc_state & (1LL << i)) &&
    279 		    irq->sc_gpio_irqfunc != NULL &&
    280 		    (irq->sc_gpio_irqmode & (GPIO_INTR_POS_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    281 			irq->sc_gpio_irqtriggered = true;
    282 			t++;
    283 		}
    284 		if ((previous_val & (1LL << i)) && (sc->sc_state & (1LL << i)) == 0 &&
    285 		    irq->sc_gpio_irqfunc != NULL &&
    286 		    (irq->sc_gpio_irqmode & (GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    287 			irq->sc_gpio_irqtriggered = true;
    288 			t++;
    289 		}
    290 		/* Simulate level interrupts ... */
    291 		if ((sc->sc_state & (1LL << i)) && irq->sc_gpio_irqfunc != NULL &&
    292 		    (irq->sc_gpio_irqmode & GPIO_INTR_HIGH_LEVEL)) {
    293 			irq->sc_gpio_irqtriggered = true;
    294 		}
    295 		if ((sc->sc_state & (1LL << i)) == 0 && irq->sc_gpio_irqfunc != NULL &&
    296 		    (irq->sc_gpio_irqmode & GPIO_INTR_LOW_LEVEL)) {
    297 			irq->sc_gpio_irqtriggered = true;
    298 		}
    299 		if ((sc->sc_state & (1LL << i)) && irq->sc_gpio_irqfunc != NULL &&
    300 		    (irq->sc_gpio_irqmode & GPIO_INTR_LOW_LEVEL)) {
    301 			irq->sc_gpio_irqtriggered = false;
    302 		}
    303 		if ((sc->sc_state & (1LL << i)) == 0 && irq->sc_gpio_irqfunc != NULL &&
    304 		    (irq->sc_gpio_irqmode & GPIO_INTR_HIGH_LEVEL)) {
    305 			irq->sc_gpio_irqtriggered = false;
    306 		}
    307 	}
    308 	mutex_exit(&sc->sc_intr_mutex);
    309 
    310 	if (t > 0) {
    311 		workqueue_enqueue(sc->sc_wq,(struct work *)&gpiosim_work,NULL);
    312 	}
    313 
    314 	return 0;
    315 }
    316 
    317 int
    318 gpiosim_ms_sysctl(SYSCTLFN_ARGS)
    319 {
    320 	int error, t;
    321 	struct sysctlnode node;
    322 
    323 	node = *rnode;
    324 	t = *(int*)rnode->sysctl_data;
    325 	node.sysctl_data = &t;
    326 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    327 	if (error || newp == NULL)
    328 		return (error);
    329 
    330 	if (t < 1)
    331 		return (EINVAL);
    332 
    333 	*(int*)rnode->sysctl_data = t;
    334 
    335 	return (0);
    336 }
    337 
    338 /* Interrupts though the read and write path are not simulated,
    339  * that is, an interrupt on the setting of an output or an
    340  * interrupt on a pin read.  It is not at all clear that it makes
    341  * any sense to do any of that, although real hardware in some cases
    342  * might trigger an interrupt on an output pin.
    343  */
    344 
    345 static int
    346 gpiosim_pin_read(void *arg, int pin)
    347 {
    348 	struct gpiosim_softc *sc = arg;
    349 
    350 	if (sc->sc_state & (1LL << pin))
    351 		return GPIO_PIN_HIGH;
    352 	else
    353 		return GPIO_PIN_LOW;
    354 }
    355 
    356 static void
    357 gpiosim_pin_write(void *arg, int pin, int value)
    358 {
    359 	struct gpiosim_softc *sc = arg;
    360 
    361 	if (value == 0)
    362 		sc->sc_state &= ~(1LL << pin);
    363 	else
    364 		sc->sc_state |= (1LL << pin);
    365 }
    366 
    367 static void
    368 gpiosim_pin_ctl(void *arg, int pin, int flags)
    369 {
    370 	struct gpiosim_softc *sc = arg;
    371 
    372 	sc->sc_gpio_pins[pin].pin_flags = flags;
    373 }
    374 
    375 static void *
    376 gpiosim_intr_establish(void *vsc, int pin, int ipl, int irqmode,
    377     int (*func)(void *), void *arg)
    378 {
    379 	struct gpiosim_softc * const sc = vsc;
    380 	struct gpiosim_irq *irq;
    381 
    382 	mutex_enter(&sc->sc_intr_mutex);
    383 	irq = &sc->sc_gpio_irqs[pin];
    384 	irq->sc_gpio_irqfunc = func;
    385 	irq->sc_gpio_irqmode = irqmode;
    386 	irq->sc_gpio_irqarg = arg;
    387 
    388 	/* The first level interrupt starts the callout if it is not running */
    389 	if (((irqmode & GPIO_INTR_HIGH_LEVEL) ||
    390 	    (irqmode & GPIO_INTR_LOW_LEVEL)) &&
    391 	    (sc->sc_co_running == false)) {
    392 		callout_schedule(&sc->sc_co,mstohz(sc->sc_ms));
    393 		sc->sc_co_running = true;
    394 	}
    395 
    396 	/* Level interrupts can start as soon as a IRQ handler is installed */
    397 	if (((irqmode & GPIO_INTR_HIGH_LEVEL) && (sc->sc_state & (1LL << pin))) ||
    398 	    ((irqmode & GPIO_INTR_LOW_LEVEL) && ((sc->sc_state & (1LL << pin)) == 0))) {
    399 		irq->sc_gpio_irqtriggered = true;
    400 	}
    401 
    402 	mutex_exit(&sc->sc_intr_mutex);
    403 
    404 	return(irq);
    405 }
    406 
    407 static void
    408 gpiosim_intr_disestablish(void *vsc, void *ih)
    409 {
    410 	struct gpiosim_softc * const sc = vsc;
    411 	struct gpiosim_irq *irq = ih;
    412 	struct gpiosim_irq *lirq;
    413 	int i;
    414 	bool has_level = false;
    415 
    416 	mutex_enter(&sc->sc_intr_mutex);
    417 	irq->sc_gpio_irqfunc = NULL;
    418 	irq->sc_gpio_irqmode = 0;
    419 	irq->sc_gpio_irqarg = NULL;
    420 	irq->sc_gpio_irqtriggered = false;
    421 
    422 	/* Check for any level interrupts and stop the callout
    423 	 * if there are none.
    424 	 */
    425 	for (i = 0;i < GPIOSIM_NPINS; i++) {
    426 		lirq = &sc->sc_gpio_irqs[i];
    427 		if (lirq->sc_gpio_irqmode & (GPIO_INTR_HIGH_LEVEL | GPIO_INTR_LOW_LEVEL)) {
    428 			has_level = true;
    429 			break;
    430 		}
    431 	}
    432 	if (has_level == false) {
    433 		sc->sc_co_running = false;
    434 	}
    435 	mutex_exit(&sc->sc_intr_mutex);
    436 }
    437 
    438 static bool
    439 gpiosim_gpio_intrstr(void *vsc, int pin, int irqmode, char *buf, size_t buflen)
    440 {
    441 
    442         if (pin < 0 || pin >= GPIOSIM_NPINS)
    443                 return (false);
    444 
    445         snprintf(buf, buflen, "GPIO %d", pin);
    446 
    447         return (true);
    448 }
    449 
    450 /* The workqueue handles edge the simulation of edge interrupts */
    451 void
    452 gpiosim_wq(struct work *wk, void *arg)
    453 {
    454 	struct gpiosim_softc *sc = arg;
    455 	struct gpiosim_irq *irq;
    456 	int i;
    457 
    458 	mutex_enter(&sc->sc_intr_mutex);
    459 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    460 		irq = &sc->sc_gpio_irqs[i];
    461 		if (irq->sc_gpio_irqtriggered &&
    462 		    irq->sc_gpio_irqfunc != NULL &&
    463 		    (irq->sc_gpio_irqmode & (GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE))) {
    464 			(*irq->sc_gpio_irqfunc)(irq->sc_gpio_irqarg);
    465 			irq->sc_gpio_irqtriggered = false;
    466 		}
    467 	}
    468 	mutex_exit(&sc->sc_intr_mutex);
    469 }
    470 
    471 /* This runs as long as there are level interrupts to simulate */
    472 void
    473 gpiosim_co(void *arg)
    474 {
    475 	struct gpiosim_softc *sc = arg;
    476 	struct gpiosim_irq *irq;
    477 	int i;
    478 
    479 	mutex_enter(&sc->sc_intr_mutex);
    480 	for (i = 0; i < GPIOSIM_NPINS; i++) {
    481 		irq = &sc->sc_gpio_irqs[i];
    482 		if (irq->sc_gpio_irqtriggered &&
    483 		    irq->sc_gpio_irqfunc != NULL &&
    484 		    (irq->sc_gpio_irqmode & (GPIO_INTR_HIGH_LEVEL | GPIO_INTR_LOW_LEVEL))) {
    485 			(*irq->sc_gpio_irqfunc)(irq->sc_gpio_irqarg);
    486 		}
    487 	}
    488 	mutex_exit(&sc->sc_intr_mutex);
    489 
    490 	if (sc->sc_co_running == true) {
    491 		callout_schedule(&sc->sc_co,mstohz(sc->sc_ms));
    492 	}
    493 }
    494 
    495 
    496 MODULE(MODULE_CLASS_DRIVER, gpiosim, "gpio");
    497 
    498 #ifdef _MODULE
    499 static const struct cfiattrdata gpiobus_iattrdata = {
    500 	"gpiobus", 0, { { NULL, NULL, 0 },}
    501 };
    502 static const struct cfiattrdata *const gpiosim_attrs[] = {
    503 	&gpiobus_iattrdata, NULL
    504 };
    505 CFDRIVER_DECL(gpiosim, DV_DULL, gpiosim_attrs);
    506 extern struct cfattach gpiosim_ca;
    507 static int gpiosimloc[] = {
    508 	-1,
    509 	-1,
    510 	-1
    511 };
    512 static struct cfdata gpiosim_cfdata[] = {
    513 	{
    514 		.cf_name = "gpiosim",
    515 		.cf_atname = "gpiosim",
    516 		.cf_unit = 0,
    517 		.cf_fstate = FSTATE_STAR,
    518 		.cf_loc = gpiosimloc,
    519 		.cf_flags = 0,
    520 		.cf_pspec = NULL,
    521 	},
    522 	{ NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
    523 };
    524 #endif
    525 
    526 static int
    527 gpiosim_modcmd(modcmd_t cmd, void *opaque)
    528 {
    529 #ifdef _MODULE
    530 	int error = 0;
    531 #endif
    532 	switch (cmd) {
    533 	case MODULE_CMD_INIT:
    534 #ifdef _MODULE
    535 		error = config_cfdriver_attach(&gpiosim_cd);
    536 		if (error)
    537 			return error;
    538 
    539 		error = config_cfattach_attach(gpiosim_cd.cd_name,
    540 		    &gpiosim_ca);
    541 		if (error) {
    542 			config_cfdriver_detach(&gpiosim_cd);
    543 			aprint_error("%s: unable to register cfattach\n",
    544 			    gpiosim_cd.cd_name);
    545 			return error;
    546 		}
    547 		error = config_cfdata_attach(gpiosim_cfdata, 1);
    548 		if (error) {
    549 			config_cfattach_detach(gpiosim_cd.cd_name,
    550 			    &gpiosim_ca);
    551 			config_cfdriver_detach(&gpiosim_cd);
    552 			aprint_error("%s: unable to register cfdata\n",
    553 			    gpiosim_cd.cd_name);
    554 			return error;
    555 		}
    556 		config_attach_pseudo(gpiosim_cfdata);
    557 #endif
    558 		return 0;
    559 	case MODULE_CMD_FINI:
    560 #ifdef _MODULE
    561 		error = config_cfdata_detach(gpiosim_cfdata);
    562 		if (error)
    563 			return error;
    564 
    565 		config_cfattach_detach(gpiosim_cd.cd_name, &gpiosim_ca);
    566 		config_cfdriver_detach(&gpiosim_cd);
    567 #endif
    568 		return 0;
    569 	case MODULE_CMD_AUTOUNLOAD:
    570 		/* no auto-unload */
    571 		return EBUSY;
    572 	default:
    573 		return ENOTTY;
    574 	}
    575 }
    576