xref: /netbsd-src/sys/dev/onewire/onewire.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* $NetBSD: onewire.c,v 1.10 2008/12/17 20:51:34 cegger 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.10 2008/12/17 20:51:34 cegger 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 			nd = malloc(sizeof(struct onewire_device),
430 				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