xref: /openbsd/sys/dev/onewire/onewire.c (revision 471aeecf)
1 /*	$OpenBSD: onewire.c,v 1.19 2022/04/06 18:59:29 naddy Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * 1-Wire bus driver.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kernel.h>
27 #include <sys/kthread.h>
28 #include <sys/malloc.h>
29 #include <sys/queue.h>
30 #include <sys/rwlock.h>
31 
32 #include <dev/onewire/onewirereg.h>
33 #include <dev/onewire/onewirevar.h>
34 
35 #ifdef ONEWIRE_DEBUG
36 #define DPRINTF(x) printf x
37 #else
38 #define DPRINTF(x)
39 #endif
40 
41 #define ONEWIRE_MAXDEVS		16
42 #define ONEWIRE_SCANTIME	SEC_TO_NSEC(3)
43 
44 struct onewire_softc {
45 	struct device			sc_dev;
46 
47 	struct onewire_bus *		sc_bus;
48 	struct rwlock			sc_lock;
49 	struct proc *			sc_thread;
50 	TAILQ_HEAD(, onewire_device)	sc_devs;
51 
52 	int				sc_dying;
53 	int				sc_flags;
54 	u_int64_t			sc_rombuf[ONEWIRE_MAXDEVS];
55 };
56 
57 struct onewire_device {
58 	TAILQ_ENTRY(onewire_device)	d_list;
59 	struct device *			d_dev;	/* may be NULL */
60 	u_int64_t			d_rom;
61 	int				d_present;
62 };
63 
64 int	onewire_match(struct device *, void *, void *);
65 void	onewire_attach(struct device *, struct device *, void *);
66 int	onewire_detach(struct device *, int);
67 int	onewire_activate(struct device *, int);
68 int	onewire_print(void *, const char *);
69 
70 void	onewire_thread(void *);
71 void	onewire_createthread(void *);
72 void	onewire_scan(struct onewire_softc *);
73 
74 const struct cfattach onewire_ca = {
75 	sizeof(struct onewire_softc),
76 	onewire_match,
77 	onewire_attach,
78 	onewire_detach,
79 	onewire_activate
80 };
81 
82 struct cfdriver onewire_cd = {
83 	NULL, "onewire", DV_DULL
84 };
85 
86 int
onewire_match(struct device * parent,void * match,void * aux)87 onewire_match(struct device *parent, void *match, void *aux)
88 {
89 	struct cfdata *cf = match;
90 
91 	return (strcmp(cf->cf_driver->cd_name, "onewire") == 0);
92 }
93 
94 void
onewire_attach(struct device * parent,struct device * self,void * aux)95 onewire_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct onewire_softc *sc = (struct onewire_softc *)self;
98 	struct onewirebus_attach_args *oba = aux;
99 
100 	sc->sc_bus = oba->oba_bus;
101 	sc->sc_flags = oba->oba_flags;
102 	rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
103 	TAILQ_INIT(&sc->sc_devs);
104 
105 	printf("\n");
106 
107 	if (sc->sc_flags & ONEWIRE_SCAN_NOW) {
108 		onewire_scan(sc);
109 		if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
110 			return;
111 	}
112 
113 	kthread_create_deferred(onewire_createthread, sc);
114 }
115 
116 int
onewire_detach(struct device * self,int flags)117 onewire_detach(struct device *self, int flags)
118 {
119 	struct onewire_softc *sc = (struct onewire_softc *)self;
120 
121 	sc->sc_dying = 1;
122 	if (sc->sc_thread != NULL) {
123 		wakeup(sc->sc_thread);
124 		tsleep_nsec(&sc->sc_dying, PWAIT, "owdt", INFSLP);
125 	}
126 
127 	return (config_detach_children(self, flags));
128 }
129 
130 int
onewire_activate(struct device * self,int act)131 onewire_activate(struct device *self, int act)
132 {
133 	struct onewire_softc *sc = (struct onewire_softc *)self;
134 
135 	switch (act) {
136 	case DVACT_DEACTIVATE:
137 		sc->sc_dying = 1;
138 		break;
139 	}
140 
141 	return (config_activate_children(self, act));
142 }
143 
144 int
onewire_print(void * aux,const char * pnp)145 onewire_print(void *aux, const char *pnp)
146 {
147 	struct onewire_attach_args *oa = aux;
148 	const char *famname;
149 
150 	if (pnp == NULL)
151 		printf(" ");
152 
153 	famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
154 	if (famname == NULL)
155 		printf("family 0x%02x", ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
156 	else
157 		printf("\"%s\"", famname);
158 	printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
159 
160 	if (pnp != NULL)
161 		printf(" at %s", pnp);
162 
163 	return (UNCONF);
164 }
165 
166 int
onewirebus_print(void * aux,const char * pnp)167 onewirebus_print(void *aux, const char *pnp)
168 {
169 	if (pnp != NULL)
170 		printf("onewire at %s", pnp);
171 
172 	return (UNCONF);
173 }
174 
175 int
onewire_lock(void * arg,int flags)176 onewire_lock(void *arg, int flags)
177 {
178 	struct onewire_softc *sc = arg;
179 	int lflags = RW_WRITE;
180 
181 	if (flags & ONEWIRE_NOWAIT)
182 		lflags |= RW_NOSLEEP;
183 
184 	return (rw_enter(&sc->sc_lock, lflags));
185 }
186 
187 void
onewire_unlock(void * arg)188 onewire_unlock(void *arg)
189 {
190 	struct onewire_softc *sc = arg;
191 
192 	rw_exit(&sc->sc_lock);
193 }
194 
195 int
onewire_reset(void * arg)196 onewire_reset(void *arg)
197 {
198 	struct onewire_softc *sc = arg;
199 	struct onewire_bus *bus = sc->sc_bus;
200 
201 	return (bus->bus_reset(bus->bus_cookie));
202 }
203 
204 int
onewire_bit(void * arg,int value)205 onewire_bit(void *arg, int value)
206 {
207 	struct onewire_softc *sc = arg;
208 	struct onewire_bus *bus = sc->sc_bus;
209 
210 	return (bus->bus_bit(bus->bus_cookie, value));
211 }
212 
213 int
onewire_read_byte(void * arg)214 onewire_read_byte(void *arg)
215 {
216 	struct onewire_softc *sc = arg;
217 	struct onewire_bus *bus = sc->sc_bus;
218 	u_int8_t value = 0;
219 	int i;
220 
221 	if (bus->bus_read_byte != NULL)
222 		return (bus->bus_read_byte(bus->bus_cookie));
223 
224 	for (i = 0; i < 8; i++)
225 		value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
226 
227 	return (value);
228 }
229 
230 void
onewire_write_byte(void * arg,int value)231 onewire_write_byte(void *arg, int value)
232 {
233 	struct onewire_softc *sc = arg;
234 	struct onewire_bus *bus = sc->sc_bus;
235 	int i;
236 
237 	if (bus->bus_write_byte != NULL)
238 		return (bus->bus_write_byte(bus->bus_cookie, value));
239 
240 	for (i = 0; i < 8; i++)
241 		bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
242 }
243 
244 void
onewire_read_block(void * arg,void * buf,int len)245 onewire_read_block(void *arg, void *buf, int len)
246 {
247 	struct onewire_softc *sc = arg;
248 	struct onewire_bus *bus = sc->sc_bus;
249 	u_int8_t *p = buf;
250 
251 	if (bus->bus_read_block != NULL)
252 		return (bus->bus_read_block(bus->bus_cookie, buf, len));
253 
254 	while (len--)
255 		*p++ = onewire_read_byte(arg);
256 }
257 
258 void
onewire_write_block(void * arg,const void * buf,int len)259 onewire_write_block(void *arg, const void *buf, int len)
260 {
261 	struct onewire_softc *sc = arg;
262 	struct onewire_bus *bus = sc->sc_bus;
263 	const u_int8_t *p = buf;
264 
265 	if (bus->bus_write_block != NULL)
266 		return (bus->bus_write_block(bus->bus_cookie, buf, len));
267 
268 	while (len--)
269 		onewire_write_byte(arg, *p++);
270 }
271 
272 int
onewire_triplet(void * arg,int dir)273 onewire_triplet(void *arg, int dir)
274 {
275 	struct onewire_softc *sc = arg;
276 	struct onewire_bus *bus = sc->sc_bus;
277 	int rv;
278 
279 	if (bus->bus_triplet != NULL)
280 		return (bus->bus_triplet(bus->bus_cookie, dir));
281 
282 	rv = bus->bus_bit(bus->bus_cookie, 1);
283 	rv <<= 1;
284 	rv |= bus->bus_bit(bus->bus_cookie, 1);
285 
286 	switch (rv) {
287 	case 0x0:
288 		bus->bus_bit(bus->bus_cookie, dir);
289 		break;
290 	case 0x1:
291 		bus->bus_bit(bus->bus_cookie, 0);
292 		break;
293 	default:
294 		bus->bus_bit(bus->bus_cookie, 1);
295 	}
296 
297 	return (rv);
298 }
299 
300 void
onewire_matchrom(void * arg,u_int64_t rom)301 onewire_matchrom(void *arg, u_int64_t rom)
302 {
303 	struct onewire_softc *sc = arg;
304 	struct onewire_bus *bus = sc->sc_bus;
305 	int i;
306 
307 	if (bus->bus_matchrom != NULL)
308 		return (bus->bus_matchrom(bus->bus_cookie, rom));
309 
310 	onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
311 	for (i = 0; i < 8; i++)
312 		onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
313 }
314 
315 int
onewire_search(void * arg,u_int64_t * buf,int size,u_int64_t startrom)316 onewire_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
317 {
318 	struct onewire_softc *sc = arg;
319 	struct onewire_bus *bus = sc->sc_bus;
320 	int search = 1, count = 0, lastd = -1, dir, rv, i, i0;
321 	u_int64_t mask, rom = startrom, lastrom;
322 	u_int8_t data[8];
323 
324 	if (bus->bus_search != NULL)
325 		return (bus->bus_search(bus->bus_cookie, buf, size, rom));
326 
327 	while (search && count < size) {
328 		/* XXX: yield processor */
329 		tsleep_nsec(sc, PWAIT, "owscan", MSEC_TO_NSEC(100));
330 
331 		/*
332 		 * Start new search. Go through the previous path to
333 		 * the point we made a decision last time and make an
334 		 * opposite decision. If we didn't make any decision
335 		 * stop searching.
336 		 */
337 		lastrom = rom;
338 		rom = 0;
339 		onewire_lock(sc, 0);
340 		onewire_reset(sc);
341 		onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
342 		for (i = 0, i0 = -1; i < 64; i++) {
343 			dir = (lastrom >> i) & 0x1;
344 			if (i == lastd)
345 				dir = 1;
346 			else if (i > lastd)
347 				dir = 0;
348 			rv = onewire_triplet(sc, dir);
349 			switch (rv) {
350 			case 0x0:
351 				if (i != lastd && dir == 0)
352 					i0 = i;
353 				mask = dir;
354 				break;
355 			case 0x1:
356 				mask = 0;
357 				break;
358 			case 0x2:
359 				mask = 1;
360 				break;
361 			default:
362 				DPRINTF(("%s: search triplet error 0x%x, "
363 				    "step %d\n",
364 				    sc->sc_dev.dv_xname, rv, i));
365 				onewire_unlock(sc);
366 				return (-1);
367 			}
368 			rom |= (mask << i);
369 		}
370 		onewire_unlock(sc);
371 
372 		if ((lastd = i0) == -1)
373 			search = 0;
374 
375 		if (rom == 0)
376 			continue;
377 
378 		/*
379 		 * The last byte of the ROM code contains a CRC calculated
380 		 * from the first 7 bytes. Re-calculate it to make sure
381 		 * we found a valid device.
382 		 */
383 		for (i = 0; i < 8; i++)
384 			data[i] = (rom >> (i * 8)) & 0xff;
385 		if (onewire_crc(data, 7) != data[7])
386 			continue;
387 
388 		buf[count++] = rom;
389 	}
390 
391 	return (count);
392 }
393 
394 void
onewire_thread(void * arg)395 onewire_thread(void *arg)
396 {
397 	struct onewire_softc *sc = arg;
398 
399 	while (!sc->sc_dying) {
400 		onewire_scan(sc);
401 		if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
402 			break;
403 		tsleep_nsec(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME);
404 	}
405 
406 	sc->sc_thread = NULL;
407 	wakeup(&sc->sc_dying);
408 	kthread_exit(0);
409 }
410 
411 void
onewire_createthread(void * arg)412 onewire_createthread(void *arg)
413 {
414 	struct onewire_softc *sc = arg;
415 
416 	if (kthread_create(onewire_thread, sc, &sc->sc_thread,
417 	    sc->sc_dev.dv_xname) != 0)
418 		printf("%s: can't create kernel thread\n",
419 		    sc->sc_dev.dv_xname);
420 }
421 
422 void
onewire_scan(struct onewire_softc * sc)423 onewire_scan(struct onewire_softc *sc)
424 {
425 	struct onewire_device *d, *next, *nd;
426 	struct onewire_attach_args oa;
427 	struct device *dev;
428 	int present;
429 	u_int64_t rom;
430 	int i, rv;
431 
432 	/*
433 	 * Mark all currently present devices as absent before
434 	 * scanning. This allows to find out later which devices
435 	 * have been disappeared.
436 	 */
437 	TAILQ_FOREACH(d, &sc->sc_devs, d_list)
438 		d->d_present = 0;
439 
440 	/*
441 	 * Reset the bus. If there's no presence pulse don't search
442 	 * for any devices.
443 	 */
444 	onewire_lock(sc, 0);
445 	rv = onewire_reset(sc);
446 	onewire_unlock(sc);
447 	if (rv != 0) {
448 		DPRINTF(("%s: no presence pulse\n", sc->sc_dev.dv_xname));
449 		goto out;
450 	}
451 
452 	/* Scan the bus */
453 	if ((rv = onewire_search(sc, sc->sc_rombuf, ONEWIRE_MAXDEVS, 0)) == -1)
454 		return;
455 
456 	for (i = 0; i < rv; i++) {
457 		rom = sc->sc_rombuf[i];
458 
459 		/*
460 		 * Go through the list of attached devices to see if we
461 		 * found a new one.
462 		 */
463 		present = 0;
464 		TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
465 			if (d->d_rom == rom) {
466 				d->d_present = 1;
467 				present = 1;
468 				break;
469 			}
470 		}
471 		if (!present) {
472 			nd = malloc(sizeof(struct onewire_device),
473 			    M_DEVBUF, M_NOWAIT);
474 			if (nd == NULL)
475 				continue;
476 
477 			bzero(&oa, sizeof(oa));
478 			oa.oa_onewire = sc;
479 			oa.oa_rom = rom;
480 			dev = config_found(&sc->sc_dev, &oa, onewire_print);
481 
482 			nd->d_dev = dev;
483 			nd->d_rom = rom;
484 			nd->d_present = 1;
485 			TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
486 		}
487 	}
488 
489 out:
490 	/* Detach disappeared devices */
491 	TAILQ_FOREACH_SAFE(d, &sc->sc_devs, d_list, next) {
492 		if (!d->d_present) {
493 			if (d->d_dev != NULL)
494 				config_detach(d->d_dev, DETACH_FORCE);
495 			TAILQ_REMOVE(&sc->sc_devs, d, d_list);
496 			free(d, M_DEVBUF, sizeof *d);
497 		}
498 	}
499 }
500