scmd.c revision 1.3 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