1188413Sthompsa/* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */ 2188413Sthompsa 3188413Sthompsa#include <sys/cdefs.h> 4188413Sthompsa__FBSDID("$FreeBSD$"); 5188413Sthompsa 6188413Sthompsa/* 7188413Sthompsa * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 8188413Sthompsa * 9188413Sthompsa * Permission to use, copy, modify, and distribute this software for any 10188413Sthompsa * purpose with or without fee is hereby granted, provided that the above 11188413Sthompsa * copyright notice and this permission notice appear in all copies. 12188413Sthompsa * 13188413Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14188413Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15188413Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16188413Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17188413Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18188413Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19188413Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20188413Sthompsa */ 21188413Sthompsa 22240660Shselasky/* 23240660Shselasky * Driver for Silicon Laboratories CP2101/CP2102/CP2103/CP2104/CP2105 24240660Shselasky * USB-Serial adapters. Based on datasheet AN571, publicly available from 25240660Shselasky * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN571.pdf 26240660Shselasky */ 27240660Shselasky 28194677Sthompsa#include <sys/stdint.h> 29194677Sthompsa#include <sys/stddef.h> 30194677Sthompsa#include <sys/param.h> 31194677Sthompsa#include <sys/queue.h> 32194677Sthompsa#include <sys/types.h> 33194677Sthompsa#include <sys/systm.h> 34194677Sthompsa#include <sys/kernel.h> 35194677Sthompsa#include <sys/bus.h> 36194677Sthompsa#include <sys/module.h> 37194677Sthompsa#include <sys/lock.h> 38194677Sthompsa#include <sys/mutex.h> 39194677Sthompsa#include <sys/condvar.h> 40194677Sthompsa#include <sys/sysctl.h> 41194677Sthompsa#include <sys/sx.h> 42194677Sthompsa#include <sys/unistd.h> 43194677Sthompsa#include <sys/callout.h> 44194677Sthompsa#include <sys/malloc.h> 45194677Sthompsa#include <sys/priv.h> 46194677Sthompsa 47194677Sthompsa#include <dev/usb/usb.h> 48194677Sthompsa#include <dev/usb/usbdi.h> 49194677Sthompsa#include <dev/usb/usbdi_util.h> 50229082Shselasky#include <dev/usb/usb_ioctl.h> 51188746Sthompsa#include "usbdevs.h" 52188413Sthompsa 53188413Sthompsa#define USB_DEBUG_VAR uslcom_debug 54188942Sthompsa#include <dev/usb/usb_debug.h> 55188942Sthompsa#include <dev/usb/usb_process.h> 56188413Sthompsa 57188942Sthompsa#include <dev/usb/serial/usb_serial.h> 58188413Sthompsa 59207077Sthompsa#ifdef USB_DEBUG 60188413Sthompsastatic int uslcom_debug = 0; 61188413Sthompsa 62248085Smariusstatic SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); 63192502SthompsaSYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW, 64188413Sthompsa &uslcom_debug, 0, "Debug level"); 65188413Sthompsa#endif 66188413Sthompsa 67188413Sthompsa#define USLCOM_BULK_BUF_SIZE 1024 68188413Sthompsa#define USLCOM_CONFIG_INDEX 0 69188413Sthompsa 70229082Shselasky/* Request types */ 71188413Sthompsa#define USLCOM_WRITE 0x41 72188413Sthompsa#define USLCOM_READ 0xc1 73188413Sthompsa 74229082Shselasky/* Request codes */ 75240660Shselasky#define USLCOM_IFC_ENABLE 0x00 76240660Shselasky#define USLCOM_SET_BAUDDIV 0x01 77240660Shselasky#define USLCOM_SET_LINE_CTL 0x03 78240660Shselasky#define USLCOM_SET_BREAK 0x05 79240660Shselasky#define USLCOM_SET_MHS 0x07 80240660Shselasky#define USLCOM_GET_MDMSTS 0x08 81240660Shselasky#define USLCOM_SET_FLOW 0x13 82240660Shselasky#define USLCOM_SET_BAUDRATE 0x1e 83229082Shselasky#define USLCOM_VENDOR_SPECIFIC 0xff 84188413Sthompsa 85240660Shselasky/* USLCOM_IFC_ENABLE values */ 86240660Shselasky#define USLCOM_IFC_ENABLE_DIS 0x00 87240660Shselasky#define USLCOM_IFC_ENABLE_EN 0x01 88188413Sthompsa 89240660Shselasky/* USLCOM_SET_MHS/USLCOM_GET_MDMSTS values */ 90240660Shselasky#define USLCOM_MHS_DTR_ON 0x0001 91240660Shselasky#define USLCOM_MHS_DTR_SET 0x0100 92240660Shselasky#define USLCOM_MHS_RTS_ON 0x0002 93240660Shselasky#define USLCOM_MHS_RTS_SET 0x0200 94240660Shselasky#define USLCOM_MHS_CTS 0x0010 95240660Shselasky#define USLCOM_MHS_DSR 0x0020 96240660Shselasky#define USLCOM_MHS_RI 0x0040 97240660Shselasky#define USLCOM_MHS_DCD 0x0080 98188413Sthompsa 99240660Shselasky/* USLCOM_SET_BAUDDIV values */ 100240660Shselasky#define USLCOM_BAUDDIV_REF 3686400 /* 3.6864 MHz */ 101188413Sthompsa 102240660Shselasky/* USLCOM_SET_LINE_CTL values */ 103188413Sthompsa#define USLCOM_STOP_BITS_1 0x00 104188413Sthompsa#define USLCOM_STOP_BITS_2 0x02 105188413Sthompsa#define USLCOM_PARITY_NONE 0x00 106188413Sthompsa#define USLCOM_PARITY_ODD 0x10 107188413Sthompsa#define USLCOM_PARITY_EVEN 0x20 108240660Shselasky#define USLCOM_SET_DATA_BITS(x) ((x) << 8) 109188413Sthompsa 110240660Shselasky/* USLCOM_SET_BREAK values */ 111240660Shselasky#define USLCOM_SET_BREAK_OFF 0x00 112240660Shselasky#define USLCOM_SET_BREAK_ON 0x01 113188413Sthompsa 114240660Shselasky/* USLCOM_SET_FLOW values - 1st word */ 115229082Shselasky#define USLCOM_FLOW_DTR_ON 0x00000001 /* DTR static active */ 116229082Shselasky#define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */ 117240660Shselasky/* USLCOM_SET_FLOW values - 2nd word */ 118229082Shselasky#define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */ 119229082Shselasky#define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */ 120229082Shselasky 121229082Shselasky/* USLCOM_VENDOR_SPECIFIC values */ 122229082Shselasky#define USLCOM_WRITE_LATCH 0x37E1 123229082Shselasky#define USLCOM_READ_LATCH 0x00C2 124229082Shselasky 125188413Sthompsaenum { 126188413Sthompsa USLCOM_BULK_DT_WR, 127188413Sthompsa USLCOM_BULK_DT_RD, 128229082Shselasky USLCOM_CTRL_DT_RD, 129188413Sthompsa USLCOM_N_TRANSFER, 130188413Sthompsa}; 131188413Sthompsa 132188413Sthompsastruct uslcom_softc { 133192984Sthompsa struct ucom_super_softc sc_super_ucom; 134192984Sthompsa struct ucom_softc sc_ucom; 135229082Shselasky struct usb_callout sc_watchdog; 136188413Sthompsa 137192984Sthompsa struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER]; 138192984Sthompsa struct usb_device *sc_udev; 139189265Sthompsa struct mtx sc_mtx; 140188413Sthompsa 141188413Sthompsa uint8_t sc_msr; 142188413Sthompsa uint8_t sc_lsr; 143239826Sgavin uint8_t sc_iface_no; 144188413Sthompsa}; 145188413Sthompsa 146188413Sthompsastatic device_probe_t uslcom_probe; 147188413Sthompsastatic device_attach_t uslcom_attach; 148188413Sthompsastatic device_detach_t uslcom_detach; 149240659Shselaskystatic void uslcom_free_softc(struct uslcom_softc *); 150188413Sthompsa 151193045Sthompsastatic usb_callback_t uslcom_write_callback; 152193045Sthompsastatic usb_callback_t uslcom_read_callback; 153229082Shselaskystatic usb_callback_t uslcom_control_callback; 154188413Sthompsa 155240659Shselaskystatic void uslcom_free(struct ucom_softc *); 156192984Sthompsastatic void uslcom_open(struct ucom_softc *); 157192984Sthompsastatic void uslcom_close(struct ucom_softc *); 158192984Sthompsastatic void uslcom_set_dtr(struct ucom_softc *, uint8_t); 159192984Sthompsastatic void uslcom_set_rts(struct ucom_softc *, uint8_t); 160192984Sthompsastatic void uslcom_set_break(struct ucom_softc *, uint8_t); 161229082Shselaskystatic int uslcom_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, 162229082Shselasky struct thread *); 163192984Sthompsastatic int uslcom_pre_param(struct ucom_softc *, struct termios *); 164192984Sthompsastatic void uslcom_param(struct ucom_softc *, struct termios *); 165192984Sthompsastatic void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 166192984Sthompsastatic void uslcom_start_read(struct ucom_softc *); 167192984Sthompsastatic void uslcom_stop_read(struct ucom_softc *); 168192984Sthompsastatic void uslcom_start_write(struct ucom_softc *); 169192984Sthompsastatic void uslcom_stop_write(struct ucom_softc *); 170197570Sthompsastatic void uslcom_poll(struct ucom_softc *ucom); 171188413Sthompsa 172192984Sthompsastatic const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { 173188413Sthompsa 174188413Sthompsa [USLCOM_BULK_DT_WR] = { 175188413Sthompsa .type = UE_BULK, 176188413Sthompsa .endpoint = UE_ADDR_ANY, 177188413Sthompsa .direction = UE_DIR_OUT, 178190734Sthompsa .bufsize = USLCOM_BULK_BUF_SIZE, 179229082Shselasky .flags = {.pipe_bof = 1,}, 180190734Sthompsa .callback = &uslcom_write_callback, 181188413Sthompsa }, 182188413Sthompsa 183188413Sthompsa [USLCOM_BULK_DT_RD] = { 184188413Sthompsa .type = UE_BULK, 185188413Sthompsa .endpoint = UE_ADDR_ANY, 186188413Sthompsa .direction = UE_DIR_IN, 187190734Sthompsa .bufsize = USLCOM_BULK_BUF_SIZE, 188190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 189190734Sthompsa .callback = &uslcom_read_callback, 190188413Sthompsa }, 191229082Shselasky [USLCOM_CTRL_DT_RD] = { 192229082Shselasky .type = UE_CONTROL, 193229082Shselasky .endpoint = 0x00, 194229082Shselasky .direction = UE_DIR_ANY, 195229082Shselasky .bufsize = sizeof(struct usb_device_request) + 8, 196229082Shselasky .flags = {.pipe_bof = 1,}, 197229082Shselasky .callback = &uslcom_control_callback, 198229082Shselasky .timeout = 1000, /* 1 second timeout */ 199229082Shselasky }, 200188413Sthompsa}; 201188413Sthompsa 202194099Sthompsastatic struct ucom_callback uslcom_callback = { 203194228Sthompsa .ucom_cfg_open = &uslcom_open, 204194228Sthompsa .ucom_cfg_close = &uslcom_close, 205194228Sthompsa .ucom_cfg_get_status = &uslcom_get_status, 206194228Sthompsa .ucom_cfg_set_dtr = &uslcom_set_dtr, 207194228Sthompsa .ucom_cfg_set_rts = &uslcom_set_rts, 208194228Sthompsa .ucom_cfg_set_break = &uslcom_set_break, 209229082Shselasky .ucom_ioctl = &uslcom_ioctl, 210194228Sthompsa .ucom_cfg_param = &uslcom_param, 211194228Sthompsa .ucom_pre_param = &uslcom_pre_param, 212194228Sthompsa .ucom_start_read = &uslcom_start_read, 213194228Sthompsa .ucom_stop_read = &uslcom_stop_read, 214194228Sthompsa .ucom_start_write = &uslcom_start_write, 215194228Sthompsa .ucom_stop_write = &uslcom_stop_write, 216197570Sthompsa .ucom_poll = &uslcom_poll, 217240659Shselasky .ucom_free = &uslcom_free, 218188413Sthompsa}; 219188413Sthompsa 220223486Shselaskystatic const STRUCT_USB_HOST_ID uslcom_devs[] = { 221201028Sthompsa#define USLCOM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 222201028Sthompsa USLCOM_DEV(BALTECH, CARDREADER), 223239817Sgavin USLCOM_DEV(CLIPSAL, 5000CT2), 224239817Sgavin USLCOM_DEV(CLIPSAL, 5500PACA), 225210524Sgavin USLCOM_DEV(CLIPSAL, 5500PCU), 226239817Sgavin USLCOM_DEV(CLIPSAL, 560884), 227239817Sgavin USLCOM_DEV(CLIPSAL, 5800PC), 228239817Sgavin USLCOM_DEV(CLIPSAL, C5000CT2), 229239817Sgavin USLCOM_DEV(CLIPSAL, L51xx), 230211022Sgavin USLCOM_DEV(DATAAPEX, MULTICOM), 231211022Sgavin USLCOM_DEV(DELL, DW700), 232211022Sgavin USLCOM_DEV(DIGIANSWER, ZIGBEE802154), 233201028Sthompsa USLCOM_DEV(DYNASTREAM, ANTDEVBOARD), 234211022Sgavin USLCOM_DEV(DYNASTREAM, ANTDEVBOARD2), 235210524Sgavin USLCOM_DEV(DYNASTREAM, ANT2USB), 236211022Sgavin USLCOM_DEV(ELV, USBI2C), 237239817Sgavin USLCOM_DEV(FESTO, CMSP), 238239817Sgavin USLCOM_DEV(FESTO, CPX_USB), 239211022Sgavin USLCOM_DEV(FOXCONN, PIRELLI_DP_L10), 240217200Sgavin USLCOM_DEV(FOXCONN, TCOM_TC_300), 241210524Sgavin USLCOM_DEV(GEMALTO, PROXPU), 242201028Sthompsa USLCOM_DEV(JABLOTRON, PC60B), 243239817Sgavin USLCOM_DEV(KAMSTRUP, OPTICALEYE), 244239817Sgavin USLCOM_DEV(KAMSTRUP, MBUS_250D), 245263166Shselasky USLCOM_DEV(LAKESHORE, 121), 246263166Shselasky USLCOM_DEV(LAKESHORE, 218A), 247263166Shselasky USLCOM_DEV(LAKESHORE, 219), 248263166Shselasky USLCOM_DEV(LAKESHORE, 233), 249263166Shselasky USLCOM_DEV(LAKESHORE, 235), 250263166Shselasky USLCOM_DEV(LAKESHORE, 335), 251263166Shselasky USLCOM_DEV(LAKESHORE, 336), 252263166Shselasky USLCOM_DEV(LAKESHORE, 350), 253263166Shselasky USLCOM_DEV(LAKESHORE, 371), 254263166Shselasky USLCOM_DEV(LAKESHORE, 411), 255263166Shselasky USLCOM_DEV(LAKESHORE, 425), 256263166Shselasky USLCOM_DEV(LAKESHORE, 455A), 257263166Shselasky USLCOM_DEV(LAKESHORE, 465), 258263166Shselasky USLCOM_DEV(LAKESHORE, 475A), 259263166Shselasky USLCOM_DEV(LAKESHORE, 625A), 260263166Shselasky USLCOM_DEV(LAKESHORE, 642A), 261263166Shselasky USLCOM_DEV(LAKESHORE, 648), 262263166Shselasky USLCOM_DEV(LAKESHORE, 737), 263263166Shselasky USLCOM_DEV(LAKESHORE, 776), 264239817Sgavin USLCOM_DEV(LINKINSTRUMENTS, MSO19), 265239817Sgavin USLCOM_DEV(LINKINSTRUMENTS, MSO28), 266239817Sgavin USLCOM_DEV(LINKINSTRUMENTS, MSO28_2), 267211022Sgavin USLCOM_DEV(MEI, CASHFLOW_SC), 268211022Sgavin USLCOM_DEV(MEI, S2000), 269263166Shselasky USLCOM_DEV(NETGEAR, M4100), 270211022Sgavin USLCOM_DEV(OWEN, AC4), 271263166Shselasky USLCOM_DEV(OWL, CM_160), 272211022Sgavin USLCOM_DEV(PHILIPS, ACE1001), 273211022Sgavin USLCOM_DEV(PLX, CA42), 274217200Sgavin USLCOM_DEV(RENESAS, RX610), 275263166Shselasky USLCOM_DEV(SEL, C662), 276239817Sgavin USLCOM_DEV(SILABS, AC_SERV_CAN), 277239817Sgavin USLCOM_DEV(SILABS, AC_SERV_CIS), 278239817Sgavin USLCOM_DEV(SILABS, AC_SERV_IBUS), 279239817Sgavin USLCOM_DEV(SILABS, AC_SERV_OBD), 280210524Sgavin USLCOM_DEV(SILABS, AEROCOMM), 281211022Sgavin USLCOM_DEV(SILABS, AMBER_AMB2560), 282201028Sthompsa USLCOM_DEV(SILABS, ARGUSISP), 283211022Sgavin USLCOM_DEV(SILABS, ARKHAM_DS101_A), 284211022Sgavin USLCOM_DEV(SILABS, ARKHAM_DS101_M), 285211022Sgavin USLCOM_DEV(SILABS, ARYGON_MIFARE), 286211022Sgavin USLCOM_DEV(SILABS, AVIT_USB_TTL), 287217200Sgavin USLCOM_DEV(SILABS, B_G_H3000), 288217200Sgavin USLCOM_DEV(SILABS, BALLUFF_RFID), 289211022Sgavin USLCOM_DEV(SILABS, BEI_VCP), 290210524Sgavin USLCOM_DEV(SILABS, BSM7DUSB), 291210524Sgavin USLCOM_DEV(SILABS, BURNSIDE), 292211022Sgavin USLCOM_DEV(SILABS, C2_EDGE_MODEM), 293210524Sgavin USLCOM_DEV(SILABS, CP2102), 294210524Sgavin USLCOM_DEV(SILABS, CP210X_2), 295239817Sgavin USLCOM_DEV(SILABS, CP210X_3), 296239817Sgavin USLCOM_DEV(SILABS, CP210X_4), 297201028Sthompsa USLCOM_DEV(SILABS, CRUMB128), 298211022Sgavin USLCOM_DEV(SILABS, CYGNAL), 299211022Sgavin USLCOM_DEV(SILABS, CYGNAL_DEBUG), 300211022Sgavin USLCOM_DEV(SILABS, CYGNAL_GPS), 301201028Sthompsa USLCOM_DEV(SILABS, DEGREE), 302239817Sgavin USLCOM_DEV(SILABS, DEKTEK_DTAPLUS), 303211022Sgavin USLCOM_DEV(SILABS, EMS_C1007), 304239817Sgavin USLCOM_DEV(SILABS, HAMLINKUSB), 305201028Sthompsa USLCOM_DEV(SILABS, HELICOM), 306211022Sgavin USLCOM_DEV(SILABS, IMS_USB_RS422), 307211022Sgavin USLCOM_DEV(SILABS, INFINITY_MIC), 308263166Shselasky USLCOM_DEV(SILABS, INGENI_ZIGBEE), 309211022Sgavin USLCOM_DEV(SILABS, INSYS_MODEM), 310239817Sgavin USLCOM_DEV(SILABS, IRZ_SG10), 311211022Sgavin USLCOM_DEV(SILABS, KYOCERA_GPS), 312201028Sthompsa USLCOM_DEV(SILABS, LIPOWSKY_HARP), 313201028Sthompsa USLCOM_DEV(SILABS, LIPOWSKY_JTAG), 314201028Sthompsa USLCOM_DEV(SILABS, LIPOWSKY_LIN), 315210524Sgavin USLCOM_DEV(SILABS, MC35PU), 316263166Shselasky USLCOM_DEV(SILABS, MMB_ZIGBEE), 317211022Sgavin USLCOM_DEV(SILABS, MJS_TOSLINK), 318211022Sgavin USLCOM_DEV(SILABS, MSD_DASHHAWK), 319239817Sgavin USLCOM_DEV(SILABS, MULTIPLEX_RC), 320239817Sgavin USLCOM_DEV(SILABS, OPTRIS_MSPRO), 321201028Sthompsa USLCOM_DEV(SILABS, POLOLU), 322211022Sgavin USLCOM_DEV(SILABS, PROCYON_AVS), 323211022Sgavin USLCOM_DEV(SILABS, SB_PARAMOUNT_ME), 324201028Sthompsa USLCOM_DEV(SILABS, SUUNTO), 325211022Sgavin USLCOM_DEV(SILABS, TAMSMASTER), 326239817Sgavin USLCOM_DEV(SILABS, TELEGESIS_ETRX2), 327210524Sgavin USLCOM_DEV(SILABS, TRACIENT), 328201028Sthompsa USLCOM_DEV(SILABS, TRAQMATE), 329210524Sgavin USLCOM_DEV(SILABS, USBCOUNT50), 330210524Sgavin USLCOM_DEV(SILABS, USBPULSE100), 331211022Sgavin USLCOM_DEV(SILABS, USBSCOPE50), 332210524Sgavin USLCOM_DEV(SILABS, USBWAVE12), 333263166Shselasky USLCOM_DEV(SILABS, V_PREON32), 334211022Sgavin USLCOM_DEV(SILABS, VSTABI), 335211022Sgavin USLCOM_DEV(SILABS, WAVIT), 336211022Sgavin USLCOM_DEV(SILABS, WMRBATT), 337211022Sgavin USLCOM_DEV(SILABS, WMRRIGBLASTER), 338211022Sgavin USLCOM_DEV(SILABS, WMRRIGTALK), 339211022Sgavin USLCOM_DEV(SILABS, ZEPHYR_BIO), 340201028Sthompsa USLCOM_DEV(SILABS2, DCU11CLONE), 341210524Sgavin USLCOM_DEV(SILABS3, GPRS_MODEM), 342211022Sgavin USLCOM_DEV(SILABS4, 100EU_MODEM), 343211022Sgavin USLCOM_DEV(SYNTECH, CYPHERLAB100), 344201028Sthompsa USLCOM_DEV(USI, MC60), 345211022Sgavin USLCOM_DEV(VAISALA, CABLE), 346217200Sgavin USLCOM_DEV(WAGO, SERVICECABLE), 347211022Sgavin USLCOM_DEV(WAVESENSE, JAZZ), 348263166Shselasky USLCOM_DEV(WESTMOUNTAIN, RIGBLASTER_ADVANTAGE), 349217200Sgavin USLCOM_DEV(WIENERPLEINBAUS, PL512), 350217200Sgavin USLCOM_DEV(WIENERPLEINBAUS, RCM), 351217200Sgavin USLCOM_DEV(WIENERPLEINBAUS, MPOD), 352217200Sgavin USLCOM_DEV(WIENERPLEINBAUS, CML), 353201028Sthompsa#undef USLCOM_DEV 354188413Sthompsa}; 355188413Sthompsa 356188413Sthompsastatic device_method_t uslcom_methods[] = { 357188413Sthompsa DEVMETHOD(device_probe, uslcom_probe), 358188413Sthompsa DEVMETHOD(device_attach, uslcom_attach), 359188413Sthompsa DEVMETHOD(device_detach, uslcom_detach), 360240659Shselasky DEVMETHOD_END 361188413Sthompsa}; 362188413Sthompsa 363188413Sthompsastatic devclass_t uslcom_devclass; 364188413Sthompsa 365188413Sthompsastatic driver_t uslcom_driver = { 366188664Sthompsa .name = "uslcom", 367188413Sthompsa .methods = uslcom_methods, 368188413Sthompsa .size = sizeof(struct uslcom_softc), 369188413Sthompsa}; 370188413Sthompsa 371189275SthompsaDRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0); 372188942SthompsaMODULE_DEPEND(uslcom, ucom, 1, 1, 1); 373188942SthompsaMODULE_DEPEND(uslcom, usb, 1, 1, 1); 374188664SthompsaMODULE_VERSION(uslcom, 1); 375188413Sthompsa 376229082Shselaskystatic void 377229082Shselaskyuslcom_watchdog(void *arg) 378229082Shselasky{ 379229082Shselasky struct uslcom_softc *sc = arg; 380229082Shselasky 381229082Shselasky mtx_assert(&sc->sc_mtx, MA_OWNED); 382229082Shselasky 383229082Shselasky usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]); 384229082Shselasky 385229082Shselasky usb_callout_reset(&sc->sc_watchdog, 386229082Shselasky hz / 4, &uslcom_watchdog, sc); 387229082Shselasky} 388229082Shselasky 389188413Sthompsastatic int 390188413Sthompsauslcom_probe(device_t dev) 391188413Sthompsa{ 392192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 393188413Sthompsa 394188413Sthompsa DPRINTFN(11, "\n"); 395188413Sthompsa 396192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 397188413Sthompsa return (ENXIO); 398188413Sthompsa } 399188413Sthompsa if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { 400188413Sthompsa return (ENXIO); 401188413Sthompsa } 402194228Sthompsa return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa)); 403188413Sthompsa} 404188413Sthompsa 405188413Sthompsastatic int 406188413Sthompsauslcom_attach(device_t dev) 407188413Sthompsa{ 408192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 409188413Sthompsa struct uslcom_softc *sc = device_get_softc(dev); 410188413Sthompsa int error; 411188413Sthompsa 412188413Sthompsa DPRINTFN(11, "\n"); 413188413Sthompsa 414194228Sthompsa device_set_usb_desc(dev); 415189265Sthompsa mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF); 416240659Shselasky ucom_ref(&sc->sc_super_ucom); 417229082Shselasky usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); 418188413Sthompsa 419188413Sthompsa sc->sc_udev = uaa->device; 420239826Sgavin /* use the interface number from the USB interface descriptor */ 421239826Sgavin sc->sc_iface_no = uaa->info.bIfaceNum; 422188413Sthompsa 423194228Sthompsa error = usbd_transfer_setup(uaa->device, 424188413Sthompsa &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config, 425189265Sthompsa USLCOM_N_TRANSFER, sc, &sc->sc_mtx); 426188413Sthompsa if (error) { 427188413Sthompsa DPRINTF("one or more missing USB endpoints, " 428194228Sthompsa "error=%s\n", usbd_errstr(error)); 429188413Sthompsa goto detach; 430188413Sthompsa } 431188413Sthompsa /* clear stall at first run */ 432189265Sthompsa mtx_lock(&sc->sc_mtx); 433194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); 434194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); 435189265Sthompsa mtx_unlock(&sc->sc_mtx); 436188413Sthompsa 437194228Sthompsa error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 438189265Sthompsa &uslcom_callback, &sc->sc_mtx); 439188413Sthompsa if (error) { 440188413Sthompsa goto detach; 441188413Sthompsa } 442214843Sn_hibma ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 443214843Sn_hibma 444188413Sthompsa return (0); 445188413Sthompsa 446188413Sthompsadetach: 447188413Sthompsa uslcom_detach(dev); 448188413Sthompsa return (ENXIO); 449188413Sthompsa} 450188413Sthompsa 451188413Sthompsastatic int 452188413Sthompsauslcom_detach(device_t dev) 453188413Sthompsa{ 454188413Sthompsa struct uslcom_softc *sc = device_get_softc(dev); 455188413Sthompsa 456188413Sthompsa DPRINTF("sc=%p\n", sc); 457188413Sthompsa 458214761Sn_hibma ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 459194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); 460229082Shselasky 461229082Shselasky usb_callout_drain(&sc->sc_watchdog); 462188413Sthompsa 463240659Shselasky device_claim_softc(dev); 464240659Shselasky 465240659Shselasky uslcom_free_softc(sc); 466240659Shselasky 467188413Sthompsa return (0); 468188413Sthompsa} 469188413Sthompsa 470240659ShselaskyUCOM_UNLOAD_DRAIN(uslcom); 471240659Shselasky 472188413Sthompsastatic void 473240659Shselaskyuslcom_free_softc(struct uslcom_softc *sc) 474240659Shselasky{ 475240659Shselasky if (ucom_unref(&sc->sc_super_ucom)) { 476240659Shselasky mtx_destroy(&sc->sc_mtx); 477240659Shselasky device_free_softc(sc); 478240659Shselasky } 479240659Shselasky} 480240659Shselasky 481240659Shselaskystatic void 482240659Shselaskyuslcom_free(struct ucom_softc *ucom) 483240659Shselasky{ 484240659Shselasky uslcom_free_softc(ucom->sc_parent); 485240659Shselasky} 486240659Shselasky 487240659Shselaskystatic void 488192984Sthompsauslcom_open(struct ucom_softc *ucom) 489188413Sthompsa{ 490188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 491192984Sthompsa struct usb_device_request req; 492188413Sthompsa 493188413Sthompsa req.bmRequestType = USLCOM_WRITE; 494240660Shselasky req.bRequest = USLCOM_IFC_ENABLE; 495240660Shselasky USETW(req.wValue, USLCOM_IFC_ENABLE_EN); 496239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 497188413Sthompsa USETW(req.wLength, 0); 498188413Sthompsa 499194228Sthompsa if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 500188413Sthompsa &req, NULL, 0, 1000)) { 501188413Sthompsa DPRINTF("UART enable failed (ignored)\n"); 502188413Sthompsa } 503229082Shselasky 504229082Shselasky /* start polling status */ 505229082Shselasky uslcom_watchdog(sc); 506188413Sthompsa} 507188413Sthompsa 508188413Sthompsastatic void 509192984Sthompsauslcom_close(struct ucom_softc *ucom) 510188413Sthompsa{ 511188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 512192984Sthompsa struct usb_device_request req; 513188413Sthompsa 514229082Shselasky /* stop polling status */ 515229082Shselasky usb_callout_stop(&sc->sc_watchdog); 516229082Shselasky 517188413Sthompsa req.bmRequestType = USLCOM_WRITE; 518240660Shselasky req.bRequest = USLCOM_IFC_ENABLE; 519240660Shselasky USETW(req.wValue, USLCOM_IFC_ENABLE_DIS); 520239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 521188413Sthompsa USETW(req.wLength, 0); 522188413Sthompsa 523229082Shselasky if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 524188413Sthompsa &req, NULL, 0, 1000)) { 525188413Sthompsa DPRINTF("UART disable failed (ignored)\n"); 526188413Sthompsa } 527188413Sthompsa} 528188413Sthompsa 529188413Sthompsastatic void 530192984Sthompsauslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 531188413Sthompsa{ 532188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 533192984Sthompsa struct usb_device_request req; 534188413Sthompsa uint16_t ctl; 535188413Sthompsa 536188413Sthompsa DPRINTF("onoff = %d\n", onoff); 537188413Sthompsa 538240660Shselasky ctl = onoff ? USLCOM_MHS_DTR_ON : 0; 539240660Shselasky ctl |= USLCOM_MHS_DTR_SET; 540188413Sthompsa 541188413Sthompsa req.bmRequestType = USLCOM_WRITE; 542240660Shselasky req.bRequest = USLCOM_SET_MHS; 543188413Sthompsa USETW(req.wValue, ctl); 544239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 545188413Sthompsa USETW(req.wLength, 0); 546188413Sthompsa 547194228Sthompsa if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 548188413Sthompsa &req, NULL, 0, 1000)) { 549188413Sthompsa DPRINTF("Setting DTR failed (ignored)\n"); 550188413Sthompsa } 551188413Sthompsa} 552188413Sthompsa 553188413Sthompsastatic void 554192984Sthompsauslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) 555188413Sthompsa{ 556188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 557192984Sthompsa struct usb_device_request req; 558188413Sthompsa uint16_t ctl; 559188413Sthompsa 560188413Sthompsa DPRINTF("onoff = %d\n", onoff); 561188413Sthompsa 562240660Shselasky ctl = onoff ? USLCOM_MHS_RTS_ON : 0; 563240660Shselasky ctl |= USLCOM_MHS_RTS_SET; 564188413Sthompsa 565188413Sthompsa req.bmRequestType = USLCOM_WRITE; 566240660Shselasky req.bRequest = USLCOM_SET_MHS; 567188413Sthompsa USETW(req.wValue, ctl); 568239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 569188413Sthompsa USETW(req.wLength, 0); 570188413Sthompsa 571194228Sthompsa if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 572188413Sthompsa &req, NULL, 0, 1000)) { 573188413Sthompsa DPRINTF("Setting DTR failed (ignored)\n"); 574188413Sthompsa } 575188413Sthompsa} 576188413Sthompsa 577188413Sthompsastatic int 578192984Sthompsauslcom_pre_param(struct ucom_softc *ucom, struct termios *t) 579188413Sthompsa{ 580188413Sthompsa if (t->c_ospeed <= 0 || t->c_ospeed > 921600) 581188413Sthompsa return (EINVAL); 582188413Sthompsa return (0); 583188413Sthompsa} 584188413Sthompsa 585188413Sthompsastatic void 586192984Sthompsauslcom_param(struct ucom_softc *ucom, struct termios *t) 587188413Sthompsa{ 588188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 589192984Sthompsa struct usb_device_request req; 590239732Sgavin uint32_t baudrate, flowctrl[4]; 591188413Sthompsa uint16_t data; 592188413Sthompsa 593188413Sthompsa DPRINTF("\n"); 594188413Sthompsa 595239732Sgavin baudrate = t->c_ospeed; 596188413Sthompsa req.bmRequestType = USLCOM_WRITE; 597240660Shselasky req.bRequest = USLCOM_SET_BAUDRATE; 598239732Sgavin USETW(req.wValue, 0); 599239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 600239732Sgavin USETW(req.wLength, sizeof(baudrate)); 601188413Sthompsa 602239732Sgavin if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 603239732Sgavin &req, &baudrate, 0, 1000)) { 604188413Sthompsa DPRINTF("Set baudrate failed (ignored)\n"); 605188413Sthompsa } 606188413Sthompsa 607188413Sthompsa if (t->c_cflag & CSTOPB) 608188413Sthompsa data = USLCOM_STOP_BITS_2; 609188413Sthompsa else 610188413Sthompsa data = USLCOM_STOP_BITS_1; 611188413Sthompsa if (t->c_cflag & PARENB) { 612188413Sthompsa if (t->c_cflag & PARODD) 613188413Sthompsa data |= USLCOM_PARITY_ODD; 614188413Sthompsa else 615188413Sthompsa data |= USLCOM_PARITY_EVEN; 616188413Sthompsa } else 617188413Sthompsa data |= USLCOM_PARITY_NONE; 618188413Sthompsa switch (t->c_cflag & CSIZE) { 619188413Sthompsa case CS5: 620188413Sthompsa data |= USLCOM_SET_DATA_BITS(5); 621188413Sthompsa break; 622188413Sthompsa case CS6: 623188413Sthompsa data |= USLCOM_SET_DATA_BITS(6); 624188413Sthompsa break; 625188413Sthompsa case CS7: 626188413Sthompsa data |= USLCOM_SET_DATA_BITS(7); 627188413Sthompsa break; 628188413Sthompsa case CS8: 629188413Sthompsa data |= USLCOM_SET_DATA_BITS(8); 630188413Sthompsa break; 631188413Sthompsa } 632188413Sthompsa 633188413Sthompsa req.bmRequestType = USLCOM_WRITE; 634240660Shselasky req.bRequest = USLCOM_SET_LINE_CTL; 635188413Sthompsa USETW(req.wValue, data); 636239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 637188413Sthompsa USETW(req.wLength, 0); 638188413Sthompsa 639194228Sthompsa if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 640188413Sthompsa &req, NULL, 0, 1000)) { 641188413Sthompsa DPRINTF("Set format failed (ignored)\n"); 642188413Sthompsa } 643229082Shselasky 644229082Shselasky if (t->c_cflag & CRTSCTS) { 645229082Shselasky flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS); 646229082Shselasky flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS); 647229082Shselasky } else { 648229082Shselasky flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON); 649229082Shselasky flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON); 650229082Shselasky } 651240660Shselasky flowctrl[2] = 0; 652240660Shselasky flowctrl[3] = 0; 653229082Shselasky req.bmRequestType = USLCOM_WRITE; 654240660Shselasky req.bRequest = USLCOM_SET_FLOW; 655229082Shselasky USETW(req.wValue, 0); 656239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 657229082Shselasky USETW(req.wLength, sizeof(flowctrl)); 658229082Shselasky 659229082Shselasky if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 660229082Shselasky &req, flowctrl, 0, 1000)) { 661229082Shselasky DPRINTF("Set flowcontrol failed (ignored)\n"); 662229082Shselasky } 663188413Sthompsa} 664188413Sthompsa 665188413Sthompsastatic void 666192984Sthompsauslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 667188413Sthompsa{ 668188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 669188413Sthompsa 670188413Sthompsa DPRINTF("\n"); 671188413Sthompsa 672188413Sthompsa *lsr = sc->sc_lsr; 673188413Sthompsa *msr = sc->sc_msr; 674188413Sthompsa} 675188413Sthompsa 676188413Sthompsastatic void 677192984Sthompsauslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) 678188413Sthompsa{ 679188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 680192984Sthompsa struct usb_device_request req; 681240660Shselasky uint16_t brk = onoff ? USLCOM_SET_BREAK_ON : USLCOM_SET_BREAK_OFF; 682188413Sthompsa 683188413Sthompsa req.bmRequestType = USLCOM_WRITE; 684240660Shselasky req.bRequest = USLCOM_SET_BREAK; 685188413Sthompsa USETW(req.wValue, brk); 686239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 687188413Sthompsa USETW(req.wLength, 0); 688188413Sthompsa 689194228Sthompsa if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 690188413Sthompsa &req, NULL, 0, 1000)) { 691188413Sthompsa DPRINTF("Set BREAK failed (ignored)\n"); 692188413Sthompsa } 693188413Sthompsa} 694188413Sthompsa 695229082Shselaskystatic int 696229082Shselaskyuslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, 697229082Shselasky int flag, struct thread *td) 698229082Shselasky{ 699229082Shselasky struct uslcom_softc *sc = ucom->sc_parent; 700229082Shselasky struct usb_device_request req; 701229082Shselasky int error = 0; 702229082Shselasky uint8_t latch; 703229082Shselasky 704229082Shselasky DPRINTF("cmd=0x%08x\n", cmd); 705229082Shselasky 706229082Shselasky switch (cmd) { 707229082Shselasky case USB_GET_GPIO: 708229082Shselasky req.bmRequestType = USLCOM_READ; 709229082Shselasky req.bRequest = USLCOM_VENDOR_SPECIFIC; 710229082Shselasky USETW(req.wValue, USLCOM_READ_LATCH); 711229082Shselasky USETW(req.wIndex, 0); 712229082Shselasky USETW(req.wLength, sizeof(latch)); 713229082Shselasky 714229082Shselasky if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 715229082Shselasky &req, &latch, 0, 1000)) { 716229082Shselasky DPRINTF("Get LATCH failed\n"); 717229082Shselasky error = EIO; 718229082Shselasky } 719229082Shselasky *(int *)data = latch; 720229082Shselasky break; 721229082Shselasky 722229082Shselasky case USB_SET_GPIO: 723229082Shselasky req.bmRequestType = USLCOM_WRITE; 724229082Shselasky req.bRequest = USLCOM_VENDOR_SPECIFIC; 725229082Shselasky USETW(req.wValue, USLCOM_WRITE_LATCH); 726229082Shselasky USETW(req.wIndex, (*(int *)data)); 727229082Shselasky USETW(req.wLength, 0); 728229082Shselasky 729229082Shselasky if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 730229082Shselasky &req, NULL, 0, 1000)) { 731229082Shselasky DPRINTF("Set LATCH failed\n"); 732229082Shselasky error = EIO; 733229082Shselasky } 734229082Shselasky break; 735229082Shselasky 736229082Shselasky default: 737229082Shselasky DPRINTF("Unknown IOCTL\n"); 738229082Shselasky error = ENOIOCTL; 739229082Shselasky break; 740229082Shselasky } 741229082Shselasky return (error); 742229082Shselasky} 743229082Shselasky 744188413Sthompsastatic void 745194677Sthompsauslcom_write_callback(struct usb_xfer *xfer, usb_error_t error) 746188413Sthompsa{ 747194677Sthompsa struct uslcom_softc *sc = usbd_xfer_softc(xfer); 748194677Sthompsa struct usb_page_cache *pc; 749188413Sthompsa uint32_t actlen; 750188413Sthompsa 751188413Sthompsa switch (USB_GET_STATE(xfer)) { 752188413Sthompsa case USB_ST_SETUP: 753188413Sthompsa case USB_ST_TRANSFERRED: 754188413Sthompsatr_setup: 755194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 756194677Sthompsa if (ucom_get_data(&sc->sc_ucom, pc, 0, 757188413Sthompsa USLCOM_BULK_BUF_SIZE, &actlen)) { 758188413Sthompsa 759188413Sthompsa DPRINTF("actlen = %d\n", actlen); 760188413Sthompsa 761194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen); 762194228Sthompsa usbd_transfer_submit(xfer); 763188413Sthompsa } 764188413Sthompsa return; 765188413Sthompsa 766188413Sthompsa default: /* Error */ 767194677Sthompsa if (error != USB_ERR_CANCELLED) { 768188413Sthompsa /* try to clear stall first */ 769194677Sthompsa usbd_xfer_set_stall(xfer); 770188413Sthompsa goto tr_setup; 771188413Sthompsa } 772188413Sthompsa return; 773188413Sthompsa } 774188413Sthompsa} 775188413Sthompsa 776188413Sthompsastatic void 777194677Sthompsauslcom_read_callback(struct usb_xfer *xfer, usb_error_t error) 778188413Sthompsa{ 779194677Sthompsa struct uslcom_softc *sc = usbd_xfer_softc(xfer); 780194677Sthompsa struct usb_page_cache *pc; 781194677Sthompsa int actlen; 782188413Sthompsa 783194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 784194677Sthompsa 785188413Sthompsa switch (USB_GET_STATE(xfer)) { 786188413Sthompsa case USB_ST_TRANSFERRED: 787194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 788194677Sthompsa ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 789188413Sthompsa 790188413Sthompsa case USB_ST_SETUP: 791188413Sthompsatr_setup: 792194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 793194228Sthompsa usbd_transfer_submit(xfer); 794188413Sthompsa return; 795188413Sthompsa 796188413Sthompsa default: /* Error */ 797194677Sthompsa if (error != USB_ERR_CANCELLED) { 798188413Sthompsa /* try to clear stall first */ 799194677Sthompsa usbd_xfer_set_stall(xfer); 800188413Sthompsa goto tr_setup; 801188413Sthompsa } 802188413Sthompsa return; 803188413Sthompsa } 804188413Sthompsa} 805188413Sthompsa 806188413Sthompsastatic void 807229082Shselaskyuslcom_control_callback(struct usb_xfer *xfer, usb_error_t error) 808229082Shselasky{ 809229082Shselasky struct uslcom_softc *sc = usbd_xfer_softc(xfer); 810229082Shselasky struct usb_page_cache *pc; 811229082Shselasky struct usb_device_request req; 812229082Shselasky uint8_t msr = 0; 813229082Shselasky uint8_t buf; 814229082Shselasky 815229082Shselasky switch (USB_GET_STATE(xfer)) { 816229082Shselasky case USB_ST_TRANSFERRED: 817229082Shselasky pc = usbd_xfer_get_frame(xfer, 1); 818229082Shselasky usbd_copy_out(pc, 0, &buf, sizeof(buf)); 819240660Shselasky if (buf & USLCOM_MHS_CTS) 820229082Shselasky msr |= SER_CTS; 821240660Shselasky if (buf & USLCOM_MHS_DSR) 822229082Shselasky msr |= SER_DSR; 823240660Shselasky if (buf & USLCOM_MHS_RI) 824229082Shselasky msr |= SER_RI; 825240660Shselasky if (buf & USLCOM_MHS_DCD) 826229082Shselasky msr |= SER_DCD; 827229082Shselasky 828229082Shselasky if (msr != sc->sc_msr) { 829229082Shselasky DPRINTF("status change msr=0x%02x " 830229082Shselasky "(was 0x%02x)\n", msr, sc->sc_msr); 831229082Shselasky sc->sc_msr = msr; 832229082Shselasky ucom_status_change(&sc->sc_ucom); 833229082Shselasky } 834229082Shselasky break; 835229082Shselasky 836229082Shselasky case USB_ST_SETUP: 837229082Shselasky req.bmRequestType = USLCOM_READ; 838240660Shselasky req.bRequest = USLCOM_GET_MDMSTS; 839229082Shselasky USETW(req.wValue, 0); 840239826Sgavin USETW(req.wIndex, sc->sc_iface_no); 841229082Shselasky USETW(req.wLength, sizeof(buf)); 842229082Shselasky 843229082Shselasky usbd_xfer_set_frames(xfer, 2); 844229082Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 845229082Shselasky usbd_xfer_set_frame_len(xfer, 1, sizeof(buf)); 846229082Shselasky 847229082Shselasky pc = usbd_xfer_get_frame(xfer, 0); 848229082Shselasky usbd_copy_in(pc, 0, &req, sizeof(req)); 849229082Shselasky usbd_transfer_submit(xfer); 850229082Shselasky break; 851229082Shselasky 852229082Shselasky default: /* error */ 853229082Shselasky if (error != USB_ERR_CANCELLED) 854229082Shselasky DPRINTF("error=%s\n", usbd_errstr(error)); 855229082Shselasky break; 856229082Shselasky } 857229082Shselasky} 858229082Shselasky 859229082Shselaskystatic void 860192984Sthompsauslcom_start_read(struct ucom_softc *ucom) 861188413Sthompsa{ 862188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 863188413Sthompsa 864188413Sthompsa /* start read endpoint */ 865194228Sthompsa usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]); 866188413Sthompsa} 867188413Sthompsa 868188413Sthompsastatic void 869192984Sthompsauslcom_stop_read(struct ucom_softc *ucom) 870188413Sthompsa{ 871188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 872188413Sthompsa 873188413Sthompsa /* stop read endpoint */ 874194228Sthompsa usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]); 875188413Sthompsa} 876188413Sthompsa 877188413Sthompsastatic void 878192984Sthompsauslcom_start_write(struct ucom_softc *ucom) 879188413Sthompsa{ 880188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 881188413Sthompsa 882194228Sthompsa usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]); 883188413Sthompsa} 884188413Sthompsa 885188413Sthompsastatic void 886192984Sthompsauslcom_stop_write(struct ucom_softc *ucom) 887188413Sthompsa{ 888188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 889188413Sthompsa 890194228Sthompsa usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]); 891188413Sthompsa} 892197570Sthompsa 893197570Sthompsastatic void 894197570Sthompsauslcom_poll(struct ucom_softc *ucom) 895197570Sthompsa{ 896197570Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 897197570Sthompsa usbd_transfer_poll(sc->sc_xfer, USLCOM_N_TRANSFER); 898197570Sthompsa} 899