uslcom.c revision 190734
1188413Sthompsa/* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */ 2188413Sthompsa 3188413Sthompsa#include <sys/cdefs.h> 4188413Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 190734 2009-04-05 18:20:38Z thompsa $"); 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 22188746Sthompsa#include "usbdevs.h" 23188942Sthompsa#include <dev/usb/usb.h> 24188942Sthompsa#include <dev/usb/usb_mfunc.h> 25188942Sthompsa#include <dev/usb/usb_error.h> 26188413Sthompsa 27188413Sthompsa#define USB_DEBUG_VAR uslcom_debug 28188413Sthompsa 29188942Sthompsa#include <dev/usb/usb_core.h> 30188942Sthompsa#include <dev/usb/usb_debug.h> 31188942Sthompsa#include <dev/usb/usb_process.h> 32188942Sthompsa#include <dev/usb/usb_request.h> 33188942Sthompsa#include <dev/usb/usb_lookup.h> 34188942Sthompsa#include <dev/usb/usb_util.h> 35188942Sthompsa#include <dev/usb/usb_busdma.h> 36188413Sthompsa 37188942Sthompsa#include <dev/usb/serial/usb_serial.h> 38188413Sthompsa 39188413Sthompsa#if USB_DEBUG 40188413Sthompsastatic int uslcom_debug = 0; 41188413Sthompsa 42188664SthompsaSYSCTL_NODE(_hw_usb2, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); 43188664SthompsaSYSCTL_INT(_hw_usb2_uslcom, OID_AUTO, debug, CTLFLAG_RW, 44188413Sthompsa &uslcom_debug, 0, "Debug level"); 45188413Sthompsa#endif 46188413Sthompsa 47188413Sthompsa#define USLCOM_BULK_BUF_SIZE 1024 48188413Sthompsa#define USLCOM_CONFIG_INDEX 0 49188413Sthompsa#define USLCOM_IFACE_INDEX 0 50188413Sthompsa 51188413Sthompsa#define USLCOM_SET_DATA_BITS(x) ((x) << 8) 52188413Sthompsa 53188413Sthompsa#define USLCOM_WRITE 0x41 54188413Sthompsa#define USLCOM_READ 0xc1 55188413Sthompsa 56188413Sthompsa#define USLCOM_UART 0x00 57188413Sthompsa#define USLCOM_BAUD_RATE 0x01 58188413Sthompsa#define USLCOM_DATA 0x03 59188413Sthompsa#define USLCOM_BREAK 0x05 60188413Sthompsa#define USLCOM_CTRL 0x07 61188413Sthompsa 62188413Sthompsa#define USLCOM_UART_DISABLE 0x00 63188413Sthompsa#define USLCOM_UART_ENABLE 0x01 64188413Sthompsa 65188413Sthompsa#define USLCOM_CTRL_DTR_ON 0x0001 66188413Sthompsa#define USLCOM_CTRL_DTR_SET 0x0100 67188413Sthompsa#define USLCOM_CTRL_RTS_ON 0x0002 68188413Sthompsa#define USLCOM_CTRL_RTS_SET 0x0200 69188413Sthompsa#define USLCOM_CTRL_CTS 0x0010 70188413Sthompsa#define USLCOM_CTRL_DSR 0x0020 71188413Sthompsa#define USLCOM_CTRL_DCD 0x0080 72188413Sthompsa 73188413Sthompsa#define USLCOM_BAUD_REF 0x384000 74188413Sthompsa 75188413Sthompsa#define USLCOM_STOP_BITS_1 0x00 76188413Sthompsa#define USLCOM_STOP_BITS_2 0x02 77188413Sthompsa 78188413Sthompsa#define USLCOM_PARITY_NONE 0x00 79188413Sthompsa#define USLCOM_PARITY_ODD 0x10 80188413Sthompsa#define USLCOM_PARITY_EVEN 0x20 81188413Sthompsa 82188413Sthompsa#define USLCOM_PORT_NO 0xFFFF /* XXX think this should be 0 --hps */ 83188413Sthompsa 84188413Sthompsa#define USLCOM_BREAK_OFF 0x00 85188413Sthompsa#define USLCOM_BREAK_ON 0x01 86188413Sthompsa 87188413Sthompsaenum { 88188413Sthompsa USLCOM_BULK_DT_WR, 89188413Sthompsa USLCOM_BULK_DT_RD, 90188413Sthompsa USLCOM_N_TRANSFER, 91188413Sthompsa}; 92188413Sthompsa 93188413Sthompsastruct uslcom_softc { 94188413Sthompsa struct usb2_com_super_softc sc_super_ucom; 95188413Sthompsa struct usb2_com_softc sc_ucom; 96188413Sthompsa 97188413Sthompsa struct usb2_xfer *sc_xfer[USLCOM_N_TRANSFER]; 98188413Sthompsa struct usb2_device *sc_udev; 99189265Sthompsa struct mtx sc_mtx; 100188413Sthompsa 101188413Sthompsa uint8_t sc_msr; 102188413Sthompsa uint8_t sc_lsr; 103188413Sthompsa}; 104188413Sthompsa 105188413Sthompsastatic device_probe_t uslcom_probe; 106188413Sthompsastatic device_attach_t uslcom_attach; 107188413Sthompsastatic device_detach_t uslcom_detach; 108188413Sthompsa 109188413Sthompsastatic usb2_callback_t uslcom_write_callback; 110188413Sthompsastatic usb2_callback_t uslcom_read_callback; 111188413Sthompsa 112188413Sthompsastatic void uslcom_open(struct usb2_com_softc *); 113188413Sthompsastatic void uslcom_close(struct usb2_com_softc *); 114188413Sthompsastatic void uslcom_set_dtr(struct usb2_com_softc *, uint8_t); 115188413Sthompsastatic void uslcom_set_rts(struct usb2_com_softc *, uint8_t); 116188413Sthompsastatic void uslcom_set_break(struct usb2_com_softc *, uint8_t); 117188413Sthompsastatic int uslcom_pre_param(struct usb2_com_softc *, struct termios *); 118188413Sthompsastatic void uslcom_param(struct usb2_com_softc *, struct termios *); 119188413Sthompsastatic void uslcom_get_status(struct usb2_com_softc *, uint8_t *, uint8_t *); 120188413Sthompsastatic void uslcom_start_read(struct usb2_com_softc *); 121188413Sthompsastatic void uslcom_stop_read(struct usb2_com_softc *); 122188413Sthompsastatic void uslcom_start_write(struct usb2_com_softc *); 123188413Sthompsastatic void uslcom_stop_write(struct usb2_com_softc *); 124188413Sthompsa 125188413Sthompsastatic const struct usb2_config uslcom_config[USLCOM_N_TRANSFER] = { 126188413Sthompsa 127188413Sthompsa [USLCOM_BULK_DT_WR] = { 128188413Sthompsa .type = UE_BULK, 129188413Sthompsa .endpoint = UE_ADDR_ANY, 130188413Sthompsa .direction = UE_DIR_OUT, 131190734Sthompsa .bufsize = USLCOM_BULK_BUF_SIZE, 132190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 133190734Sthompsa .callback = &uslcom_write_callback, 134188413Sthompsa }, 135188413Sthompsa 136188413Sthompsa [USLCOM_BULK_DT_RD] = { 137188413Sthompsa .type = UE_BULK, 138188413Sthompsa .endpoint = UE_ADDR_ANY, 139188413Sthompsa .direction = UE_DIR_IN, 140190734Sthompsa .bufsize = USLCOM_BULK_BUF_SIZE, 141190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 142190734Sthompsa .callback = &uslcom_read_callback, 143188413Sthompsa }, 144188413Sthompsa}; 145188413Sthompsa 146188413Sthompsastruct usb2_com_callback uslcom_callback = { 147188413Sthompsa .usb2_com_cfg_open = &uslcom_open, 148188413Sthompsa .usb2_com_cfg_close = &uslcom_close, 149188413Sthompsa .usb2_com_cfg_get_status = &uslcom_get_status, 150188413Sthompsa .usb2_com_cfg_set_dtr = &uslcom_set_dtr, 151188413Sthompsa .usb2_com_cfg_set_rts = &uslcom_set_rts, 152188413Sthompsa .usb2_com_cfg_set_break = &uslcom_set_break, 153188413Sthompsa .usb2_com_cfg_param = &uslcom_param, 154188413Sthompsa .usb2_com_pre_param = &uslcom_pre_param, 155188413Sthompsa .usb2_com_start_read = &uslcom_start_read, 156188413Sthompsa .usb2_com_stop_read = &uslcom_stop_read, 157188413Sthompsa .usb2_com_start_write = &uslcom_start_write, 158188413Sthompsa .usb2_com_stop_write = &uslcom_stop_write, 159188413Sthompsa}; 160188413Sthompsa 161188413Sthompsastatic const struct usb2_device_id uslcom_devs[] = { 162188413Sthompsa { USB_VPI(USB_VENDOR_BALTECH, USB_PRODUCT_BALTECH_CARDREADER, 0) }, 163188413Sthompsa { USB_VPI(USB_VENDOR_DYNASTREAM, USB_PRODUCT_DYNASTREAM_ANTDEVBOARD, 0) }, 164188413Sthompsa { USB_VPI(USB_VENDOR_JABLOTRON, USB_PRODUCT_JABLOTRON_PC60B, 0) }, 165188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_ARGUSISP, 0) }, 166188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CRUMB128, 0) }, 167188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DEGREE, 0) }, 168188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_BURNSIDE, 0) }, 169188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_HELICOM, 0) }, 170188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_HARP, 0) }, 171188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_JTAG, 0) }, 172188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_LIN, 0) }, 173188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_POLOLU, 0) }, 174188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP2102, 0) }, 175188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_2, 0) }, 176188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SUUNTO, 0) }, 177188413Sthompsa { USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_TRAQMATE, 0) }, 178188413Sthompsa { USB_VPI(USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE, 0) }, 179188413Sthompsa { USB_VPI(USB_VENDOR_USI, USB_PRODUCT_USI_MC60, 0) }, 180188413Sthompsa}; 181188413Sthompsa 182188413Sthompsastatic device_method_t uslcom_methods[] = { 183188413Sthompsa DEVMETHOD(device_probe, uslcom_probe), 184188413Sthompsa DEVMETHOD(device_attach, uslcom_attach), 185188413Sthompsa DEVMETHOD(device_detach, uslcom_detach), 186188413Sthompsa {0, 0} 187188413Sthompsa}; 188188413Sthompsa 189188413Sthompsastatic devclass_t uslcom_devclass; 190188413Sthompsa 191188413Sthompsastatic driver_t uslcom_driver = { 192188664Sthompsa .name = "uslcom", 193188413Sthompsa .methods = uslcom_methods, 194188413Sthompsa .size = sizeof(struct uslcom_softc), 195188413Sthompsa}; 196188413Sthompsa 197189275SthompsaDRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0); 198188942SthompsaMODULE_DEPEND(uslcom, ucom, 1, 1, 1); 199188942SthompsaMODULE_DEPEND(uslcom, usb, 1, 1, 1); 200188664SthompsaMODULE_VERSION(uslcom, 1); 201188413Sthompsa 202188413Sthompsastatic int 203188413Sthompsauslcom_probe(device_t dev) 204188413Sthompsa{ 205188413Sthompsa struct usb2_attach_arg *uaa = device_get_ivars(dev); 206188413Sthompsa 207188413Sthompsa DPRINTFN(11, "\n"); 208188413Sthompsa 209188413Sthompsa if (uaa->usb2_mode != USB_MODE_HOST) { 210188413Sthompsa return (ENXIO); 211188413Sthompsa } 212188413Sthompsa if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { 213188413Sthompsa return (ENXIO); 214188413Sthompsa } 215188413Sthompsa if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) { 216188413Sthompsa return (ENXIO); 217188413Sthompsa } 218188413Sthompsa return (usb2_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa)); 219188413Sthompsa} 220188413Sthompsa 221188413Sthompsastatic int 222188413Sthompsauslcom_attach(device_t dev) 223188413Sthompsa{ 224188413Sthompsa struct usb2_attach_arg *uaa = device_get_ivars(dev); 225188413Sthompsa struct uslcom_softc *sc = device_get_softc(dev); 226188413Sthompsa int error; 227188413Sthompsa 228188413Sthompsa DPRINTFN(11, "\n"); 229188413Sthompsa 230188413Sthompsa device_set_usb2_desc(dev); 231189265Sthompsa mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF); 232188413Sthompsa 233188413Sthompsa sc->sc_udev = uaa->device; 234188413Sthompsa 235188413Sthompsa error = usb2_transfer_setup(uaa->device, 236188413Sthompsa &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config, 237189265Sthompsa USLCOM_N_TRANSFER, sc, &sc->sc_mtx); 238188413Sthompsa if (error) { 239188413Sthompsa DPRINTF("one or more missing USB endpoints, " 240188413Sthompsa "error=%s\n", usb2_errstr(error)); 241188413Sthompsa goto detach; 242188413Sthompsa } 243188413Sthompsa /* clear stall at first run */ 244189265Sthompsa mtx_lock(&sc->sc_mtx); 245188413Sthompsa usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); 246188413Sthompsa usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); 247189265Sthompsa mtx_unlock(&sc->sc_mtx); 248188413Sthompsa 249188413Sthompsa error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 250189265Sthompsa &uslcom_callback, &sc->sc_mtx); 251188413Sthompsa if (error) { 252188413Sthompsa goto detach; 253188413Sthompsa } 254188413Sthompsa return (0); 255188413Sthompsa 256188413Sthompsadetach: 257188413Sthompsa uslcom_detach(dev); 258188413Sthompsa return (ENXIO); 259188413Sthompsa} 260188413Sthompsa 261188413Sthompsastatic int 262188413Sthompsauslcom_detach(device_t dev) 263188413Sthompsa{ 264188413Sthompsa struct uslcom_softc *sc = device_get_softc(dev); 265188413Sthompsa 266188413Sthompsa DPRINTF("sc=%p\n", sc); 267188413Sthompsa 268188413Sthompsa usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 269188413Sthompsa usb2_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); 270189265Sthompsa mtx_destroy(&sc->sc_mtx); 271188413Sthompsa 272188413Sthompsa return (0); 273188413Sthompsa} 274188413Sthompsa 275188413Sthompsastatic void 276188413Sthompsauslcom_open(struct usb2_com_softc *ucom) 277188413Sthompsa{ 278188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 279188413Sthompsa struct usb2_device_request req; 280188413Sthompsa 281188413Sthompsa req.bmRequestType = USLCOM_WRITE; 282188413Sthompsa req.bRequest = USLCOM_UART; 283188413Sthompsa USETW(req.wValue, USLCOM_UART_ENABLE); 284188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 285188413Sthompsa USETW(req.wLength, 0); 286188413Sthompsa 287188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 288188413Sthompsa &req, NULL, 0, 1000)) { 289188413Sthompsa DPRINTF("UART enable failed (ignored)\n"); 290188413Sthompsa } 291188413Sthompsa} 292188413Sthompsa 293188413Sthompsastatic void 294188413Sthompsauslcom_close(struct usb2_com_softc *ucom) 295188413Sthompsa{ 296188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 297188413Sthompsa struct usb2_device_request req; 298188413Sthompsa 299188413Sthompsa req.bmRequestType = USLCOM_WRITE; 300188413Sthompsa req.bRequest = USLCOM_UART; 301188413Sthompsa USETW(req.wValue, USLCOM_UART_DISABLE); 302188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 303188413Sthompsa USETW(req.wLength, 0); 304188413Sthompsa 305188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 306188413Sthompsa &req, NULL, 0, 1000)) { 307188413Sthompsa DPRINTF("UART disable failed (ignored)\n"); 308188413Sthompsa } 309188413Sthompsa} 310188413Sthompsa 311188413Sthompsastatic void 312188413Sthompsauslcom_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 313188413Sthompsa{ 314188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 315188413Sthompsa struct usb2_device_request req; 316188413Sthompsa uint16_t ctl; 317188413Sthompsa 318188413Sthompsa DPRINTF("onoff = %d\n", onoff); 319188413Sthompsa 320188413Sthompsa ctl = onoff ? USLCOM_CTRL_DTR_ON : 0; 321188413Sthompsa ctl |= USLCOM_CTRL_DTR_SET; 322188413Sthompsa 323188413Sthompsa req.bmRequestType = USLCOM_WRITE; 324188413Sthompsa req.bRequest = USLCOM_CTRL; 325188413Sthompsa USETW(req.wValue, ctl); 326188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 327188413Sthompsa USETW(req.wLength, 0); 328188413Sthompsa 329188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 330188413Sthompsa &req, NULL, 0, 1000)) { 331188413Sthompsa DPRINTF("Setting DTR failed (ignored)\n"); 332188413Sthompsa } 333188413Sthompsa} 334188413Sthompsa 335188413Sthompsastatic void 336188413Sthompsauslcom_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 337188413Sthompsa{ 338188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 339188413Sthompsa struct usb2_device_request req; 340188413Sthompsa uint16_t ctl; 341188413Sthompsa 342188413Sthompsa DPRINTF("onoff = %d\n", onoff); 343188413Sthompsa 344188413Sthompsa ctl = onoff ? USLCOM_CTRL_RTS_ON : 0; 345188413Sthompsa ctl |= USLCOM_CTRL_RTS_SET; 346188413Sthompsa 347188413Sthompsa req.bmRequestType = USLCOM_WRITE; 348188413Sthompsa req.bRequest = USLCOM_CTRL; 349188413Sthompsa USETW(req.wValue, ctl); 350188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 351188413Sthompsa USETW(req.wLength, 0); 352188413Sthompsa 353188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 354188413Sthompsa &req, NULL, 0, 1000)) { 355188413Sthompsa DPRINTF("Setting DTR failed (ignored)\n"); 356188413Sthompsa } 357188413Sthompsa} 358188413Sthompsa 359188413Sthompsastatic int 360188413Sthompsauslcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 361188413Sthompsa{ 362188413Sthompsa if (t->c_ospeed <= 0 || t->c_ospeed > 921600) 363188413Sthompsa return (EINVAL); 364188413Sthompsa return (0); 365188413Sthompsa} 366188413Sthompsa 367188413Sthompsastatic void 368188413Sthompsauslcom_param(struct usb2_com_softc *ucom, struct termios *t) 369188413Sthompsa{ 370188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 371188413Sthompsa struct usb2_device_request req; 372188413Sthompsa uint16_t data; 373188413Sthompsa 374188413Sthompsa DPRINTF("\n"); 375188413Sthompsa 376188413Sthompsa req.bmRequestType = USLCOM_WRITE; 377188413Sthompsa req.bRequest = USLCOM_BAUD_RATE; 378188413Sthompsa USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed); 379188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 380188413Sthompsa USETW(req.wLength, 0); 381188413Sthompsa 382188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 383188413Sthompsa &req, NULL, 0, 1000)) { 384188413Sthompsa DPRINTF("Set baudrate failed (ignored)\n"); 385188413Sthompsa } 386188413Sthompsa 387188413Sthompsa if (t->c_cflag & CSTOPB) 388188413Sthompsa data = USLCOM_STOP_BITS_2; 389188413Sthompsa else 390188413Sthompsa data = USLCOM_STOP_BITS_1; 391188413Sthompsa if (t->c_cflag & PARENB) { 392188413Sthompsa if (t->c_cflag & PARODD) 393188413Sthompsa data |= USLCOM_PARITY_ODD; 394188413Sthompsa else 395188413Sthompsa data |= USLCOM_PARITY_EVEN; 396188413Sthompsa } else 397188413Sthompsa data |= USLCOM_PARITY_NONE; 398188413Sthompsa switch (t->c_cflag & CSIZE) { 399188413Sthompsa case CS5: 400188413Sthompsa data |= USLCOM_SET_DATA_BITS(5); 401188413Sthompsa break; 402188413Sthompsa case CS6: 403188413Sthompsa data |= USLCOM_SET_DATA_BITS(6); 404188413Sthompsa break; 405188413Sthompsa case CS7: 406188413Sthompsa data |= USLCOM_SET_DATA_BITS(7); 407188413Sthompsa break; 408188413Sthompsa case CS8: 409188413Sthompsa data |= USLCOM_SET_DATA_BITS(8); 410188413Sthompsa break; 411188413Sthompsa } 412188413Sthompsa 413188413Sthompsa req.bmRequestType = USLCOM_WRITE; 414188413Sthompsa req.bRequest = USLCOM_DATA; 415188413Sthompsa USETW(req.wValue, data); 416188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 417188413Sthompsa USETW(req.wLength, 0); 418188413Sthompsa 419188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 420188413Sthompsa &req, NULL, 0, 1000)) { 421188413Sthompsa DPRINTF("Set format failed (ignored)\n"); 422188413Sthompsa } 423188413Sthompsa return; 424188413Sthompsa} 425188413Sthompsa 426188413Sthompsastatic void 427188413Sthompsauslcom_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 428188413Sthompsa{ 429188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 430188413Sthompsa 431188413Sthompsa DPRINTF("\n"); 432188413Sthompsa 433188413Sthompsa *lsr = sc->sc_lsr; 434188413Sthompsa *msr = sc->sc_msr; 435188413Sthompsa} 436188413Sthompsa 437188413Sthompsastatic void 438188413Sthompsauslcom_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 439188413Sthompsa{ 440188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 441188413Sthompsa struct usb2_device_request req; 442188413Sthompsa uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF; 443188413Sthompsa 444188413Sthompsa req.bmRequestType = USLCOM_WRITE; 445188413Sthompsa req.bRequest = USLCOM_BREAK; 446188413Sthompsa USETW(req.wValue, brk); 447188413Sthompsa USETW(req.wIndex, USLCOM_PORT_NO); 448188413Sthompsa USETW(req.wLength, 0); 449188413Sthompsa 450188413Sthompsa if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 451188413Sthompsa &req, NULL, 0, 1000)) { 452188413Sthompsa DPRINTF("Set BREAK failed (ignored)\n"); 453188413Sthompsa } 454188413Sthompsa} 455188413Sthompsa 456188413Sthompsastatic void 457188413Sthompsauslcom_write_callback(struct usb2_xfer *xfer) 458188413Sthompsa{ 459188413Sthompsa struct uslcom_softc *sc = xfer->priv_sc; 460188413Sthompsa uint32_t actlen; 461188413Sthompsa 462188413Sthompsa switch (USB_GET_STATE(xfer)) { 463188413Sthompsa case USB_ST_SETUP: 464188413Sthompsa case USB_ST_TRANSFERRED: 465188413Sthompsatr_setup: 466188413Sthompsa if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 467188413Sthompsa USLCOM_BULK_BUF_SIZE, &actlen)) { 468188413Sthompsa 469188413Sthompsa DPRINTF("actlen = %d\n", actlen); 470188413Sthompsa 471188413Sthompsa xfer->frlengths[0] = actlen; 472188413Sthompsa usb2_start_hardware(xfer); 473188413Sthompsa } 474188413Sthompsa return; 475188413Sthompsa 476188413Sthompsa default: /* Error */ 477188413Sthompsa if (xfer->error != USB_ERR_CANCELLED) { 478188413Sthompsa /* try to clear stall first */ 479188413Sthompsa xfer->flags.stall_pipe = 1; 480188413Sthompsa goto tr_setup; 481188413Sthompsa } 482188413Sthompsa return; 483188413Sthompsa } 484188413Sthompsa} 485188413Sthompsa 486188413Sthompsastatic void 487188413Sthompsauslcom_read_callback(struct usb2_xfer *xfer) 488188413Sthompsa{ 489188413Sthompsa struct uslcom_softc *sc = xfer->priv_sc; 490188413Sthompsa 491188413Sthompsa switch (USB_GET_STATE(xfer)) { 492188413Sthompsa case USB_ST_TRANSFERRED: 493188413Sthompsa usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 494188413Sthompsa 495188413Sthompsa case USB_ST_SETUP: 496188413Sthompsatr_setup: 497188413Sthompsa xfer->frlengths[0] = xfer->max_data_length; 498188413Sthompsa usb2_start_hardware(xfer); 499188413Sthompsa return; 500188413Sthompsa 501188413Sthompsa default: /* Error */ 502188413Sthompsa if (xfer->error != USB_ERR_CANCELLED) { 503188413Sthompsa /* try to clear stall first */ 504188413Sthompsa xfer->flags.stall_pipe = 1; 505188413Sthompsa goto tr_setup; 506188413Sthompsa } 507188413Sthompsa return; 508188413Sthompsa } 509188413Sthompsa} 510188413Sthompsa 511188413Sthompsastatic void 512188413Sthompsauslcom_start_read(struct usb2_com_softc *ucom) 513188413Sthompsa{ 514188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 515188413Sthompsa 516188413Sthompsa /* start read endpoint */ 517188413Sthompsa usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]); 518188413Sthompsa} 519188413Sthompsa 520188413Sthompsastatic void 521188413Sthompsauslcom_stop_read(struct usb2_com_softc *ucom) 522188413Sthompsa{ 523188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 524188413Sthompsa 525188413Sthompsa /* stop read endpoint */ 526188413Sthompsa usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]); 527188413Sthompsa} 528188413Sthompsa 529188413Sthompsastatic void 530188413Sthompsauslcom_start_write(struct usb2_com_softc *ucom) 531188413Sthompsa{ 532188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 533188413Sthompsa 534188413Sthompsa usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]); 535188413Sthompsa} 536188413Sthompsa 537188413Sthompsastatic void 538188413Sthompsauslcom_stop_write(struct usb2_com_softc *ucom) 539188413Sthompsa{ 540188413Sthompsa struct uslcom_softc *sc = ucom->sc_parent; 541188413Sthompsa 542188413Sthompsa usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]); 543188413Sthompsa} 544