The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/serial/umct.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include <sys/cdefs.h>
    2 __FBSDID("$FreeBSD$");
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    6  *
    7  * Copyright (c) 2003 Scott Long
    8  * All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  */
   32 
   33 /*
   34  * Driver for the MCT (Magic Control Technology) USB-RS232 Converter.
   35  * Based on the superb documentation from the linux mct_u232 driver by
   36  * Wolfgang Grandeggar <wolfgang@cec.ch>.
   37  * This device smells a lot like the Belkin F5U103, except that it has
   38  * suffered some mild brain-damage.  This driver is based off of the ubsa.c
   39  * driver from Alexander Kabaev <kan@FreeBSD.org>.  Merging the two together
   40  * might be useful, though the subtle differences might lead to lots of
   41  * #ifdef's.
   42  */
   43 
   44 /*
   45  * NOTE: all function names beginning like "umct_cfg_" can only
   46  * be called from within the config thread function !
   47  */
   48 
   49 #include <sys/stdint.h>
   50 #include <sys/stddef.h>
   51 #include <sys/param.h>
   52 #include <sys/queue.h>
   53 #include <sys/types.h>
   54 #include <sys/systm.h>
   55 #include <sys/kernel.h>
   56 #include <sys/bus.h>
   57 #include <sys/module.h>
   58 #include <sys/lock.h>
   59 #include <sys/mutex.h>
   60 #include <sys/condvar.h>
   61 #include <sys/sysctl.h>
   62 #include <sys/sx.h>
   63 #include <sys/unistd.h>
   64 #include <sys/callout.h>
   65 #include <sys/malloc.h>
   66 #include <sys/priv.h>
   67 
   68 #include <dev/usb/usb.h>
   69 #include <dev/usb/usbdi.h>
   70 #include <dev/usb/usbdi_util.h>
   71 #include "usbdevs.h"
   72 
   73 #define USB_DEBUG_VAR usb_debug
   74 #include <dev/usb/usb_debug.h>
   75 #include <dev/usb/usb_process.h>
   76 
   77 #include <dev/usb/serial/usb_serial.h>
   78 
   79 /* The UMCT advertises the standard 8250 UART registers */
   80 #define UMCT_GET_MSR            2       /* Get Modem Status Register */
   81 #define UMCT_GET_MSR_SIZE       1
   82 #define UMCT_GET_LCR            6       /* Get Line Control Register */
   83 #define UMCT_GET_LCR_SIZE       1
   84 #define UMCT_SET_BAUD           5       /* Set the Baud Rate Divisor */
   85 #define UMCT_SET_BAUD_SIZE      4
   86 #define UMCT_SET_LCR            7       /* Set Line Control Register */
   87 #define UMCT_SET_LCR_SIZE       1
   88 #define UMCT_SET_MCR            10      /* Set Modem Control Register */
   89 #define UMCT_SET_MCR_SIZE       1
   90 
   91 #define UMCT_MSR_CTS_CHG        0x01
   92 #define UMCT_MSR_DSR_CHG        0x02
   93 #define UMCT_MSR_RI_CHG         0x04
   94 #define UMCT_MSR_CD_CHG         0x08
   95 #define UMCT_MSR_CTS            0x10
   96 #define UMCT_MSR_RTS            0x20
   97 #define UMCT_MSR_RI             0x40
   98 #define UMCT_MSR_CD             0x80
   99 
  100 #define UMCT_INTR_INTERVAL      100
  101 #define UMCT_IFACE_INDEX        0
  102 #define UMCT_CONFIG_INDEX       0
  103 
  104 enum {
  105         UMCT_BULK_DT_WR,
  106         UMCT_BULK_DT_RD,
  107         UMCT_INTR_DT_RD,
  108         UMCT_N_TRANSFER,
  109 };
  110 
  111 struct umct_softc {
  112         struct ucom_super_softc sc_super_ucom;
  113         struct ucom_softc sc_ucom;
  114 
  115         struct usb_device *sc_udev;
  116         struct usb_xfer *sc_xfer[UMCT_N_TRANSFER];
  117         struct mtx sc_mtx;
  118 
  119         uint32_t sc_unit;
  120 
  121         uint16_t sc_obufsize;
  122 
  123         uint8_t sc_lsr;
  124         uint8_t sc_msr;
  125         uint8_t sc_lcr;
  126         uint8_t sc_mcr;
  127         uint8_t sc_iface_no;
  128         uint8_t sc_swap_cb;
  129 };
  130 
  131 /* prototypes */
  132 
  133 static device_probe_t umct_probe;
  134 static device_attach_t umct_attach;
  135 static device_detach_t umct_detach;
  136 static void umct_free_softc(struct umct_softc *);
  137 
  138 static usb_callback_t umct_intr_callback;
  139 static usb_callback_t umct_intr_callback_sub;
  140 static usb_callback_t umct_read_callback;
  141 static usb_callback_t umct_read_callback_sub;
  142 static usb_callback_t umct_write_callback;
  143 
  144 static void     umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
  145                     uint16_t len, uint32_t value);
  146 static void     umct_free(struct ucom_softc *);
  147 static void     umct_cfg_get_status(struct ucom_softc *, uint8_t *,
  148                     uint8_t *);
  149 static void     umct_cfg_set_break(struct ucom_softc *, uint8_t);
  150 static void     umct_cfg_set_dtr(struct ucom_softc *, uint8_t);
  151 static void     umct_cfg_set_rts(struct ucom_softc *, uint8_t);
  152 static uint8_t  umct_calc_baud(uint32_t);
  153 static int      umct_pre_param(struct ucom_softc *, struct termios *);
  154 static void     umct_cfg_param(struct ucom_softc *, struct termios *);
  155 static void     umct_start_read(struct ucom_softc *);
  156 static void     umct_stop_read(struct ucom_softc *);
  157 static void     umct_start_write(struct ucom_softc *);
  158 static void     umct_stop_write(struct ucom_softc *);
  159 static void     umct_poll(struct ucom_softc *ucom);
  160 
  161 static const struct usb_config umct_config[UMCT_N_TRANSFER] = {
  162         [UMCT_BULK_DT_WR] = {
  163                 .type = UE_BULK,
  164                 .endpoint = UE_ADDR_ANY,
  165                 .direction = UE_DIR_OUT,
  166                 .bufsize = 0,   /* use wMaxPacketSize */
  167                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  168                 .callback = &umct_write_callback,
  169         },
  170 
  171         [UMCT_BULK_DT_RD] = {
  172                 .type = UE_INTERRUPT,
  173                 .endpoint = UE_ADDR_ANY,
  174                 .direction = UE_DIR_IN,
  175                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  176                 .bufsize = 0,   /* use wMaxPacketSize */
  177                 .callback = &umct_read_callback,
  178                 .ep_index = 0,          /* first interrupt endpoint */
  179         },
  180 
  181         [UMCT_INTR_DT_RD] = {
  182                 .type = UE_INTERRUPT,
  183                 .endpoint = UE_ADDR_ANY,
  184                 .direction = UE_DIR_IN,
  185                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  186                 .bufsize = 0,   /* use wMaxPacketSize */
  187                 .callback = &umct_intr_callback,
  188                 .ep_index = 1,          /* second interrupt endpoint */
  189         },
  190 };
  191 
  192 static const struct ucom_callback umct_callback = {
  193         .ucom_cfg_get_status = &umct_cfg_get_status,
  194         .ucom_cfg_set_dtr = &umct_cfg_set_dtr,
  195         .ucom_cfg_set_rts = &umct_cfg_set_rts,
  196         .ucom_cfg_set_break = &umct_cfg_set_break,
  197         .ucom_cfg_param = &umct_cfg_param,
  198         .ucom_pre_param = &umct_pre_param,
  199         .ucom_start_read = &umct_start_read,
  200         .ucom_stop_read = &umct_stop_read,
  201         .ucom_start_write = &umct_start_write,
  202         .ucom_stop_write = &umct_stop_write,
  203         .ucom_poll = &umct_poll,
  204         .ucom_free = &umct_free,
  205 };
  206 
  207 static const STRUCT_USB_HOST_ID umct_devs[] = {
  208         {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)},
  209         {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)},
  210         {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)},
  211         {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)},
  212         {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)},
  213 };
  214 
  215 static device_method_t umct_methods[] = {
  216         DEVMETHOD(device_probe, umct_probe),
  217         DEVMETHOD(device_attach, umct_attach),
  218         DEVMETHOD(device_detach, umct_detach),
  219         DEVMETHOD_END
  220 };
  221 
  222 static driver_t umct_driver = {
  223         .name = "umct",
  224         .methods = umct_methods,
  225         .size = sizeof(struct umct_softc),
  226 };
  227 
  228 DRIVER_MODULE(umct, uhub, umct_driver, NULL, NULL);
  229 MODULE_DEPEND(umct, ucom, 1, 1, 1);
  230 MODULE_DEPEND(umct, usb, 1, 1, 1);
  231 MODULE_VERSION(umct, 1);
  232 USB_PNP_HOST_INFO(umct_devs);
  233 
  234 static int
  235 umct_probe(device_t dev)
  236 {
  237         struct usb_attach_arg *uaa = device_get_ivars(dev);
  238 
  239         if (uaa->usb_mode != USB_MODE_HOST) {
  240                 return (ENXIO);
  241         }
  242         if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) {
  243                 return (ENXIO);
  244         }
  245         if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) {
  246                 return (ENXIO);
  247         }
  248         return (usbd_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa));
  249 }
  250 
  251 static int
  252 umct_attach(device_t dev)
  253 {
  254         struct usb_attach_arg *uaa = device_get_ivars(dev);
  255         struct umct_softc *sc = device_get_softc(dev);
  256         int32_t error;
  257         uint16_t maxp;
  258         uint8_t iface_index;
  259 
  260         sc->sc_udev = uaa->device;
  261         sc->sc_unit = device_get_unit(dev);
  262 
  263         device_set_usb_desc(dev);
  264         mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF);
  265         ucom_ref(&sc->sc_super_ucom);
  266 
  267         sc->sc_iface_no = uaa->info.bIfaceNum;
  268 
  269         iface_index = UMCT_IFACE_INDEX;
  270         error = usbd_transfer_setup(uaa->device, &iface_index,
  271             sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &sc->sc_mtx);
  272 
  273         if (error) {
  274                 device_printf(dev, "allocating USB "
  275                     "transfers failed\n");
  276                 goto detach;
  277         }
  278 
  279         /*
  280          * The real bulk-in endpoint is also marked as an interrupt.
  281          * The only way to differentiate it from the real interrupt
  282          * endpoint is to look at the wMaxPacketSize field.
  283          */
  284         maxp = usbd_xfer_max_framelen(sc->sc_xfer[UMCT_BULK_DT_RD]);
  285         if (maxp == 0x2) {
  286                 /* guessed wrong - switch around endpoints */
  287 
  288                 struct usb_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD];
  289 
  290                 sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD];
  291                 sc->sc_xfer[UMCT_BULK_DT_RD] = temp;
  292                 sc->sc_swap_cb = 1;
  293         }
  294 
  295         sc->sc_obufsize = usbd_xfer_max_len(sc->sc_xfer[UMCT_BULK_DT_WR]);
  296 
  297         if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) {
  298                 if (sc->sc_obufsize > 16) {
  299                         sc->sc_obufsize = 16;
  300                 }
  301         }
  302         error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
  303             &umct_callback, &sc->sc_mtx);
  304         if (error) {
  305                 goto detach;
  306         }
  307         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
  308 
  309         return (0);                     /* success */
  310 
  311 detach:
  312         umct_detach(dev);
  313         return (ENXIO);                 /* failure */
  314 }
  315 
  316 static int
  317 umct_detach(device_t dev)
  318 {
  319         struct umct_softc *sc = device_get_softc(dev);
  320 
  321         ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
  322         usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER);
  323 
  324         device_claim_softc(dev);
  325 
  326         umct_free_softc(sc);
  327 
  328         return (0);
  329 }
  330 
  331 UCOM_UNLOAD_DRAIN(umct);
  332 
  333 static void
  334 umct_free_softc(struct umct_softc *sc)
  335 {
  336         if (ucom_unref(&sc->sc_super_ucom)) {
  337                 mtx_destroy(&sc->sc_mtx);
  338                 device_free_softc(sc);
  339         }
  340 }
  341 
  342 static void
  343 umct_free(struct ucom_softc *ucom)
  344 {
  345         umct_free_softc(ucom->sc_parent);
  346 }
  347 
  348 static void
  349 umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
  350     uint16_t len, uint32_t value)
  351 {
  352         struct usb_device_request req;
  353         usb_error_t err;
  354         uint8_t temp[4];
  355 
  356         if (len > 4)
  357                 len = 4;
  358         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  359         req.bRequest = request;
  360         USETW(req.wValue, 0);
  361         req.wIndex[0] = sc->sc_iface_no;
  362         req.wIndex[1] = 0;
  363         USETW(req.wLength, len);
  364         USETDW(temp, value);
  365 
  366         err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  367             &req, temp, 0, 1000);
  368         if (err) {
  369                 DPRINTFN(0, "device request failed, err=%s "
  370                     "(ignored)\n", usbd_errstr(err));
  371         }
  372         return;
  373 }
  374 
  375 static void
  376 umct_intr_callback_sub(struct usb_xfer *xfer, usb_error_t error)
  377 {
  378         struct umct_softc *sc = usbd_xfer_softc(xfer);
  379         struct usb_page_cache *pc;
  380         uint8_t buf[2];
  381         int actlen;
  382 
  383         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  384 
  385         switch (USB_GET_STATE(xfer)) {
  386         case USB_ST_TRANSFERRED:
  387                 if (actlen < 2) {
  388                         DPRINTF("too short message\n");
  389                         goto tr_setup;
  390                 }
  391                 pc = usbd_xfer_get_frame(xfer, 0);
  392                 usbd_copy_out(pc, 0, buf, sizeof(buf));
  393 
  394                 /*
  395                  * MSR bits need translation from ns16550 to SER_* values.
  396                  * LSR bits are ns16550 in hardware and ucom.
  397                  */
  398                 sc->sc_msr = 0;
  399                 if (buf[0] & UMCT_MSR_CTS)
  400                         sc->sc_msr |= SER_CTS;
  401                 if (buf[0] & UMCT_MSR_CD)
  402                         sc->sc_msr |= SER_DCD;
  403                 if (buf[0] & UMCT_MSR_RI)
  404                         sc->sc_msr |= SER_RI;
  405                 if (buf[0] & UMCT_MSR_RTS)
  406                         sc->sc_msr |= SER_DSR;
  407                 sc->sc_lsr = buf[1];
  408 
  409                 ucom_status_change(&sc->sc_ucom);
  410                 /* FALLTHROUGH */
  411         case USB_ST_SETUP:
  412 tr_setup:
  413                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  414                 usbd_transfer_submit(xfer);
  415                 return;
  416 
  417         default:                        /* Error */
  418                 if (error != USB_ERR_CANCELLED) {
  419                         /* try to clear stall first */
  420                         usbd_xfer_set_stall(xfer);
  421                         goto tr_setup;
  422                 }
  423                 return;
  424         }
  425 }
  426 
  427 static void
  428 umct_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
  429 {
  430         struct umct_softc *sc = ucom->sc_parent;
  431 
  432         *lsr = sc->sc_lsr;
  433         *msr = sc->sc_msr;
  434 }
  435 
  436 static void
  437 umct_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
  438 {
  439         struct umct_softc *sc = ucom->sc_parent;
  440 
  441         if (onoff)
  442                 sc->sc_lcr |= 0x40;
  443         else
  444                 sc->sc_lcr &= ~0x40;
  445 
  446         umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr);
  447 }
  448 
  449 static void
  450 umct_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
  451 {
  452         struct umct_softc *sc = ucom->sc_parent;
  453 
  454         if (onoff)
  455                 sc->sc_mcr |= 0x01;
  456         else
  457                 sc->sc_mcr &= ~0x01;
  458 
  459         umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
  460 }
  461 
  462 static void
  463 umct_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
  464 {
  465         struct umct_softc *sc = ucom->sc_parent;
  466 
  467         if (onoff)
  468                 sc->sc_mcr |= 0x02;
  469         else
  470                 sc->sc_mcr &= ~0x02;
  471 
  472         umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
  473 }
  474 
  475 static uint8_t
  476 umct_calc_baud(uint32_t baud)
  477 {
  478         switch (baud) {
  479         case B300:
  480                 return (0x1);
  481         case B600:
  482                 return (0x2);
  483         case B1200:
  484                 return (0x3);
  485         case B2400:
  486                 return (0x4);
  487         case B4800:
  488                 return (0x6);
  489         case B9600:
  490                 return (0x8);
  491         case B19200:
  492                 return (0x9);
  493         case B38400:
  494                 return (0xa);
  495         case B57600:
  496                 return (0xb);
  497         case 115200:
  498                 return (0xc);
  499         case B0:
  500         default:
  501                 break;
  502         }
  503         return (0x0);
  504 }
  505 
  506 static int
  507 umct_pre_param(struct ucom_softc *ucom, struct termios *t)
  508 {
  509         return (0);                     /* we accept anything */
  510 }
  511 
  512 static void
  513 umct_cfg_param(struct ucom_softc *ucom, struct termios *t)
  514 {
  515         struct umct_softc *sc = ucom->sc_parent;
  516         uint32_t value;
  517 
  518         value = umct_calc_baud(t->c_ospeed);
  519         umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value);
  520 
  521         value = (sc->sc_lcr & 0x40);
  522 
  523         switch (t->c_cflag & CSIZE) {
  524         case CS5:
  525                 value |= 0x0;
  526                 break;
  527         case CS6:
  528                 value |= 0x1;
  529                 break;
  530         case CS7:
  531                 value |= 0x2;
  532                 break;
  533         default:
  534         case CS8:
  535                 value |= 0x3;
  536                 break;
  537         }
  538 
  539         value |= (t->c_cflag & CSTOPB) ? 0x4 : 0;
  540         if (t->c_cflag & PARENB) {
  541                 value |= 0x8;
  542                 value |= (t->c_cflag & PARODD) ? 0x0 : 0x10;
  543         }
  544         /*
  545          * XXX There doesn't seem to be a way to tell the device
  546          * to use flow control.
  547          */
  548 
  549         sc->sc_lcr = value;
  550         umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value);
  551 }
  552 
  553 static void
  554 umct_start_read(struct ucom_softc *ucom)
  555 {
  556         struct umct_softc *sc = ucom->sc_parent;
  557 
  558         /* start interrupt endpoint */
  559         usbd_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]);
  560 
  561         /* start read endpoint */
  562         usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]);
  563 }
  564 
  565 static void
  566 umct_stop_read(struct ucom_softc *ucom)
  567 {
  568         struct umct_softc *sc = ucom->sc_parent;
  569 
  570         /* stop interrupt endpoint */
  571         usbd_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]);
  572 
  573         /* stop read endpoint */
  574         usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]);
  575 }
  576 
  577 static void
  578 umct_start_write(struct ucom_softc *ucom)
  579 {
  580         struct umct_softc *sc = ucom->sc_parent;
  581 
  582         usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]);
  583 }
  584 
  585 static void
  586 umct_stop_write(struct ucom_softc *ucom)
  587 {
  588         struct umct_softc *sc = ucom->sc_parent;
  589 
  590         usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]);
  591 }
  592 
  593 static void
  594 umct_read_callback(struct usb_xfer *xfer, usb_error_t error)
  595 {
  596         struct umct_softc *sc = usbd_xfer_softc(xfer);
  597 
  598         if (sc->sc_swap_cb)
  599                 umct_intr_callback_sub(xfer, error);
  600         else
  601                 umct_read_callback_sub(xfer, error);
  602 }
  603 
  604 static void
  605 umct_intr_callback(struct usb_xfer *xfer, usb_error_t error)
  606 {
  607         struct umct_softc *sc = usbd_xfer_softc(xfer);
  608 
  609         if (sc->sc_swap_cb)
  610                 umct_read_callback_sub(xfer, error);
  611         else
  612                 umct_intr_callback_sub(xfer, error);
  613 }
  614 
  615 static void
  616 umct_write_callback(struct usb_xfer *xfer, usb_error_t error)
  617 {
  618         struct umct_softc *sc = usbd_xfer_softc(xfer);
  619         struct usb_page_cache *pc;
  620         uint32_t actlen;
  621 
  622         switch (USB_GET_STATE(xfer)) {
  623         case USB_ST_SETUP:
  624         case USB_ST_TRANSFERRED:
  625 tr_setup:
  626                 pc = usbd_xfer_get_frame(xfer, 0);
  627                 if (ucom_get_data(&sc->sc_ucom, pc, 0,
  628                     sc->sc_obufsize, &actlen)) {
  629                         usbd_xfer_set_frame_len(xfer, 0, actlen);
  630                         usbd_transfer_submit(xfer);
  631                 }
  632                 return;
  633 
  634         default:                        /* Error */
  635                 if (error != USB_ERR_CANCELLED) {
  636                         /* try to clear stall first */
  637                         usbd_xfer_set_stall(xfer);
  638                         goto tr_setup;
  639                 }
  640                 return;
  641         }
  642 }
  643 
  644 static void
  645 umct_read_callback_sub(struct usb_xfer *xfer, usb_error_t error)
  646 {
  647         struct umct_softc *sc = usbd_xfer_softc(xfer);
  648         struct usb_page_cache *pc;
  649         int actlen;
  650 
  651         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  652 
  653         switch (USB_GET_STATE(xfer)) {
  654         case USB_ST_TRANSFERRED:
  655                 pc = usbd_xfer_get_frame(xfer, 0);
  656                 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
  657 
  658         case USB_ST_SETUP:
  659 tr_setup:
  660                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  661                 usbd_transfer_submit(xfer);
  662                 return;
  663 
  664         default:                        /* Error */
  665                 if (error != USB_ERR_CANCELLED) {
  666                         /* try to clear stall first */
  667                         usbd_xfer_set_stall(xfer);
  668                         goto tr_setup;
  669                 }
  670                 return;
  671         }
  672 }
  673 
  674 static void
  675 umct_poll(struct ucom_softc *ucom)
  676 {
  677         struct umct_softc *sc = ucom->sc_parent;
  678         usbd_transfer_poll(sc->sc_xfer, UMCT_N_TRANSFER);
  679 }

Cache object: 8188cfb77ce921742dae9f64a10b999b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.