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