1/* $NetBSD: onewire.c,v 1.16 2014/07/25 08:10:38 dholland 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@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.16 2014/07/25 08:10:38 dholland 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#include <sys/module.h>
38
39#include <dev/onewire/onewirereg.h>
40#include <dev/onewire/onewirevar.h>
41
42#ifdef ONEWIRE_DEBUG
43#define DPRINTF(x) printf x
44#else
45#define DPRINTF(x)
46#endif
47
48//#define ONEWIRE_MAXDEVS 256
49#define ONEWIRE_MAXDEVS 8
50#define ONEWIRE_SCANTIME 3
51
52struct onewire_softc {
53 device_t sc_dev;
54
55 struct onewire_bus * sc_bus;
56 krwlock_t sc_rwlock;
57 struct lwp * sc_thread;
58 TAILQ_HEAD(, onewire_device) sc_devs;
59
60 int sc_dying;
61};
62
63struct onewire_device {
64 TAILQ_ENTRY(onewire_device) d_list;
65 device_t d_dev;
66 u_int64_t d_rom;
67 int d_present;
68};
69
70static int onewire_match(device_t, cfdata_t, void *);
71static void onewire_attach(device_t, device_t, void *);
72static int onewire_detach(device_t, int);
73static int onewire_activate(device_t, enum devact);
74int onewire_print(void *, const char *);
75
76static void onewire_thread(void *);
77static void onewire_scan(struct onewire_softc *);
78
79CFATTACH_DECL_NEW(onewire, sizeof(struct onewire_softc),
80 onewire_match, onewire_attach, onewire_detach, onewire_activate);
81
82const struct cdevsw onewire_cdevsw = {
83 .d_open = noopen,
84 .d_close = noclose,
85 .d_read = noread,
86 .d_write = nowrite,
87 .d_ioctl = noioctl,
88 .d_stop = nostop,
89 .d_tty = notty,
90 .d_poll = nopoll,
91 .d_mmap = nommap,
92 .d_kqfilter = nokqfilter,
93 .d_discard = nodiscard,
94 .d_flag = D_OTHER
95};
96
97extern struct cfdriver onewire_cd;
98
99static int
100onewire_match(device_t parent, cfdata_t cf, void *aux)
101{
102 return 1;
103}
104
105static void
106onewire_attach(device_t parent, device_t self, void *aux)
107{
108 struct onewire_softc *sc = device_private(self);
109 struct onewirebus_attach_args *oba = aux;
110
111 sc->sc_dev = self;
112 sc->sc_bus = oba->oba_bus;
113 rw_init(&sc->sc_rwlock);
114 TAILQ_INIT(&sc->sc_devs);
115
116 aprint_normal("\n");
117
118 if (kthread_create(PRI_NONE, 0, NULL, onewire_thread, sc,
119 &sc->sc_thread, "%s", device_xname(self)) != 0)
120 aprint_error_dev(self, "can't create kernel thread\n");
121}
122
123static int
124onewire_detach(device_t self, int flags)
125{
126 struct onewire_softc *sc = device_private(self);
127 int rv;
128
129 sc->sc_dying = 1;
130 if (sc->sc_thread != NULL) {
131 wakeup(sc->sc_thread);
132 tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
133 }
134
135 onewire_lock(sc);
136 //rv = config_detach_children(self, flags);
137 rv = 0; /* XXX riz */
138 onewire_unlock(sc);
139 rw_destroy(&sc->sc_rwlock);
140
141 return rv;
142}
143
144static int
145onewire_activate(device_t self, enum devact act)
146{
147 struct onewire_softc *sc = device_private(self);
148
149 switch (act) {
150 case DVACT_DEACTIVATE:
151 sc->sc_dying = 1;
152 return 0;
153 default:
154 return EOPNOTSUPP;
155 }
156}
157
158int
159onewire_print(void *aux, const char *pnp)
160{
161 struct onewire_attach_args *oa = aux;
162 const char *famname;
163
164 if (pnp == NULL)
165 aprint_normal(" ");
166
167 famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
168 if (famname == NULL)
169 aprint_normal("family 0x%02x",
170 (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
171 else
172 aprint_normal("\"%s\"", famname);
173 aprint_normal(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
174
175 if (pnp != NULL)
176 aprint_normal(" at %s", pnp);
177
178 return UNCONF;
179}
180
181int
182onewirebus_print(void *aux, const char *pnp)
183{
184 if (pnp != NULL)
185 aprint_normal("onewire at %s", pnp);
186
187 return UNCONF;
188}
189
190void
191onewire_lock(void *arg)
192{
193 struct onewire_softc *sc = arg;
194
195 rw_enter(&sc->sc_rwlock, RW_WRITER);
196}
197
198void
199onewire_unlock(void *arg)
200{
201 struct onewire_softc *sc = arg;
202
203 rw_exit(&sc->sc_rwlock);
204}
205
206int
207onewire_reset(void *arg)
208{
209 struct onewire_softc *sc = arg;
210 struct onewire_bus *bus = sc->sc_bus;
211
212 return bus->bus_reset(bus->bus_cookie);
213}
214
215int
216onewire_bit(void *arg, int value)
217{
218 struct onewire_softc *sc = arg;
219 struct onewire_bus *bus = sc->sc_bus;
220
221 return bus->bus_bit(bus->bus_cookie, value);
222}
223
224int
225onewire_read_byte(void *arg)
226{
227 struct onewire_softc *sc = arg;
228 struct onewire_bus *bus = sc->sc_bus;
229 uint8_t value = 0;
230 int i;
231
232 if (bus->bus_read_byte != NULL)
233 return bus->bus_read_byte(bus->bus_cookie);
234
235 for (i = 0; i < 8; i++)
236 value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
237
238 return value;
239}
240
241void
242onewire_write_byte(void *arg, int value)
243{
244 struct onewire_softc *sc = arg;
245 struct onewire_bus *bus = sc->sc_bus;
246 int i;
247
248 if (bus->bus_write_byte != NULL)
249 return bus->bus_write_byte(bus->bus_cookie, value);
250
251 for (i = 0; i < 8; i++)
252 bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
253}
254
255int
256onewire_triplet(void *arg, int dir)
257{
258 struct onewire_softc *sc = arg;
259 struct onewire_bus *bus = sc->sc_bus;
260 int rv;
261
262 if (bus->bus_triplet != NULL)
263 return bus->bus_triplet(bus->bus_cookie, dir);
264
265 rv = bus->bus_bit(bus->bus_cookie, 1);
266 rv <<= 1;
267 rv |= bus->bus_bit(bus->bus_cookie, 1);
268
269 switch (rv) {
270 case 0x0:
271 bus->bus_bit(bus->bus_cookie, dir);
272 break;
273 case 0x1:
274 bus->bus_bit(bus->bus_cookie, 0);
275 break;
276 default:
277 bus->bus_bit(bus->bus_cookie, 1);
278 }
279
280 return rv;
281}
282
283void
284onewire_read_block(void *arg, void *buf, int len)
285{
286 uint8_t *p = buf;
287
288 while (len--)
289 *p++ = onewire_read_byte(arg);
290}
291
292void
293onewire_write_block(void *arg, const void *buf, int len)
294{
295 const uint8_t *p = buf;
296
297 while (len--)
298 onewire_write_byte(arg, *p++);
299}
300
301void
302onewire_matchrom(void *arg, u_int64_t rom)
303{
304 int i;
305
306 onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
307 for (i = 0; i < 8; i++)
308 onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
309}
310
311static void
312onewire_thread(void *arg)
313{
314 struct onewire_softc *sc = arg;
315
316 while (!sc->sc_dying) {
317 onewire_scan(sc);
318 tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz);
319 }
320
321 sc->sc_thread = NULL;
322 wakeup(&sc->sc_dying);
323 kthread_exit(0);
324}
325
326static void
327onewire_scan(struct onewire_softc *sc)
328{
329 struct onewire_device *d, *next, *nd;
330 struct onewire_attach_args oa;
331 device_t dev;
332 int search = 1, count = 0, present;
333 int dir, rv;
334 uint64_t mask, rom = 0, lastrom;
335 uint8_t data[8];
336 int i, i0 = -1, lastd = -1;
337
338 TAILQ_FOREACH(d, &sc->sc_devs, d_list)
339 d->d_present = 0;
340
341 while (search && count++ < ONEWIRE_MAXDEVS) {
342 /* XXX: yield processor */
343 tsleep(sc, PWAIT, "owscan", hz / 10);
344
345 /*
346 * Reset the bus. If there's no presence pulse
347 * don't search for any devices.
348 */
349 onewire_lock(sc);
350 if (onewire_reset(sc) != 0) {
351 DPRINTF(("%s: scan: no presence pulse\n",
352 device_xname(sc->sc_dev)));
353 onewire_unlock(sc);
354 break;
355 }
356
357 /*
358 * Start new search. Go through the previous path to
359 * the point we made a decision last time and make an
360 * opposite decision. If we didn't make any decision
361 * stop searching.
362 */
363 search = 0;
364 lastrom = rom;
365 rom = 0;
366 onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
367 for (i = 0,i0 = -1; i < 64; i++) {
368 dir = (lastrom >> i) & 0x1;
369 if (i == lastd)
370 dir = 1;
371 else if (i > lastd)
372 dir = 0;
373 rv = onewire_triplet(sc, dir);
374 switch (rv) {
375 case 0x0:
376 if (i != lastd) {
377 if (dir == 0)
378 i0 = i;
379 search = 1;
380 }
381 mask = dir;
382 break;
383 case 0x1:
384 mask = 0;
385 break;
386 case 0x2:
387 mask = 1;
388 break;
389 default:
390 DPRINTF(("%s: scan: triplet error 0x%x, "
391 "step %d\n",
392 device_xname(sc->sc_dev), rv, i));
393 onewire_unlock(sc);
394 return;
395 }
396 rom |= (mask << i);
397 }
398 lastd = i0;
399 onewire_unlock(sc);
400
401 if (rom == 0)
402 continue;
403
404 /*
405 * The last byte of the ROM code contains a CRC calculated
406 * from the first 7 bytes. Re-calculate it to make sure
407 * we found a valid device.
408 */
409 for (i = 0; i < 8; i++)
410 data[i] = (rom >> (i * 8)) & 0xff;
411 if (onewire_crc(data, 7) != data[7])
412 continue;
413
414 /*
415 * Go through the list of attached devices to see if we
416 * found a new one.
417 */
418 present = 0;
419 TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
420 if (d->d_rom == rom) {
421 d->d_present = 1;
422 present = 1;
423 break;
424 }
425 }
426 if (!present) {
427 memset(&oa, 0, sizeof(oa));
428 oa.oa_onewire = sc;
429 oa.oa_rom = rom;
430 if ((dev = config_found(sc->sc_dev, &oa,
431 onewire_print)) == NULL)
432 continue;
433
434 nd = malloc(sizeof(struct onewire_device),
435 M_DEVBUF, M_NOWAIT);
436 if (nd == NULL)
437 continue;
438 nd->d_dev = dev;
439 nd->d_rom = rom;
440 nd->d_present = 1;
441 TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
442 }
443 }
444
445 /* Detach disappeared devices */
446 onewire_lock(sc);
447 for (d = TAILQ_FIRST(&sc->sc_devs);
448 d != NULL; d = next) {
449 next = TAILQ_NEXT(d, d_list);
450 if (!d->d_present) {
451 config_detach(d->d_dev, DETACH_FORCE);
452 TAILQ_REMOVE(&sc->sc_devs, d, d_list);
453 free(d, M_DEVBUF);
454 }
455 }
456 onewire_unlock(sc);
457}
458
459MODULE(MODULE_CLASS_DRIVER, onewire, NULL);
460
461#ifdef _MODULE
462#include "ioconf.c"
463#endif
464
465static int
466onewire_modcmd(modcmd_t cmd, void *opaque)
467{
468 int error;
469
470 error = 0;
471 switch (cmd) {
472 case MODULE_CMD_INIT:
473#ifdef _MODULE
474 error = config_init_component(cfdriver_ioconf_onewire,
475 cfattach_ioconf_onewire, cfdata_ioconf_onewire);
476 if (error)
477 aprint_error("%s: unable to init component\n",
478 onewire_cd.cd_name);
479#endif
480 break;
481 case MODULE_CMD_FINI:
482#ifdef _MODULE
483 config_fini_component(cfdriver_ioconf_onewire,
484 cfattach_ioconf_onewire, cfdata_ioconf_onewire);
485#endif
486 break;
487 default:
488 error = ENOTTY;
489 }
490 return error;
491}
492