1 1.1 brad 2 1.3 andvar /* $NetBSD: scmd.c,v 1.3 2022/10/06 19:38:54 andvar 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.3 andvar __KERNEL_RCSID(0, "$NetBSD: scmd.c,v 1.3 2022/10/06 19:38:54 andvar 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.3 andvar /* This is a meaningless assignment 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.3 andvar * a restart and not re-enumeration, 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 = devsw_attach("scmd", NULL, &bmaj, 596 1.1 brad &scmd_cdevsw, &cmaj); 597 1.1 brad if (error) { 598 1.1 brad aprint_error("%s: unable to attach devsw: %d\n", 599 1.1 brad scmd_cd.cd_name, error); 600 1.2 pgoyette return error; 601 1.1 brad } 602 1.1 brad 603 1.2 pgoyette error = config_init_component(cfdriver_ioconf_scmd, 604 1.2 pgoyette cfattach_ioconf_scmd, cfdata_ioconf_scmd); 605 1.2 pgoyette if (error) { 606 1.2 pgoyette aprint_error("%s: unable to init component: %d\n", 607 1.2 pgoyette scmd_cd.cd_name, error); 608 1.2 pgoyette devsw_detach(NULL, &scmd_cdevsw); 609 1.2 pgoyette } 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 error = config_fini_component(cfdriver_ioconf_scmd, 617 1.1 brad cfattach_ioconf_scmd, cfdata_ioconf_scmd); 618 1.2 pgoyette devsw_detach(NULL, &scmd_cdevsw); 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