1 /* $OpenBSD: onewire.c,v 1.19 2022/04/06 18:59:29 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * 1-Wire bus driver.
21 */
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kernel.h>
27 #include <sys/kthread.h>
28 #include <sys/malloc.h>
29 #include <sys/queue.h>
30 #include <sys/rwlock.h>
31
32 #include <dev/onewire/onewirereg.h>
33 #include <dev/onewire/onewirevar.h>
34
35 #ifdef ONEWIRE_DEBUG
36 #define DPRINTF(x) printf x
37 #else
38 #define DPRINTF(x)
39 #endif
40
41 #define ONEWIRE_MAXDEVS 16
42 #define ONEWIRE_SCANTIME SEC_TO_NSEC(3)
43
44 struct onewire_softc {
45 struct device sc_dev;
46
47 struct onewire_bus * sc_bus;
48 struct rwlock sc_lock;
49 struct proc * sc_thread;
50 TAILQ_HEAD(, onewire_device) sc_devs;
51
52 int sc_dying;
53 int sc_flags;
54 u_int64_t sc_rombuf[ONEWIRE_MAXDEVS];
55 };
56
57 struct onewire_device {
58 TAILQ_ENTRY(onewire_device) d_list;
59 struct device * d_dev; /* may be NULL */
60 u_int64_t d_rom;
61 int d_present;
62 };
63
64 int onewire_match(struct device *, void *, void *);
65 void onewire_attach(struct device *, struct device *, void *);
66 int onewire_detach(struct device *, int);
67 int onewire_activate(struct device *, int);
68 int onewire_print(void *, const char *);
69
70 void onewire_thread(void *);
71 void onewire_createthread(void *);
72 void onewire_scan(struct onewire_softc *);
73
74 const struct cfattach onewire_ca = {
75 sizeof(struct onewire_softc),
76 onewire_match,
77 onewire_attach,
78 onewire_detach,
79 onewire_activate
80 };
81
82 struct cfdriver onewire_cd = {
83 NULL, "onewire", DV_DULL
84 };
85
86 int
onewire_match(struct device * parent,void * match,void * aux)87 onewire_match(struct device *parent, void *match, void *aux)
88 {
89 struct cfdata *cf = match;
90
91 return (strcmp(cf->cf_driver->cd_name, "onewire") == 0);
92 }
93
94 void
onewire_attach(struct device * parent,struct device * self,void * aux)95 onewire_attach(struct device *parent, struct device *self, void *aux)
96 {
97 struct onewire_softc *sc = (struct onewire_softc *)self;
98 struct onewirebus_attach_args *oba = aux;
99
100 sc->sc_bus = oba->oba_bus;
101 sc->sc_flags = oba->oba_flags;
102 rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
103 TAILQ_INIT(&sc->sc_devs);
104
105 printf("\n");
106
107 if (sc->sc_flags & ONEWIRE_SCAN_NOW) {
108 onewire_scan(sc);
109 if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
110 return;
111 }
112
113 kthread_create_deferred(onewire_createthread, sc);
114 }
115
116 int
onewire_detach(struct device * self,int flags)117 onewire_detach(struct device *self, int flags)
118 {
119 struct onewire_softc *sc = (struct onewire_softc *)self;
120
121 sc->sc_dying = 1;
122 if (sc->sc_thread != NULL) {
123 wakeup(sc->sc_thread);
124 tsleep_nsec(&sc->sc_dying, PWAIT, "owdt", INFSLP);
125 }
126
127 return (config_detach_children(self, flags));
128 }
129
130 int
onewire_activate(struct device * self,int act)131 onewire_activate(struct device *self, int act)
132 {
133 struct onewire_softc *sc = (struct onewire_softc *)self;
134
135 switch (act) {
136 case DVACT_DEACTIVATE:
137 sc->sc_dying = 1;
138 break;
139 }
140
141 return (config_activate_children(self, act));
142 }
143
144 int
onewire_print(void * aux,const char * pnp)145 onewire_print(void *aux, const char *pnp)
146 {
147 struct onewire_attach_args *oa = aux;
148 const char *famname;
149
150 if (pnp == NULL)
151 printf(" ");
152
153 famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
154 if (famname == NULL)
155 printf("family 0x%02x", ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
156 else
157 printf("\"%s\"", famname);
158 printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
159
160 if (pnp != NULL)
161 printf(" at %s", pnp);
162
163 return (UNCONF);
164 }
165
166 int
onewirebus_print(void * aux,const char * pnp)167 onewirebus_print(void *aux, const char *pnp)
168 {
169 if (pnp != NULL)
170 printf("onewire at %s", pnp);
171
172 return (UNCONF);
173 }
174
175 int
onewire_lock(void * arg,int flags)176 onewire_lock(void *arg, int flags)
177 {
178 struct onewire_softc *sc = arg;
179 int lflags = RW_WRITE;
180
181 if (flags & ONEWIRE_NOWAIT)
182 lflags |= RW_NOSLEEP;
183
184 return (rw_enter(&sc->sc_lock, lflags));
185 }
186
187 void
onewire_unlock(void * arg)188 onewire_unlock(void *arg)
189 {
190 struct onewire_softc *sc = arg;
191
192 rw_exit(&sc->sc_lock);
193 }
194
195 int
onewire_reset(void * arg)196 onewire_reset(void *arg)
197 {
198 struct onewire_softc *sc = arg;
199 struct onewire_bus *bus = sc->sc_bus;
200
201 return (bus->bus_reset(bus->bus_cookie));
202 }
203
204 int
onewire_bit(void * arg,int value)205 onewire_bit(void *arg, int value)
206 {
207 struct onewire_softc *sc = arg;
208 struct onewire_bus *bus = sc->sc_bus;
209
210 return (bus->bus_bit(bus->bus_cookie, value));
211 }
212
213 int
onewire_read_byte(void * arg)214 onewire_read_byte(void *arg)
215 {
216 struct onewire_softc *sc = arg;
217 struct onewire_bus *bus = sc->sc_bus;
218 u_int8_t value = 0;
219 int i;
220
221 if (bus->bus_read_byte != NULL)
222 return (bus->bus_read_byte(bus->bus_cookie));
223
224 for (i = 0; i < 8; i++)
225 value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
226
227 return (value);
228 }
229
230 void
onewire_write_byte(void * arg,int value)231 onewire_write_byte(void *arg, int value)
232 {
233 struct onewire_softc *sc = arg;
234 struct onewire_bus *bus = sc->sc_bus;
235 int i;
236
237 if (bus->bus_write_byte != NULL)
238 return (bus->bus_write_byte(bus->bus_cookie, value));
239
240 for (i = 0; i < 8; i++)
241 bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
242 }
243
244 void
onewire_read_block(void * arg,void * buf,int len)245 onewire_read_block(void *arg, void *buf, int len)
246 {
247 struct onewire_softc *sc = arg;
248 struct onewire_bus *bus = sc->sc_bus;
249 u_int8_t *p = buf;
250
251 if (bus->bus_read_block != NULL)
252 return (bus->bus_read_block(bus->bus_cookie, buf, len));
253
254 while (len--)
255 *p++ = onewire_read_byte(arg);
256 }
257
258 void
onewire_write_block(void * arg,const void * buf,int len)259 onewire_write_block(void *arg, const void *buf, int len)
260 {
261 struct onewire_softc *sc = arg;
262 struct onewire_bus *bus = sc->sc_bus;
263 const u_int8_t *p = buf;
264
265 if (bus->bus_write_block != NULL)
266 return (bus->bus_write_block(bus->bus_cookie, buf, len));
267
268 while (len--)
269 onewire_write_byte(arg, *p++);
270 }
271
272 int
onewire_triplet(void * arg,int dir)273 onewire_triplet(void *arg, int dir)
274 {
275 struct onewire_softc *sc = arg;
276 struct onewire_bus *bus = sc->sc_bus;
277 int rv;
278
279 if (bus->bus_triplet != NULL)
280 return (bus->bus_triplet(bus->bus_cookie, dir));
281
282 rv = bus->bus_bit(bus->bus_cookie, 1);
283 rv <<= 1;
284 rv |= bus->bus_bit(bus->bus_cookie, 1);
285
286 switch (rv) {
287 case 0x0:
288 bus->bus_bit(bus->bus_cookie, dir);
289 break;
290 case 0x1:
291 bus->bus_bit(bus->bus_cookie, 0);
292 break;
293 default:
294 bus->bus_bit(bus->bus_cookie, 1);
295 }
296
297 return (rv);
298 }
299
300 void
onewire_matchrom(void * arg,u_int64_t rom)301 onewire_matchrom(void *arg, u_int64_t rom)
302 {
303 struct onewire_softc *sc = arg;
304 struct onewire_bus *bus = sc->sc_bus;
305 int i;
306
307 if (bus->bus_matchrom != NULL)
308 return (bus->bus_matchrom(bus->bus_cookie, rom));
309
310 onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
311 for (i = 0; i < 8; i++)
312 onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
313 }
314
315 int
onewire_search(void * arg,u_int64_t * buf,int size,u_int64_t startrom)316 onewire_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
317 {
318 struct onewire_softc *sc = arg;
319 struct onewire_bus *bus = sc->sc_bus;
320 int search = 1, count = 0, lastd = -1, dir, rv, i, i0;
321 u_int64_t mask, rom = startrom, lastrom;
322 u_int8_t data[8];
323
324 if (bus->bus_search != NULL)
325 return (bus->bus_search(bus->bus_cookie, buf, size, rom));
326
327 while (search && count < size) {
328 /* XXX: yield processor */
329 tsleep_nsec(sc, PWAIT, "owscan", MSEC_TO_NSEC(100));
330
331 /*
332 * Start new search. Go through the previous path to
333 * the point we made a decision last time and make an
334 * opposite decision. If we didn't make any decision
335 * stop searching.
336 */
337 lastrom = rom;
338 rom = 0;
339 onewire_lock(sc, 0);
340 onewire_reset(sc);
341 onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
342 for (i = 0, i0 = -1; i < 64; i++) {
343 dir = (lastrom >> i) & 0x1;
344 if (i == lastd)
345 dir = 1;
346 else if (i > lastd)
347 dir = 0;
348 rv = onewire_triplet(sc, dir);
349 switch (rv) {
350 case 0x0:
351 if (i != lastd && dir == 0)
352 i0 = i;
353 mask = dir;
354 break;
355 case 0x1:
356 mask = 0;
357 break;
358 case 0x2:
359 mask = 1;
360 break;
361 default:
362 DPRINTF(("%s: search triplet error 0x%x, "
363 "step %d\n",
364 sc->sc_dev.dv_xname, rv, i));
365 onewire_unlock(sc);
366 return (-1);
367 }
368 rom |= (mask << i);
369 }
370 onewire_unlock(sc);
371
372 if ((lastd = i0) == -1)
373 search = 0;
374
375 if (rom == 0)
376 continue;
377
378 /*
379 * The last byte of the ROM code contains a CRC calculated
380 * from the first 7 bytes. Re-calculate it to make sure
381 * we found a valid device.
382 */
383 for (i = 0; i < 8; i++)
384 data[i] = (rom >> (i * 8)) & 0xff;
385 if (onewire_crc(data, 7) != data[7])
386 continue;
387
388 buf[count++] = rom;
389 }
390
391 return (count);
392 }
393
394 void
onewire_thread(void * arg)395 onewire_thread(void *arg)
396 {
397 struct onewire_softc *sc = arg;
398
399 while (!sc->sc_dying) {
400 onewire_scan(sc);
401 if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
402 break;
403 tsleep_nsec(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME);
404 }
405
406 sc->sc_thread = NULL;
407 wakeup(&sc->sc_dying);
408 kthread_exit(0);
409 }
410
411 void
onewire_createthread(void * arg)412 onewire_createthread(void *arg)
413 {
414 struct onewire_softc *sc = arg;
415
416 if (kthread_create(onewire_thread, sc, &sc->sc_thread,
417 sc->sc_dev.dv_xname) != 0)
418 printf("%s: can't create kernel thread\n",
419 sc->sc_dev.dv_xname);
420 }
421
422 void
onewire_scan(struct onewire_softc * sc)423 onewire_scan(struct onewire_softc *sc)
424 {
425 struct onewire_device *d, *next, *nd;
426 struct onewire_attach_args oa;
427 struct device *dev;
428 int present;
429 u_int64_t rom;
430 int i, rv;
431
432 /*
433 * Mark all currently present devices as absent before
434 * scanning. This allows to find out later which devices
435 * have been disappeared.
436 */
437 TAILQ_FOREACH(d, &sc->sc_devs, d_list)
438 d->d_present = 0;
439
440 /*
441 * Reset the bus. If there's no presence pulse don't search
442 * for any devices.
443 */
444 onewire_lock(sc, 0);
445 rv = onewire_reset(sc);
446 onewire_unlock(sc);
447 if (rv != 0) {
448 DPRINTF(("%s: no presence pulse\n", sc->sc_dev.dv_xname));
449 goto out;
450 }
451
452 /* Scan the bus */
453 if ((rv = onewire_search(sc, sc->sc_rombuf, ONEWIRE_MAXDEVS, 0)) == -1)
454 return;
455
456 for (i = 0; i < rv; i++) {
457 rom = sc->sc_rombuf[i];
458
459 /*
460 * Go through the list of attached devices to see if we
461 * found a new one.
462 */
463 present = 0;
464 TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
465 if (d->d_rom == rom) {
466 d->d_present = 1;
467 present = 1;
468 break;
469 }
470 }
471 if (!present) {
472 nd = malloc(sizeof(struct onewire_device),
473 M_DEVBUF, M_NOWAIT);
474 if (nd == NULL)
475 continue;
476
477 bzero(&oa, sizeof(oa));
478 oa.oa_onewire = sc;
479 oa.oa_rom = rom;
480 dev = config_found(&sc->sc_dev, &oa, onewire_print);
481
482 nd->d_dev = dev;
483 nd->d_rom = rom;
484 nd->d_present = 1;
485 TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
486 }
487 }
488
489 out:
490 /* Detach disappeared devices */
491 TAILQ_FOREACH_SAFE(d, &sc->sc_devs, d_list, next) {
492 if (!d->d_present) {
493 if (d->d_dev != NULL)
494 config_detach(d->d_dev, DETACH_FORCE);
495 TAILQ_REMOVE(&sc->sc_devs, d, d_list);
496 free(d, M_DEVBUF, sizeof *d);
497 }
498 }
499 }
500