Home | History | Annotate | Line # | Download | only in onewire
onewire.c revision 1.15.2.1
      1 /* $NetBSD: onewire.c,v 1.15.2.1 2014/08/10 06:54:54 tls 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 (at) 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.15.2.1 2014/08/10 06:54:54 tls 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 
     52 struct 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 
     63 struct 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 
     70 static int	onewire_match(device_t, cfdata_t, void *);
     71 static void	onewire_attach(device_t, device_t, void *);
     72 static int	onewire_detach(device_t, int);
     73 static int	onewire_activate(device_t, enum devact);
     74 int		onewire_print(void *, const char *);
     75 
     76 static void	onewire_thread(void *);
     77 static void	onewire_scan(struct onewire_softc *);
     78 
     79 CFATTACH_DECL_NEW(onewire, sizeof(struct onewire_softc),
     80 	onewire_match, onewire_attach, onewire_detach, onewire_activate);
     81 
     82 const 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 
     97 extern struct cfdriver onewire_cd;
     98 
     99 static int
    100 onewire_match(device_t parent, cfdata_t cf, void *aux)
    101 {
    102 	return 1;
    103 }
    104 
    105 static void
    106 onewire_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 
    123 static int
    124 onewire_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 
    144 static int
    145 onewire_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 
    158 int
    159 onewire_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 
    181 int
    182 onewirebus_print(void *aux, const char *pnp)
    183 {
    184 	if (pnp != NULL)
    185 		aprint_normal("onewire at %s", pnp);
    186 
    187 	return UNCONF;
    188 }
    189 
    190 void
    191 onewire_lock(void *arg)
    192 {
    193 	struct onewire_softc *sc = arg;
    194 
    195 	rw_enter(&sc->sc_rwlock, RW_WRITER);
    196 }
    197 
    198 void
    199 onewire_unlock(void *arg)
    200 {
    201 	struct onewire_softc *sc = arg;
    202 
    203 	rw_exit(&sc->sc_rwlock);
    204 }
    205 
    206 int
    207 onewire_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 
    215 int
    216 onewire_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 
    224 int
    225 onewire_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 
    241 void
    242 onewire_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 
    255 int
    256 onewire_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 
    283 void
    284 onewire_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 
    292 void
    293 onewire_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 
    301 void
    302 onewire_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 
    311 static void
    312 onewire_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 
    326 static void
    327 onewire_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 
    459 MODULE(MODULE_CLASS_DRIVER, onewire, NULL);
    460 
    461 #ifdef _MODULE
    462 #include "ioconf.c"
    463 #endif
    464 
    465 static int
    466 onewire_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