xref: /netbsd-src/sys/dev/onewire/onewire.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: onewire.c,v 1.7 2007/09/05 15:24:07 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@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.7 2007/09/05 15:24:07 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 	struct device			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 	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, void *aux)
90 {
91 	return 1;
92 }
93 
94 void
95 onewire_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct onewire_softc *sc = device_private(self);
98 	struct onewirebus_attach_args *oba = aux;
99 
100 	sc->sc_bus = oba->oba_bus;
101 	rw_init(&sc->sc_rwlock);
102 	TAILQ_INIT(&sc->sc_devs);
103 
104 	aprint_naive("\n");
105 	aprint_normal("\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 		aprint_error("%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);
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 int
135 onewire_activate(struct device *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 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 void
321 onewire_scan(struct onewire_softc *sc)
322 {
323 	struct onewire_device *d, *next, *nd;
324 	struct onewire_attach_args oa;
325 	struct device *dev;
326 	int search = 1, count = 0, present;
327 	int dir, rv;
328 	uint64_t mask, rom = 0, lastrom;
329 	uint8_t data[8];
330 	int i, i0 = -1, lastd = -1;
331 
332 	TAILQ_FOREACH(d, &sc->sc_devs, d_list)
333 		d->d_present = 0;
334 
335 	while (search && count++ < ONEWIRE_MAXDEVS) {
336 		/* XXX: yield processor */
337 		tsleep(sc, PWAIT, "owscan", hz / 10);
338 
339 		/*
340 		 * Reset the bus. If there's no presence pulse
341 		 * don't search for any devices.
342 		 */
343 		onewire_lock(sc);
344 		if (onewire_reset(sc) != 0) {
345 			DPRINTF(("%s: scan: no presence pulse\n",
346 			    sc->sc_dev.dv_xname));
347 			onewire_unlock(sc);
348 			break;
349 		}
350 
351 		/*
352 		 * Start new search. Go through the previous path to
353 		 * the point we made a decision last time and make an
354 		 * opposite decision. If we didn't make any decision
355 		 * stop searching.
356 		 */
357 		search = 0;
358 		lastrom = rom;
359 		rom = 0;
360 		onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
361 		for (i = 0,i0 = -1; i < 64; i++) {
362 			dir = (lastrom >> i) & 0x1;
363 			if (i == lastd)
364 				dir = 1;
365 			else if (i > lastd)
366 				dir = 0;
367 			rv = onewire_triplet(sc, dir);
368 			switch (rv) {
369 			case 0x0:
370 				if (i != lastd) {
371 					if (dir == 0)
372 						i0 = i;
373 					search = 1;
374 				}
375 				mask = dir;
376 				break;
377 			case 0x1:
378 				mask = 0;
379 				break;
380 			case 0x2:
381 				mask = 1;
382 				break;
383 			default:
384 				DPRINTF(("%s: scan: triplet error 0x%x, "
385 				    "step %d\n",
386 				    sc->sc_dev.dv_xname, rv, i));
387 				onewire_unlock(sc);
388 				return;
389 			}
390 			rom |= (mask << i);
391 		}
392 		lastd = i0;
393 		onewire_unlock(sc);
394 
395 		if (rom == 0)
396 			continue;
397 
398 		/*
399 		 * The last byte of the ROM code contains a CRC calculated
400 		 * from the first 7 bytes. Re-calculate it to make sure
401 		 * we found a valid device.
402 		 */
403 		for (i = 0; i < 8; i++)
404 			data[i] = (rom >> (i * 8)) & 0xff;
405 		if (onewire_crc(data, 7) != data[7])
406 			continue;
407 
408 		/*
409 		 * Go through the list of attached devices to see if we
410 		 * found a new one.
411 		 */
412 		present = 0;
413 		TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
414 			if (d->d_rom == rom) {
415 				d->d_present = 1;
416 				present = 1;
417 				break;
418 			}
419 		}
420 		if (!present) {
421 			bzero(&oa, sizeof(oa));
422 			oa.oa_onewire = sc;
423 			oa.oa_rom = rom;
424 			if ((dev = config_found(&sc->sc_dev, &oa,
425 			    onewire_print)) == NULL)
426 				continue;
427 
428 			MALLOC(nd, struct onewire_device *,
429 			    sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT);
430 			if (nd == NULL)
431 				continue;
432 			nd->d_dev = dev;
433 			nd->d_rom = rom;
434 			nd->d_present = 1;
435 			TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
436 		}
437 	}
438 
439 	/* Detach disappeared devices */
440 	onewire_lock(sc);
441 	for (d = TAILQ_FIRST(&sc->sc_devs);
442 	    d != NULL; d = next) {
443 		next = TAILQ_NEXT(d, d_list);
444 		if (!d->d_present) {
445 			config_detach(d->d_dev, DETACH_FORCE);
446 			TAILQ_REMOVE(&sc->sc_devs, d, d_list);
447 			FREE(d, M_DEVBUF);
448 		}
449 	}
450 	onewire_unlock(sc);
451 }
452