onewire.c revision 1.5 1 /* $NetBSD: onewire.c,v 1.5 2007/07/09 21:00:52 ad 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.5 2007/07/09 21:00:52 ad 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 lwp * 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_scan(struct onewire_softc *);
77
78 CFATTACH_DECL(onewire, sizeof(struct onewire_softc),
79 onewire_match, onewire_attach, onewire_detach, onewire_activate);
80
81 const struct cdevsw onewire_cdevsw = {
82 noopen, noclose, noread, nowrite, noioctl, nostop, notty,
83 nopoll, nommap, nokqfilter, D_OTHER,
84 };
85
86 extern struct cfdriver onewire_cd;
87
88 int
89 onewire_match(struct device *parent, struct cfdata *cf,
90 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 if (kthread_create(PRI_NONE, 0, NULL, onewire_thread, sc,
108 &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0)
109 printf("%s: can't create kernel thread\n",
110 sc->sc_dev.dv_xname);
111 }
112
113 int
114 onewire_detach(struct device *self, int flags)
115 {
116 struct onewire_softc *sc = device_private(self);
117 int rv;
118
119 sc->sc_dying = 1;
120 if (sc->sc_thread != NULL) {
121 wakeup(sc->sc_thread);
122 tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
123 }
124
125 onewire_lock(sc, 0);
126 //rv = config_detach_children(self, flags);
127 rv = 0; /* XXX riz */
128 onewire_unlock(sc);
129
130 return (rv);
131 }
132
133 int
134 onewire_activate(struct device *self, enum devact act)
135 {
136 struct onewire_softc *sc = device_private(self);
137 int rv = 0;
138
139 switch (act) {
140 case DVACT_ACTIVATE:
141 rv = EOPNOTSUPP;
142 break;
143 case DVACT_DEACTIVATE:
144 sc->sc_dying = 1;
145 break;
146 }
147
148 //return (config_activate_children(self, act));
149 return rv;
150 }
151
152 int
153 onewire_print(void *aux, const char *pnp)
154 {
155 struct onewire_attach_args *oa = aux;
156 const char *famname;
157
158 if (pnp == NULL)
159 printf(" ");
160
161 famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
162 if (famname == NULL)
163 printf("family 0x%02x", (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
164 else
165 printf("\"%s\"", famname);
166 printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
167
168 if (pnp != NULL)
169 printf(" at %s", pnp);
170
171 return (UNCONF);
172 }
173
174 int
175 onewirebus_print(void *aux, const char *pnp)
176 {
177 if (pnp != NULL)
178 printf("onewire at %s", pnp);
179
180 return (UNCONF);
181 }
182
183 int
184 onewire_lock(void *arg, int flags)
185 {
186 struct onewire_softc *sc = arg;
187 int lflags = LK_EXCLUSIVE;
188
189 if (flags & ONEWIRE_NOWAIT)
190 lflags |= LK_NOWAIT;
191
192 return (lockmgr(&sc->sc_lock, lflags, NULL));
193 }
194
195 void
196 onewire_unlock(void *arg)
197 {
198 struct onewire_softc *sc = arg;
199
200 lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
201 }
202
203 int
204 onewire_reset(void *arg)
205 {
206 struct onewire_softc *sc = arg;
207 struct onewire_bus *bus = sc->sc_bus;
208
209 return (bus->bus_reset(bus->bus_cookie));
210 }
211
212 int
213 onewire_bit(void *arg, int value)
214 {
215 struct onewire_softc *sc = arg;
216 struct onewire_bus *bus = sc->sc_bus;
217
218 return (bus->bus_bit(bus->bus_cookie, value));
219 }
220
221 int
222 onewire_read_byte(void *arg)
223 {
224 struct onewire_softc *sc = arg;
225 struct onewire_bus *bus = sc->sc_bus;
226 u_int8_t value = 0;
227 int i;
228
229 if (bus->bus_read_byte != NULL)
230 return (bus->bus_read_byte(bus->bus_cookie));
231
232 for (i = 0; i < 8; i++)
233 value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
234
235 return (value);
236 }
237
238 void
239 onewire_write_byte(void *arg, int value)
240 {
241 struct onewire_softc *sc = arg;
242 struct onewire_bus *bus = sc->sc_bus;
243 int i;
244
245 if (bus->bus_write_byte != NULL)
246 return (bus->bus_write_byte(bus->bus_cookie, value));
247
248 for (i = 0; i < 8; i++)
249 bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
250 }
251
252 int
253 onewire_triplet(void *arg, int dir)
254 {
255 struct onewire_softc *sc = arg;
256 struct onewire_bus *bus = sc->sc_bus;
257 int rv;
258
259 if (bus->bus_triplet != NULL)
260 return (bus->bus_triplet(bus->bus_cookie, dir));
261
262 rv = bus->bus_bit(bus->bus_cookie, 1);
263 rv <<= 1;
264 rv |= bus->bus_bit(bus->bus_cookie, 1);
265
266 switch (rv) {
267 case 0x0:
268 bus->bus_bit(bus->bus_cookie, dir);
269 break;
270 case 0x1:
271 bus->bus_bit(bus->bus_cookie, 0);
272 break;
273 default:
274 bus->bus_bit(bus->bus_cookie, 1);
275 }
276
277 return (rv);
278 }
279
280 void
281 onewire_read_block(void *arg, void *buf, int len)
282 {
283 u_int8_t *p = buf;
284
285 while (len--)
286 *p++ = onewire_read_byte(arg);
287 }
288
289 void
290 onewire_write_block(void *arg, const void *buf, int len)
291 {
292 const u_int8_t *p = buf;
293
294 while (len--)
295 onewire_write_byte(arg, *p++);
296 }
297
298 void
299 onewire_matchrom(void *arg, u_int64_t rom)
300 {
301 int i;
302
303 onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
304 for (i = 0; i < 8; i++)
305 onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
306 }
307
308 void
309 onewire_thread(void *arg)
310 {
311 struct onewire_softc *sc = arg;
312
313 while (!sc->sc_dying) {
314 onewire_scan(sc);
315 tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz);
316 }
317
318 sc->sc_thread = NULL;
319 wakeup(&sc->sc_dying);
320 kthread_exit(0);
321 }
322 void
323 onewire_scan(struct onewire_softc *sc)
324 {
325 struct onewire_device *d, *next, *nd;
326 struct onewire_attach_args oa;
327 struct device *dev;
328 int search = 1, count = 0, present;
329 int dir, rv;
330 u_int64_t mask, rom = 0, lastrom;
331 u_int8_t data[8];
332 int i, i0 = -1, lastd = -1;
333
334 TAILQ_FOREACH(d, &sc->sc_devs, d_list)
335 d->d_present = 0;
336
337 while (search && count++ < ONEWIRE_MAXDEVS) {
338 /* XXX: yield processor */
339 tsleep(sc, PWAIT, "owscan", hz / 10);
340
341 /*
342 * Reset the bus. If there's no presence pulse
343 * don't search for any devices.
344 */
345 onewire_lock(sc, 0);
346 if (onewire_reset(sc) != 0) {
347 DPRINTF(("%s: scan: no presence pulse\n",
348 sc->sc_dev.dv_xname));
349 onewire_unlock(sc);
350 break;
351 }
352
353 /*
354 * Start new search. Go through the previous path to
355 * the point we made a decision last time and make an
356 * opposite decision. If we didn't make any decision
357 * stop searching.
358 */
359 search = 0;
360 lastrom = rom;
361 rom = 0;
362 onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
363 for (i = 0,i0 = -1; i < 64; i++) {
364 dir = (lastrom >> i) & 0x1;
365 if (i == lastd)
366 dir = 1;
367 else if (i > lastd)
368 dir = 0;
369 rv = onewire_triplet(sc, dir);
370 switch (rv) {
371 case 0x0:
372 if (i != lastd) {
373 if (dir == 0)
374 i0 = i;
375 search = 1;
376 }
377 mask = dir;
378 break;
379 case 0x1:
380 mask = 0;
381 break;
382 case 0x2:
383 mask = 1;
384 break;
385 default:
386 DPRINTF(("%s: scan: triplet error 0x%x, "
387 "step %d\n",
388 sc->sc_dev.dv_xname, rv, i));
389 onewire_unlock(sc);
390 return;
391 }
392 rom |= (mask << i);
393 }
394 lastd = i0;
395 onewire_unlock(sc);
396
397 if (rom == 0)
398 continue;
399
400 /*
401 * The last byte of the ROM code contains a CRC calculated
402 * from the first 7 bytes. Re-calculate it to make sure
403 * we found a valid device.
404 */
405 for (i = 0; i < 8; i++)
406 data[i] = (rom >> (i * 8)) & 0xff;
407 if (onewire_crc(data, 7) != data[7])
408 continue;
409
410 /*
411 * Go through the list of attached devices to see if we
412 * found a new one.
413 */
414 present = 0;
415 TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
416 if (d->d_rom == rom) {
417 d->d_present = 1;
418 present = 1;
419 break;
420 }
421 }
422 if (!present) {
423 bzero(&oa, sizeof(oa));
424 oa.oa_onewire = sc;
425 oa.oa_rom = rom;
426 if ((dev = config_found(&sc->sc_dev, &oa,
427 onewire_print)) == NULL)
428 continue;
429
430 MALLOC(nd, struct onewire_device *,
431 sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT);
432 if (nd == NULL)
433 continue;
434 nd->d_dev = dev;
435 nd->d_rom = rom;
436 nd->d_present = 1;
437 TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
438 }
439 }
440
441 /* Detach disappeared devices */
442 onewire_lock(sc, 0);
443 for (d = TAILQ_FIRST(&sc->sc_devs);
444 d != NULL; d = next) {
445 next = TAILQ_NEXT(d, d_list);
446 if (!d->d_present) {
447 config_detach(d->d_dev, DETACH_FORCE);
448 TAILQ_REMOVE(&sc->sc_devs, d, d_list);
449 FREE(d, M_DEVBUF);
450 }
451 }
452 onewire_unlock(sc);
453 }
454