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

Annotation of sys/dev/usb/uow.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: uow.c,v 1.23 2007/06/14 10:11:16 mbalmer 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:  * Maxim/Dallas DS2490 USB 1-Wire adapter 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/proc.h>
                     28:
                     29: #include <dev/onewire/onewirereg.h>
                     30: #include <dev/onewire/onewirevar.h>
                     31:
                     32: #include <dev/usb/usb.h>
                     33: #include <dev/usb/usbdevs.h>
                     34: #include <dev/usb/usbdi.h>
                     35: #include <dev/usb/usbdi_util.h>
                     36:
                     37: #include <dev/usb/uowreg.h>
                     38:
                     39: #ifdef UOW_DEBUG
                     40: #define DPRINTF(x) printf x
                     41: #else
                     42: #define DPRINTF(x)
                     43: #endif
                     44:
                     45: #define UOW_TIMEOUT    1000    /* ms */
                     46:
                     47: struct uow_softc {
                     48:        struct device            sc_dev;
                     49:
                     50:        struct onewire_bus       sc_ow_bus;
                     51:        struct device           *sc_ow_dev;
                     52:
                     53:        usbd_device_handle       sc_udev;
                     54:        usbd_interface_handle    sc_iface;
                     55:        usbd_pipe_handle         sc_ph_ibulk;
                     56:        usbd_pipe_handle         sc_ph_obulk;
                     57:        usbd_pipe_handle         sc_ph_intr;
                     58:        u_int8_t                 sc_regs[DS2490_NREGS];
                     59:        usbd_xfer_handle         sc_xfer;
                     60:        u_int8_t                 sc_fifo[DS2490_DATAFIFOSIZE];
                     61: };
                     62:
                     63: int uow_match(struct device *, void *, void *);
                     64: void uow_attach(struct device *, struct device *, void *);
                     65: int uow_detach(struct device *, int);
                     66: int uow_activate(struct device *, enum devact);
                     67:
                     68: struct cfdriver uow_cd = {
                     69:        NULL, "uow", DV_DULL
                     70: };
                     71:
                     72: const struct cfattach uow_ca = {
                     73:        sizeof(struct uow_softc),
                     74:        uow_match,
                     75:        uow_attach,
                     76:        uow_detach,
                     77:        uow_activate,
                     78: };
                     79:
                     80: /* List of supported devices */
                     81: static const struct usb_devno uow_devs[] = {
                     82:        { USB_VENDOR_DALLAS,            USB_PRODUCT_DALLAS_USB_FOB_IBUTTON }
                     83: };
                     84:
                     85: int    uow_ow_reset(void *);
                     86: int    uow_ow_bit(void *, int);
                     87: int    uow_ow_read_byte(void *);
                     88: void   uow_ow_write_byte(void *, int);
                     89: void   uow_ow_read_block(void *, void *, int);
                     90: void   uow_ow_write_block(void *, const void *, int);
                     91: void   uow_ow_matchrom(void *, u_int64_t);
                     92: int    uow_ow_search(void *, u_int64_t *, int, u_int64_t);
                     93:
                     94: int    uow_cmd(struct uow_softc *, int, int, int);
                     95: #define uow_ctlcmd(s, c, p)    uow_cmd((s), DS2490_CONTROL_CMD, (c), (p))
                     96: #define uow_commcmd(s, c, p)   uow_cmd((s), DS2490_COMM_CMD, (c), (p))
                     97: #define uow_modecmd(s, c, p)   uow_cmd((s), DS2490_MODE_CMD, (c), (p))
                     98:
                     99: void   uow_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
                    100: int    uow_read(struct uow_softc *, void *, int);
                    101: int    uow_write(struct uow_softc *, const void *, int);
                    102: int    uow_reset(struct uow_softc *);
                    103:
                    104: int
                    105: uow_match(struct device *parent, void *match, void *aux)
                    106: {
                    107:        struct usb_attach_arg *uaa = aux;
                    108:
                    109:        if (uaa->iface != NULL)
                    110:                return (UMATCH_NONE);
                    111:
                    112:        return ((usb_lookup(uow_devs, uaa->vendor, uaa->product) != NULL) ?
                    113:            UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
                    114: }
                    115:
                    116: void
                    117: uow_attach(struct device *parent, struct device *self, void *aux)
                    118: {
                    119:        struct uow_softc *sc = (struct uow_softc *)self;
                    120:        struct usb_attach_arg *uaa = aux;
                    121:        usb_interface_descriptor_t *id;
                    122:        usb_endpoint_descriptor_t *ed;
                    123:        char *devinfop;
                    124:        int ep_ibulk = -1, ep_obulk = -1, ep_intr = -1;
                    125:        struct onewirebus_attach_args oba;
                    126:        usbd_status error;
                    127:        int i;
                    128:
                    129:        sc->sc_udev = uaa->device;
                    130:
                    131:        /* Display device info string */
                    132:        printf("\n");
                    133:        devinfop = usbd_devinfo_alloc(uaa->device, 0);
                    134:        printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
                    135:        usbd_devinfo_free(devinfop);
                    136:
                    137:        /* Set USB configuration */
                    138:        if ((error = usbd_set_config_no(sc->sc_udev,
                    139:            DS2490_USB_CONFIG, 0)) != 0) {
                    140:                printf("%s: failed to set config %d: %s\n",
                    141:                    sc->sc_dev.dv_xname, DS2490_USB_CONFIG,
                    142:                    usbd_errstr(error));
                    143:                return;
                    144:        }
                    145:
                    146:        /* Get interface handle */
                    147:        if ((error = usbd_device2interface_handle(sc->sc_udev,
                    148:            DS2490_USB_IFACE, &sc->sc_iface)) != 0) {
                    149:                printf("%s: failed to get iface %d: %s\n",
                    150:                    sc->sc_dev.dv_xname, DS2490_USB_IFACE,
                    151:                    usbd_errstr(error));
                    152:                return;
                    153:        }
                    154:
                    155:        /* Find endpoints */
                    156:        id = usbd_get_interface_descriptor(sc->sc_iface);
                    157:        for (i = 0; i < id->bNumEndpoints; i++) {
                    158:                ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
                    159:                if (ed == NULL) {
                    160:                        printf("%s: failed to get endpoint %d descriptor\n",
                    161:                            sc->sc_dev.dv_xname, i);
                    162:                        return;
                    163:                }
                    164:
                    165:                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                    166:                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
                    167:                        ep_ibulk = ed->bEndpointAddress;
                    168:                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
                    169:                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
                    170:                        ep_obulk = ed->bEndpointAddress;
                    171:                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                    172:                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT)
                    173:                        ep_intr = ed->bEndpointAddress;
                    174:        }
                    175:        if (ep_ibulk == -1 || ep_obulk == -1 || ep_intr == -1) {
                    176:                printf("%s: missing endpoint: ibulk %d, obulk %d, intr %d\n",
                    177:                   sc->sc_dev.dv_xname, ep_ibulk, ep_obulk, ep_intr);
                    178:                return;
                    179:        }
                    180:
                    181:        /* Open pipes */
                    182:        if ((error = usbd_open_pipe(sc->sc_iface, ep_ibulk, USBD_EXCLUSIVE_USE,
                    183:            &sc->sc_ph_ibulk)) != 0) {
                    184:                printf("%s: failed to open bulk-in pipe: %s\n",
                    185:                    sc->sc_dev.dv_xname, usbd_errstr(error));
                    186:                return;
                    187:        }
                    188:        if ((error = usbd_open_pipe(sc->sc_iface, ep_obulk, USBD_EXCLUSIVE_USE,
                    189:            &sc->sc_ph_obulk)) != 0) {
                    190:                printf("%s: failed to open bulk-out pipe: %s\n",
                    191:                    sc->sc_dev.dv_xname, usbd_errstr(error));
                    192:                goto fail;
                    193:        }
                    194:        if ((error = usbd_open_pipe_intr(sc->sc_iface, ep_intr,
                    195:            USBD_SHORT_XFER_OK, &sc->sc_ph_intr, sc,
                    196:            sc->sc_regs, sizeof(sc->sc_regs), uow_intr,
                    197:            USBD_DEFAULT_INTERVAL)) != 0) {
                    198:                printf("%s: failed to open intr pipe: %s\n",
                    199:                    sc->sc_dev.dv_xname, usbd_errstr(error));
                    200:                goto fail;
                    201:        }
                    202:
                    203: #if 0
                    204:        /* Allocate xfer for bulk transfers */
                    205:        if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
                    206:                printf("%s: failed to alloc bulk xfer\n",
                    207:                    sc->sc_dev.dv_xname);
                    208:                goto fail;
                    209:        }
                    210: #endif
                    211:
                    212:        memset(sc->sc_fifo, 0xff, sizeof(sc->sc_fifo));
                    213:
                    214:        /* Reset device */
                    215:        uow_reset(sc);
                    216:
                    217:        /* Attach 1-Wire bus */
                    218:        sc->sc_ow_bus.bus_cookie = sc;
                    219:        sc->sc_ow_bus.bus_reset = uow_ow_reset;
                    220:        sc->sc_ow_bus.bus_bit = uow_ow_bit;
                    221:        sc->sc_ow_bus.bus_read_byte = uow_ow_read_byte;
                    222:        sc->sc_ow_bus.bus_write_byte = uow_ow_write_byte;
                    223:        sc->sc_ow_bus.bus_read_block = uow_ow_read_block;
                    224:        sc->sc_ow_bus.bus_write_block = uow_ow_write_block;
                    225:        sc->sc_ow_bus.bus_matchrom = uow_ow_matchrom;
                    226:        sc->sc_ow_bus.bus_search = uow_ow_search;
                    227:
                    228:        bzero(&oba, sizeof(oba));
                    229:        oba.oba_bus = &sc->sc_ow_bus;
                    230:        sc->sc_ow_dev = config_found(self, &oba, onewirebus_print);
                    231:
                    232:        return;
                    233:
                    234: fail:
                    235:        if (sc->sc_ph_ibulk != NULL)
                    236:                usbd_close_pipe(sc->sc_ph_ibulk);
                    237:        if (sc->sc_ph_obulk != NULL)
                    238:                usbd_close_pipe(sc->sc_ph_obulk);
                    239:        if (sc->sc_ph_intr != NULL)
                    240:                usbd_close_pipe(sc->sc_ph_intr);
                    241:        if (sc->sc_xfer != NULL)
                    242:                usbd_free_xfer(sc->sc_xfer);
                    243: }
                    244:
                    245: int
                    246: uow_detach(struct device *self, int flags)
                    247: {
                    248:        struct uow_softc *sc = (struct uow_softc *)self;
                    249:        int rv = 0, s;
                    250:
                    251:        s = splusb();
                    252:
                    253:        if (sc->sc_ph_ibulk != NULL) {
                    254:                usbd_abort_pipe(sc->sc_ph_ibulk);
                    255:                usbd_close_pipe(sc->sc_ph_ibulk);
                    256:        }
                    257:        if (sc->sc_ph_obulk != NULL) {
                    258:                usbd_abort_pipe(sc->sc_ph_obulk);
                    259:                usbd_close_pipe(sc->sc_ph_obulk);
                    260:        }
                    261:        if (sc->sc_ph_intr != NULL) {
                    262:                usbd_abort_pipe(sc->sc_ph_intr);
                    263:                usbd_close_pipe(sc->sc_ph_intr);
                    264:        }
                    265:
                    266:        if (sc->sc_xfer != NULL)
                    267:                usbd_free_xfer(sc->sc_xfer);
                    268:
                    269:        if (sc->sc_ow_dev != NULL)
                    270:                rv = config_detach(sc->sc_ow_dev, flags);
                    271:
                    272:        splx(s);
                    273:
                    274:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
                    275:            &sc->sc_dev);
                    276:
                    277:        return (rv);
                    278: }
                    279:
                    280: int
                    281: uow_activate(struct device *self, enum devact act)
                    282: {
                    283:        struct uow_softc *sc = (struct uow_softc *)self;
                    284:        int rv = 0;
                    285:
                    286:        switch (act) {
                    287:        case DVACT_ACTIVATE:
                    288:                break;
                    289:        case DVACT_DEACTIVATE:
                    290:                if (sc->sc_ow_dev != NULL)
                    291:                        rv = config_deactivate(sc->sc_ow_dev);
                    292:                break;
                    293:        }
                    294:
                    295:        return (rv);
                    296: }
                    297:
                    298: int
                    299: uow_ow_reset(void *arg)
                    300: {
                    301:        struct uow_softc *sc = arg;
                    302:
                    303:        if (uow_commcmd(sc, DS2490_COMM_1WIRE_RESET | DS2490_BIT_IM, 0) != 0)
                    304:                return (1);
                    305:
                    306:        /* XXX: check presence pulse */
                    307:        return (0);
                    308: }
                    309:
                    310: int
                    311: uow_ow_bit(void *arg, int value)
                    312: {
                    313:        struct uow_softc *sc = arg;
                    314:        u_int8_t data;
                    315:
                    316:        if (uow_commcmd(sc, DS2490_COMM_BIT_IO | DS2490_BIT_IM |
                    317:            (value ? DS2490_BIT_D : 0), 0) != 0)
                    318:                return (1);
                    319:        if (uow_read(sc, &data, 1) != 1)
                    320:                return (1);
                    321:
                    322:        return (data);
                    323: }
                    324:
                    325: int
                    326: uow_ow_read_byte(void *arg)
                    327: {
                    328:        struct uow_softc *sc = arg;
                    329:        u_int8_t data;
                    330:
                    331:        if (uow_commcmd(sc, DS2490_COMM_BYTE_IO | DS2490_BIT_IM, 0xff) != 0)
                    332:                return (-1);
                    333:        if (uow_read(sc, &data, 1) != 1)
                    334:                return (-1);
                    335:
                    336:        return (data);
                    337: }
                    338:
                    339: void
                    340: uow_ow_write_byte(void *arg, int value)
                    341: {
                    342:        struct uow_softc *sc = arg;
                    343:        u_int8_t data;
                    344:
                    345:        if (uow_commcmd(sc, DS2490_COMM_BYTE_IO | DS2490_BIT_IM, value) != 0)
                    346:                return;
                    347:        uow_read(sc, &data, sizeof(data));
                    348: }
                    349:
                    350: void
                    351: uow_ow_read_block(void *arg, void *buf, int len)
                    352: {
                    353:        struct uow_softc *sc = arg;
                    354:
                    355:        if (uow_write(sc, sc->sc_fifo, len) != 0)
                    356:                return;
                    357:        if (uow_commcmd(sc, DS2490_COMM_BLOCK_IO | DS2490_BIT_IM, len) != 0)
                    358:                return;
                    359:        uow_read(sc, buf, len);
                    360: }
                    361:
                    362: void
                    363: uow_ow_write_block(void *arg, const void *buf, int len)
                    364: {
                    365:        struct uow_softc *sc = arg;
                    366:
                    367:        if (uow_write(sc, buf, len) != 0)
                    368:                return;
                    369:        if (uow_commcmd(sc, DS2490_COMM_BLOCK_IO | DS2490_BIT_IM, len) != 0)
                    370:                return;
                    371: }
                    372:
                    373: void
                    374: uow_ow_matchrom(void *arg, u_int64_t rom)
                    375: {
                    376:        struct uow_softc *sc = arg;
                    377:        u_int8_t data[8];
                    378:        int i;
                    379:
                    380:        for (i = 0; i < 8; i++)
                    381:                data[i] = (rom >> (i * 8)) & 0xff;
                    382:
                    383:        if (uow_write(sc, data, 8) != 0)
                    384:                return;
                    385:        if (uow_commcmd(sc, DS2490_COMM_MATCH_ACCESS | DS2490_BIT_IM,
                    386:            ONEWIRE_CMD_MATCH_ROM) != 0)
                    387:                return;
                    388: }
                    389:
                    390: int
                    391: uow_ow_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
                    392: {
                    393:        struct uow_softc *sc = arg;
                    394:        u_int8_t data[8];
                    395:        int i, rv;
                    396:
                    397:        for (i = 0; i < 8; i++)
                    398:                data[i] = (startrom >> (i * 8)) & 0xff;
                    399:
                    400:        if (uow_write(sc, data, 8) != 0)
                    401:                return (-1);
                    402:        if (uow_commcmd(sc, DS2490_COMM_SEARCH_ACCESS | DS2490_BIT_IM |
                    403:            DS2490_BIT_SM | DS2490_BIT_RST | DS2490_BIT_F, size << 8 |
                    404:            ONEWIRE_CMD_SEARCH_ROM) != 0)
                    405:                return (-1);
                    406:
                    407:        if ((rv = uow_read(sc, buf, size * 8)) == -1)
                    408:                return (-1);
                    409:
                    410:        return (rv / 8);
                    411: }
                    412:
                    413: int
                    414: uow_cmd(struct uow_softc *sc, int type, int cmd, int param)
                    415: {
                    416:        usb_device_request_t req;
                    417:        usbd_status error;
                    418:
                    419:        req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
                    420:        req.bRequest = type;
                    421:        USETW(req.wValue, cmd);
                    422:        USETW(req.wIndex, param);
                    423:        USETW(req.wLength, 0);
                    424:        if ((error = usbd_do_request(sc->sc_udev, &req, NULL)) != 0) {
                    425:                printf("%s: cmd failed, type 0x%02x, cmd 0x%04x, "
                    426:                    "param 0x%04x: %s\n", sc->sc_dev.dv_xname, type, cmd,
                    427:                    param, usbd_errstr(error));
                    428:                if (cmd != DS2490_CTL_RESET_DEVICE)
                    429:                        uow_reset(sc);
                    430:                return (1);
                    431:        }
                    432:
                    433: again:
                    434:        if (tsleep(sc->sc_regs, PRIBIO, "uowcmd",
                    435:            (UOW_TIMEOUT * hz) / 1000) != 0) {
                    436:                printf("%s: cmd timeout, type 0x%02x, cmd 0x%04x, "
                    437:                    "param 0x%04x\n", sc->sc_dev.dv_xname, type, cmd,
                    438:                    param);
                    439:                return (1);
                    440:        }
                    441:        if ((sc->sc_regs[DS2490_ST_STFL] & DS2490_ST_STFL_IDLE) == 0)
                    442:                goto again;
                    443:
                    444:        return (0);
                    445: }
                    446:
                    447: void
                    448: uow_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
                    449: {
                    450:        struct uow_softc *sc = priv;
                    451:
                    452:        if (status != USBD_NORMAL_COMPLETION) {
                    453:                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
                    454:                        return;
                    455:                if (status == USBD_STALLED)
                    456:                        usbd_clear_endpoint_stall_async(sc->sc_ph_intr);
                    457:                return;
                    458:        }
                    459:
                    460:        wakeup(sc->sc_regs);
                    461: }
                    462:
                    463: int
                    464: uow_read(struct uow_softc *sc, void *buf, int len)
                    465: {
                    466:        usbd_status error;
                    467:        int count;
                    468:
                    469:        /* XXX: implement FIFO status monitoring */
                    470:        if (len > DS2490_DATAFIFOSIZE) {
                    471:                printf("%s: read %d bytes, xfer too big\n",
                    472:                    sc->sc_dev.dv_xname, len);
                    473:                return (-1);
                    474:        }
                    475:
                    476:        if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
                    477:                printf("%s: failed to alloc xfer\n", sc->sc_dev.dv_xname);
                    478:                return (-1);
                    479:        }
                    480:        usbd_setup_xfer(sc->sc_xfer, sc->sc_ph_ibulk, sc, buf, len,
                    481:            USBD_SHORT_XFER_OK, UOW_TIMEOUT, NULL);
                    482:        error = usbd_sync_transfer(sc->sc_xfer);
                    483:        usbd_free_xfer(sc->sc_xfer);
                    484:        if (error != 0) {
                    485:                printf("%s: read failed, len %d: %s\n",
                    486:                    sc->sc_dev.dv_xname, len, usbd_errstr(error));
                    487:                uow_reset(sc);
                    488:                return (-1);
                    489:        }
                    490:
                    491:        usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &count, &error);
                    492:        return (count);
                    493: }
                    494:
                    495: int
                    496: uow_write(struct uow_softc *sc, const void *buf, int len)
                    497: {
                    498:        usbd_status error;
                    499:
                    500:        /* XXX: implement FIFO status monitoring */
                    501:        if (len > DS2490_DATAFIFOSIZE) {
                    502:                printf("%s: write %d bytes, xfer too big\n",
                    503:                    sc->sc_dev.dv_xname, len);
                    504:                return (1);
                    505:        }
                    506:
                    507:        if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
                    508:                printf("%s: failed to alloc xfer\n", sc->sc_dev.dv_xname);
                    509:                return (-1);
                    510:        }
                    511:        usbd_setup_xfer(sc->sc_xfer, sc->sc_ph_obulk, sc, (void *)buf, len, 0,
                    512:            UOW_TIMEOUT, NULL);
                    513:        error = usbd_sync_transfer(sc->sc_xfer);
                    514:        usbd_free_xfer(sc->sc_xfer);
                    515:        if (error != 0) {
                    516:                printf("%s: write failed, len %d: %s\n",
                    517:                    sc->sc_dev.dv_xname, len, usbd_errstr(error));
                    518:                uow_reset(sc);
                    519:                return (1);
                    520:        }
                    521:
                    522:        return (0);
                    523: }
                    524:
                    525: int
                    526: uow_reset(struct uow_softc *sc)
                    527: {
                    528:        return (uow_ctlcmd(sc, DS2490_CTL_RESET_DEVICE, 0));
                    529: }

CVSweb