Annotation of sys/dev/onewire/onewire.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: onewire.c,v 1.7 2006/10/08 21:12:51 grange 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/proc.h>
! 30: #include <sys/queue.h>
! 31: #include <sys/rwlock.h>
! 32:
! 33: #include <dev/onewire/onewirereg.h>
! 34: #include <dev/onewire/onewirevar.h>
! 35:
! 36: #ifdef ONEWIRE_DEBUG
! 37: #define DPRINTF(x) printf x
! 38: #else
! 39: #define DPRINTF(x)
! 40: #endif
! 41:
! 42: #define ONEWIRE_MAXDEVS 16
! 43: #define ONEWIRE_SCANTIME 3
! 44:
! 45: struct onewire_softc {
! 46: struct device sc_dev;
! 47:
! 48: struct onewire_bus * sc_bus;
! 49: struct rwlock sc_lock;
! 50: struct proc * sc_thread;
! 51: TAILQ_HEAD(, onewire_device) sc_devs;
! 52:
! 53: int sc_dying;
! 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;
! 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 *, enum devact);
! 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: 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
! 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
! 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: rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
! 102: TAILQ_INIT(&sc->sc_devs);
! 103:
! 104: printf("\n");
! 105:
! 106: kthread_create_deferred(onewire_createthread, sc);
! 107: }
! 108:
! 109: int
! 110: onewire_detach(struct device *self, int flags)
! 111: {
! 112: struct onewire_softc *sc = (struct onewire_softc *)self;
! 113:
! 114: sc->sc_dying = 1;
! 115: if (sc->sc_thread != NULL) {
! 116: wakeup(sc->sc_thread);
! 117: tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
! 118: }
! 119:
! 120: return (config_detach_children(self, flags));
! 121: }
! 122:
! 123: int
! 124: onewire_activate(struct device *self, enum devact act)
! 125: {
! 126: struct onewire_softc *sc = (struct onewire_softc *)self;
! 127:
! 128: switch (act) {
! 129: case DVACT_ACTIVATE:
! 130: break;
! 131: case DVACT_DEACTIVATE:
! 132: sc->sc_dying = 1;
! 133: break;
! 134: }
! 135:
! 136: return (config_activate_children(self, act));
! 137: }
! 138:
! 139: int
! 140: onewire_print(void *aux, const char *pnp)
! 141: {
! 142: struct onewire_attach_args *oa = aux;
! 143: const char *famname;
! 144:
! 145: if (pnp == NULL)
! 146: printf(" ");
! 147:
! 148: famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
! 149: if (famname == NULL)
! 150: printf("family 0x%02x", ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
! 151: else
! 152: printf("\"%s\"", famname);
! 153: printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
! 154:
! 155: if (pnp != NULL)
! 156: printf(" at %s", pnp);
! 157:
! 158: return (UNCONF);
! 159: }
! 160:
! 161: int
! 162: onewirebus_print(void *aux, const char *pnp)
! 163: {
! 164: if (pnp != NULL)
! 165: printf("onewire at %s", pnp);
! 166:
! 167: return (UNCONF);
! 168: }
! 169:
! 170: int
! 171: onewire_lock(void *arg, int flags)
! 172: {
! 173: struct onewire_softc *sc = arg;
! 174: int lflags = RW_WRITE;
! 175:
! 176: if (flags & ONEWIRE_NOWAIT)
! 177: lflags |= RW_NOSLEEP;
! 178:
! 179: return (rw_enter(&sc->sc_lock, lflags));
! 180: }
! 181:
! 182: void
! 183: onewire_unlock(void *arg)
! 184: {
! 185: struct onewire_softc *sc = arg;
! 186:
! 187: rw_exit(&sc->sc_lock);
! 188: }
! 189:
! 190: int
! 191: onewire_reset(void *arg)
! 192: {
! 193: struct onewire_softc *sc = arg;
! 194: struct onewire_bus *bus = sc->sc_bus;
! 195:
! 196: return (bus->bus_reset(bus->bus_cookie));
! 197: }
! 198:
! 199: int
! 200: onewire_bit(void *arg, int value)
! 201: {
! 202: struct onewire_softc *sc = arg;
! 203: struct onewire_bus *bus = sc->sc_bus;
! 204:
! 205: return (bus->bus_bit(bus->bus_cookie, value));
! 206: }
! 207:
! 208: int
! 209: onewire_read_byte(void *arg)
! 210: {
! 211: struct onewire_softc *sc = arg;
! 212: struct onewire_bus *bus = sc->sc_bus;
! 213: u_int8_t value = 0;
! 214: int i;
! 215:
! 216: if (bus->bus_read_byte != NULL)
! 217: return (bus->bus_read_byte(bus->bus_cookie));
! 218:
! 219: for (i = 0; i < 8; i++)
! 220: value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
! 221:
! 222: return (value);
! 223: }
! 224:
! 225: void
! 226: onewire_write_byte(void *arg, int value)
! 227: {
! 228: struct onewire_softc *sc = arg;
! 229: struct onewire_bus *bus = sc->sc_bus;
! 230: int i;
! 231:
! 232: if (bus->bus_write_byte != NULL)
! 233: return (bus->bus_write_byte(bus->bus_cookie, value));
! 234:
! 235: for (i = 0; i < 8; i++)
! 236: bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
! 237: }
! 238:
! 239: void
! 240: onewire_read_block(void *arg, void *buf, int len)
! 241: {
! 242: struct onewire_softc *sc = arg;
! 243: struct onewire_bus *bus = sc->sc_bus;
! 244: u_int8_t *p = buf;
! 245:
! 246: if (bus->bus_read_block != NULL)
! 247: return (bus->bus_read_block(bus->bus_cookie, buf, len));
! 248:
! 249: while (len--)
! 250: *p++ = onewire_read_byte(arg);
! 251: }
! 252:
! 253: void
! 254: onewire_write_block(void *arg, const void *buf, int len)
! 255: {
! 256: struct onewire_softc *sc = arg;
! 257: struct onewire_bus *bus = sc->sc_bus;
! 258: const u_int8_t *p = buf;
! 259:
! 260: if (bus->bus_write_block != NULL)
! 261: return (bus->bus_write_block(bus->bus_cookie, buf, len));
! 262:
! 263: while (len--)
! 264: onewire_write_byte(arg, *p++);
! 265: }
! 266:
! 267: int
! 268: onewire_triplet(void *arg, int dir)
! 269: {
! 270: struct onewire_softc *sc = arg;
! 271: struct onewire_bus *bus = sc->sc_bus;
! 272: int rv;
! 273:
! 274: if (bus->bus_triplet != NULL)
! 275: return (bus->bus_triplet(bus->bus_cookie, dir));
! 276:
! 277: rv = bus->bus_bit(bus->bus_cookie, 1);
! 278: rv <<= 1;
! 279: rv |= bus->bus_bit(bus->bus_cookie, 1);
! 280:
! 281: switch (rv) {
! 282: case 0x0:
! 283: bus->bus_bit(bus->bus_cookie, dir);
! 284: break;
! 285: case 0x1:
! 286: bus->bus_bit(bus->bus_cookie, 0);
! 287: break;
! 288: default:
! 289: bus->bus_bit(bus->bus_cookie, 1);
! 290: }
! 291:
! 292: return (rv);
! 293: }
! 294:
! 295: void
! 296: onewire_matchrom(void *arg, u_int64_t rom)
! 297: {
! 298: struct onewire_softc *sc = arg;
! 299: struct onewire_bus *bus = sc->sc_bus;
! 300: int i;
! 301:
! 302: if (bus->bus_matchrom != NULL)
! 303: return (bus->bus_matchrom(bus->bus_cookie, rom));
! 304:
! 305: onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
! 306: for (i = 0; i < 8; i++)
! 307: onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
! 308: }
! 309:
! 310: int
! 311: onewire_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
! 312: {
! 313: struct onewire_softc *sc = arg;
! 314: struct onewire_bus *bus = sc->sc_bus;
! 315: int search = 1, count = 0, lastd = -1, dir, rv, i, i0;
! 316: u_int64_t mask, rom = startrom, lastrom;
! 317: u_int8_t data[8];
! 318:
! 319: if (bus->bus_search != NULL)
! 320: return (bus->bus_search(bus->bus_cookie, buf, size, rom));
! 321:
! 322: while (search && count < size) {
! 323: /* XXX: yield processor */
! 324: tsleep(sc, PWAIT, "owscan", hz / 10);
! 325:
! 326: /*
! 327: * Start new search. Go through the previous path to
! 328: * the point we made a decision last time and make an
! 329: * opposite decision. If we didn't make any decision
! 330: * stop searching.
! 331: */
! 332: lastrom = rom;
! 333: rom = 0;
! 334: onewire_lock(sc, 0);
! 335: onewire_reset(sc);
! 336: onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
! 337: for (i = 0, i0 = -1; i < 64; i++) {
! 338: dir = (lastrom >> i) & 0x1;
! 339: if (i == lastd)
! 340: dir = 1;
! 341: else if (i > lastd)
! 342: dir = 0;
! 343: rv = onewire_triplet(sc, dir);
! 344: switch (rv) {
! 345: case 0x0:
! 346: if (i != lastd && dir == 0)
! 347: i0 = i;
! 348: mask = dir;
! 349: break;
! 350: case 0x1:
! 351: mask = 0;
! 352: break;
! 353: case 0x2:
! 354: mask = 1;
! 355: break;
! 356: default:
! 357: DPRINTF(("%s: search triplet error 0x%x, "
! 358: "step %d\n",
! 359: sc->sc_dev.dv_xname, rv, i));
! 360: onewire_unlock(sc);
! 361: return (-1);
! 362: }
! 363: rom |= (mask << i);
! 364: }
! 365: onewire_unlock(sc);
! 366:
! 367: if ((lastd = i0) == -1)
! 368: search = 0;
! 369:
! 370: if (rom == 0)
! 371: continue;
! 372:
! 373: /*
! 374: * The last byte of the ROM code contains a CRC calculated
! 375: * from the first 7 bytes. Re-calculate it to make sure
! 376: * we found a valid device.
! 377: */
! 378: for (i = 0; i < 8; i++)
! 379: data[i] = (rom >> (i * 8)) & 0xff;
! 380: if (onewire_crc(data, 7) != data[7])
! 381: continue;
! 382:
! 383: buf[count++] = rom;
! 384: }
! 385:
! 386: return (count);
! 387: }
! 388:
! 389: void
! 390: onewire_thread(void *arg)
! 391: {
! 392: struct onewire_softc *sc = arg;
! 393:
! 394: while (!sc->sc_dying) {
! 395: onewire_scan(sc);
! 396: tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz);
! 397: }
! 398:
! 399: sc->sc_thread = NULL;
! 400: wakeup(&sc->sc_dying);
! 401: kthread_exit(0);
! 402: }
! 403:
! 404: void
! 405: onewire_createthread(void *arg)
! 406: {
! 407: struct onewire_softc *sc = arg;
! 408:
! 409: if (kthread_create(onewire_thread, sc, &sc->sc_thread,
! 410: "%s", sc->sc_dev.dv_xname) != 0)
! 411: printf("%s: can't create kernel thread\n",
! 412: sc->sc_dev.dv_xname);
! 413: }
! 414:
! 415: void
! 416: onewire_scan(struct onewire_softc *sc)
! 417: {
! 418: struct onewire_device *d, *next, *nd;
! 419: struct onewire_attach_args oa;
! 420: struct device *dev;
! 421: int present;
! 422: u_int64_t rom;
! 423: int i, rv;
! 424:
! 425: /*
! 426: * Mark all currently present devices as absent before
! 427: * scanning. This allows to find out later which devices
! 428: * have been disappeared.
! 429: */
! 430: TAILQ_FOREACH(d, &sc->sc_devs, d_list)
! 431: d->d_present = 0;
! 432:
! 433: /*
! 434: * Reset the bus. If there's no presence pulse don't search
! 435: * for any devices.
! 436: */
! 437: onewire_lock(sc, 0);
! 438: rv = onewire_reset(sc);
! 439: onewire_unlock(sc);
! 440: if (rv != 0) {
! 441: DPRINTF(("%s: no presence pulse\n", sc->sc_dev.dv_xname));
! 442: goto out;
! 443: }
! 444:
! 445: /* Scan the bus */
! 446: if ((rv = onewire_search(sc, sc->sc_rombuf, ONEWIRE_MAXDEVS, 0)) == -1)
! 447: return;
! 448:
! 449: for (i = 0; i < rv; i++) {
! 450: rom = sc->sc_rombuf[i];
! 451:
! 452: /*
! 453: * Go through the list of attached devices to see if we
! 454: * found a new one.
! 455: */
! 456: present = 0;
! 457: TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
! 458: if (d->d_rom == rom) {
! 459: d->d_present = 1;
! 460: present = 1;
! 461: break;
! 462: }
! 463: }
! 464: if (!present) {
! 465: bzero(&oa, sizeof(oa));
! 466: oa.oa_onewire = sc;
! 467: oa.oa_rom = rom;
! 468: if ((dev = config_found(&sc->sc_dev, &oa,
! 469: onewire_print)) == NULL)
! 470: continue;
! 471:
! 472: MALLOC(nd, struct onewire_device *,
! 473: sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT);
! 474: if (nd == NULL)
! 475: continue;
! 476: nd->d_dev = dev;
! 477: nd->d_rom = rom;
! 478: nd->d_present = 1;
! 479: TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
! 480: }
! 481: }
! 482:
! 483: out:
! 484: /* Detach disappeared devices */
! 485: for (d = TAILQ_FIRST(&sc->sc_devs);
! 486: d != TAILQ_END(&sc->sc_dev); d = next) {
! 487: next = TAILQ_NEXT(d, d_list);
! 488: if (!d->d_present) {
! 489: config_detach(d->d_dev, DETACH_FORCE);
! 490: TAILQ_REMOVE(&sc->sc_devs, d, d_list);
! 491: FREE(d, M_DEVBUF);
! 492: }
! 493: }
! 494: }
CVSweb