[BACK]Return to onewire.c CVS log [TXT][DIR] Up to [local] / sys / dev / onewire

Annotation of sys/dev/onewire/onewire.c, Revision 1.1.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