xref: /netbsd-src/sys/dev/onewire/onewire.c (revision ce2c90c7c172d95d2402a5b3d96d8f8e6d138a21)
1 /* $NetBSD: onewire.c,v 1.3 2006/10/12 01:31:27 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@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.3 2006/10/12 01:31:27 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 __unused, struct cfdata *cf __unused,
91     void *aux __unused)
92 {
93 	return 1;
94 }
95 
96 void
97 onewire_attach(struct device *parent __unused, struct device *self, void *aux)
98 {
99 	struct onewire_softc *sc = device_private(self);
100 	struct onewirebus_attach_args *oba = aux;
101 
102 	sc->sc_bus = oba->oba_bus;
103 	lockinit(&sc->sc_lock, PRIBIO, "owlock", 0, 0);
104 	TAILQ_INIT(&sc->sc_devs);
105 
106 	printf("\n");
107 
108 	kthread_create(onewire_createthread, sc);
109 }
110 
111 int
112 onewire_detach(struct device *self, int flags __unused)
113 {
114 	struct onewire_softc *sc = device_private(self);
115 	int rv;
116 
117 	sc->sc_dying = 1;
118 	if (sc->sc_thread != NULL) {
119 		wakeup(sc->sc_thread);
120 		tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
121 	}
122 
123 	onewire_lock(sc, 0);
124 	//rv = config_detach_children(self, flags);
125 	rv = 0;  /* XXX riz */
126 	onewire_unlock(sc);
127 
128 	return (rv);
129 }
130 
131 int
132 onewire_activate(struct device *self, enum devact act)
133 {
134 	struct onewire_softc *sc = device_private(self);
135 	int rv = 0;
136 
137 	switch (act) {
138 	case DVACT_ACTIVATE:
139 		rv = EOPNOTSUPP;
140 		break;
141 	case DVACT_DEACTIVATE:
142 		sc->sc_dying = 1;
143 		break;
144 	}
145 
146 	//return (config_activate_children(self, act));
147 	return rv;
148 }
149 
150 int
151 onewire_print(void *aux, const char *pnp)
152 {
153 	struct onewire_attach_args *oa = aux;
154 	const char *famname;
155 
156 	if (pnp == NULL)
157 		printf(" ");
158 
159 	famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
160 	if (famname == NULL)
161 		printf("family 0x%02x", (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
162 	else
163 		printf("\"%s\"", famname);
164 	printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
165 
166 	if (pnp != NULL)
167 		printf(" at %s", pnp);
168 
169 	return (UNCONF);
170 }
171 
172 int
173 onewirebus_print(void *aux __unused, const char *pnp)
174 {
175 	if (pnp != NULL)
176 		printf("onewire at %s", pnp);
177 
178 	return (UNCONF);
179 }
180 
181 int
182 onewire_lock(void *arg, int flags)
183 {
184 	struct onewire_softc *sc = arg;
185 	int lflags = LK_EXCLUSIVE;
186 
187 	if (flags & ONEWIRE_NOWAIT)
188 		lflags |= LK_NOWAIT;
189 
190 	return (lockmgr(&sc->sc_lock, lflags, NULL));
191 }
192 
193 void
194 onewire_unlock(void *arg)
195 {
196 	struct onewire_softc *sc = arg;
197 
198 	lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
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 	u_int8_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 	u_int8_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 u_int8_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 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 void
322 onewire_createthread(void *arg)
323 {
324 	struct onewire_softc *sc = arg;
325 
326 	if (kthread_create1(onewire_thread, sc, &sc->sc_thread,
327 	    "%s", sc->sc_dev.dv_xname) != 0)
328 		printf("%s: can't create kernel thread\n",
329 		    sc->sc_dev.dv_xname);
330 }
331 
332 void
333 onewire_scan(struct onewire_softc *sc)
334 {
335 	struct onewire_device *d, *next, *nd;
336 	struct onewire_attach_args oa;
337 	struct device *dev;
338 	int search = 1, count = 0, present;
339 	int dir, rv;
340 	u_int64_t mask, rom = 0, lastrom;
341 	u_int8_t data[8];
342 	int i, i0 = -1, lastd = -1;
343 
344 	TAILQ_FOREACH(d, &sc->sc_devs, d_list)
345 		d->d_present = 0;
346 
347 	while (search && count++ < ONEWIRE_MAXDEVS) {
348 		/* XXX: yield processor */
349 		tsleep(sc, PWAIT, "owscan", hz / 10);
350 
351 		/*
352 		 * Reset the bus. If there's no presence pulse
353 		 * don't search for any devices.
354 		 */
355 		onewire_lock(sc, 0);
356 		if (onewire_reset(sc) != 0) {
357 			DPRINTF(("%s: scan: no presence pulse\n",
358 			    sc->sc_dev.dv_xname));
359 			onewire_unlock(sc);
360 			break;
361 		}
362 
363 		/*
364 		 * Start new search. Go through the previous path to
365 		 * the point we made a decision last time and make an
366 		 * opposite decision. If we didn't make any decision
367 		 * stop searching.
368 		 */
369 		search = 0;
370 		lastrom = rom;
371 		rom = 0;
372 		onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
373 		for (i = 0,i0 = -1; i < 64; i++) {
374 			dir = (lastrom >> i) & 0x1;
375 			if (i == lastd)
376 				dir = 1;
377 			else if (i > lastd)
378 				dir = 0;
379 			rv = onewire_triplet(sc, dir);
380 			switch (rv) {
381 			case 0x0:
382 				if (i != lastd) {
383 					if (dir == 0)
384 						i0 = i;
385 					search = 1;
386 				}
387 				mask = dir;
388 				break;
389 			case 0x1:
390 				mask = 0;
391 				break;
392 			case 0x2:
393 				mask = 1;
394 				break;
395 			default:
396 				DPRINTF(("%s: scan: triplet error 0x%x, "
397 				    "step %d\n",
398 				    sc->sc_dev.dv_xname, rv, i));
399 				onewire_unlock(sc);
400 				return;
401 			}
402 			rom |= (mask << i);
403 		}
404 		lastd = i0;
405 		onewire_unlock(sc);
406 
407 		if (rom == 0)
408 			continue;
409 
410 		/*
411 		 * The last byte of the ROM code contains a CRC calculated
412 		 * from the first 7 bytes. Re-calculate it to make sure
413 		 * we found a valid device.
414 		 */
415 		for (i = 0; i < 8; i++)
416 			data[i] = (rom >> (i * 8)) & 0xff;
417 		if (onewire_crc(data, 7) != data[7])
418 			continue;
419 
420 		/*
421 		 * Go through the list of attached devices to see if we
422 		 * found a new one.
423 		 */
424 		present = 0;
425 		TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
426 			if (d->d_rom == rom) {
427 				d->d_present = 1;
428 				present = 1;
429 				break;
430 			}
431 		}
432 		if (!present) {
433 			bzero(&oa, sizeof(oa));
434 			oa.oa_onewire = sc;
435 			oa.oa_rom = rom;
436 			if ((dev = config_found(&sc->sc_dev, &oa,
437 			    onewire_print)) == NULL)
438 				continue;
439 
440 			MALLOC(nd, struct onewire_device *,
441 			    sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT);
442 			if (nd == NULL)
443 				continue;
444 			nd->d_dev = dev;
445 			nd->d_rom = rom;
446 			nd->d_present = 1;
447 			TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
448 		}
449 	}
450 
451 	/* Detach disappeared devices */
452 	onewire_lock(sc, 0);
453 	for (d = TAILQ_FIRST(&sc->sc_devs);
454 	    d != NULL; d = next) {
455 		next = TAILQ_NEXT(d, d_list);
456 		if (!d->d_present) {
457 			config_detach(d->d_dev, DETACH_FORCE);
458 			TAILQ_REMOVE(&sc->sc_devs, d, d_list);
459 			FREE(d, M_DEVBUF);
460 		}
461 	}
462 	onewire_unlock(sc);
463 }
464