Home | History | Annotate | Line # | Download | only in ic
      1 
      2 /*	$NetBSD: scmd.c,v 1.3 2022/10/06 19:38:54 andvar Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __KERNEL_RCSID(0, "$NetBSD: scmd.c,v 1.3 2022/10/06 19:38:54 andvar Exp $");
     22 
     23 /*
     24  * Common driver for the Sparkfun Serial motor controller.
     25  * Calls out to specific frontends to move bits.
     26 */
     27 
     28 #include <sys/param.h>
     29 #include <sys/systm.h>
     30 #include <sys/kernel.h>
     31 #include <sys/device.h>
     32 #include <sys/module.h>
     33 #include <sys/conf.h>
     34 #include <sys/sysctl.h>
     35 #include <sys/mutex.h>
     36 #include <sys/pool.h>
     37 #include <sys/kmem.h>
     38 
     39 #include <dev/i2c/i2cvar.h>
     40 #include <dev/spi/spivar.h>
     41 #include <dev/ic/scmdreg.h>
     42 #include <dev/ic/scmdvar.h>
     43 
     44 void		scmd_attach(struct scmd_sc *);
     45 static void	scmd_wait_restart(struct scmd_sc *, bool);
     46 static int	scmd_get_topaddr(struct scmd_sc *);
     47 static int 	scmd_verify_sysctl(SYSCTLFN_ARGS);
     48 static int	scmd_local_read(struct scmd_sc *, uint8_t, uint8_t *);
     49 static int	scmd_remote_read(struct scmd_sc *, int, uint8_t *);
     50 static int	scmd_local_write(struct scmd_sc *, uint8_t, uint8_t);
     51 static int	scmd_remote_write(struct scmd_sc *, int, uint8_t);
     52 
     53 #define SCMD_DEBUG
     54 #ifdef SCMD_DEBUG
     55 #define DPRINTF(s, l, x) \
     56     do { \
     57 	if (l <= s->sc_scmddebug) \
     58 	    printf x; \
     59     } while (/*CONSTCOND*/0)
     60 #else
     61 #define DPRINTF(s, l, x)
     62 #endif
     63 
     64 extern struct cfdriver scmd_cd;
     65 
     66 static dev_type_open(scmd_open);
     67 static dev_type_read(scmd_read);
     68 static dev_type_write(scmd_write);
     69 static dev_type_close(scmd_close);
     70 const struct cdevsw scmd_cdevsw = {
     71 	.d_open = scmd_open,
     72 	.d_close = scmd_close,
     73 	.d_read = scmd_read,
     74 	.d_write = scmd_write,
     75 	.d_ioctl = noioctl,
     76 	.d_stop = nostop,
     77 	.d_tty = notty,
     78 	.d_poll = nopoll,
     79 	.d_mmap = nommap,
     80 	.d_kqfilter = nokqfilter,
     81 	.d_discard = nodiscard,
     82 	.d_flag = D_OTHER
     83 };
     84 
     85 static int
     86 scmd_verify_sysctl(SYSCTLFN_ARGS)
     87 {
     88 	int error, t;
     89 	struct sysctlnode node;
     90 
     91 	node = *rnode;
     92 	t = *(int *)rnode->sysctl_data;
     93 	node.sysctl_data = &t;
     94 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
     95 	if (error || newp == NULL)
     96 		return error;
     97 
     98 	if (t < 0)
     99 		return EINVAL;
    100 
    101 	*(int *)rnode->sysctl_data = t;
    102 
    103 	return 0;
    104 }
    105 
    106 static int
    107 scmd_sysctl_init(struct scmd_sc *sc)
    108 {
    109 	int error;
    110 	const struct sysctlnode *cnode;
    111 	int sysctlroot_num;
    112 
    113 	if ((error = sysctl_createv(&sc->sc_scmdlog, 0, NULL, &cnode,
    114 	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
    115 	    SYSCTL_DESCR("scmd controls"), NULL, 0, NULL, 0, CTL_HW,
    116 	    CTL_CREATE, CTL_EOL)) != 0)
    117 		return error;
    118 
    119 	sysctlroot_num = cnode->sysctl_num;
    120 
    121 #ifdef SCMD_DEBUG
    122 	if ((error = sysctl_createv(&sc->sc_scmdlog, 0, NULL, &cnode,
    123 	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
    124 	    SYSCTL_DESCR("Debug level"), scmd_verify_sysctl, 0,
    125 	    &sc->sc_scmddebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
    126 	    CTL_EOL)) != 0)
    127 		return error;
    128 
    129 #endif
    130 
    131 	return 0;
    132 }
    133 
    134 /* Restarts and re-enumeration of the device is a little strange.
    135  * It will take a very long time to complete.  It would be more polite
    136  * to use a condvar for this wait, but it was noticed that those may
    137  * not work if done too early in boot and will just hang the boot, so
    138  * delay is also offered as an option.
    139  */
    140 static void
    141 scmd_wait_restart(struct scmd_sc *sc, bool usedelay)
    142 {
    143 	int error;
    144 	uint8_t buf = SCMD_HOLE_VALUE;
    145 	int c = 0;
    146 
    147 	do {
    148 		if (usedelay) {
    149 			delay(1000000);
    150 		} else {
    151 			mutex_enter(&sc->sc_condmutex);
    152 			cv_timedwait(&sc->sc_condvar, &sc->sc_condmutex,
    153 			    mstohz(1000));
    154 			mutex_exit(&sc->sc_condmutex);
    155 		}
    156 
    157 		error = (*(sc->sc_func_read_register))(sc, SCMD_REG_STATUS_1, &buf);
    158 
    159 		DPRINTF(sc, 2, ("%s: Read back status after restart: %02x %d\n",
    160 		    device_xname(sc->sc_dev), buf, error));
    161 
    162 		c++;
    163 	} while (c <= 20 && buf != 0x00);
    164 }
    165 
    166 static int
    167 scmd_get_topaddr(struct scmd_sc *sc)
    168 {
    169 	uint8_t topaddr;
    170 	int error;
    171 
    172 	error = (*(sc->sc_func_read_register))(sc, SCMD_REG_SLV_TOP_ADDR, &topaddr);
    173 
    174 	if (error) {
    175 		topaddr = 0;
    176 	}
    177 	return topaddr;
    178 }
    179 
    180 /* Note that this assumes that you can actually access the device.
    181  * In at least one case right now, SPI on a Raspberry PI 3, the pins
    182  * have not been set up to allow SPI to function, but nothing is
    183  * returned as an error either.  We do the best that can be done right
    184  * now.
    185  */
    186 void
    187 scmd_attach(struct scmd_sc *sc)
    188 {
    189 	int error;
    190 
    191 	aprint_normal("\n");
    192 
    193 	if ((error = scmd_sysctl_init(sc)) != 0) {
    194 		aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error);
    195 		goto out;
    196 	}
    197 
    198 	error = (*(sc->sc_func_acquire_bus))(sc);
    199 	if (error) {
    200 		aprint_error_dev(sc->sc_dev, "Could not acquire iic bus: %d\n",
    201 		    error);
    202 		goto out;
    203 	}
    204 
    205 	error = (*(sc->sc_func_write_register))(sc, SCMD_REG_CONTROL_1, SCMD_CONTROL_1_RESTART);
    206 	if (error != 0)
    207 		aprint_error_dev(sc->sc_dev, "Reset failed: %d\n", error);
    208 
    209 	scmd_wait_restart(sc, true);
    210 
    211 	sc->sc_topaddr = scmd_get_topaddr(sc);
    212 
    213 	DPRINTF(sc, 2, ("%s: Top remote module address: %02x\n",
    214 	    device_xname(sc->sc_dev), sc->sc_topaddr));
    215 
    216 	uint8_t fwversion;
    217 	uint8_t id;
    218 	uint8_t pins;
    219 
    220 	error = (*(sc->sc_func_read_register))(sc, SCMD_REG_FID, &fwversion);
    221 	if (error) {
    222 		aprint_error_dev(sc->sc_dev, "Read of FID failed: %d\n",
    223 		    error);
    224 		goto out;
    225 	}
    226 
    227 	error = (*(sc->sc_func_read_register))(sc, SCMD_REG_ID, &id);
    228 	if (error) {
    229 		aprint_error_dev(sc->sc_dev, "Read of ID failed: %d\n",
    230 		    error);
    231 		goto out;
    232 	}
    233 
    234 	error = (*(sc->sc_func_read_register))(sc, SCMD_REG_CONFIG_BITS, &pins);
    235 	if (error) {
    236 		aprint_error_dev(sc->sc_dev, "Read of CONFIG_BITS failed: %d\n",
    237 		    error);
    238 		goto out;
    239 	}
    240 
    241 	aprint_normal_dev(sc->sc_dev, "Sparkfun Serial motor controller, "
    242 	    "Firmware version: %02x, ID: %02x%s, Jumper pins: %02x\n",
    243 	    fwversion, id, (id == SCMD_EXPECTED_ID) ? " (expected ID)" : " (unexpected ID)",
    244 	    pins);
    245 
    246  out:
    247 	(*(sc->sc_func_release_bus))(sc);
    248 	if (error != 0) {
    249 		aprint_error_dev(sc->sc_dev, "Unable to setup device\n");
    250 	}
    251 
    252 	return;
    253 }
    254 
    255 /* This device has the effect of creating a virtual register space of all
    256  * of the attached modules.  All you have to do is read and write to anything
    257  * in that space and you can hit the main module and all chained slave modules
    258  * without having to worry about the view port set up.
    259  *
    260  * 0x00 - 0x7E -- the first and main module
    261  * 0x7F - 0xFD -- the first slaved module
    262  * ...etc...
    263  *
    264  */
    265 static int
    266 scmd_open(dev_t dev, int flags, int fmt, struct lwp *l)
    267 {
    268 	struct scmd_sc *sc;
    269 
    270 	sc = device_lookup_private(&scmd_cd, minor(dev));
    271 	if (!sc)
    272 		return ENXIO;
    273 
    274 	if (sc->sc_opened)
    275 		return EBUSY;
    276 
    277 	/* This is a meaningless assignment to keep GCC from
    278 	 * complaining.
    279 	 */
    280 	sc->sc_func_attach = &scmd_attach;
    281 
    282 	mutex_enter(&sc->sc_mutex);
    283 	sc->sc_opened = true;
    284 	mutex_exit(&sc->sc_mutex);
    285 
    286 	return 0;
    287 }
    288 
    289 static int
    290 scmd_maxregister(int topaddr)
    291 {
    292 	if (topaddr >= SCMD_REMOTE_ADDR_LOW &&
    293 	    topaddr <= SCMD_REMOTE_ADDR_HIGH) {
    294 		int i = (topaddr - SCMD_REMOTE_ADDR_LOW) + 2;
    295 		return (SCMD_REG_SIZE * i) - 1;
    296 	} else {
    297 		return SCMD_LAST_REG;
    298 	}
    299 }
    300 
    301 /* Please note that that setting up and using the view port
    302  * to get access to SCMD devices that are chained off of the main
    303  * device is not atomic.  Hopefully this all happens fast enough
    304  * so that nothing can sneak in and mess with the registers.
    305  */
    306 static int
    307 scmd_set_view_port(struct scmd_sc *sc, int reg)
    308 {
    309 	int err;
    310 	int loc = reg / SCMD_REG_SIZE;
    311 	uint8_t vpi2creg = reg % SCMD_REG_SIZE;
    312 	uint8_t vpi2caddr = (SCMD_REMOTE_ADDR_LOW + loc) - 1;
    313 
    314 	DPRINTF(sc, 2, ("%s: View port addr: %02x ; View port register: %02x ; Orig register: %04x\n",
    315 	    device_xname(sc->sc_dev), vpi2caddr, vpi2creg, reg));
    316 
    317 	err = (*(sc->sc_func_write_register))(sc, SCMD_REG_REM_ADDR, vpi2caddr);
    318 	if (! err)
    319 		err = (*(sc->sc_func_write_register))(sc, SCMD_REG_REM_OFFSET, vpi2creg);
    320 
    321 	return err;
    322 }
    323 
    324 /* It is not defined what happens if the Not Defined in the datasheet
    325  * registers are accessed, so block them.
    326  */
    327 static int
    328 scmd_local_read(struct scmd_sc *sc, uint8_t reg, uint8_t *buf)
    329 {
    330 	if (SCMD_IS_HOLE(reg)) {
    331 		*buf = SCMD_HOLE_VALUE;
    332 		return 0;
    333 	}
    334 
    335 	return (*(sc->sc_func_read_register))(sc, reg, buf);
    336 }
    337 
    338 static int
    339 scmd_remote_read(struct scmd_sc *sc, int reg, uint8_t *buf)
    340 {
    341 	int err;
    342 	int c;
    343 	uint8_t b;
    344 
    345 	if (SCMD_IS_HOLE(reg % SCMD_REG_SIZE)) {
    346 		*buf = SCMD_HOLE_VALUE;
    347 		return 0;
    348 	}
    349 
    350 	err = scmd_set_view_port(sc, reg);
    351 	if (! err) {
    352 		b = 0xff; /* you can write anything here.. it doesn't matter */
    353 		err = (*(sc->sc_func_write_register))(sc, SCMD_REG_REM_READ, b);
    354 		if (! err) {
    355 			/* So ...  there is no way to really know that the data is ready and
    356 			 * there is no way to know if there was an error in the master module reading
    357 			 * the data from the slave module.  The data sheet says wait 5ms.. so do that
    358 			 * and see if the register cleared, but don't wait forever...  I can't see how
    359 			 * it would not be possible to read junk at times.
    360 			 */
    361 			c = 0;
    362 			do {
    363 				delay(5000);
    364 				err = (*(sc->sc_func_read_register))(sc, SCMD_REG_REM_READ, &b);
    365 				c++;
    366 			} while ((c < 10) && (b != 0x00) && (!err));
    367 			/* We can only hope that whatever was read from the slave module is there */
    368 			if (! err)
    369 				err = (*(sc->sc_func_read_register))(sc, SCMD_REG_REM_DATA_RD, buf);
    370 		}
    371 	}
    372 
    373 	return err;
    374 }
    375 
    376 static int
    377 scmd_read(dev_t dev, struct uio *uio, int flags)
    378 {
    379 	struct scmd_sc *sc;
    380 	int error;
    381 
    382 	if ((sc = device_lookup_private(&scmd_cd, minor(dev))) == NULL)
    383 		return ENXIO;
    384 
    385 	/* We do not make this an error.  There is nothing wrong with running
    386 	 * off the end here, just return EOF.
    387 	 */
    388 	if (uio->uio_offset > scmd_maxregister(sc->sc_topaddr))
    389 		return 0;
    390 
    391 	if ((error = (*(sc->sc_func_acquire_bus))(sc)) != 0)
    392 		return error;
    393 
    394 	while (uio->uio_resid &&
    395 	    uio->uio_offset <= scmd_maxregister(sc->sc_topaddr) &&
    396 	    !sc->sc_dying) {
    397 		uint8_t buf;
    398 		int reg_addr = uio->uio_offset;
    399 
    400 		if (reg_addr <= SCMD_LAST_REG) {
    401 			if ((error = scmd_local_read(sc, (uint8_t)reg_addr, &buf)) != 0) {
    402 				(*(sc->sc_func_release_bus))(sc);
    403 				aprint_error_dev(sc->sc_dev,
    404 				    "%s: local read failed at 0x%02x: %d\n",
    405 				    __func__, reg_addr, error);
    406 				return error;
    407 			}
    408 		} else {
    409 			if ((error = scmd_remote_read(sc, reg_addr, &buf)) != 0) {
    410 				(*(sc->sc_func_release_bus))(sc);
    411 				aprint_error_dev(sc->sc_dev,
    412 				    "%s: remote read failed at 0x%02x: %d\n",
    413 				    __func__, reg_addr, error);
    414 				return error;
    415 			}
    416 		}
    417 
    418 		if (sc->sc_dying)
    419 			break;
    420 
    421 		if ((error = uiomove(&buf, 1, uio)) != 0) {
    422 			(*(sc->sc_func_release_bus))(sc);
    423 			return error;
    424 		}
    425 	}
    426 
    427 	(*(sc->sc_func_release_bus))(sc);
    428 
    429 	if (sc->sc_dying) {
    430 		return EIO;
    431 	}
    432 
    433 	return 0;
    434 }
    435 
    436 /* Same thing about the undefined registers.  Don't actually allow
    437  * writes as it is not clear what happens when you do that.
    438  */
    439 static int
    440 scmd_local_write(struct scmd_sc *sc, uint8_t reg, uint8_t buf)
    441 {
    442 	if (SCMD_IS_HOLE(reg))
    443 		return 0;
    444 
    445 	return (*(sc->sc_func_write_register))(sc, reg, buf);
    446 }
    447 
    448 static int
    449 scmd_remote_write(struct scmd_sc *sc, int reg, uint8_t buf)
    450 {
    451 	int err;
    452 	int c;
    453 	uint8_t b;
    454 
    455 	if (SCMD_IS_HOLE(reg % SCMD_REG_SIZE)) {
    456 		return 0;
    457 	}
    458 
    459 	err = scmd_set_view_port(sc, reg);
    460 	if (! err) {
    461 		/* We just sort of send this write off and wait to see if the register
    462 		 * clears.  There really isn't any indication that the data made it to the
    463 		 * slave modules and there really are not any errors reported.
    464 		 */
    465 		err = (*(sc->sc_func_write_register))(sc, SCMD_REG_REM_DATA_WR, buf);
    466 		if (! err) {
    467 			b = 0xff; /* you can write anything here.. it doesn't matter */
    468 			err = (*(sc->sc_func_write_register))(sc, SCMD_REG_REM_WRITE, b);
    469 			if (! err) {
    470 				c = 0;
    471 				do {
    472 					delay(5000);
    473 					err = (*(sc->sc_func_read_register))(sc, SCMD_REG_REM_WRITE, &b);
    474 					c++;
    475 				} while ((c < 10) && (b != 0x00) && (!err));
    476 			}
    477 		}
    478 	}
    479 
    480 	return err;
    481 }
    482 
    483 static int
    484 scmd_write(dev_t dev, struct uio *uio, int flags)
    485 {
    486 	struct scmd_sc *sc;
    487 	int error;
    488 
    489 	if ((sc = device_lookup_private(&scmd_cd, minor(dev))) == NULL)
    490 		return ENXIO;
    491 
    492 	/* Same thing as read, this is not considered an error */
    493 	if (uio->uio_offset > scmd_maxregister(sc->sc_topaddr))
    494 		return 0;
    495 
    496 	if ((error = (*(sc->sc_func_acquire_bus))(sc)) != 0)
    497 		return error;
    498 
    499 	while (uio->uio_resid &&
    500 	    uio->uio_offset <= scmd_maxregister(sc->sc_topaddr) &&
    501 	    !sc->sc_dying) {
    502 		uint8_t buf;
    503 		int reg_addr = uio->uio_offset;
    504 
    505 		if ((error = uiomove(&buf, 1, uio)) != 0)
    506 			break;
    507 
    508 		if (sc->sc_dying)
    509 			break;
    510 
    511 		if (reg_addr <= SCMD_LAST_REG) {
    512 			if ((error = scmd_local_write(sc, (uint8_t)reg_addr, buf)) != 0) {
    513 				(*(sc->sc_func_release_bus))(sc);
    514 				aprint_error_dev(sc->sc_dev,
    515 				    "%s: local write failed at 0x%02x: %d\n",
    516 				    __func__, reg_addr, error);
    517 				return error;
    518 			}
    519 
    520 			/* If this was a local command to the control register that
    521 			 * can perform re-enumeration, then do the wait thing.
    522 			 * It is not as important that this be done for remote module
    523 			 * access as the only thing that you could really do there is
    524 			 * a restart and not re-enumeration, which is really what the wait
    525 			 * is all about.
    526 			 */
    527 			if (reg_addr == SCMD_REG_CONTROL_1) {
    528 				scmd_wait_restart(sc, false);
    529 
    530 				sc->sc_topaddr = scmd_get_topaddr(sc);
    531 				aprint_normal_dev(sc->sc_dev, "Highest I2C address on expansion bus is: %02x\n",
    532 				    sc->sc_topaddr);
    533 			}
    534 		} else {
    535 			if ((error = scmd_remote_write(sc, reg_addr, buf)) != 0) {
    536 				(*(sc->sc_func_release_bus))(sc);
    537 				aprint_error_dev(sc->sc_dev,
    538 				    "%s: remote write failed at 0x%02x: %d\n",
    539 				    __func__, reg_addr, error);
    540 				return error;
    541 			}
    542 		}
    543 	}
    544 
    545 	(*(sc->sc_func_release_bus))(sc);
    546 
    547 	if (sc->sc_dying) {
    548 		return EIO;
    549 	}
    550 
    551 	return error;
    552 }
    553 
    554 static int
    555 scmd_close(dev_t dev, int flags, int fmt, struct lwp *l)
    556 {
    557 	struct scmd_sc *sc;
    558 
    559 	sc = device_lookup_private(&scmd_cd, minor(dev));
    560 
    561 	if (sc->sc_dying) {
    562 		DPRINTF(sc, 2, ("%s: Telling all we are almost dead\n",
    563 		    device_xname(sc->sc_dev)));
    564 		mutex_enter(&sc->sc_dying_mutex);
    565 		cv_signal(&sc->sc_cond_dying);
    566 		mutex_exit(&sc->sc_dying_mutex);
    567 		return EIO;
    568 	}
    569 
    570 	mutex_enter(&sc->sc_mutex);
    571 	sc->sc_opened = false;
    572 	mutex_exit(&sc->sc_mutex);
    573 
    574 	return(0);
    575 }
    576 
    577 MODULE(MODULE_CLASS_DRIVER, scmd, NULL);
    578 
    579 #ifdef _MODULE
    580 CFDRIVER_DECL(scmd, DV_DULL, NULL);
    581 #include "ioconf.c"
    582 #endif
    583 
    584 static int
    585 scmd_modcmd(modcmd_t cmd, void *opaque)
    586 {
    587 #ifdef _MODULE
    588 	int error = 0;
    589 	int bmaj = -1, cmaj = -1;
    590 #endif
    591 
    592 	switch (cmd) {
    593 	case MODULE_CMD_INIT:
    594 #ifdef _MODULE
    595 		error = devsw_attach("scmd", NULL, &bmaj,
    596 		    &scmd_cdevsw, &cmaj);
    597 		if (error) {
    598 			aprint_error("%s: unable to attach devsw: %d\n",
    599 			    scmd_cd.cd_name, error);
    600 			return error;
    601 		}
    602 
    603 		error = config_init_component(cfdriver_ioconf_scmd,
    604 		    cfattach_ioconf_scmd, cfdata_ioconf_scmd);
    605 		if (error) {
    606 			aprint_error("%s: unable to init component: %d\n",
    607 			    scmd_cd.cd_name, error);
    608 			devsw_detach(NULL, &scmd_cdevsw);
    609 		}
    610 		return error;
    611 #else
    612 		return 0;
    613 #endif
    614 	case MODULE_CMD_FINI:
    615 #ifdef _MODULE
    616 		error = config_fini_component(cfdriver_ioconf_scmd,
    617 		    cfattach_ioconf_scmd, cfdata_ioconf_scmd);
    618 		devsw_detach(NULL, &scmd_cdevsw);
    619 
    620 		return error;
    621 #else
    622 		return 0;
    623 #endif
    624 	default:
    625 		return ENOTTY;
    626 	}
    627 }
    628