uslcom.c revision 223486
1204431Sraj/* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */ 2204431Sraj 3204431Sraj#include <sys/cdefs.h> 4204431Sraj__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 223486 2011-06-24 02:30:02Z hselasky $"); 5204431Sraj 6204431Sraj/* 7204431Sraj * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 8204431Sraj * 9204431Sraj * Permission to use, copy, modify, and distribute this software for any 10204431Sraj * purpose with or without fee is hereby granted, provided that the above 11204431Sraj * copyright notice and this permission notice appear in all copies. 12204431Sraj * 13204431Sraj * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14204431Sraj * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15204431Sraj * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16204431Sraj * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17204431Sraj * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18204431Sraj * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19204431Sraj * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20204431Sraj */ 21204431Sraj 22204431Sraj#include <sys/stdint.h> 23204431Sraj#include <sys/stddef.h> 24204431Sraj#include <sys/param.h> 25204431Sraj#include <sys/queue.h> 26204431Sraj#include <sys/types.h> 27204431Sraj#include <sys/systm.h> 28204431Sraj#include <sys/kernel.h> 29204431Sraj#include <sys/bus.h> 30204431Sraj#include <sys/module.h> 31204431Sraj#include <sys/lock.h> 32204431Sraj#include <sys/mutex.h> 33204431Sraj#include <sys/condvar.h> 34204431Sraj#include <sys/sysctl.h> 35204431Sraj#include <sys/sx.h> 36204431Sraj#include <sys/unistd.h> 37204431Sraj#include <sys/callout.h> 38204431Sraj#include <sys/malloc.h> 39204431Sraj#include <sys/priv.h> 40204431Sraj 41204431Sraj#include <dev/usb/usb.h> 42204431Sraj#include <dev/usb/usbdi.h> 43204431Sraj#include <dev/usb/usbdi_util.h> 44204431Sraj#include "usbdevs.h" 45204431Sraj 46204431Sraj#define USB_DEBUG_VAR uslcom_debug 47204431Sraj#include <dev/usb/usb_debug.h> 48204431Sraj#include <dev/usb/usb_process.h> 49204431Sraj 50204431Sraj#include <dev/usb/serial/usb_serial.h> 51204431Sraj 52204431Sraj#ifdef USB_DEBUG 53204431Srajstatic int uslcom_debug = 0; 54204431Sraj 55204431SrajSYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); 56204431SrajSYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW, 57204431Sraj &uslcom_debug, 0, "Debug level"); 58204431Sraj#endif 59204431Sraj 60204431Sraj#define USLCOM_BULK_BUF_SIZE 1024 61204431Sraj#define USLCOM_CONFIG_INDEX 0 62204431Sraj#define USLCOM_IFACE_INDEX 0 63204431Sraj 64204431Sraj#define USLCOM_SET_DATA_BITS(x) ((x) << 8) 65204431Sraj 66204431Sraj#define USLCOM_WRITE 0x41 67204431Sraj#define USLCOM_READ 0xc1 68204431Sraj 69204431Sraj#define USLCOM_UART 0x00 70204431Sraj#define USLCOM_BAUD_RATE 0x01 71204431Sraj#define USLCOM_DATA 0x03 72204431Sraj#define USLCOM_BREAK 0x05 73204431Sraj#define USLCOM_CTRL 0x07 74204431Sraj 75204431Sraj#define USLCOM_UART_DISABLE 0x00 76204431Sraj#define USLCOM_UART_ENABLE 0x01 77204431Sraj 78204431Sraj#define USLCOM_CTRL_DTR_ON 0x0001 79204431Sraj#define USLCOM_CTRL_DTR_SET 0x0100 80204431Sraj#define USLCOM_CTRL_RTS_ON 0x0002 81204431Sraj#define USLCOM_CTRL_RTS_SET 0x0200 82204431Sraj#define USLCOM_CTRL_CTS 0x0010 83204431Sraj#define USLCOM_CTRL_DSR 0x0020 84204431Sraj#define USLCOM_CTRL_DCD 0x0080 85204431Sraj 86204431Sraj#define USLCOM_BAUD_REF 0x384000 87204431Sraj 88204431Sraj#define USLCOM_STOP_BITS_1 0x00 89204431Sraj#define USLCOM_STOP_BITS_2 0x02 90204431Sraj 91204431Sraj#define USLCOM_PARITY_NONE 0x00 92204431Sraj#define USLCOM_PARITY_ODD 0x10 93204431Sraj#define USLCOM_PARITY_EVEN 0x20 94204431Sraj 95204431Sraj#define USLCOM_PORT_NO 0xFFFF /* XXX think this should be 0 --hps */ 96204431Sraj 97204431Sraj#define USLCOM_BREAK_OFF 0x00 98204431Sraj#define USLCOM_BREAK_ON 0x01 99204431Sraj 100204431Srajenum { 101204431Sraj USLCOM_BULK_DT_WR, 102204431Sraj USLCOM_BULK_DT_RD, 103204431Sraj USLCOM_N_TRANSFER, 104204431Sraj}; 105204431Sraj 106204431Srajstruct uslcom_softc { 107204431Sraj struct ucom_super_softc sc_super_ucom; 108204431Sraj struct ucom_softc sc_ucom; 109204431Sraj 110204431Sraj struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER]; 111204431Sraj struct usb_device *sc_udev; 112204431Sraj struct mtx sc_mtx; 113204431Sraj 114204431Sraj uint8_t sc_msr; 115204431Sraj uint8_t sc_lsr; 116204431Sraj}; 117204431Sraj 118204431Srajstatic device_probe_t uslcom_probe; 119204431Srajstatic device_attach_t uslcom_attach; 120204431Srajstatic device_detach_t uslcom_detach; 121204431Sraj 122204431Srajstatic usb_callback_t uslcom_write_callback; 123204431Srajstatic usb_callback_t uslcom_read_callback; 124204431Sraj 125204433Srajstatic void uslcom_open(struct ucom_softc *); 126204431Srajstatic void uslcom_close(struct ucom_softc *); 127204431Srajstatic void uslcom_set_dtr(struct ucom_softc *, uint8_t); 128204431Srajstatic void uslcom_set_rts(struct ucom_softc *, uint8_t); 129204431Srajstatic void uslcom_set_break(struct ucom_softc *, uint8_t); 130204431Srajstatic int uslcom_pre_param(struct ucom_softc *, struct termios *); 131204431Srajstatic void uslcom_param(struct ucom_softc *, struct termios *); 132204431Srajstatic void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 133204431Srajstatic void uslcom_start_read(struct ucom_softc *); 134204431Srajstatic void uslcom_stop_read(struct ucom_softc *); 135204431Srajstatic void uslcom_start_write(struct ucom_softc *); 136204431Srajstatic void uslcom_stop_write(struct ucom_softc *); 137204431Srajstatic void uslcom_poll(struct ucom_softc *ucom); 138204431Sraj 139204431Srajstatic const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { 140204431Sraj 141204431Sraj [USLCOM_BULK_DT_WR] = { 142204431Sraj .type = UE_BULK, 143204431Sraj .endpoint = UE_ADDR_ANY, 144204431Sraj .direction = UE_DIR_OUT, 145204431Sraj .bufsize = USLCOM_BULK_BUF_SIZE, 146204431Sraj .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 147204431Sraj .callback = &uslcom_write_callback, 148204431Sraj }, 149204431Sraj 150204431Sraj [USLCOM_BULK_DT_RD] = { 151204431Sraj .type = UE_BULK, 152204431Sraj .endpoint = UE_ADDR_ANY, 153204431Sraj .direction = UE_DIR_IN, 154204431Sraj .bufsize = USLCOM_BULK_BUF_SIZE, 155204431Sraj .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 156204431Sraj .callback = &uslcom_read_callback, 157204431Sraj }, 158204431Sraj}; 159204433Sraj 160204431Srajstatic struct ucom_callback uslcom_callback = { 161204431Sraj .ucom_cfg_open = &uslcom_open, 162204431Sraj .ucom_cfg_close = &uslcom_close, 163204431Sraj .ucom_cfg_get_status = &uslcom_get_status, 164204431Sraj .ucom_cfg_set_dtr = &uslcom_set_dtr, 165204431Sraj .ucom_cfg_set_rts = &uslcom_set_rts, 166204431Sraj .ucom_cfg_set_break = &uslcom_set_break, 167204431Sraj .ucom_cfg_param = &uslcom_param, 168204431Sraj .ucom_pre_param = &uslcom_pre_param, 169204431Sraj .ucom_start_read = &uslcom_start_read, 170204431Sraj .ucom_stop_read = &uslcom_stop_read, 171204431Sraj .ucom_start_write = &uslcom_start_write, 172204431Sraj .ucom_stop_write = &uslcom_stop_write, 173204431Sraj .ucom_poll = &uslcom_poll, 174204431Sraj}; 175204431Sraj 176204431Srajstatic const STRUCT_USB_HOST_ID uslcom_devs[] = { 177204431Sraj#define USLCOM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 178204431Sraj USLCOM_DEV(BALTECH, CARDREADER), 179204431Sraj USLCOM_DEV(CLIPSAL, 5500PCU), 180204431Sraj USLCOM_DEV(DATAAPEX, MULTICOM), 181204431Sraj USLCOM_DEV(DELL, DW700), 182204431Sraj USLCOM_DEV(DIGIANSWER, ZIGBEE802154), 183204431Sraj USLCOM_DEV(DYNASTREAM, ANTDEVBOARD), 184204431Sraj USLCOM_DEV(DYNASTREAM, ANTDEVBOARD2), 185204431Sraj USLCOM_DEV(DYNASTREAM, ANT2USB), 186204431Sraj USLCOM_DEV(ELV, USBI2C), 187204431Sraj USLCOM_DEV(FOXCONN, PIRELLI_DP_L10), 188204431Sraj USLCOM_DEV(FOXCONN, TCOM_TC_300), 189204431Sraj USLCOM_DEV(GEMALTO, PROXPU), 190204431Sraj USLCOM_DEV(JABLOTRON, PC60B), 191204431Sraj USLCOM_DEV(MEI, CASHFLOW_SC), 192204431Sraj USLCOM_DEV(MEI, S2000), 193204431Sraj USLCOM_DEV(JABLOTRON, PC60B), 194204431Sraj USLCOM_DEV(OWEN, AC4), 195204431Sraj USLCOM_DEV(PHILIPS, ACE1001), 196204431Sraj USLCOM_DEV(PLX, CA42), 197204431Sraj USLCOM_DEV(RENESAS, RX610), 198204431Sraj USLCOM_DEV(SILABS, AEROCOMM), 199204431Sraj USLCOM_DEV(SILABS, AMBER_AMB2560), 200204431Sraj USLCOM_DEV(SILABS, ARGUSISP), 201204431Sraj USLCOM_DEV(SILABS, ARKHAM_DS101_A), 202204431Sraj USLCOM_DEV(SILABS, ARKHAM_DS101_M), 203204431Sraj USLCOM_DEV(SILABS, ARYGON_MIFARE), 204204431Sraj USLCOM_DEV(SILABS, AVIT_USB_TTL), 205204431Sraj USLCOM_DEV(SILABS, B_G_H3000), 206204431Sraj USLCOM_DEV(SILABS, BALLUFF_RFID), 207204431Sraj USLCOM_DEV(SILABS, BEI_VCP), 208204431Sraj USLCOM_DEV(SILABS, BSM7DUSB), 209204431Sraj USLCOM_DEV(SILABS, BURNSIDE), 210204431Sraj USLCOM_DEV(SILABS, C2_EDGE_MODEM), 211204431Sraj USLCOM_DEV(SILABS, CP2102), 212204431Sraj USLCOM_DEV(SILABS, CP210X_2), 213204431Sraj USLCOM_DEV(SILABS, CRUMB128), 214204431Sraj USLCOM_DEV(SILABS, CYGNAL), 215204431Sraj USLCOM_DEV(SILABS, CYGNAL_DEBUG), 216204431Sraj USLCOM_DEV(SILABS, CYGNAL_GPS), 217204431Sraj USLCOM_DEV(SILABS, DEGREE), 218204431Sraj USLCOM_DEV(SILABS, EMS_C1007), 219204431Sraj USLCOM_DEV(SILABS, HELICOM), 220204431Sraj USLCOM_DEV(SILABS, IMS_USB_RS422), 221204431Sraj USLCOM_DEV(SILABS, INFINITY_MIC), 222204431Sraj USLCOM_DEV(SILABS, INSYS_MODEM), 223204431Sraj USLCOM_DEV(SILABS, KYOCERA_GPS), 224204431Sraj USLCOM_DEV(SILABS, LIPOWSKY_HARP), 225204431Sraj USLCOM_DEV(SILABS, LIPOWSKY_JTAG), 226204431Sraj USLCOM_DEV(SILABS, LIPOWSKY_LIN), 227204431Sraj USLCOM_DEV(SILABS, MC35PU), 228204431Sraj USLCOM_DEV(SILABS, MJS_TOSLINK), 229204431Sraj USLCOM_DEV(SILABS, MSD_DASHHAWK), 230204431Sraj USLCOM_DEV(SILABS, POLOLU), 231204431Sraj USLCOM_DEV(SILABS, PROCYON_AVS), 232204431Sraj USLCOM_DEV(SILABS, SB_PARAMOUNT_ME), 233204431Sraj USLCOM_DEV(SILABS, SUUNTO), 234204431Sraj USLCOM_DEV(SILABS, TAMSMASTER), 235204431Sraj USLCOM_DEV(SILABS, TELEGESYS_ETRX2), 236204431Sraj USLCOM_DEV(SILABS, TRACIENT), 237204431Sraj USLCOM_DEV(SILABS, TRAQMATE), 238204431Sraj USLCOM_DEV(SILABS, USBCOUNT50), 239204431Sraj USLCOM_DEV(SILABS, USBPULSE100), 240204431Sraj USLCOM_DEV(SILABS, USBSCOPE50), 241204431Sraj USLCOM_DEV(SILABS, USBWAVE12), 242204431Sraj USLCOM_DEV(SILABS, VSTABI), 243204431Sraj USLCOM_DEV(SILABS, WAVIT), 244204431Sraj USLCOM_DEV(SILABS, WMRBATT), 245204431Sraj USLCOM_DEV(SILABS, WMRRIGBLASTER), 246204431Sraj USLCOM_DEV(SILABS, WMRRIGTALK), 247204431Sraj USLCOM_DEV(SILABS, ZEPHYR_BIO), 248204431Sraj USLCOM_DEV(SILABS2, DCU11CLONE), 249204431Sraj USLCOM_DEV(SILABS3, GPRS_MODEM), 250204431Sraj USLCOM_DEV(SILABS4, 100EU_MODEM), 251204431Sraj USLCOM_DEV(SYNTECH, CYPHERLAB100), 252204431Sraj USLCOM_DEV(USI, MC60), 253204431Sraj USLCOM_DEV(VAISALA, CABLE), 254204431Sraj USLCOM_DEV(WAGO, SERVICECABLE), 255204431Sraj USLCOM_DEV(WAVESENSE, JAZZ), 256204431Sraj USLCOM_DEV(WIENERPLEINBAUS, PL512), 257204431Sraj USLCOM_DEV(WIENERPLEINBAUS, RCM), 258204431Sraj USLCOM_DEV(WIENERPLEINBAUS, MPOD), 259204431Sraj USLCOM_DEV(WIENERPLEINBAUS, CML), 260204431Sraj#undef USLCOM_DEV 261204431Sraj}; 262204431Sraj 263204431Srajstatic device_method_t uslcom_methods[] = { 264204431Sraj DEVMETHOD(device_probe, uslcom_probe), 265204431Sraj DEVMETHOD(device_attach, uslcom_attach), 266204431Sraj DEVMETHOD(device_detach, uslcom_detach), 267204431Sraj {0, 0} 268204431Sraj}; 269204431Sraj 270204431Srajstatic devclass_t uslcom_devclass; 271204431Sraj 272204431Srajstatic driver_t uslcom_driver = { 273204431Sraj .name = "uslcom", 274204431Sraj .methods = uslcom_methods, 275204431Sraj .size = sizeof(struct uslcom_softc), 276204431Sraj}; 277204431Sraj 278204431SrajDRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0); 279204431SrajMODULE_DEPEND(uslcom, ucom, 1, 1, 1); 280204431SrajMODULE_DEPEND(uslcom, usb, 1, 1, 1); 281204431SrajMODULE_VERSION(uslcom, 1); 282204431Sraj 283204431Srajstatic int 284204431Srajuslcom_probe(device_t dev) 285204431Sraj{ 286204431Sraj struct usb_attach_arg *uaa = device_get_ivars(dev); 287204431Sraj 288204431Sraj DPRINTFN(11, "\n"); 289204431Sraj 290204431Sraj if (uaa->usb_mode != USB_MODE_HOST) { 291204431Sraj return (ENXIO); 292204431Sraj } 293204431Sraj if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { 294204431Sraj return (ENXIO); 295204431Sraj } 296204431Sraj if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) { 297204431Sraj return (ENXIO); 298204431Sraj } 299204431Sraj return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa)); 300204431Sraj} 301204431Sraj 302204431Srajstatic int 303204431Srajuslcom_attach(device_t dev) 304204431Sraj{ 305204431Sraj struct usb_attach_arg *uaa = device_get_ivars(dev); 306204431Sraj struct uslcom_softc *sc = device_get_softc(dev); 307204431Sraj int error; 308204431Sraj 309204431Sraj DPRINTFN(11, "\n"); 310204431Sraj 311204431Sraj device_set_usb_desc(dev); 312204431Sraj mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF); 313204431Sraj 314204431Sraj sc->sc_udev = uaa->device; 315204431Sraj 316204431Sraj error = usbd_transfer_setup(uaa->device, 317204431Sraj &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config, 318204431Sraj USLCOM_N_TRANSFER, sc, &sc->sc_mtx); 319204431Sraj if (error) { 320204431Sraj DPRINTF("one or more missing USB endpoints, " 321204431Sraj "error=%s\n", usbd_errstr(error)); 322204431Sraj goto detach; 323204431Sraj } 324204431Sraj /* clear stall at first run */ 325204431Sraj mtx_lock(&sc->sc_mtx); 326204431Sraj usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); 327204431Sraj usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); 328204431Sraj mtx_unlock(&sc->sc_mtx); 329204431Sraj 330204431Sraj error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 331204431Sraj &uslcom_callback, &sc->sc_mtx); 332204431Sraj if (error) { 333204431Sraj goto detach; 334204431Sraj } 335204431Sraj ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 336204431Sraj 337204431Sraj return (0); 338204431Sraj 339204431Srajdetach: 340204431Sraj uslcom_detach(dev); 341204431Sraj return (ENXIO); 342204431Sraj} 343204431Sraj 344204431Srajstatic int 345204431Srajuslcom_detach(device_t dev) 346238742Simp{ 347238742Simp struct uslcom_softc *sc = device_get_softc(dev); 348238742Simp 349238742Simp DPRINTF("sc=%p\n", sc); 350238742Simp 351238742Simp ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 352238742Simp usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); 353238742Simp mtx_destroy(&sc->sc_mtx); 354238742Simp 355238742Simp return (0); 356238742Simp} 357238742Simp 358238742Simpstatic void 359238742Simpuslcom_open(struct ucom_softc *ucom) 360238742Simp{ 361238742Simp struct uslcom_softc *sc = ucom->sc_parent; 362238742Simp struct usb_device_request req; 363238742Simp 364238742Simp req.bmRequestType = USLCOM_WRITE; 365238742Simp req.bRequest = USLCOM_UART; 366238742Simp USETW(req.wValue, USLCOM_UART_ENABLE); 367238742Simp USETW(req.wIndex, USLCOM_PORT_NO); 368238742Simp USETW(req.wLength, 0); 369238742Simp 370238742Simp if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 371238742Simp &req, NULL, 0, 1000)) { 372238742Simp DPRINTF("UART enable failed (ignored)\n"); 373238742Simp } 374238742Simp} 375238742Simp 376238742Simpstatic void 377238742Simpuslcom_close(struct ucom_softc *ucom) 378238742Simp{ 379238742Simp struct uslcom_softc *sc = ucom->sc_parent; 380238742Simp struct usb_device_request req; 381238742Simp 382238742Simp req.bmRequestType = USLCOM_WRITE; 383238742Simp req.bRequest = USLCOM_UART; 384238742Simp USETW(req.wValue, USLCOM_UART_DISABLE); 385238742Simp USETW(req.wIndex, USLCOM_PORT_NO); 386238742Simp USETW(req.wLength, 0); 387238742Simp 388238742Simp if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 389238742Simp &req, NULL, 0, 1000)) { 390238742Simp DPRINTF("UART disable failed (ignored)\n"); 391238742Simp } 392238742Simp} 393238742Simp 394238742Simpstatic void 395238742Simpuslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 396238742Simp{ 397238742Simp struct uslcom_softc *sc = ucom->sc_parent; 398238742Simp struct usb_device_request req; 399238742Simp uint16_t ctl; 400238742Simp 401238742Simp DPRINTF("onoff = %d\n", onoff); 402238742Simp 403238742Simp ctl = onoff ? USLCOM_CTRL_DTR_ON : 0; 404238742Simp ctl |= USLCOM_CTRL_DTR_SET; 405238742Simp 406238742Simp req.bmRequestType = USLCOM_WRITE; 407238742Simp req.bRequest = USLCOM_CTRL; 408238742Simp USETW(req.wValue, ctl); 409238742Simp USETW(req.wIndex, USLCOM_PORT_NO); 410238742Simp USETW(req.wLength, 0); 411238742Simp 412238742Simp if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 413238742Simp &req, NULL, 0, 1000)) { 414238742Simp DPRINTF("Setting DTR failed (ignored)\n"); 415204433Sraj } 416204433Sraj} 417204433Sraj 418204433Srajstatic void 419204433Srajuslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) 420204433Sraj{ 421204433Sraj struct uslcom_softc *sc = ucom->sc_parent; 422204433Sraj struct usb_device_request req; 423204433Sraj uint16_t ctl; 424204433Sraj 425204433Sraj DPRINTF("onoff = %d\n", onoff); 426204433Sraj 427204433Sraj ctl = onoff ? USLCOM_CTRL_RTS_ON : 0; 428204433Sraj ctl |= USLCOM_CTRL_RTS_SET; 429204433Sraj 430204433Sraj req.bmRequestType = USLCOM_WRITE; 431204431Sraj req.bRequest = USLCOM_CTRL; 432204431Sraj USETW(req.wValue, ctl); 433204431Sraj USETW(req.wIndex, USLCOM_PORT_NO); 434204431Sraj USETW(req.wLength, 0); 435204431Sraj 436204431Sraj if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 437204431Sraj &req, NULL, 0, 1000)) { 438204431Sraj DPRINTF("Setting DTR failed (ignored)\n"); 439204431Sraj } 440204431Sraj} 441204431Sraj 442204431Srajstatic int 443204431Srajuslcom_pre_param(struct ucom_softc *ucom, struct termios *t) 444204431Sraj{ 445204431Sraj if (t->c_ospeed <= 0 || t->c_ospeed > 921600) 446204431Sraj return (EINVAL); 447204431Sraj return (0); 448204431Sraj} 449204431Sraj 450204431Srajstatic void 451204431Srajuslcom_param(struct ucom_softc *ucom, struct termios *t) 452204431Sraj{ 453204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 454204431Sraj struct usb_device_request req; 455204431Sraj uint16_t data; 456204431Sraj 457204431Sraj DPRINTF("\n"); 458204431Sraj 459204431Sraj req.bmRequestType = USLCOM_WRITE; 460204431Sraj req.bRequest = USLCOM_BAUD_RATE; 461204431Sraj USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed); 462204431Sraj USETW(req.wIndex, USLCOM_PORT_NO); 463204431Sraj USETW(req.wLength, 0); 464204431Sraj 465204431Sraj if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 466204431Sraj &req, NULL, 0, 1000)) { 467204431Sraj DPRINTF("Set baudrate failed (ignored)\n"); 468238742Simp } 469238742Simp 470238742Simp if (t->c_cflag & CSTOPB) 471238742Simp data = USLCOM_STOP_BITS_2; 472238742Simp else 473238742Simp data = USLCOM_STOP_BITS_1; 474238742Simp if (t->c_cflag & PARENB) { 475238742Simp if (t->c_cflag & PARODD) 476238742Simp data |= USLCOM_PARITY_ODD; 477238742Simp else 478238742Simp data |= USLCOM_PARITY_EVEN; 479238742Simp } else 480238742Simp data |= USLCOM_PARITY_NONE; 481238742Simp switch (t->c_cflag & CSIZE) { 482238742Simp case CS5: 483238742Simp data |= USLCOM_SET_DATA_BITS(5); 484238742Simp break; 485238742Simp case CS6: 486238742Simp data |= USLCOM_SET_DATA_BITS(6); 487238742Simp break; 488238742Simp case CS7: 489238742Simp data |= USLCOM_SET_DATA_BITS(7); 490238742Simp break; 491238742Simp case CS8: 492238742Simp data |= USLCOM_SET_DATA_BITS(8); 493238742Simp break; 494238742Simp } 495238742Simp 496238742Simp req.bmRequestType = USLCOM_WRITE; 497238742Simp req.bRequest = USLCOM_DATA; 498238742Simp USETW(req.wValue, data); 499238742Simp USETW(req.wIndex, USLCOM_PORT_NO); 500238742Simp USETW(req.wLength, 0); 501238742Simp 502204433Sraj if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 503204433Sraj &req, NULL, 0, 1000)) { 504204433Sraj DPRINTF("Set format failed (ignored)\n"); 505204433Sraj } 506204433Sraj return; 507204433Sraj} 508204433Sraj 509204433Srajstatic void 510204433Srajuslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 511204433Sraj{ 512204433Sraj struct uslcom_softc *sc = ucom->sc_parent; 513204433Sraj 514204433Sraj DPRINTF("\n"); 515204433Sraj 516204431Sraj *lsr = sc->sc_lsr; 517204431Sraj *msr = sc->sc_msr; 518204431Sraj} 519204431Sraj 520204431Srajstatic void 521204431Srajuslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) 522204431Sraj{ 523204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 524204431Sraj struct usb_device_request req; 525204431Sraj uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF; 526204431Sraj 527204431Sraj req.bmRequestType = USLCOM_WRITE; 528204431Sraj req.bRequest = USLCOM_BREAK; 529204431Sraj USETW(req.wValue, brk); 530204431Sraj USETW(req.wIndex, USLCOM_PORT_NO); 531204431Sraj USETW(req.wLength, 0); 532204431Sraj 533204431Sraj if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 534204431Sraj &req, NULL, 0, 1000)) { 535204431Sraj DPRINTF("Set BREAK failed (ignored)\n"); 536204431Sraj } 537204431Sraj} 538204431Sraj 539204431Srajstatic void 540204431Srajuslcom_write_callback(struct usb_xfer *xfer, usb_error_t error) 541204431Sraj{ 542204431Sraj struct uslcom_softc *sc = usbd_xfer_softc(xfer); 543204431Sraj struct usb_page_cache *pc; 544204431Sraj uint32_t actlen; 545204431Sraj 546204431Sraj switch (USB_GET_STATE(xfer)) { 547204431Sraj case USB_ST_SETUP: 548204431Sraj case USB_ST_TRANSFERRED: 549204431Srajtr_setup: 550204431Sraj pc = usbd_xfer_get_frame(xfer, 0); 551204431Sraj if (ucom_get_data(&sc->sc_ucom, pc, 0, 552204431Sraj USLCOM_BULK_BUF_SIZE, &actlen)) { 553204431Sraj 554204431Sraj DPRINTF("actlen = %d\n", actlen); 555204431Sraj 556204431Sraj usbd_xfer_set_frame_len(xfer, 0, actlen); 557204431Sraj usbd_transfer_submit(xfer); 558204431Sraj } 559204431Sraj return; 560204431Sraj 561204431Sraj default: /* Error */ 562204431Sraj if (error != USB_ERR_CANCELLED) { 563204431Sraj /* try to clear stall first */ 564204431Sraj usbd_xfer_set_stall(xfer); 565204433Sraj goto tr_setup; 566204433Sraj } 567204433Sraj return; 568204433Sraj } 569204433Sraj} 570204433Sraj 571204433Srajstatic void 572204433Srajuslcom_read_callback(struct usb_xfer *xfer, usb_error_t error) 573204433Sraj{ 574204433Sraj struct uslcom_softc *sc = usbd_xfer_softc(xfer); 575204433Sraj struct usb_page_cache *pc; 576204433Sraj int actlen; 577204433Sraj 578204433Sraj usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 579204433Sraj 580204433Sraj switch (USB_GET_STATE(xfer)) { 581204433Sraj case USB_ST_TRANSFERRED: 582204433Sraj pc = usbd_xfer_get_frame(xfer, 0); 583204433Sraj ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 584204433Sraj 585204433Sraj case USB_ST_SETUP: 586204433Srajtr_setup: 587204433Sraj usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 588204433Sraj usbd_transfer_submit(xfer); 589204433Sraj return; 590204433Sraj 591204431Sraj default: /* Error */ 592204431Sraj if (error != USB_ERR_CANCELLED) { 593204431Sraj /* try to clear stall first */ 594204431Sraj usbd_xfer_set_stall(xfer); 595204431Sraj goto tr_setup; 596204431Sraj } 597204431Sraj return; 598204431Sraj } 599204431Sraj} 600204431Sraj 601204431Srajstatic void 602204431Srajuslcom_start_read(struct ucom_softc *ucom) 603204431Sraj{ 604204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 605204431Sraj 606204431Sraj /* start read endpoint */ 607204431Sraj usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]); 608204431Sraj} 609204431Sraj 610204431Srajstatic void 611204431Srajuslcom_stop_read(struct ucom_softc *ucom) 612204431Sraj{ 613204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 614204431Sraj 615204431Sraj /* stop read endpoint */ 616204431Sraj usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]); 617204431Sraj} 618204431Sraj 619204431Srajstatic void 620204431Srajuslcom_start_write(struct ucom_softc *ucom) 621204431Sraj{ 622204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 623204431Sraj 624204431Sraj usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]); 625204431Sraj} 626204431Sraj 627204431Srajstatic void 628204431Srajuslcom_stop_write(struct ucom_softc *ucom) 629204431Sraj{ 630204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 631204431Sraj 632204431Sraj usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]); 633204431Sraj} 634204431Sraj 635204431Srajstatic void 636204431Srajuslcom_poll(struct ucom_softc *ucom) 637204431Sraj{ 638204431Sraj struct uslcom_softc *sc = ucom->sc_parent; 639204431Sraj usbd_transfer_poll(sc->sc_xfer, USLCOM_N_TRANSFER); 640204431Sraj} 641204431Sraj