root/dev/usb/uow.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uow_match
  2. uow_attach
  3. uow_detach
  4. uow_activate
  5. uow_ow_reset
  6. uow_ow_bit
  7. uow_ow_read_byte
  8. uow_ow_write_byte
  9. uow_ow_read_block
  10. uow_ow_write_block
  11. uow_ow_matchrom
  12. uow_ow_search
  13. uow_cmd
  14. uow_intr
  15. uow_read
  16. uow_write
  17. uow_reset

    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 }

/* [<][>][^][v][top][bottom][index][help] */