Annotation of sys/dev/onewire/onewire.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: onewire.c,v 1.7 2006/10/08 21:12:51 grange 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/proc.h>
30: #include <sys/queue.h>
31: #include <sys/rwlock.h>
32:
33: #include <dev/onewire/onewirereg.h>
34: #include <dev/onewire/onewirevar.h>
35:
36: #ifdef ONEWIRE_DEBUG
37: #define DPRINTF(x) printf x
38: #else
39: #define DPRINTF(x)
40: #endif
41:
42: #define ONEWIRE_MAXDEVS 16
43: #define ONEWIRE_SCANTIME 3
44:
45: struct onewire_softc {
46: struct device sc_dev;
47:
48: struct onewire_bus * sc_bus;
49: struct rwlock sc_lock;
50: struct proc * sc_thread;
51: TAILQ_HEAD(, onewire_device) sc_devs;
52:
53: int sc_dying;
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;
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 *, enum devact);
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: 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
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
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: rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
102: TAILQ_INIT(&sc->sc_devs);
103:
104: printf("\n");
105:
106: kthread_create_deferred(onewire_createthread, sc);
107: }
108:
109: int
110: onewire_detach(struct device *self, int flags)
111: {
112: struct onewire_softc *sc = (struct onewire_softc *)self;
113:
114: sc->sc_dying = 1;
115: if (sc->sc_thread != NULL) {
116: wakeup(sc->sc_thread);
117: tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
118: }
119:
120: return (config_detach_children(self, flags));
121: }
122:
123: int
124: onewire_activate(struct device *self, enum devact act)
125: {
126: struct onewire_softc *sc = (struct onewire_softc *)self;
127:
128: switch (act) {
129: case DVACT_ACTIVATE:
130: break;
131: case DVACT_DEACTIVATE:
132: sc->sc_dying = 1;
133: break;
134: }
135:
136: return (config_activate_children(self, act));
137: }
138:
139: int
140: onewire_print(void *aux, const char *pnp)
141: {
142: struct onewire_attach_args *oa = aux;
143: const char *famname;
144:
145: if (pnp == NULL)
146: printf(" ");
147:
148: famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
149: if (famname == NULL)
150: printf("family 0x%02x", ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
151: else
152: printf("\"%s\"", famname);
153: printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
154:
155: if (pnp != NULL)
156: printf(" at %s", pnp);
157:
158: return (UNCONF);
159: }
160:
161: int
162: onewirebus_print(void *aux, const char *pnp)
163: {
164: if (pnp != NULL)
165: printf("onewire at %s", pnp);
166:
167: return (UNCONF);
168: }
169:
170: int
171: onewire_lock(void *arg, int flags)
172: {
173: struct onewire_softc *sc = arg;
174: int lflags = RW_WRITE;
175:
176: if (flags & ONEWIRE_NOWAIT)
177: lflags |= RW_NOSLEEP;
178:
179: return (rw_enter(&sc->sc_lock, lflags));
180: }
181:
182: void
183: onewire_unlock(void *arg)
184: {
185: struct onewire_softc *sc = arg;
186:
187: rw_exit(&sc->sc_lock);
188: }
189:
190: int
191: onewire_reset(void *arg)
192: {
193: struct onewire_softc *sc = arg;
194: struct onewire_bus *bus = sc->sc_bus;
195:
196: return (bus->bus_reset(bus->bus_cookie));
197: }
198:
199: int
200: onewire_bit(void *arg, int value)
201: {
202: struct onewire_softc *sc = arg;
203: struct onewire_bus *bus = sc->sc_bus;
204:
205: return (bus->bus_bit(bus->bus_cookie, value));
206: }
207:
208: int
209: onewire_read_byte(void *arg)
210: {
211: struct onewire_softc *sc = arg;
212: struct onewire_bus *bus = sc->sc_bus;
213: u_int8_t value = 0;
214: int i;
215:
216: if (bus->bus_read_byte != NULL)
217: return (bus->bus_read_byte(bus->bus_cookie));
218:
219: for (i = 0; i < 8; i++)
220: value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
221:
222: return (value);
223: }
224:
225: void
226: onewire_write_byte(void *arg, int value)
227: {
228: struct onewire_softc *sc = arg;
229: struct onewire_bus *bus = sc->sc_bus;
230: int i;
231:
232: if (bus->bus_write_byte != NULL)
233: return (bus->bus_write_byte(bus->bus_cookie, value));
234:
235: for (i = 0; i < 8; i++)
236: bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
237: }
238:
239: void
240: onewire_read_block(void *arg, void *buf, int len)
241: {
242: struct onewire_softc *sc = arg;
243: struct onewire_bus *bus = sc->sc_bus;
244: u_int8_t *p = buf;
245:
246: if (bus->bus_read_block != NULL)
247: return (bus->bus_read_block(bus->bus_cookie, buf, len));
248:
249: while (len--)
250: *p++ = onewire_read_byte(arg);
251: }
252:
253: void
254: onewire_write_block(void *arg, const void *buf, int len)
255: {
256: struct onewire_softc *sc = arg;
257: struct onewire_bus *bus = sc->sc_bus;
258: const u_int8_t *p = buf;
259:
260: if (bus->bus_write_block != NULL)
261: return (bus->bus_write_block(bus->bus_cookie, buf, len));
262:
263: while (len--)
264: onewire_write_byte(arg, *p++);
265: }
266:
267: int
268: onewire_triplet(void *arg, int dir)
269: {
270: struct onewire_softc *sc = arg;
271: struct onewire_bus *bus = sc->sc_bus;
272: int rv;
273:
274: if (bus->bus_triplet != NULL)
275: return (bus->bus_triplet(bus->bus_cookie, dir));
276:
277: rv = bus->bus_bit(bus->bus_cookie, 1);
278: rv <<= 1;
279: rv |= bus->bus_bit(bus->bus_cookie, 1);
280:
281: switch (rv) {
282: case 0x0:
283: bus->bus_bit(bus->bus_cookie, dir);
284: break;
285: case 0x1:
286: bus->bus_bit(bus->bus_cookie, 0);
287: break;
288: default:
289: bus->bus_bit(bus->bus_cookie, 1);
290: }
291:
292: return (rv);
293: }
294:
295: void
296: onewire_matchrom(void *arg, u_int64_t rom)
297: {
298: struct onewire_softc *sc = arg;
299: struct onewire_bus *bus = sc->sc_bus;
300: int i;
301:
302: if (bus->bus_matchrom != NULL)
303: return (bus->bus_matchrom(bus->bus_cookie, rom));
304:
305: onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
306: for (i = 0; i < 8; i++)
307: onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
308: }
309:
310: int
311: onewire_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
312: {
313: struct onewire_softc *sc = arg;
314: struct onewire_bus *bus = sc->sc_bus;
315: int search = 1, count = 0, lastd = -1, dir, rv, i, i0;
316: u_int64_t mask, rom = startrom, lastrom;
317: u_int8_t data[8];
318:
319: if (bus->bus_search != NULL)
320: return (bus->bus_search(bus->bus_cookie, buf, size, rom));
321:
322: while (search && count < size) {
323: /* XXX: yield processor */
324: tsleep(sc, PWAIT, "owscan", hz / 10);
325:
326: /*
327: * Start new search. Go through the previous path to
328: * the point we made a decision last time and make an
329: * opposite decision. If we didn't make any decision
330: * stop searching.
331: */
332: lastrom = rom;
333: rom = 0;
334: onewire_lock(sc, 0);
335: onewire_reset(sc);
336: onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
337: for (i = 0, i0 = -1; i < 64; i++) {
338: dir = (lastrom >> i) & 0x1;
339: if (i == lastd)
340: dir = 1;
341: else if (i > lastd)
342: dir = 0;
343: rv = onewire_triplet(sc, dir);
344: switch (rv) {
345: case 0x0:
346: if (i != lastd && dir == 0)
347: i0 = i;
348: mask = dir;
349: break;
350: case 0x1:
351: mask = 0;
352: break;
353: case 0x2:
354: mask = 1;
355: break;
356: default:
357: DPRINTF(("%s: search triplet error 0x%x, "
358: "step %d\n",
359: sc->sc_dev.dv_xname, rv, i));
360: onewire_unlock(sc);
361: return (-1);
362: }
363: rom |= (mask << i);
364: }
365: onewire_unlock(sc);
366:
367: if ((lastd = i0) == -1)
368: search = 0;
369:
370: if (rom == 0)
371: continue;
372:
373: /*
374: * The last byte of the ROM code contains a CRC calculated
375: * from the first 7 bytes. Re-calculate it to make sure
376: * we found a valid device.
377: */
378: for (i = 0; i < 8; i++)
379: data[i] = (rom >> (i * 8)) & 0xff;
380: if (onewire_crc(data, 7) != data[7])
381: continue;
382:
383: buf[count++] = rom;
384: }
385:
386: return (count);
387: }
388:
389: void
390: onewire_thread(void *arg)
391: {
392: struct onewire_softc *sc = arg;
393:
394: while (!sc->sc_dying) {
395: onewire_scan(sc);
396: tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz);
397: }
398:
399: sc->sc_thread = NULL;
400: wakeup(&sc->sc_dying);
401: kthread_exit(0);
402: }
403:
404: void
405: onewire_createthread(void *arg)
406: {
407: struct onewire_softc *sc = arg;
408:
409: if (kthread_create(onewire_thread, sc, &sc->sc_thread,
410: "%s", sc->sc_dev.dv_xname) != 0)
411: printf("%s: can't create kernel thread\n",
412: sc->sc_dev.dv_xname);
413: }
414:
415: void
416: onewire_scan(struct onewire_softc *sc)
417: {
418: struct onewire_device *d, *next, *nd;
419: struct onewire_attach_args oa;
420: struct device *dev;
421: int present;
422: u_int64_t rom;
423: int i, rv;
424:
425: /*
426: * Mark all currently present devices as absent before
427: * scanning. This allows to find out later which devices
428: * have been disappeared.
429: */
430: TAILQ_FOREACH(d, &sc->sc_devs, d_list)
431: d->d_present = 0;
432:
433: /*
434: * Reset the bus. If there's no presence pulse don't search
435: * for any devices.
436: */
437: onewire_lock(sc, 0);
438: rv = onewire_reset(sc);
439: onewire_unlock(sc);
440: if (rv != 0) {
441: DPRINTF(("%s: no presence pulse\n", sc->sc_dev.dv_xname));
442: goto out;
443: }
444:
445: /* Scan the bus */
446: if ((rv = onewire_search(sc, sc->sc_rombuf, ONEWIRE_MAXDEVS, 0)) == -1)
447: return;
448:
449: for (i = 0; i < rv; i++) {
450: rom = sc->sc_rombuf[i];
451:
452: /*
453: * Go through the list of attached devices to see if we
454: * found a new one.
455: */
456: present = 0;
457: TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
458: if (d->d_rom == rom) {
459: d->d_present = 1;
460: present = 1;
461: break;
462: }
463: }
464: if (!present) {
465: bzero(&oa, sizeof(oa));
466: oa.oa_onewire = sc;
467: oa.oa_rom = rom;
468: if ((dev = config_found(&sc->sc_dev, &oa,
469: onewire_print)) == NULL)
470: continue;
471:
472: MALLOC(nd, struct onewire_device *,
473: sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT);
474: if (nd == NULL)
475: continue;
476: nd->d_dev = dev;
477: nd->d_rom = rom;
478: nd->d_present = 1;
479: TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
480: }
481: }
482:
483: out:
484: /* Detach disappeared devices */
485: for (d = TAILQ_FIRST(&sc->sc_devs);
486: d != TAILQ_END(&sc->sc_dev); d = next) {
487: next = TAILQ_NEXT(d, d_list);
488: if (!d->d_present) {
489: config_detach(d->d_dev, DETACH_FORCE);
490: TAILQ_REMOVE(&sc->sc_devs, d, d_list);
491: FREE(d, M_DEVBUF);
492: }
493: }
494: }
CVSweb