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