root/dev/usb/uslcom.c

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

DEFINITIONS

This source file includes following definitions.
  1. uslcom_match
  2. uslcom_attach
  3. uslcom_detach
  4. uslcom_activate
  5. uslcom_open
  6. uslcom_close
  7. uslcom_set
  8. uslcom_param
  9. ISSET
  10. uslcom_get_status
  11. uslcom_break

    1 /*      $OpenBSD: uslcom.c,v 1.13 2007/06/14 10:11:16 mbalmer Exp $     */
    2 
    3 /*
    4  * Copyright (c) 2006 Jonathan Gray <jsg@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 #include <sys/param.h>
   20 #include <sys/systm.h>
   21 #include <sys/kernel.h>
   22 #include <sys/conf.h>
   23 #include <sys/tty.h>
   24 #include <sys/device.h>
   25 
   26 #include <dev/usb/usb.h>
   27 #include <dev/usb/usbdi.h>
   28 #include <dev/usb/usbdi_util.h>
   29 #include <dev/usb/usbdevs.h>
   30 
   31 #include <dev/usb/usbdevs.h>
   32 #include <dev/usb/ucomvar.h>
   33 
   34 #ifdef USLCOM_DEBUG
   35 #define DPRINTFN(n, x)  do { if (uslcomdebug > (n)) printf x; } while (0)
   36 int     uslcomdebug = 0;
   37 #else
   38 #define DPRINTFN(n, x)
   39 #endif
   40 #define DPRINTF(x) DPRINTFN(0, x)
   41 
   42 #define USLCOMBUFSZ             256
   43 #define USLCOM_CONFIG_NO        0
   44 #define USLCOM_IFACE_NO         0
   45 
   46 #define USLCOM_SET_DATA_BITS(x) (x << 8)
   47 
   48 #define USLCOM_WRITE            0x41
   49 #define USLCOM_READ             0xc1
   50 
   51 #define USLCOM_UART             0x00
   52 #define USLCOM_BAUD_RATE        0x01    
   53 #define USLCOM_DATA             0x03
   54 #define USLCOM_BREAK            0x05
   55 #define USLCOM_CTRL             0x07
   56 
   57 #define USLCOM_UART_DISABLE     0x00
   58 #define USLCOM_UART_ENABLE      0x01
   59 
   60 #define USLCOM_CTRL_DTR_ON      0x0001  
   61 #define USLCOM_CTRL_DTR_SET     0x0100
   62 #define USLCOM_CTRL_RTS_ON      0x0002
   63 #define USLCOM_CTRL_RTS_SET     0x0200
   64 #define USLCOM_CTRL_CTS         0x0010
   65 #define USLCOM_CTRL_DSR         0x0020
   66 #define USLCOM_CTRL_DCD         0x0080
   67 
   68 
   69 #define USLCOM_BAUD_REF         0x384000
   70 
   71 #define USLCOM_STOP_BITS_1      0x00
   72 #define USLCOM_STOP_BITS_2      0x02
   73 
   74 #define USLCOM_PARITY_NONE      0x00
   75 #define USLCOM_PARITY_ODD       0x10
   76 #define USLCOM_PARITY_EVEN      0x20
   77 
   78 #define USLCOM_BREAK_OFF        0x00
   79 #define USLCOM_BREAK_ON         0x01
   80 
   81 
   82 struct uslcom_softc {
   83         struct device            sc_dev;
   84         usbd_device_handle       sc_udev;
   85         usbd_interface_handle    sc_iface;
   86         struct device           *sc_subdev;
   87 
   88         u_char                   sc_msr;
   89         u_char                   sc_lsr;
   90 
   91         u_char                   sc_dying;
   92 };
   93 
   94 void    uslcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
   95 void    uslcom_set(void *, int, int, int);
   96 int     uslcom_param(void *, int, struct termios *);
   97 int     uslcom_open(void *sc, int portno);
   98 void    uslcom_close(void *, int);
   99 void    uslcom_break(void *sc, int portno, int onoff);
  100 
  101 struct ucom_methods uslcom_methods = {
  102         uslcom_get_status,
  103         uslcom_set,
  104         uslcom_param,
  105         NULL,
  106         uslcom_open,
  107         uslcom_close,
  108         NULL,
  109         NULL,
  110 };
  111 
  112 static const struct usb_devno uslcom_devs[] = {
  113         { USB_VENDOR_BALTECH,           USB_PRODUCT_BALTECH_CARDREADER },
  114         { USB_VENDOR_DYNASTREAM,        USB_PRODUCT_DYNASTREAM_ANTDEVBOARD },
  115         { USB_VENDOR_JABLOTRON,         USB_PRODUCT_JABLOTRON_PC60B },
  116         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_ARGUSISP },
  117         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_CRUMB128 },
  118         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_DEGREECONT },
  119         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_DESKTOPMOBILE },
  120         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_IPLINK1220 },
  121         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_LIPOWSKY_HARP },
  122         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_LIPOWSKY_JTAG },
  123         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_LIPOWSKY_LIN },
  124         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_POLOLU },
  125         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_CP210X_1 },
  126         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_CP210X_2 },
  127         { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_SUNNTO },
  128         { USB_VENDOR_SILABS2,           USB_PRODUCT_SILABS2_DCU11CLONE },
  129         { USB_VENDOR_USI,               USB_PRODUCT_USI_MC60 }
  130 };
  131 
  132 int uslcom_match(struct device *, void *, void *); 
  133 void uslcom_attach(struct device *, struct device *, void *); 
  134 int uslcom_detach(struct device *, int); 
  135 int uslcom_activate(struct device *, enum devact); 
  136 
  137 struct cfdriver uslcom_cd = { 
  138         NULL, "uslcom", DV_DULL 
  139 }; 
  140 
  141 const struct cfattach uslcom_ca = { 
  142         sizeof(struct uslcom_softc), 
  143         uslcom_match, 
  144         uslcom_attach, 
  145         uslcom_detach, 
  146         uslcom_activate, 
  147 };
  148 
  149 int
  150 uslcom_match(struct device *parent, void *match, void *aux)
  151 {
  152         struct usb_attach_arg *uaa = aux;
  153 
  154         if (uaa->iface != NULL)
  155                 return UMATCH_NONE;
  156 
  157         return (usb_lookup(uslcom_devs, uaa->vendor, uaa->product) != NULL) ?
  158             UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
  159 }
  160 
  161 void
  162 uslcom_attach(struct device *parent, struct device *self, void *aux)
  163 {
  164         struct uslcom_softc *sc = (struct uslcom_softc *)self;
  165         struct usb_attach_arg *uaa = aux;
  166         struct ucom_attach_args uca;
  167         usb_interface_descriptor_t *id;
  168         usb_endpoint_descriptor_t *ed;
  169         usbd_status error;
  170         char *devinfop;
  171         int i;
  172 
  173         bzero(&uca, sizeof(uca));
  174         sc->sc_udev = uaa->device;
  175         devinfop = usbd_devinfo_alloc(uaa->device, 0);
  176         printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
  177         usbd_devinfo_free(devinfop);
  178 
  179         if (usbd_set_config_index(sc->sc_udev, USLCOM_CONFIG_NO, 1) != 0) {
  180                 printf("%s: could not set configuration no\n",
  181                     sc->sc_dev.dv_xname);
  182                 sc->sc_dying = 1;
  183                 return;
  184         }
  185 
  186         /* get the first interface handle */
  187         error = usbd_device2interface_handle(sc->sc_udev, USLCOM_IFACE_NO,
  188             &sc->sc_iface);
  189         if (error != 0) {
  190                 printf("%s: could not get interface handle\n",
  191                     sc->sc_dev.dv_xname);
  192                 sc->sc_dying = 1;
  193                 return;
  194         }
  195 
  196         id = usbd_get_interface_descriptor(sc->sc_iface);
  197 
  198         uca.bulkin = uca.bulkout = -1;
  199         for (i = 0; i < id->bNumEndpoints; i++) {
  200                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
  201                 if (ed == NULL) {
  202                         printf("%s: no endpoint descriptor found for %d\n",
  203                             sc->sc_dev.dv_xname, i);
  204                         sc->sc_dying = 1;
  205                         return;
  206                 }
  207 
  208                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  209                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
  210                         uca.bulkin = ed->bEndpointAddress;
  211                 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  212                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
  213                         uca.bulkout = ed->bEndpointAddress;
  214         }
  215 
  216         if (uca.bulkin == -1 || uca.bulkout == -1) {
  217                 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
  218                 sc->sc_dying = 1;
  219                 return;
  220         }
  221 
  222         uca.ibufsize = USLCOMBUFSZ;
  223         uca.obufsize = USLCOMBUFSZ;
  224         uca.ibufsizepad = USLCOMBUFSZ;
  225         uca.opkthdrlen = 0;
  226         uca.device = sc->sc_udev;
  227         uca.iface = sc->sc_iface;
  228         uca.methods = &uslcom_methods;
  229         uca.arg = sc;
  230         uca.info = NULL;
  231 
  232         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
  233             &sc->sc_dev);
  234         
  235         sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
  236 }
  237 
  238 int
  239 uslcom_detach(struct device *self, int flags)
  240 {
  241         struct uslcom_softc *sc = (struct uslcom_softc *)self;
  242         int rv = 0;
  243 
  244         sc->sc_dying = 1;
  245         if (sc->sc_subdev != NULL) {
  246                 rv = config_detach(sc->sc_subdev, flags);
  247                 sc->sc_subdev = NULL;
  248         }
  249 
  250         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
  251                            &sc->sc_dev);
  252 
  253         return (rv);
  254 }
  255 
  256 int
  257 uslcom_activate(struct device *self, enum devact act)
  258 {
  259         struct uslcom_softc *sc = (struct uslcom_softc *)self;
  260         int rv = 0;
  261 
  262         switch (act) {
  263         case DVACT_ACTIVATE:
  264                 break;
  265 
  266         case DVACT_DEACTIVATE:
  267                 if (sc->sc_subdev != NULL)
  268                         rv = config_deactivate(sc->sc_subdev);
  269                 sc->sc_dying = 1;
  270                 break;
  271         }
  272         return (rv);
  273 }
  274 
  275 int
  276 uslcom_open(void *vsc, int portno)
  277 {
  278         struct uslcom_softc *sc = vsc;
  279         usb_device_request_t req;
  280         usbd_status err;
  281 
  282         if (sc->sc_dying)
  283                 return (EIO);
  284 
  285         req.bmRequestType = USLCOM_WRITE;
  286         req.bRequest = USLCOM_UART;
  287         USETW(req.wValue, USLCOM_UART_ENABLE);
  288         USETW(req.wIndex, portno);
  289         USETW(req.wLength, 0);
  290         err = usbd_do_request(sc->sc_udev, &req, NULL);
  291         if (err)
  292                 return (EIO);
  293 
  294         return (0);
  295 }
  296 
  297 void
  298 uslcom_close(void *vsc, int portno)
  299 {
  300         struct uslcom_softc *sc = vsc;
  301         usb_device_request_t req;
  302 
  303         if (sc->sc_dying)
  304                 return;
  305 
  306         req.bmRequestType = USLCOM_WRITE;
  307         req.bRequest = USLCOM_UART;
  308         USETW(req.wValue, USLCOM_UART_DISABLE);
  309         USETW(req.wIndex, portno);
  310         USETW(req.wLength, 0);
  311         usbd_do_request(sc->sc_udev, &req, NULL);
  312 }
  313 
  314 void
  315 uslcom_set(void *vsc, int portno, int reg, int onoff)
  316 {
  317         struct uslcom_softc *sc = vsc;
  318         usb_device_request_t req;
  319         int ctl;
  320 
  321         switch (reg) {
  322         case UCOM_SET_DTR:
  323                 ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
  324                 ctl |= USLCOM_CTRL_DTR_SET;
  325                 break;
  326         case UCOM_SET_RTS:
  327                 ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
  328                 ctl |= USLCOM_CTRL_RTS_SET;
  329                 break;
  330         case UCOM_SET_BREAK:
  331                 uslcom_break(sc, portno, onoff);
  332                 return;
  333         default:
  334                 return;
  335         }
  336         req.bmRequestType = USLCOM_WRITE;
  337         req.bRequest = USLCOM_CTRL;
  338         USETW(req.wValue, ctl);
  339         USETW(req.wIndex, portno);
  340         USETW(req.wLength, 0);
  341         usbd_do_request(sc->sc_udev, &req, NULL);
  342 }
  343 
  344 int
  345 uslcom_param(void *vsc, int portno, struct termios *t)
  346 {
  347         struct uslcom_softc *sc = (struct uslcom_softc *)vsc;
  348         usbd_status err;
  349         usb_device_request_t req;
  350         int data;
  351 
  352         switch (t->c_ospeed) {
  353         case 600:
  354         case 1200:
  355         case 1800:
  356         case 2400:
  357         case 4800:
  358         case 9600:
  359         case 19200:
  360         case 38400:
  361         case 57600:
  362         case 115200:
  363         case 460800:
  364         case 921600:
  365                 req.bmRequestType = USLCOM_WRITE;
  366                 req.bRequest = USLCOM_BAUD_RATE;
  367                 USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
  368                 USETW(req.wIndex, portno);
  369                 USETW(req.wLength, 0);
  370                 err = usbd_do_request(sc->sc_udev, &req, NULL);
  371                 if (err)
  372                         return (EIO);
  373                 break;
  374         default:
  375                 return (EINVAL);
  376         }
  377 
  378         if (ISSET(t->c_cflag, CSTOPB))
  379                 data = USLCOM_STOP_BITS_2;
  380         else
  381                 data = USLCOM_STOP_BITS_1;
  382         if (ISSET(t->c_cflag, PARENB)) {
  383                 if (ISSET(t->c_cflag, PARODD))
  384                         data |= USLCOM_PARITY_ODD;
  385                 else
  386                         data |= USLCOM_PARITY_EVEN;
  387         } else
  388                 data |= USLCOM_PARITY_NONE;
  389         switch (ISSET(t->c_cflag, CSIZE)) {
  390         case CS5:
  391                 data |= USLCOM_SET_DATA_BITS(5);
  392                 break;
  393         case CS6:
  394                 data |= USLCOM_SET_DATA_BITS(6);
  395                 break;
  396         case CS7:
  397                 data |= USLCOM_SET_DATA_BITS(7);
  398                 break;
  399         case CS8:
  400                 data |= USLCOM_SET_DATA_BITS(8);
  401                 break;
  402         }
  403 
  404         req.bmRequestType = USLCOM_WRITE;
  405         req.bRequest = USLCOM_DATA;
  406         USETW(req.wValue, data);
  407         USETW(req.wIndex, portno);
  408         USETW(req.wLength, 0);
  409         err = usbd_do_request(sc->sc_udev, &req, NULL);
  410         if (err)
  411                 return (EIO);
  412 
  413 #if 0
  414         /* XXX flow control */
  415         if (ISSET(t->c_cflag, CRTSCTS))
  416                 /*  rts/cts flow ctl */
  417         } else if (ISSET(t->c_iflag, IXON|IXOFF)) {
  418                 /*  xon/xoff flow ctl */
  419         } else {
  420                 /* disable flow ctl */
  421         }
  422 #endif
  423 
  424         return (0);
  425 }
  426 
  427 void
  428 uslcom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
  429 {
  430         struct uslcom_softc *sc = vsc;
  431         
  432         if (msr != NULL)
  433                 *msr = sc->sc_msr;
  434         if (lsr != NULL)
  435                 *lsr = sc->sc_lsr;
  436 }
  437 
  438 void
  439 uslcom_break(void *vsc, int portno, int onoff)
  440 {
  441         struct uslcom_softc *sc = vsc;
  442         usb_device_request_t req;
  443         int brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;   
  444 
  445         req.bmRequestType = USLCOM_WRITE;
  446         req.bRequest = USLCOM_BREAK;
  447         USETW(req.wValue, brk);
  448         USETW(req.wIndex, portno);
  449         USETW(req.wLength, 0);
  450         usbd_do_request(sc->sc_udev, &req, NULL);
  451 }

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