uslcom.c revision 194228
1218885Sdim/* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */ 2218885Sdim 3218885Sdim#include <sys/cdefs.h> 4218885Sdim__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 194228 2009-06-15 01:02:43Z thompsa $"); 5218885Sdim 6218885Sdim/* 7218885Sdim * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 8218885Sdim * 9218885Sdim * Permission to use, copy, modify, and distribute this software for any 10218885Sdim * purpose with or without fee is hereby granted, provided that the above 11218885Sdim * copyright notice and this permission notice appear in all copies. 12218885Sdim * 13218885Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14218885Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15218885Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16218885Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17223017Sdim * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18223017Sdim * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19223017Sdim * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20218885Sdim */ 21218885Sdim 22218885Sdim#include "usbdevs.h" 23218885Sdim#include <dev/usb/usb.h> 24218885Sdim#include <dev/usb/usb_mfunc.h> 25218885Sdim#include <dev/usb/usb_error.h> 26218885Sdim 27218885Sdim#define USB_DEBUG_VAR uslcom_debug 28218885Sdim 29218885Sdim#include <dev/usb/usb_core.h> 30218885Sdim#include <dev/usb/usb_debug.h> 31218885Sdim#include <dev/usb/usb_process.h> 32218885Sdim#include <dev/usb/usb_request.h> 33218885Sdim#include <dev/usb/usb_lookup.h> 34218885Sdim#include <dev/usb/usb_util.h> 35218885Sdim#include <dev/usb/usb_busdma.h> 36218885Sdim 37218885Sdim#include <dev/usb/serial/usb_serial.h> 38218885Sdim 39218885Sdim#if USB_DEBUG 40218885Sdimstatic int uslcom_debug = 0; 41218885Sdim 42218885SdimSYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); 43218885SdimSYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW, 44218885Sdim &uslcom_debug, 0, "Debug level"); 45218885Sdim#endif 46218885Sdim 47223017Sdim#define USLCOM_BULK_BUF_SIZE 1024 48223017Sdim#define USLCOM_CONFIG_INDEX 0 49223017Sdim#define USLCOM_IFACE_INDEX 0 50223017Sdim 51223017Sdim#define USLCOM_SET_DATA_BITS(x) ((x) << 8) 52223017Sdim 53223017Sdim#define USLCOM_WRITE 0x41 54223017Sdim#define USLCOM_READ 0xc1 55223017Sdim 56223017Sdim#define USLCOM_UART 0x00 57223017Sdim#define USLCOM_BAUD_RATE 0x01 58223017Sdim#define USLCOM_DATA 0x03 59223017Sdim#define USLCOM_BREAK 0x05 60223017Sdim#define USLCOM_CTRL 0x07 61223017Sdim 62223017Sdim#define USLCOM_UART_DISABLE 0x00 63223017Sdim#define USLCOM_UART_ENABLE 0x01 64223017Sdim 65223017Sdim#define USLCOM_CTRL_DTR_ON 0x0001 66223017Sdim#define USLCOM_CTRL_DTR_SET 0x0100 67223017Sdim#define USLCOM_CTRL_RTS_ON 0x0002 68223017Sdim#define USLCOM_CTRL_RTS_SET 0x0200 69223017Sdim#define USLCOM_CTRL_CTS 0x0010 70223017Sdim#define USLCOM_CTRL_DSR 0x0020 71223017Sdim#define USLCOM_CTRL_DCD 0x0080 72223017Sdim 73223017Sdim#define USLCOM_BAUD_REF 0x384000 74223017Sdim 75218885Sdim#define USLCOM_STOP_BITS_1 0x00 76218885Sdim#define USLCOM_STOP_BITS_2 0x02 77218885Sdim 78218885Sdim#define USLCOM_PARITY_NONE 0x00 79218885Sdim#define USLCOM_PARITY_ODD 0x10 80218885Sdim#define USLCOM_PARITY_EVEN 0x20 81218885Sdim 82218885Sdim#define USLCOM_PORT_NO 0xFFFF /* XXX think this should be 0 --hps */ 83218885Sdim 84218885Sdim#define USLCOM_BREAK_OFF 0x00 85218885Sdim#define USLCOM_BREAK_ON 0x01 86218885Sdim 87218885Sdimenum { 88218885Sdim USLCOM_BULK_DT_WR, 89218885Sdim USLCOM_BULK_DT_RD, 90218885Sdim USLCOM_N_TRANSFER, 91218885Sdim}; 92218885Sdim 93218885Sdimstruct uslcom_softc { 94218885Sdim struct ucom_super_softc sc_super_ucom; 95218885Sdim struct ucom_softc sc_ucom; 96218885Sdim 97218885Sdim struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER]; 98218885Sdim struct usb_device *sc_udev; 99218885Sdim struct mtx sc_mtx; 100218885Sdim 101218885Sdim uint8_t sc_msr; 102218885Sdim uint8_t sc_lsr; 103218885Sdim}; 104223017Sdim 105223017Sdimstatic device_probe_t uslcom_probe; 106223017Sdimstatic device_attach_t uslcom_attach; 107223017Sdimstatic device_detach_t uslcom_detach; 108223017Sdim 109223017Sdimstatic usb_callback_t uslcom_write_callback; 110223017Sdimstatic usb_callback_t uslcom_read_callback; 111223017Sdim 112223017Sdimstatic void uslcom_open(struct ucom_softc *); 113223017Sdimstatic void uslcom_close(struct ucom_softc *); 114223017Sdimstatic void uslcom_set_dtr(struct ucom_softc *, uint8_t); 115223017Sdimstatic void uslcom_set_rts(struct ucom_softc *, uint8_t); 116223017Sdimstatic void uslcom_set_break(struct ucom_softc *, uint8_t); 117223017Sdimstatic int uslcom_pre_param(struct ucom_softc *, struct termios *); 118223017Sdimstatic void uslcom_param(struct ucom_softc *, struct termios *); 119223017Sdimstatic void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 120223017Sdimstatic void uslcom_start_read(struct ucom_softc *); 121218885Sdimstatic void uslcom_stop_read(struct ucom_softc *); 122218885Sdimstatic void uslcom_start_write(struct ucom_softc *); 123218885Sdimstatic void uslcom_stop_write(struct ucom_softc *); 124218885Sdim 125218885Sdimstatic const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { 126218885Sdim 127218885Sdim [USLCOM_BULK_DT_WR] = { 128218885Sdim .type = UE_BULK, 129218885Sdim .endpoint = UE_ADDR_ANY, 130218885Sdim .direction = UE_DIR_OUT, 131218885Sdim .bufsize = USLCOM_BULK_BUF_SIZE, 132218885Sdim .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 133218885Sdim .callback = &uslcom_write_callback, 134218885Sdim }, 135218885Sdim 136218885Sdim [USLCOM_BULK_DT_RD] = { 137218885Sdim .type = UE_BULK, 138218885Sdim .endpoint = UE_ADDR_ANY, 139218885Sdim .direction = UE_DIR_IN, 140218885Sdim .bufsize = USLCOM_BULK_BUF_SIZE, 141218885Sdim .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 142218885Sdim .callback = &uslcom_read_callback, 143218885Sdim }, 144218885Sdim}; 145218885Sdim 146218885Sdimstatic struct ucom_callback uslcom_callback = { 147218885Sdim .ucom_cfg_open = &uslcom_open, 148218885Sdim .ucom_cfg_close = &uslcom_close, 149218885Sdim .ucom_cfg_get_status = &uslcom_get_status, 150218885Sdim .ucom_cfg_set_dtr = &uslcom_set_dtr, 151218885Sdim .ucom_cfg_set_rts = &uslcom_set_rts, 152218885Sdim .ucom_cfg_set_break = &uslcom_set_break, 153218885Sdim .ucom_cfg_param = &uslcom_param, 154218885Sdim .ucom_pre_param = &uslcom_pre_param, 155218885Sdim .ucom_start_read = &uslcom_start_read, 156218885Sdim .ucom_stop_read = &uslcom_stop_read, 157218885Sdim .ucom_start_write = &uslcom_start_write, 158218885Sdim .ucom_stop_write = &uslcom_stop_write, 159218885Sdim}; 160218885Sdim 161218885Sdimstatic const struct usb_device_id uslcom_devs[] = { 162218885Sdim { USB_VPI(USB_VENDOR_BALTECH, USB_PRODUCT_BALTECH_CARDREADER, 0) }, 163218885Sdim { USB_VPI(USB_VENDOR_DYNASTREAM, USB_PRODUCT_DYNASTREAM_ANTDEVBOARD, 0) }, 164218885Sdim { USB_VPI(USB_VENDOR_JABLOTRON, USB_PRODUCT_JABLOTRON_PC60B, 0) }, 165218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_ARGUSISP, 0) }, 166218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CRUMB128, 0) }, 167218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DEGREE, 0) }, 168218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_BURNSIDE, 0) }, 169218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_HELICOM, 0) }, 170218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_HARP, 0) }, 171218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_JTAG, 0) }, 172218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_LIN, 0) }, 173218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_POLOLU, 0) }, 174218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP2102, 0) }, 175218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_2, 0) }, 176218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SUUNTO, 0) }, 177218885Sdim { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_TRAQMATE, 0) }, 178218885Sdim { USB_VPI(USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE, 0) }, 179218885Sdim { USB_VPI(USB_VENDOR_USI, USB_PRODUCT_USI_MC60, 0) }, 180218885Sdim}; 181218885Sdim 182218885Sdimstatic device_method_t uslcom_methods[] = { 183218885Sdim DEVMETHOD(device_probe, uslcom_probe), 184218885Sdim DEVMETHOD(device_attach, uslcom_attach), 185218885Sdim DEVMETHOD(device_detach, uslcom_detach), 186223017Sdim {0, 0} 187223017Sdim}; 188223017Sdim 189223017Sdimstatic devclass_t uslcom_devclass; 190223017Sdim 191223017Sdimstatic driver_t uslcom_driver = { 192223017Sdim .name = "uslcom", 193223017Sdim .methods = uslcom_methods, 194223017Sdim .size = sizeof(struct uslcom_softc), 195223017Sdim}; 196223017Sdim 197223017SdimDRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0); 198223017SdimMODULE_DEPEND(uslcom, ucom, 1, 1, 1); 199223017SdimMODULE_DEPEND(uslcom, usb, 1, 1, 1); 200223017SdimMODULE_VERSION(uslcom, 1); 201223017Sdim 202223017Sdimstatic int 203223017Sdimuslcom_probe(device_t dev) 204223017Sdim{ 205223017Sdim struct usb_attach_arg *uaa = device_get_ivars(dev); 206223017Sdim 207223017Sdim DPRINTFN(11, "\n"); 208223017Sdim 209223017Sdim if (uaa->usb_mode != USB_MODE_HOST) { 210223017Sdim return (ENXIO); 211223017Sdim } 212223017Sdim if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { 213223017Sdim return (ENXIO); 214223017Sdim } 215223017Sdim if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) { 216223017Sdim return (ENXIO); 217223017Sdim } 218223017Sdim return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa)); 219223017Sdim} 220223017Sdim 221223017Sdimstatic int 222223017Sdimuslcom_attach(device_t dev) 223223017Sdim{ 224223017Sdim struct usb_attach_arg *uaa = device_get_ivars(dev); 225223017Sdim struct uslcom_softc *sc = device_get_softc(dev); 226223017Sdim int error; 227223017Sdim 228223017Sdim DPRINTFN(11, "\n"); 229223017Sdim 230223017Sdim device_set_usb_desc(dev); 231223017Sdim mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF); 232223017Sdim 233223017Sdim sc->sc_udev = uaa->device; 234223017Sdim 235223017Sdim error = usbd_transfer_setup(uaa->device, 236223017Sdim &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config, 237223017Sdim USLCOM_N_TRANSFER, sc, &sc->sc_mtx); 238223017Sdim if (error) { 239223017Sdim DPRINTF("one or more missing USB endpoints, " 240223017Sdim "error=%s\n", usbd_errstr(error)); 241223017Sdim goto detach; 242223017Sdim } 243223017Sdim /* clear stall at first run */ 244223017Sdim mtx_lock(&sc->sc_mtx); 245223017Sdim usbd_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); 246223017Sdim usbd_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); 247223017Sdim mtx_unlock(&sc->sc_mtx); 248223017Sdim 249223017Sdim error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 250223017Sdim &uslcom_callback, &sc->sc_mtx); 251223017Sdim if (error) { 252223017Sdim goto detach; 253223017Sdim } 254223017Sdim return (0); 255223017Sdim 256223017Sdimdetach: 257223017Sdim uslcom_detach(dev); 258223017Sdim return (ENXIO); 259223017Sdim} 260223017Sdim 261223017Sdimstatic int 262223017Sdimuslcom_detach(device_t dev) 263223017Sdim{ 264223017Sdim struct uslcom_softc *sc = device_get_softc(dev); 265223017Sdim 266223017Sdim DPRINTF("sc=%p\n", sc); 267223017Sdim 268223017Sdim ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 269223017Sdim usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); 270223017Sdim mtx_destroy(&sc->sc_mtx); 271223017Sdim 272223017Sdim return (0); 273223017Sdim} 274223017Sdim 275223017Sdimstatic void 276223017Sdimuslcom_open(struct ucom_softc *ucom) 277223017Sdim{ 278223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 279223017Sdim struct usb_device_request req; 280223017Sdim 281223017Sdim req.bmRequestType = USLCOM_WRITE; 282223017Sdim req.bRequest = USLCOM_UART; 283223017Sdim USETW(req.wValue, USLCOM_UART_ENABLE); 284223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 285223017Sdim USETW(req.wLength, 0); 286223017Sdim 287223017Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 288223017Sdim &req, NULL, 0, 1000)) { 289223017Sdim DPRINTF("UART enable failed (ignored)\n"); 290223017Sdim } 291223017Sdim} 292223017Sdim 293223017Sdimstatic void 294223017Sdimuslcom_close(struct ucom_softc *ucom) 295223017Sdim{ 296223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 297223017Sdim struct usb_device_request req; 298223017Sdim 299223017Sdim req.bmRequestType = USLCOM_WRITE; 300223017Sdim req.bRequest = USLCOM_UART; 301223017Sdim USETW(req.wValue, USLCOM_UART_DISABLE); 302223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 303223017Sdim USETW(req.wLength, 0); 304223017Sdim 305223017Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 306223017Sdim &req, NULL, 0, 1000)) { 307223017Sdim DPRINTF("UART disable failed (ignored)\n"); 308223017Sdim } 309223017Sdim} 310223017Sdim 311223017Sdimstatic void 312223017Sdimuslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 313223017Sdim{ 314223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 315223017Sdim struct usb_device_request req; 316223017Sdim uint16_t ctl; 317223017Sdim 318223017Sdim DPRINTF("onoff = %d\n", onoff); 319223017Sdim 320223017Sdim ctl = onoff ? USLCOM_CTRL_DTR_ON : 0; 321223017Sdim ctl |= USLCOM_CTRL_DTR_SET; 322223017Sdim 323223017Sdim req.bmRequestType = USLCOM_WRITE; 324223017Sdim req.bRequest = USLCOM_CTRL; 325223017Sdim USETW(req.wValue, ctl); 326223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 327223017Sdim USETW(req.wLength, 0); 328223017Sdim 329223017Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 330223017Sdim &req, NULL, 0, 1000)) { 331223017Sdim DPRINTF("Setting DTR failed (ignored)\n"); 332223017Sdim } 333223017Sdim} 334223017Sdim 335223017Sdimstatic void 336223017Sdimuslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) 337223017Sdim{ 338223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 339223017Sdim struct usb_device_request req; 340223017Sdim uint16_t ctl; 341223017Sdim 342223017Sdim DPRINTF("onoff = %d\n", onoff); 343223017Sdim 344223017Sdim ctl = onoff ? USLCOM_CTRL_RTS_ON : 0; 345223017Sdim ctl |= USLCOM_CTRL_RTS_SET; 346223017Sdim 347223017Sdim req.bmRequestType = USLCOM_WRITE; 348223017Sdim req.bRequest = USLCOM_CTRL; 349223017Sdim USETW(req.wValue, ctl); 350223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 351223017Sdim USETW(req.wLength, 0); 352223017Sdim 353223017Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 354223017Sdim &req, NULL, 0, 1000)) { 355223017Sdim DPRINTF("Setting DTR failed (ignored)\n"); 356223017Sdim } 357223017Sdim} 358223017Sdim 359223017Sdimstatic int 360223017Sdimuslcom_pre_param(struct ucom_softc *ucom, struct termios *t) 361223017Sdim{ 362223017Sdim if (t->c_ospeed <= 0 || t->c_ospeed > 921600) 363223017Sdim return (EINVAL); 364223017Sdim return (0); 365223017Sdim} 366223017Sdim 367223017Sdimstatic void 368223017Sdimuslcom_param(struct ucom_softc *ucom, struct termios *t) 369223017Sdim{ 370223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 371223017Sdim struct usb_device_request req; 372223017Sdim uint16_t data; 373223017Sdim 374223017Sdim DPRINTF("\n"); 375223017Sdim 376223017Sdim req.bmRequestType = USLCOM_WRITE; 377223017Sdim req.bRequest = USLCOM_BAUD_RATE; 378223017Sdim USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed); 379223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 380223017Sdim USETW(req.wLength, 0); 381223017Sdim 382223017Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 383223017Sdim &req, NULL, 0, 1000)) { 384223017Sdim DPRINTF("Set baudrate failed (ignored)\n"); 385223017Sdim } 386223017Sdim 387223017Sdim if (t->c_cflag & CSTOPB) 388223017Sdim data = USLCOM_STOP_BITS_2; 389223017Sdim else 390223017Sdim data = USLCOM_STOP_BITS_1; 391223017Sdim if (t->c_cflag & PARENB) { 392223017Sdim if (t->c_cflag & PARODD) 393223017Sdim data |= USLCOM_PARITY_ODD; 394223017Sdim else 395223017Sdim data |= USLCOM_PARITY_EVEN; 396223017Sdim } else 397223017Sdim data |= USLCOM_PARITY_NONE; 398223017Sdim switch (t->c_cflag & CSIZE) { 399223017Sdim case CS5: 400223017Sdim data |= USLCOM_SET_DATA_BITS(5); 401223017Sdim break; 402223017Sdim case CS6: 403223017Sdim data |= USLCOM_SET_DATA_BITS(6); 404224145Sdim break; 405223017Sdim case CS7: 406223017Sdim data |= USLCOM_SET_DATA_BITS(7); 407223017Sdim break; 408223017Sdim case CS8: 409223017Sdim data |= USLCOM_SET_DATA_BITS(8); 410223017Sdim break; 411224145Sdim } 412223017Sdim 413223017Sdim req.bmRequestType = USLCOM_WRITE; 414223017Sdim req.bRequest = USLCOM_DATA; 415223017Sdim USETW(req.wValue, data); 416223017Sdim USETW(req.wIndex, USLCOM_PORT_NO); 417223017Sdim USETW(req.wLength, 0); 418223017Sdim 419224145Sdim if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 420223017Sdim &req, NULL, 0, 1000)) { 421223017Sdim DPRINTF("Set format failed (ignored)\n"); 422223017Sdim } 423223017Sdim return; 424223017Sdim} 425223017Sdim 426223017Sdimstatic void 427223017Sdimuslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 428223017Sdim{ 429223017Sdim struct uslcom_softc *sc = ucom->sc_parent; 430223017Sdim 431223017Sdim DPRINTF("\n"); 432223017Sdim 433223017Sdim *lsr = sc->sc_lsr; 434223017Sdim *msr = sc->sc_msr; 435223017Sdim} 436218885Sdim 437218885Sdimstatic void 438218885Sdimuslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) 439218885Sdim{ 440218885Sdim struct uslcom_softc *sc = ucom->sc_parent; 441218885Sdim struct usb_device_request req; 442218885Sdim uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF; 443 444 req.bmRequestType = USLCOM_WRITE; 445 req.bRequest = USLCOM_BREAK; 446 USETW(req.wValue, brk); 447 USETW(req.wIndex, USLCOM_PORT_NO); 448 USETW(req.wLength, 0); 449 450 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 451 &req, NULL, 0, 1000)) { 452 DPRINTF("Set BREAK failed (ignored)\n"); 453 } 454} 455 456static void 457uslcom_write_callback(struct usb_xfer *xfer) 458{ 459 struct uslcom_softc *sc = xfer->priv_sc; 460 uint32_t actlen; 461 462 switch (USB_GET_STATE(xfer)) { 463 case USB_ST_SETUP: 464 case USB_ST_TRANSFERRED: 465tr_setup: 466 if (ucom_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 467 USLCOM_BULK_BUF_SIZE, &actlen)) { 468 469 DPRINTF("actlen = %d\n", actlen); 470 471 xfer->frlengths[0] = actlen; 472 usbd_transfer_submit(xfer); 473 } 474 return; 475 476 default: /* Error */ 477 if (xfer->error != USB_ERR_CANCELLED) { 478 /* try to clear stall first */ 479 xfer->flags.stall_pipe = 1; 480 goto tr_setup; 481 } 482 return; 483 } 484} 485 486static void 487uslcom_read_callback(struct usb_xfer *xfer) 488{ 489 struct uslcom_softc *sc = xfer->priv_sc; 490 491 switch (USB_GET_STATE(xfer)) { 492 case USB_ST_TRANSFERRED: 493 ucom_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 494 495 case USB_ST_SETUP: 496tr_setup: 497 xfer->frlengths[0] = xfer->max_data_length; 498 usbd_transfer_submit(xfer); 499 return; 500 501 default: /* Error */ 502 if (xfer->error != USB_ERR_CANCELLED) { 503 /* try to clear stall first */ 504 xfer->flags.stall_pipe = 1; 505 goto tr_setup; 506 } 507 return; 508 } 509} 510 511static void 512uslcom_start_read(struct ucom_softc *ucom) 513{ 514 struct uslcom_softc *sc = ucom->sc_parent; 515 516 /* start read endpoint */ 517 usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]); 518} 519 520static void 521uslcom_stop_read(struct ucom_softc *ucom) 522{ 523 struct uslcom_softc *sc = ucom->sc_parent; 524 525 /* stop read endpoint */ 526 usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]); 527} 528 529static void 530uslcom_start_write(struct ucom_softc *ucom) 531{ 532 struct uslcom_softc *sc = ucom->sc_parent; 533 534 usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]); 535} 536 537static void 538uslcom_stop_write(struct ucom_softc *ucom) 539{ 540 struct uslcom_softc *sc = ucom->sc_parent; 541 542 usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]); 543} 544