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