diff options
| author | riz <riz@NetBSD.org> | 2006-04-07 18:55:21 +0000 |
|---|---|---|
| committer | riz <riz@NetBSD.org> | 2006-04-07 18:55:21 +0000 |
| commit | 637bfc29f9b717579ac32fb830009fc467e5f862 (patch) | |
| tree | d61cab55f51d45c366edc296049c13b38f1f039b /sys/dev | |
| parent | 5b93dbb4b1a333f52258aad7f780efd30bee936f (diff) | |
Dallas Semiconductor 1-Wire bus support, from OpenBSD. Currently includes
gpioow(4), attaching a bit-banging driver via a GPIO pin. Also,
owtemp(4) which supports some of the 1-Wire temperature sensors, including
the DS18b20 and DS1920 - temperatures are returned via the envsys(4)
framework.
Original drivers by Alexander Yurchenko (grange@openbsd), with envsys(4)
support and a fix to the 1-wire search algorithm (for discovering
devices on the bus) by me.
As discussed on tech-kern earlier this week.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/gpio/files.gpio | 6 | ||||
| -rw-r--r-- | sys/dev/gpio/gpioow.c | 240 | ||||
| -rw-r--r-- | sys/dev/onewire/Makefile.onewiredevs | 8 | ||||
| -rw-r--r-- | sys/dev/onewire/devlist2h.awk | 56 | ||||
| -rw-r--r-- | sys/dev/onewire/files.onewire | 15 | ||||
| -rw-r--r-- | sys/dev/onewire/onewire.c | 462 | ||||
| -rw-r--r-- | sys/dev/onewire/onewire_bitbang.c | 81 | ||||
| -rw-r--r-- | sys/dev/onewire/onewire_subr.c | 112 | ||||
| -rw-r--r-- | sys/dev/onewire/onewiredevs | 34 | ||||
| -rw-r--r-- | sys/dev/onewire/onewiredevs.h | 20 | ||||
| -rw-r--r-- | sys/dev/onewire/onewiredevs_data.h | 23 | ||||
| -rw-r--r-- | sys/dev/onewire/onewirereg.h | 72 | ||||
| -rw-r--r-- | sys/dev/onewire/onewirevar.h | 86 | ||||
| -rw-r--r-- | sys/dev/onewire/owtemp.c | 294 |
14 files changed, 1508 insertions, 1 deletions
diff --git a/sys/dev/gpio/files.gpio b/sys/dev/gpio/files.gpio index 0798a5c7e0f..61131a3b531 100644 --- a/sys/dev/gpio/files.gpio +++ b/sys/dev/gpio/files.gpio @@ -1,7 +1,11 @@ -# $NetBSD: files.gpio,v 1.3 2006/02/20 03:18:36 riz Exp $ +# $NetBSD: files.gpio,v 1.4 2006/04/07 18:55:21 riz Exp $ define gpio {offset, mask} device gpio: gpio attach gpio at gpiobus file dev/gpio/gpio.c gpio needs-flag + +device gpioow: onewirebus, onewire_bitbang +attach gpioow at gpio +file dev/gpio/gpioow.c gpioow diff --git a/sys/dev/gpio/gpioow.c b/sys/dev/gpio/gpioow.c new file mode 100644 index 00000000000..035ec82b414 --- /dev/null +++ b/sys/dev/gpio/gpioow.c @@ -0,0 +1,240 @@ +/* $NetBSD: gpioow.c,v 1.1 2006/04/07 18:55:21 riz Exp $ */ +/* $OpenBSD: gpioow.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: gpioow.c,v 1.1 2006/04/07 18:55:21 riz Exp $"); + +/* + * 1-Wire bus bit-banging through GPIO pin. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/gpio.h> + +#include <dev/gpio/gpiovar.h> + +#include <dev/onewire/onewirevar.h> + +#define GPIOOW_NPINS 1 +#define GPIOOW_PIN_DATA 0 + +struct gpioow_softc { + struct device sc_dev; + + void * sc_gpio; + struct gpio_pinmap sc_map; + int __map[GPIOOW_NPINS]; + + struct onewire_bus sc_ow_bus; + struct device * sc_ow_dev; + + int sc_data; + int sc_dying; +}; + +int gpioow_match(struct device *, struct cfdata *, void *); +void gpioow_attach(struct device *, struct device *, void *); +int gpioow_detach(struct device *, int); +int gpioow_activate(struct device *, enum devact); + +int gpioow_ow_reset(void *); +int gpioow_ow_bit(void *, int); + +void gpioow_bb_rx(void *); +void gpioow_bb_tx(void *); +int gpioow_bb_get(void *); +void gpioow_bb_set(void *, int); + +CFATTACH_DECL(gpioow, sizeof(struct gpioow_softc), + gpioow_match, gpioow_attach, gpioow_detach, gpioow_activate); + +extern struct cfdriver gpioow_cd; + +static const struct onewire_bbops gpioow_bbops = { + gpioow_bb_rx, + gpioow_bb_tx, + gpioow_bb_get, + gpioow_bb_set +}; + +int +gpioow_match(struct device *parent, struct cfdata *cf, void *aux) +{ + return 1; +} + +void +gpioow_attach(struct device *parent, struct device *self, void *aux) +{ + struct gpioow_softc *sc = device_private(self); + struct gpio_attach_args *ga = aux; + struct onewirebus_attach_args oba; + int caps; + + /* Check that we have enough pins */ + if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { + printf(": invalid pin mask\n"); + return; + } + + /* Map pins */ + sc->sc_gpio = ga->ga_gpio; + sc->sc_map.pm_map = sc->__map; + if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, + &sc->sc_map)) { + printf(": can't map pins\n"); + return; + } + + /* Configure data pin */ + caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); + if (!(caps & GPIO_PIN_OUTPUT)) { + printf(": data pin is unable to drive output\n"); + goto fail; + } + if (!(caps & GPIO_PIN_INPUT)) { + printf(": data pin is unable to read input\n"); + goto fail; + } + printf(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); + sc->sc_data = GPIO_PIN_OUTPUT; + if (caps & GPIO_PIN_OPENDRAIN) { + printf(" open-drain"); + sc->sc_data |= GPIO_PIN_OPENDRAIN; + } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { + printf(" push-pull tri-state"); + sc->sc_data |= GPIO_PIN_PUSHPULL; + } + if (caps & GPIO_PIN_PULLUP) { + printf(" pull-up"); + sc->sc_data |= GPIO_PIN_PULLUP; + } + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data); + + printf("\n"); + + /* Attach 1-Wire bus */ + sc->sc_ow_bus.bus_cookie = sc; + sc->sc_ow_bus.bus_reset = gpioow_ow_reset; + sc->sc_ow_bus.bus_bit = gpioow_ow_bit; + + bzero(&oba, sizeof(oba)); + oba.oba_bus = &sc->sc_ow_bus; + sc->sc_ow_dev = config_found(self, &oba, onewirebus_print); + + return; + +fail: + gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); +} + +int +gpioow_detach(struct device *self, int flags) +{ + struct gpioow_softc *sc = device_private(self); + int rv = 0; + + if (sc->sc_ow_dev != NULL) + rv = config_detach(sc->sc_ow_dev, flags); + + return (rv); +} + +int +gpioow_activate(struct device *self, enum devact act) +{ + struct gpioow_softc *sc = device_private(self); + int rv = 0; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + if (sc->sc_ow_dev != NULL) + rv = config_deactivate(sc->sc_ow_dev); + break; + } + + return (rv); +} + +int +gpioow_ow_reset(void *arg) +{ + return (onewire_bb_reset(&gpioow_bbops, arg)); +} + +int +gpioow_ow_bit(void *arg, int value) +{ + return (onewire_bb_bit(&gpioow_bbops, arg, value)); +} + +void +gpioow_bb_rx(void *arg) +{ + struct gpioow_softc *sc = arg; + int data = sc->sc_data; + + data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); + data |= GPIO_PIN_INPUT; + if (data & GPIO_PIN_PUSHPULL) + data |= GPIO_PIN_TRISTATE; + if (sc->sc_data != data) { + sc->sc_data = data; + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, + sc->sc_data); + } +} + +void +gpioow_bb_tx(void *arg) +{ + struct gpioow_softc *sc = arg; + int data = sc->sc_data; + + data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); + data |= GPIO_PIN_OUTPUT; + if (sc->sc_data != data) { + sc->sc_data = data; + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, + sc->sc_data); + } +} + +int +gpioow_bb_get(void *arg) +{ + struct gpioow_softc *sc = arg; + + return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) == + GPIO_PIN_HIGH ? 1 : 0); +} + +void +gpioow_bb_set(void *arg, int value) +{ + struct gpioow_softc *sc = arg; + + gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, + value ? GPIO_PIN_HIGH : GPIO_PIN_LOW); +} diff --git a/sys/dev/onewire/Makefile.onewiredevs b/sys/dev/onewire/Makefile.onewiredevs new file mode 100644 index 00000000000..e3861bcd546 --- /dev/null +++ b/sys/dev/onewire/Makefile.onewiredevs @@ -0,0 +1,8 @@ +# $NetBSD: Makefile.onewiredevs,v 1.1 2006/04/07 18:55:22 riz Exp $ +# $OpenBSD: Makefile,v 1.1 2006/03/04 16:27:03 grange Exp $ + +AWK?= awk + +onewiredevs.h onewiredevs_data.h: onewiredevs devlist2h.awk + /bin/rm -f onewiredevs.h onewiredevs_data.h + ${AWK} -f devlist2h.awk onewiredevs diff --git a/sys/dev/onewire/devlist2h.awk b/sys/dev/onewire/devlist2h.awk new file mode 100644 index 00000000000..149af6e0b23 --- /dev/null +++ b/sys/dev/onewire/devlist2h.awk @@ -0,0 +1,56 @@ +# $NetBSD: devlist2h.awk,v 1.1 2006/04/07 18:55:22 riz Exp $ +# $OpenBSD: devlist2h.awk,v 1.3 2006/03/10 14:36:32 grange Exp $ + +# +# Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +BEGIN { + hfile = "onewiredevs.h" + dfile = "onewiredevs_data.h" +} + +NR == 1 { + VERSION = $0 + gsub("\\$", "", VERSION) + + printf("/*\t\$NetBSD\$\t*/\n\n" \ + "/*\n * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n" \ + " *\n * Generated from:\n *\t%s\n */\n\n", VERSION) > hfile + printf("/*\t\$NetBSD\$\t*/\n\n" \ + "/*\n * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n" \ + " *\n * Generated from:\n *\t%s\n */\n\n", VERSION) > dfile + printf("static const struct onewire_family " \ + "onewire_famtab[] = {\n") > dfile +} + +$1 == "family" { + printf("#define ONEWIRE_FAMILY_%s\t%s\n", toupper($2), $3) > hfile + printf("\t{ ONEWIRE_FAMILY_%s, \"", toupper($2)) > dfile + + f = 4 + while (f <= NF) { + if (f > 4) + printf(" ") > dfile + printf("%s", $f) > dfile + f++ + } + printf("\" },\n") > dfile + next +} + +END { + printf("\t{ 0, NULL }\n};\n") > dfile +} diff --git a/sys/dev/onewire/files.onewire b/sys/dev/onewire/files.onewire new file mode 100644 index 00000000000..6dc17462822 --- /dev/null +++ b/sys/dev/onewire/files.onewire @@ -0,0 +1,15 @@ +# $OpenBSD: files.onewire,v 1.1 2006/03/04 16:27:03 grange Exp $ + +define onewire {} + +device onewire: onewire +attach onewire at onewirebus +file dev/onewire/onewire.c onewire +file dev/onewire/onewire_subr.c onewire + +file dev/onewire/onewire_bitbang.c onewire_bitbang + +# Temperature family type device +device owtemp: sysmon_envsys +attach owtemp at onewire +file dev/onewire/owtemp.c owtemp diff --git a/sys/dev/onewire/onewire.c b/sys/dev/onewire/onewire.c new file mode 100644 index 00000000000..b87656790a2 --- /dev/null +++ b/sys/dev/onewire/onewire.c @@ -0,0 +1,462 @@ +/* $NetBSD: onewire.c,v 1.1 2006/04/07 18:55:22 riz Exp $ */ +/* $OpenBSD: onewire.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: onewire.c,v 1.1 2006/04/07 18:55:22 riz Exp $"); + +/* + * 1-Wire bus driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/queue.h> + +#include <dev/onewire/onewirereg.h> +#include <dev/onewire/onewirevar.h> + +#ifdef ONEWIRE_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + +//#define ONEWIRE_MAXDEVS 256 +#define ONEWIRE_MAXDEVS 8 +#define ONEWIRE_SCANTIME 3 + +struct onewire_softc { + struct device sc_dev; + + struct onewire_bus * sc_bus; + struct lock sc_lock; + struct proc * sc_thread; + TAILQ_HEAD(, onewire_device) sc_devs; + + int sc_dying; +}; + +struct onewire_device { + TAILQ_ENTRY(onewire_device) d_list; + struct device * d_dev; + u_int64_t d_rom; + int d_present; +}; + +int onewire_match(struct device *, struct cfdata *, void *); +void onewire_attach(struct device *, struct device *, void *); +int onewire_detach(struct device *, int); +int onewire_activate(struct device *, enum devact); +int onewire_print(void *, const char *); + +void onewire_thread(void *); +void onewire_createthread(void *); +void onewire_scan(struct onewire_softc *); + +CFATTACH_DECL(onewire, sizeof(struct onewire_softc), + onewire_match, onewire_attach, onewire_detach, onewire_activate); + +const struct cdevsw onewire_cdevsw = { + noopen, noclose, noread, nowrite, noioctl, nostop, notty, + nopoll, nommap, nokqfilter, +}; + +extern struct cfdriver onewire_cd; + +int +onewire_match(struct device *parent, struct cfdata *cf, void *aux) +{ + return 1; +} + +void +onewire_attach(struct device *parent, struct device *self, void *aux) +{ + struct onewire_softc *sc = device_private(self); + struct onewirebus_attach_args *oba = aux; + + sc->sc_bus = oba->oba_bus; + lockinit(&sc->sc_lock, PRIBIO, "owlock", 0, 0); + TAILQ_INIT(&sc->sc_devs); + + printf("\n"); + + kthread_create(onewire_createthread, sc); +} + +int +onewire_detach(struct device *self, int flags) +{ + struct onewire_softc *sc = device_private(self); + int rv; + + sc->sc_dying = 1; + if (sc->sc_thread != NULL) { + wakeup(sc->sc_thread); + tsleep(&sc->sc_dying, PWAIT, "owdt", 0); + } + + onewire_lock(sc, 0); + //rv = config_detach_children(self, flags); + rv = 0; /* XXX riz */ + onewire_unlock(sc); + + return (rv); +} + +int +onewire_activate(struct device *self, enum devact act) +{ + struct onewire_softc *sc = device_private(self); + int rv = 0; + + switch (act) { + case DVACT_ACTIVATE: + rv = EOPNOTSUPP; + break; + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + break; + } + + //return (config_activate_children(self, act)); + return rv; +} + +int +onewire_print(void *aux, const char *pnp) +{ + struct onewire_attach_args *oa = aux; + const char *famname; + + if (pnp == NULL) + printf(" "); + + famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); + if (famname == NULL) + printf("family 0x%02x", (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); + else + printf("\"%s\"", famname); + printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); + + if (pnp != NULL) + printf(" at %s", pnp); + + return (UNCONF); +} + +int +onewirebus_print(void *aux, const char *pnp) +{ + if (pnp != NULL) + printf("onewire at %s", pnp); + + return (UNCONF); +} + +int +onewire_lock(void *arg, int flags) +{ + struct onewire_softc *sc = arg; + int lflags = LK_EXCLUSIVE; + + if (flags & ONEWIRE_NOWAIT) + lflags |= LK_NOWAIT; + + return (lockmgr(&sc->sc_lock, lflags, NULL)); +} + +void +onewire_unlock(void *arg) +{ + struct onewire_softc *sc = arg; + + lockmgr(&sc->sc_lock, LK_RELEASE, NULL); +} + +int +onewire_reset(void *arg) +{ + struct onewire_softc *sc = arg; + struct onewire_bus *bus = sc->sc_bus; + + return (bus->bus_reset(bus->bus_cookie)); +} + +int +onewire_bit(void *arg, int value) +{ + struct onewire_softc *sc = arg; + struct onewire_bus *bus = sc->sc_bus; + + return (bus->bus_bit(bus->bus_cookie, value)); +} + +int +onewire_read_byte(void *arg) +{ + struct onewire_softc *sc = arg; + struct onewire_bus *bus = sc->sc_bus; + u_int8_t value = 0; + int i; + + if (bus->bus_read_byte != NULL) + return (bus->bus_read_byte(bus->bus_cookie)); + + for (i = 0; i < 8; i++) + value |= (bus->bus_bit(bus->bus_cookie, 1) << i); + + return (value); +} + +void +onewire_write_byte(void *arg, int value) +{ + struct onewire_softc *sc = arg; + struct onewire_bus *bus = sc->sc_bus; + int i; + + if (bus->bus_write_byte != NULL) + return (bus->bus_write_byte(bus->bus_cookie, value)); + + for (i = 0; i < 8; i++) + bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1); +} + +int +onewire_triplet(void *arg, int dir) +{ + struct onewire_softc *sc = arg; + struct onewire_bus *bus = sc->sc_bus; + int rv; + + if (bus->bus_triplet != NULL) + return (bus->bus_triplet(bus->bus_cookie, dir)); + + rv = bus->bus_bit(bus->bus_cookie, 1); + rv <<= 1; + rv |= bus->bus_bit(bus->bus_cookie, 1); + + switch (rv) { + case 0x0: + bus->bus_bit(bus->bus_cookie, dir); + break; + case 0x1: + bus->bus_bit(bus->bus_cookie, 0); + break; + default: + bus->bus_bit(bus->bus_cookie, 1); + } + + return (rv); +} + +void +onewire_read_block(void *arg, void *buf, int len) +{ + u_int8_t *p = buf; + + while (len--) + *p++ = onewire_read_byte(arg); +} + +void +onewire_write_block(void *arg, const void *buf, int len) +{ + const u_int8_t *p = buf; + + while (len--) + onewire_write_byte(arg, *p++); +} + +void +onewire_matchrom(void *arg, u_int64_t rom) +{ + int i; + + onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM); + for (i = 0; i < 8; i++) + onewire_write_byte(arg, (rom >> (i * 8)) & 0xff); +} + +void +onewire_thread(void *arg) +{ + struct onewire_softc *sc = arg; + + while (!sc->sc_dying) { + onewire_scan(sc); + tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz); + } + + sc->sc_thread = NULL; + wakeup(&sc->sc_dying); + kthread_exit(0); +} + +void +onewire_createthread(void *arg) +{ + struct onewire_softc *sc = arg; + + if (kthread_create1(onewire_thread, sc, &sc->sc_thread, + "%s", sc->sc_dev.dv_xname) != 0) + printf("%s: can't create kernel thread\n", + sc->sc_dev.dv_xname); +} + +void +onewire_scan(struct onewire_softc *sc) +{ + struct onewire_device *d, *next, *nd; + struct onewire_attach_args oa; + struct device *dev; + int search = 1, count = 0, present; + int dir, rv; + u_int64_t mask, rom = 0, lastrom; + u_int8_t data[8]; + int i, i0 = -1, lastd = -1; + + TAILQ_FOREACH(d, &sc->sc_devs, d_list) + d->d_present = 0; + + while (search && count++ < ONEWIRE_MAXDEVS) { + /* XXX: yield processor */ + tsleep(sc, PWAIT, "owscan", hz / 10); + + /* + * Reset the bus. If there's no presence pulse + * don't search for any devices. + */ + onewire_lock(sc, 0); + if (onewire_reset(sc) != 0) { + DPRINTF(("%s: scan: no presence pulse\n", + sc->sc_dev.dv_xname)); + onewire_unlock(sc); + break; + } + + /* + * Start new search. Go through the previous path to + * the point we made a decision last time and make an + * opposite decision. If we didn't make any decision + * stop searching. + */ + search = 0; + lastrom = rom; + rom = 0; + onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM); + for (i = 0,i0 = -1; i < 64; i++) { + dir = (lastrom >> i) & 0x1; + if (i == lastd) + dir = 1; + else if (i > lastd) + dir = 0; + rv = onewire_triplet(sc, dir); + switch (rv) { + case 0x0: + if (i != lastd) { + if (dir == 0) + i0 = i; + search = 1; + } + mask = dir; + break; + case 0x1: + mask = 0; + break; + case 0x2: + mask = 1; + break; + default: + DPRINTF(("%s: scan: triplet error 0x%x, " + "step %d\n", + sc->sc_dev.dv_xname, rv, i)); + onewire_unlock(sc); + return; + } + rom |= (mask << i); + } + lastd = i0; + onewire_unlock(sc); + + if (rom == 0) + continue; + + /* + * The last byte of the ROM code contains a CRC calculated + * from the first 7 bytes. Re-calculate it to make sure + * we found a valid device. + */ + for (i = 0; i < 8; i++) + data[i] = (rom >> (i * 8)) & 0xff; + if (onewire_crc(data, 7) != data[7]) + continue; + + /* + * Go through the list of attached devices to see if we + * found a new one. + */ + present = 0; + TAILQ_FOREACH(d, &sc->sc_devs, d_list) { + if (d->d_rom == rom) { + d->d_present = 1; + present = 1; + break; + } + } + if (!present) { + bzero(&oa, sizeof(oa)); + oa.oa_onewire = sc; + oa.oa_rom = rom; + if ((dev = config_found(&sc->sc_dev, &oa, + onewire_print)) == NULL) + continue; + + MALLOC(nd, struct onewire_device *, + sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT); + if (nd == NULL) + continue; + nd->d_dev = dev; + nd->d_rom = rom; + nd->d_present = 1; + TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list); + } + } + + /* Detach disappeared devices */ + onewire_lock(sc, 0); + for (d = TAILQ_FIRST(&sc->sc_devs); + d != NULL; d = next) { + next = TAILQ_NEXT(d, d_list); + if (!d->d_present) { + config_detach(d->d_dev, DETACH_FORCE); + TAILQ_REMOVE(&sc->sc_devs, d, d_list); + FREE(d, M_DEVBUF); + } + } + onewire_unlock(sc); +} diff --git a/sys/dev/onewire/onewire_bitbang.c b/sys/dev/onewire/onewire_bitbang.c new file mode 100644 index 00000000000..5ebc7459566 --- /dev/null +++ b/sys/dev/onewire/onewire_bitbang.c @@ -0,0 +1,81 @@ +/* $NetBSD: onewire_bitbang.c,v 1.1 2006/04/07 18:55:22 riz Exp $ */ +/* $OpenBSD: onewire_bitbang.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: onewire_bitbang.c,v 1.1 2006/04/07 18:55:22 riz Exp $"); + +/* + * 1-Wire bus bit-banging routines. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/onewire/onewirevar.h> + +int +onewire_bb_reset(const struct onewire_bbops *ops, void *arg) +{ + int s, rv = 0, i; + + s = splhigh(); + ops->bb_tx(arg); + ops->bb_set(arg, 0); + DELAY(480); + ops->bb_set(arg, 1); + ops->bb_rx(arg); + DELAY(30); + for (i = 0; i < 6; i++) { + if ((rv = ops->bb_get(arg)) == 0) + break; + DELAY(20); + } + DELAY(450); + splx(s); + + return (rv); +} + +int +onewire_bb_bit(const struct onewire_bbops *ops, void *arg, int value) +{ + int s, rv = 0, i; + + s = splhigh(); + ops->bb_tx(arg); + ops->bb_set(arg, 0); + DELAY(2); + if (value) { + ops->bb_set(arg, 1); + ops->bb_rx(arg); + for (i = 0; i < 15; i++) { + if ((rv = ops->bb_get(arg)) == 0) + break; + DELAY(2); + } + ops->bb_tx(arg); + } + DELAY(60); + ops->bb_set(arg, 1); + DELAY(5); + splx(s); + + return (rv); +} diff --git a/sys/dev/onewire/onewire_subr.c b/sys/dev/onewire/onewire_subr.c new file mode 100644 index 00000000000..f20e4913914 --- /dev/null +++ b/sys/dev/onewire/onewire_subr.c @@ -0,0 +1,112 @@ +/* $OpenBSD: onewire_subr.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * 1-Wire bus miscellaneous routines. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/onewire/onewiredevs.h> +#include <dev/onewire/onewirereg.h> +#include <dev/onewire/onewirevar.h> + +#ifdef ONEWIREVERBOSE +struct onewire_family { + int of_type; + const char * of_name; +}; +#include <dev/onewire/onewiredevs_data.h> +#endif + +static const u_int8_t crctable[] = { + 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, + 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, + 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, + 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, + 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, + 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, + 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, + 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, + 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, + 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, + 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, + 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, + 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, + 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, + 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, + 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, + 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, + 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, + 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, + 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, + 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, + 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, + 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, + 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, + 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, + 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, + 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, + 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, + 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, + 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, + 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, + 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35 +}; + +int +onewire_crc(const void *buf, int len) +{ + const u_int8_t *p = buf; + u_int8_t crc = 0; + + while (len--) + crc = crctable[crc ^ *p++]; + + return (crc); +} + +const char * +onewire_famname(int type) +{ +#ifdef ONEWIREVERBOSE + const struct onewire_family *of; + + for (of = onewire_famtab; of->of_name != NULL; of++) + if (of->of_type == type) + return (of->of_name); +#endif + + return (NULL); +} + +int +onewire_matchbyfam(struct onewire_attach_args *oa, + const struct onewire_matchfam *fams, int nent) +{ + const struct onewire_matchfam *om; + int i; + + for (i = 0, om = fams; i < nent; i++, om++) + if (ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom) == om->om_type) + return (1); + + return (0); +} diff --git a/sys/dev/onewire/onewiredevs b/sys/dev/onewire/onewiredevs new file mode 100644 index 00000000000..129f8021ba4 --- /dev/null +++ b/sys/dev/onewire/onewiredevs @@ -0,0 +1,34 @@ +$NetBSD: onewiredevs,v 1.1 2006/04/07 18:55:22 riz Exp $ +/* $OpenBSD: onewiredevs,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * List of known 1-Wire family types. + */ + +family DS1990 0x01 ID +family DS1991 0x02 MultiKey +family DS1994 0x04 4kb NVRAM + RTC +family DS1993 0x06 4kb NVRAM +family DS1992 0x08 1kb NVRAM +family DS1982 0x09 1kb EPROM +family DS1995 0x0a 16kb NVRAM +family DS1996 0x0c 64kb NVRAM +family DS1920 0x10 Temperature +family DS1822 0x22 Temperature +family DS18B20 0x28 Temperature diff --git a/sys/dev/onewire/onewiredevs.h b/sys/dev/onewire/onewiredevs.h new file mode 100644 index 00000000000..2e09ce65d0f --- /dev/null +++ b/sys/dev/onewire/onewiredevs.h @@ -0,0 +1,20 @@ +/* $NetBSD: onewiredevs.h,v 1.1 2006/04/07 18:55:22 riz Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * Generated from: + * NetBSD + */ + +#define ONEWIRE_FAMILY_DS1990 0x01 +#define ONEWIRE_FAMILY_DS1991 0x02 +#define ONEWIRE_FAMILY_DS1994 0x04 +#define ONEWIRE_FAMILY_DS1993 0x06 +#define ONEWIRE_FAMILY_DS1992 0x08 +#define ONEWIRE_FAMILY_DS1982 0x09 +#define ONEWIRE_FAMILY_DS1995 0x0a +#define ONEWIRE_FAMILY_DS1996 0x0c +#define ONEWIRE_FAMILY_DS1920 0x10 +#define ONEWIRE_FAMILY_DS1822 0x22 +#define ONEWIRE_FAMILY_DS18B20 0x28 diff --git a/sys/dev/onewire/onewiredevs_data.h b/sys/dev/onewire/onewiredevs_data.h new file mode 100644 index 00000000000..4f1a1d2fe68 --- /dev/null +++ b/sys/dev/onewire/onewiredevs_data.h @@ -0,0 +1,23 @@ +/* $NetBSD: onewiredevs_data.h,v 1.1 2006/04/07 18:55:22 riz Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * Generated from: + * NetBSD + */ + +static const struct onewire_family onewire_famtab[] = { + { ONEWIRE_FAMILY_DS1990, "ID" }, + { ONEWIRE_FAMILY_DS1991, "MultiKey" }, + { ONEWIRE_FAMILY_DS1994, "4kb NVRAM + RTC" }, + { ONEWIRE_FAMILY_DS1993, "4kb NVRAM" }, + { ONEWIRE_FAMILY_DS1992, "1kb NVRAM" }, + { ONEWIRE_FAMILY_DS1982, "1kb EPROM" }, + { ONEWIRE_FAMILY_DS1995, "16kb NVRAM" }, + { ONEWIRE_FAMILY_DS1996, "64kb NVRAM" }, + { ONEWIRE_FAMILY_DS1920, "Temperature" }, + { ONEWIRE_FAMILY_DS1822, "Temperature" }, + { ONEWIRE_FAMILY_DS18B20, "Temperature" }, + { 0, NULL } +}; diff --git a/sys/dev/onewire/onewirereg.h b/sys/dev/onewire/onewirereg.h new file mode 100644 index 00000000000..6462e8db696 --- /dev/null +++ b/sys/dev/onewire/onewirereg.h @@ -0,0 +1,72 @@ +/* $OpenBSD: onewirereg.h,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DEV_ONEWIRE_ONEWIREREG_H_ +#define _DEV_ONEWIRE_ONEWIREREG_H_ + +/* + * 1-Wire bus protocol definitions. + */ + +/* + * 64-bit ROM section. + */ + +/* Family code */ +#define ONEWIRE_ROM_FAMILY(x) ((x) & 0xff) +#define ONEWIRE_ROM_FAMILY_TYPE(x) ((x) & 0x7f) +#define ONEWIRE_ROM_FAMILY_CUSTOM(x) (((x) >> 7) & 0x1) + +/* Serial number */ +#define ONEWIRE_ROM_SN(x) (((x) >> 8) & 0xffffffffffffULL) + +/* CRC */ +#define ONEWIRE_ROM_CRC(x) (((x) >> 56) & 0xff) + +/* + * Command set. + */ + +/* ROM commands */ +#define ONEWIRE_CMD_READ_ROM 0x33 +#define ONEWIRE_CMD_SKIP_ROM 0xcc +#define ONEWIRE_CMD_MATCH_ROM 0x55 +#define ONEWIRE_CMD_SEARCH_ROM 0xf0 +#define ONEWIRE_CMD_OVERDRIVE_SKIP_ROM 0x3c +#define ONEWIRE_CMD_OVERDRIVE_MATCH_ROM 0x69 + +/* Scratchpad commands */ +#define ONEWIRE_CMD_READ_SCRATCHPAD 0xaa +#define ONEWIRE_CMD_WRITE_SCRATCHPAD 0x0f +#define ONEWIRE_CMD_COPY_SCRATCHPAD 0x55 + +/* Memory commands */ +#define ONEWIRE_CMD_READ_MEMORY 0xf0 +#define ONEWIRE_CMD_WRITE_MEMORY 0x0f +#define ONEWIRE_CMD_EXT_READ_MEMORY 0xa5 + +/* Password commands */ +#define ONEWIRE_CMD_READ_SUBKEY 0x66 +#define ONEWIRE_CMD_WRITE_SUBKEY 0x99 +#define ONEWIRE_CMD_WRITE_PASSWORD 0x5a + +/* Status commands */ +#define ONEWIRE_CMD_READ_STATUS 0xaa +#define ONEWIRE_CMD_WRITE_STATUS 0x55 + +#endif /* !_DEV_ONEWIRE_ONEWIREREG_H_ */ diff --git a/sys/dev/onewire/onewirevar.h b/sys/dev/onewire/onewirevar.h new file mode 100644 index 00000000000..51b7ea4a434 --- /dev/null +++ b/sys/dev/onewire/onewirevar.h @@ -0,0 +1,86 @@ +/* $OpenBSD: onewirevar.h,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DEV_ONEWIRE_ONEWIREVAR_H_ +#define _DEV_ONEWIRE_ONEWIREVAR_H_ + +/* + * 1-Wire bus interface. + */ + +/* Bus master interface */ +struct onewire_bus { + void * bus_cookie; + + int (*bus_reset)(void *); + int (*bus_bit)(void *, int); + int (*bus_read_byte)(void *); + void (*bus_write_byte)(void *, int); + int (*bus_triplet)(void *, int); +}; + +/* Bus methods */ +int onewire_lock(void *, int); +void onewire_unlock(void *); +int onewire_reset(void *); +int onewire_bit(void *, int); +int onewire_read_byte(void *); +void onewire_write_byte(void *, int); +int onewire_triplet(void *, int); +void onewire_read_block(void *, void *, int); +void onewire_write_block(void *, const void *, int); +void onewire_matchrom(void *, u_int64_t); + +#define ONEWIRE_NOWAIT 0x0001 + +/* Bus attachment */ +struct onewirebus_attach_args { + struct onewire_bus * oba_bus; +}; + +int onewirebus_print(void *, const char *); + +/* Device attachment */ +struct onewire_attach_args { + void * oa_onewire; + u_int64_t oa_rom; +}; + +/* Family matching */ +struct onewire_matchfam { + int om_type; +}; + +/* Miscellaneous routines */ +int onewire_crc(const void *, int); +const char * onewire_famname(int); +int onewire_matchbyfam(struct onewire_attach_args *, + const struct onewire_matchfam *, int); + +/* Bus bit-banging */ +struct onewire_bbops { + void (*bb_rx)(void *); + void (*bb_tx)(void *); + int (*bb_get)(void *); + void (*bb_set)(void *, int); +}; + +int onewire_bb_reset(const struct onewire_bbops *, void *); +int onewire_bb_bit(const struct onewire_bbops *, void *, int); + +#endif /* !_DEV_ONEWIRE_ONEWIREVAR_H_ */ diff --git a/sys/dev/onewire/owtemp.c b/sys/dev/onewire/owtemp.c new file mode 100644 index 00000000000..a00bc6da476 --- /dev/null +++ b/sys/dev/onewire/owtemp.c @@ -0,0 +1,294 @@ +/* $NetBSD */ +/* $OpenBSD: owtemp.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * 1-Wire temperature family type device driver. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/proc.h> + +#include <dev/sysmon/sysmonvar.h> + +#include <dev/onewire/onewiredevs.h> +#include <dev/onewire/onewirereg.h> +#include <dev/onewire/onewirevar.h> + +#define DS_CMD_CONVERT 0x44 +#define DS_CMD_READ_SCRATCHPAD 0xbe + +struct owtemp_softc { + struct device sc_dev; + + void * sc_onewire; + u_int64_t sc_rom; + + struct envsys_tre_data sc_sensor[1]; + struct envsys_basic_info sc_info[1]; + + struct sysmon_envsys sc_sysmon; + + uint32_t (*sc_owtemp_decode)(const uint8_t *); + + int sc_dying; +}; + +int owtemp_match(struct device *, struct cfdata *, void *); +void owtemp_attach(struct device *, struct device *, void *); +int owtemp_detach(struct device *, int); +int owtemp_activate(struct device *, enum devact); + +void owtemp_update(void *); + +CFATTACH_DECL(owtemp, sizeof(struct owtemp_softc), + owtemp_match, owtemp_attach, owtemp_detach, owtemp_activate); + +extern struct cfdriver owtemp_cd; + +static const struct onewire_matchfam owtemp_fams[] = { + { ONEWIRE_FAMILY_DS1920 }, + { ONEWIRE_FAMILY_DS18B20 }, + { ONEWIRE_FAMILY_DS1822 }, +}; + +static const struct envsys_range owtemp_ranges[] = { + { 0, 1, ENVSYS_STEMP }, + { 1, 0, -1 }, +}; + +static int owtemp_gtredata(struct sysmon_envsys *, + struct envsys_tre_data *); +static int owtemp_streinfo(struct sysmon_envsys *, + struct envsys_basic_info *); + +static uint32_t owtemp_decode_ds18b20(const uint8_t *); +static uint32_t owtemp_decode_ds1920(const uint8_t *); + +int +owtemp_match(struct device *parent, struct cfdata *cf, void *aux) +{ + return (onewire_matchbyfam(aux, owtemp_fams, + sizeof(owtemp_fams) /sizeof(owtemp_fams[0]))); +} + +void +owtemp_attach(struct device *parent, struct device *self, void *aux) +{ + struct owtemp_softc *sc = device_private(self); + struct onewire_attach_args *oa = aux; + int ptype; + + sc->sc_onewire = oa->oa_onewire; + sc->sc_rom = oa->oa_rom; + + switch(ONEWIRE_ROM_FAMILY_TYPE(sc->sc_rom)) { + case ONEWIRE_FAMILY_DS18B20: + case ONEWIRE_FAMILY_DS1822: + sc->sc_owtemp_decode = owtemp_decode_ds18b20; + break; + case ONEWIRE_FAMILY_DS1920: + sc->sc_owtemp_decode = owtemp_decode_ds1920; + break; + } + + /* Initialize sensor */ + sc->sc_sensor[0].sensor = sc->sc_info[0].sensor = 0; + sc->sc_sensor[0].validflags = ENVSYS_FVALID; + sc->sc_info[0].validflags = ENVSYS_FVALID; + sc->sc_sensor[0].warnflags = ENVSYS_WARN_OK; + + sc->sc_sensor[0].units = sc->sc_info[0].units = ENVSYS_STEMP; + if (devprop_get(&sc->sc_dev, "description", + sc->sc_info[0].desc, sizeof(sc->sc_info[0].desc), + &ptype) < 1 || + ptype != PROP_STRING) + strcpy(sc->sc_info[0].desc, sc->sc_dev.dv_xname); + + /* Hook into system monitor. */ + sc->sc_sysmon.sme_ranges = owtemp_ranges; + sc->sc_sysmon.sme_sensor_info = sc->sc_info; + sc->sc_sysmon.sme_sensor_data = sc->sc_sensor; + sc->sc_sysmon.sme_cookie = sc; + + sc->sc_sysmon.sme_gtredata = owtemp_gtredata; + sc->sc_sysmon.sme_streinfo = owtemp_streinfo; + + sc->sc_sysmon.sme_nsensors = 1; + sc->sc_sysmon.sme_envsys_version = 1000; + + if (sysmon_envsys_register(&sc->sc_sysmon)) + aprint_error("%s: unable to register with sysmon\n", + sc->sc_dev.dv_xname); + +#if 0 /* Old OpenBSD code */ + strlcpy(sc->sc_sensor.device, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensor.device)); + sc->sc_sensor.type = SENSOR_TEMP; + strlcpy(sc->sc_sensor.desc, "Temp", sizeof(sc->sc_sensor.desc)); + + if (sensor_task_register(sc, owtemp_update, 5)) { + printf(": unable to register update task\n"); + return; + } + sensor_add(&sc->sc_sensor); +#endif + + printf("\n"); +} + +int +owtemp_detach(struct device *self, int flags) +{ + struct owtemp_softc *sc = device_private(self); + + sysmon_envsys_unregister(&sc->sc_sysmon); + + return 0; +} + +int +owtemp_activate(struct device *self, enum devact act) +{ + struct owtemp_softc *sc = device_private(self); + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + break; + } + + return (0); +} + +void +owtemp_update(void *arg) +{ + struct owtemp_softc *sc = arg; + u_int8_t data[9]; + + onewire_lock(sc->sc_onewire, 0); + if (onewire_reset(sc->sc_onewire) != 0) + goto done; + onewire_matchrom(sc->sc_onewire, sc->sc_rom); + + /* + * Start temperature conversion. The conversion takes up to 750ms. + * After sending the command, the data line must be held high for + * at least 750ms to provide power during the conversion process. + * As such, no other activity may take place on the 1-Wire bus for + * at least this period. + */ + onewire_write_byte(sc->sc_onewire, DS_CMD_CONVERT); + tsleep(sc, PRIBIO, "owtemp", hz); + + if (onewire_reset(sc->sc_onewire) != 0) + goto done; + onewire_matchrom(sc->sc_onewire, sc->sc_rom); + + /* + * The result of the temperature measurement is placed in the + * first two bytes of the scratchpad. + */ + onewire_write_byte(sc->sc_onewire, DS_CMD_READ_SCRATCHPAD); + onewire_read_block(sc->sc_onewire, data, 9); +#if 0 + if (onewire_crc(data, 8) == data[8]) { + sc->sc_sensor.value = 273150000 + + (int)((u_int16_t)data[1] << 8 | data[0]) * 500000; + } +#endif + + sc->sc_sensor[0].cur.data_us = sc->sc_owtemp_decode(data); + sc->sc_sensor[0].validflags |= ENVSYS_FCURVALID; + +done: + onewire_unlock(sc->sc_onewire); +} + +static int +owtemp_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred) +{ + struct owtemp_softc *sc = sme->sme_cookie; + + owtemp_update(sc); + *tred = sc->sc_sensor[tred->sensor]; + + return 0; +} + +static int +owtemp_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo) +{ + struct owtemp_softc *sc = sme->sme_cookie; + + onewire_lock(sc->sc_onewire,0); /* Also locks our instance */ + + memcpy(sc->sc_info[binfo->sensor].desc, binfo->desc, + sizeof(sc->sc_info[binfo->sensor].desc)); + sc->sc_info[binfo->sensor].desc[ + sizeof(sc->sc_info[binfo->sensor].desc) - 1] = '\0'; + + onewire_unlock(sc->sc_onewire); + + binfo->validflags = ENVSYS_FVALID; + + return 0; +} + +static uint32_t +owtemp_decode_ds18b20(const uint8_t *buf) +{ + int temp; + + /* + * Sign-extend the MSB byte, and add in the fractions of a + * degree contained in the LSB (precision 1/16th DegC). + */ + temp = (int8_t)buf[1]; + temp = (temp << 8) | buf[0]; + + /* + * Conversion to uK is simple. + */ + return (temp * 62500 + 273150000); +} + +static uint32_t +owtemp_decode_ds1920(const uint8_t *buf) +{ + int temp; + + /* + * Sign-extend the MSB byte, and add in the fractions of a + * degree contained in the LSB (precision 1/2 DegC). + */ + temp = (int8_t)buf[1]; + temp = (temp << 8) | buf[0]; + + /* Convert to uK */ + return (temp * 500000 + 273150000); +} |
