1184610Salfred/*- 2184610Salfred * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>. 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27184610Salfred#include <sys/cdefs.h> 28184610Salfred__FBSDID("$FreeBSD$"); 29184610Salfred/*- 30184610Salfred * Copyright (c) 2001 The NetBSD Foundation, Inc. 31184610Salfred * All rights reserved. 32184610Salfred * 33184610Salfred * This code is derived from software contributed to The NetBSD Foundation 34184610Salfred * by Ichiro FUKUHARA (ichiro@ichiro.org). 35184610Salfred * 36184610Salfred * Redistribution and use in source and binary forms, with or without 37184610Salfred * modification, are permitted provided that the following conditions 38184610Salfred * are met: 39184610Salfred * 1. Redistributions of source code must retain the above copyright 40184610Salfred * notice, this list of conditions and the following disclaimer. 41184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 42184610Salfred * notice, this list of conditions and the following disclaimer in the 43184610Salfred * documentation and/or other materials provided with the distribution. 44184610Salfred * 45184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 46184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 49184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 52184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 53184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 55184610Salfred * POSSIBILITY OF SUCH DAMAGE. 56184610Salfred */ 57184610Salfred 58194677Sthompsa#include <sys/stdint.h> 59194677Sthompsa#include <sys/stddef.h> 60194677Sthompsa#include <sys/param.h> 61194677Sthompsa#include <sys/queue.h> 62194677Sthompsa#include <sys/types.h> 63194677Sthompsa#include <sys/systm.h> 64194677Sthompsa#include <sys/kernel.h> 65194677Sthompsa#include <sys/bus.h> 66194677Sthompsa#include <sys/module.h> 67194677Sthompsa#include <sys/lock.h> 68194677Sthompsa#include <sys/mutex.h> 69194677Sthompsa#include <sys/condvar.h> 70194677Sthompsa#include <sys/sysctl.h> 71194677Sthompsa#include <sys/sx.h> 72194677Sthompsa#include <sys/unistd.h> 73194677Sthompsa#include <sys/callout.h> 74194677Sthompsa#include <sys/malloc.h> 75194677Sthompsa#include <sys/priv.h> 76194677Sthompsa 77194677Sthompsa#include <dev/usb/usb.h> 78194677Sthompsa#include <dev/usb/usbdi.h> 79194677Sthompsa#include <dev/usb/usbdi_util.h> 80188746Sthompsa#include "usbdevs.h" 81184610Salfred 82184610Salfred#define USB_DEBUG_VAR ubsa_debug 83188942Sthompsa#include <dev/usb/usb_debug.h> 84188942Sthompsa#include <dev/usb/usb_process.h> 85184610Salfred 86188942Sthompsa#include <dev/usb/serial/usb_serial.h> 87184610Salfred 88207077Sthompsa#ifdef USB_DEBUG 89184610Salfredstatic int ubsa_debug = 0; 90184610Salfred 91227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa"); 92192502SthompsaSYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW, 93184610Salfred &ubsa_debug, 0, "ubsa debug level"); 94184610Salfred#endif 95184610Salfred 96184610Salfred#define UBSA_BSIZE 1024 /* bytes */ 97184610Salfred 98187161Sthompsa#define UBSA_CONFIG_INDEX 0 99184610Salfred#define UBSA_IFACE_INDEX 0 100184610Salfred 101184610Salfred#define UBSA_REG_BAUDRATE 0x00 102184610Salfred#define UBSA_REG_STOP_BITS 0x01 103184610Salfred#define UBSA_REG_DATA_BITS 0x02 104184610Salfred#define UBSA_REG_PARITY 0x03 105184610Salfred#define UBSA_REG_DTR 0x0A 106184610Salfred#define UBSA_REG_RTS 0x0B 107184610Salfred#define UBSA_REG_BREAK 0x0C 108184610Salfred#define UBSA_REG_FLOW_CTRL 0x10 109184610Salfred 110184610Salfred#define UBSA_PARITY_NONE 0x00 111184610Salfred#define UBSA_PARITY_EVEN 0x01 112184610Salfred#define UBSA_PARITY_ODD 0x02 113184610Salfred#define UBSA_PARITY_MARK 0x03 114184610Salfred#define UBSA_PARITY_SPACE 0x04 115184610Salfred 116184610Salfred#define UBSA_FLOW_NONE 0x0000 117184610Salfred#define UBSA_FLOW_OCTS 0x0001 118184610Salfred#define UBSA_FLOW_ODSR 0x0002 119184610Salfred#define UBSA_FLOW_IDSR 0x0004 120184610Salfred#define UBSA_FLOW_IDTR 0x0008 121184610Salfred#define UBSA_FLOW_IRTS 0x0010 122184610Salfred#define UBSA_FLOW_ORTS 0x0020 123184610Salfred#define UBSA_FLOW_UNKNOWN 0x0040 124184610Salfred#define UBSA_FLOW_OXON 0x0080 125184610Salfred#define UBSA_FLOW_IXON 0x0100 126184610Salfred 127184610Salfred/* line status register */ 128184610Salfred#define UBSA_LSR_TSRE 0x40 /* Transmitter empty: byte sent */ 129184610Salfred#define UBSA_LSR_TXRDY 0x20 /* Transmitter buffer empty */ 130184610Salfred#define UBSA_LSR_BI 0x10 /* Break detected */ 131184610Salfred#define UBSA_LSR_FE 0x08 /* Framing error: bad stop bit */ 132184610Salfred#define UBSA_LSR_PE 0x04 /* Parity error */ 133184610Salfred#define UBSA_LSR_OE 0x02 /* Overrun, lost incoming byte */ 134184610Salfred#define UBSA_LSR_RXRDY 0x01 /* Byte ready in Receive Buffer */ 135184610Salfred#define UBSA_LSR_RCV_MASK 0x1f /* Mask for incoming data or error */ 136184610Salfred 137184610Salfred/* modem status register */ 138184610Salfred/* All deltas are from the last read of the MSR. */ 139184610Salfred#define UBSA_MSR_DCD 0x80 /* Current Data Carrier Detect */ 140184610Salfred#define UBSA_MSR_RI 0x40 /* Current Ring Indicator */ 141184610Salfred#define UBSA_MSR_DSR 0x20 /* Current Data Set Ready */ 142184610Salfred#define UBSA_MSR_CTS 0x10 /* Current Clear to Send */ 143184610Salfred#define UBSA_MSR_DDCD 0x08 /* DCD has changed state */ 144184610Salfred#define UBSA_MSR_TERI 0x04 /* RI has toggled low to high */ 145184610Salfred#define UBSA_MSR_DDSR 0x02 /* DSR has changed state */ 146184610Salfred#define UBSA_MSR_DCTS 0x01 /* CTS has changed state */ 147184610Salfred 148187259Sthompsaenum { 149187259Sthompsa UBSA_BULK_DT_WR, 150187259Sthompsa UBSA_BULK_DT_RD, 151187259Sthompsa UBSA_INTR_DT_RD, 152188413Sthompsa UBSA_N_TRANSFER, 153187259Sthompsa}; 154187259Sthompsa 155184610Salfredstruct ubsa_softc { 156192984Sthompsa struct ucom_super_softc sc_super_ucom; 157192984Sthompsa struct ucom_softc sc_ucom; 158184610Salfred 159192984Sthompsa struct usb_xfer *sc_xfer[UBSA_N_TRANSFER]; 160192984Sthompsa struct usb_device *sc_udev; 161189265Sthompsa struct mtx sc_mtx; 162184610Salfred 163184610Salfred uint8_t sc_iface_no; /* interface number */ 164184610Salfred uint8_t sc_iface_index; /* interface index */ 165184610Salfred uint8_t sc_lsr; /* local status register */ 166184610Salfred uint8_t sc_msr; /* UBSA status register */ 167184610Salfred}; 168184610Salfred 169184610Salfredstatic device_probe_t ubsa_probe; 170184610Salfredstatic device_attach_t ubsa_attach; 171184610Salfredstatic device_detach_t ubsa_detach; 172239299Shselaskystatic void ubsa_free_softc(struct ubsa_softc *); 173184610Salfred 174193045Sthompsastatic usb_callback_t ubsa_write_callback; 175193045Sthompsastatic usb_callback_t ubsa_read_callback; 176193045Sthompsastatic usb_callback_t ubsa_intr_callback; 177184610Salfred 178185948Sthompsastatic void ubsa_cfg_request(struct ubsa_softc *, uint8_t, uint16_t); 179239180Shselaskystatic void ubsa_free(struct ucom_softc *); 180192984Sthompsastatic void ubsa_cfg_set_dtr(struct ucom_softc *, uint8_t); 181192984Sthompsastatic void ubsa_cfg_set_rts(struct ucom_softc *, uint8_t); 182192984Sthompsastatic void ubsa_cfg_set_break(struct ucom_softc *, uint8_t); 183192984Sthompsastatic int ubsa_pre_param(struct ucom_softc *, struct termios *); 184192984Sthompsastatic void ubsa_cfg_param(struct ucom_softc *, struct termios *); 185192984Sthompsastatic void ubsa_start_read(struct ucom_softc *); 186192984Sthompsastatic void ubsa_stop_read(struct ucom_softc *); 187192984Sthompsastatic void ubsa_start_write(struct ucom_softc *); 188192984Sthompsastatic void ubsa_stop_write(struct ucom_softc *); 189192984Sthompsastatic void ubsa_cfg_get_status(struct ucom_softc *, uint8_t *, 190185948Sthompsa uint8_t *); 191197570Sthompsastatic void ubsa_poll(struct ucom_softc *ucom); 192184610Salfred 193192984Sthompsastatic const struct usb_config ubsa_config[UBSA_N_TRANSFER] = { 194184610Salfred 195187259Sthompsa [UBSA_BULK_DT_WR] = { 196184610Salfred .type = UE_BULK, 197184610Salfred .endpoint = UE_ADDR_ANY, 198184610Salfred .direction = UE_DIR_OUT, 199190734Sthompsa .bufsize = UBSA_BSIZE, /* bytes */ 200190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 201190734Sthompsa .callback = &ubsa_write_callback, 202184610Salfred }, 203184610Salfred 204187259Sthompsa [UBSA_BULK_DT_RD] = { 205184610Salfred .type = UE_BULK, 206184610Salfred .endpoint = UE_ADDR_ANY, 207184610Salfred .direction = UE_DIR_IN, 208190734Sthompsa .bufsize = UBSA_BSIZE, /* bytes */ 209190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 210190734Sthompsa .callback = &ubsa_read_callback, 211184610Salfred }, 212184610Salfred 213187259Sthompsa [UBSA_INTR_DT_RD] = { 214184610Salfred .type = UE_INTERRUPT, 215184610Salfred .endpoint = UE_ADDR_ANY, 216184610Salfred .direction = UE_DIR_IN, 217190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 218190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 219190734Sthompsa .callback = &ubsa_intr_callback, 220184610Salfred }, 221184610Salfred}; 222184610Salfred 223192984Sthompsastatic const struct ucom_callback ubsa_callback = { 224194228Sthompsa .ucom_cfg_get_status = &ubsa_cfg_get_status, 225194228Sthompsa .ucom_cfg_set_dtr = &ubsa_cfg_set_dtr, 226194228Sthompsa .ucom_cfg_set_rts = &ubsa_cfg_set_rts, 227194228Sthompsa .ucom_cfg_set_break = &ubsa_cfg_set_break, 228194228Sthompsa .ucom_cfg_param = &ubsa_cfg_param, 229194228Sthompsa .ucom_pre_param = &ubsa_pre_param, 230194228Sthompsa .ucom_start_read = &ubsa_start_read, 231194228Sthompsa .ucom_stop_read = &ubsa_stop_read, 232194228Sthompsa .ucom_start_write = &ubsa_start_write, 233194228Sthompsa .ucom_stop_write = &ubsa_stop_write, 234197570Sthompsa .ucom_poll = &ubsa_poll, 235239180Shselasky .ucom_free = &ubsa_free, 236184610Salfred}; 237184610Salfred 238223486Shselaskystatic const STRUCT_USB_HOST_ID ubsa_devs[] = { 239184610Salfred /* AnyData ADU-500A */ 240184610Salfred {USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A, 0)}, 241184610Salfred /* AnyData ADU-E100A/H */ 242184610Salfred {USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_E100X, 0)}, 243184610Salfred /* Axesstel MV100H */ 244184610Salfred {USB_VPI(USB_VENDOR_AXESSTEL, USB_PRODUCT_AXESSTEL_DATAMODEM, 0)}, 245184610Salfred /* BELKIN F5U103 */ 246184610Salfred {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U103, 0)}, 247184610Salfred /* BELKIN F5U120 */ 248184610Salfred {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U120, 0)}, 249184610Salfred /* GoHubs GO-COM232 */ 250184610Salfred {USB_VPI(USB_VENDOR_ETEK, USB_PRODUCT_ETEK_1COM, 0)}, 251184610Salfred /* GoHubs GO-COM232 */ 252184610Salfred {USB_VPI(USB_VENDOR_GOHUBS, USB_PRODUCT_GOHUBS_GOCOM232, 0)}, 253184610Salfred /* Peracom */ 254184610Salfred {USB_VPI(USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1, 0)}, 255184610Salfred}; 256184610Salfred 257184610Salfredstatic device_method_t ubsa_methods[] = { 258184610Salfred DEVMETHOD(device_probe, ubsa_probe), 259184610Salfred DEVMETHOD(device_attach, ubsa_attach), 260184610Salfred DEVMETHOD(device_detach, ubsa_detach), 261239180Shselasky DEVMETHOD_END 262184610Salfred}; 263184610Salfred 264184610Salfredstatic devclass_t ubsa_devclass; 265184610Salfred 266184610Salfredstatic driver_t ubsa_driver = { 267184610Salfred .name = "ubsa", 268184610Salfred .methods = ubsa_methods, 269184610Salfred .size = sizeof(struct ubsa_softc), 270184610Salfred}; 271184610Salfred 272189275SthompsaDRIVER_MODULE(ubsa, uhub, ubsa_driver, ubsa_devclass, NULL, 0); 273188942SthompsaMODULE_DEPEND(ubsa, ucom, 1, 1, 1); 274188942SthompsaMODULE_DEPEND(ubsa, usb, 1, 1, 1); 275212122SthompsaMODULE_VERSION(ubsa, 1); 276184610Salfred 277184610Salfredstatic int 278184610Salfredubsa_probe(device_t dev) 279184610Salfred{ 280192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 281184610Salfred 282192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 283184610Salfred return (ENXIO); 284184610Salfred } 285184610Salfred if (uaa->info.bConfigIndex != UBSA_CONFIG_INDEX) { 286184610Salfred return (ENXIO); 287184610Salfred } 288184610Salfred if (uaa->info.bIfaceIndex != UBSA_IFACE_INDEX) { 289184610Salfred return (ENXIO); 290184610Salfred } 291194228Sthompsa return (usbd_lookup_id_by_uaa(ubsa_devs, sizeof(ubsa_devs), uaa)); 292184610Salfred} 293184610Salfred 294184610Salfredstatic int 295184610Salfredubsa_attach(device_t dev) 296184610Salfred{ 297192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 298184610Salfred struct ubsa_softc *sc = device_get_softc(dev); 299184610Salfred int error; 300184610Salfred 301184610Salfred DPRINTF("sc=%p\n", sc); 302184610Salfred 303194228Sthompsa device_set_usb_desc(dev); 304189265Sthompsa mtx_init(&sc->sc_mtx, "ubsa", NULL, MTX_DEF); 305239180Shselasky ucom_ref(&sc->sc_super_ucom); 306184610Salfred 307184610Salfred sc->sc_udev = uaa->device; 308184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 309184610Salfred sc->sc_iface_index = UBSA_IFACE_INDEX; 310184610Salfred 311194228Sthompsa error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, 312189265Sthompsa sc->sc_xfer, ubsa_config, UBSA_N_TRANSFER, sc, &sc->sc_mtx); 313184610Salfred 314184610Salfred if (error) { 315184610Salfred DPRINTF("could not allocate all pipes\n"); 316184610Salfred goto detach; 317184610Salfred } 318184610Salfred /* clear stall at first run */ 319189265Sthompsa mtx_lock(&sc->sc_mtx); 320194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_WR]); 321194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_RD]); 322189265Sthompsa mtx_unlock(&sc->sc_mtx); 323184610Salfred 324194228Sthompsa error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 325189265Sthompsa &ubsa_callback, &sc->sc_mtx); 326184610Salfred if (error) { 327194228Sthompsa DPRINTF("ucom_attach failed\n"); 328184610Salfred goto detach; 329184610Salfred } 330214843Sn_hibma ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 331214843Sn_hibma 332184610Salfred return (0); 333184610Salfred 334184610Salfreddetach: 335184610Salfred ubsa_detach(dev); 336184610Salfred return (ENXIO); 337184610Salfred} 338184610Salfred 339184610Salfredstatic int 340184610Salfredubsa_detach(device_t dev) 341184610Salfred{ 342184610Salfred struct ubsa_softc *sc = device_get_softc(dev); 343184610Salfred 344184610Salfred DPRINTF("sc=%p\n", sc); 345184610Salfred 346214761Sn_hibma ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 347194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UBSA_N_TRANSFER); 348184610Salfred 349239299Shselasky device_claim_softc(dev); 350239299Shselasky 351239299Shselasky ubsa_free_softc(sc); 352239299Shselasky 353184610Salfred return (0); 354184610Salfred} 355184610Salfred 356239180ShselaskyUCOM_UNLOAD_DRAIN(ubsa); 357239180Shselasky 358184610Salfredstatic void 359239299Shselaskyubsa_free_softc(struct ubsa_softc *sc) 360239180Shselasky{ 361239180Shselasky if (ucom_unref(&sc->sc_super_ucom)) { 362239299Shselasky mtx_destroy(&sc->sc_mtx); 363239299Shselasky device_free_softc(sc); 364239180Shselasky } 365239180Shselasky} 366239180Shselasky 367239180Shselaskystatic void 368239180Shselaskyubsa_free(struct ucom_softc *ucom) 369239180Shselasky{ 370239299Shselasky ubsa_free_softc(ucom->sc_parent); 371239180Shselasky} 372239180Shselasky 373239180Shselaskystatic void 374184610Salfredubsa_cfg_request(struct ubsa_softc *sc, uint8_t index, uint16_t value) 375184610Salfred{ 376192984Sthompsa struct usb_device_request req; 377193045Sthompsa usb_error_t err; 378184610Salfred 379184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 380184610Salfred req.bRequest = index; 381184610Salfred USETW(req.wValue, value); 382184610Salfred req.wIndex[0] = sc->sc_iface_no; 383184610Salfred req.wIndex[1] = 0; 384184610Salfred USETW(req.wLength, 0); 385184610Salfred 386194228Sthompsa err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 387188413Sthompsa &req, NULL, 0, 1000); 388184610Salfred if (err) { 389184610Salfred DPRINTFN(0, "device request failed, err=%s " 390194228Sthompsa "(ignored)\n", usbd_errstr(err)); 391184610Salfred } 392184610Salfred} 393184610Salfred 394184610Salfredstatic void 395192984Sthompsaubsa_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 396184610Salfred{ 397184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 398184610Salfred 399184610Salfred DPRINTF("onoff = %d\n", onoff); 400184610Salfred 401184610Salfred ubsa_cfg_request(sc, UBSA_REG_DTR, onoff ? 1 : 0); 402184610Salfred} 403184610Salfred 404184610Salfredstatic void 405192984Sthompsaubsa_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 406184610Salfred{ 407184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 408184610Salfred 409184610Salfred DPRINTF("onoff = %d\n", onoff); 410184610Salfred 411184610Salfred ubsa_cfg_request(sc, UBSA_REG_RTS, onoff ? 1 : 0); 412184610Salfred} 413184610Salfred 414184610Salfredstatic void 415192984Sthompsaubsa_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 416184610Salfred{ 417184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 418184610Salfred 419184610Salfred DPRINTF("onoff = %d\n", onoff); 420184610Salfred 421184610Salfred ubsa_cfg_request(sc, UBSA_REG_BREAK, onoff ? 1 : 0); 422184610Salfred} 423184610Salfred 424184610Salfredstatic int 425192984Sthompsaubsa_pre_param(struct ucom_softc *ucom, struct termios *t) 426184610Salfred{ 427184610Salfred 428207077Sthompsa DPRINTF("sc = %p\n", ucom->sc_parent); 429184610Salfred 430184610Salfred switch (t->c_ospeed) { 431184610Salfred case B0: 432184610Salfred case B300: 433184610Salfred case B600: 434184610Salfred case B1200: 435184610Salfred case B2400: 436184610Salfred case B4800: 437184610Salfred case B9600: 438184610Salfred case B19200: 439184610Salfred case B38400: 440184610Salfred case B57600: 441184610Salfred case B115200: 442184610Salfred case B230400: 443184610Salfred break; 444184610Salfred default: 445184610Salfred return (EINVAL); 446184610Salfred } 447184610Salfred return (0); 448184610Salfred} 449184610Salfred 450184610Salfredstatic void 451192984Sthompsaubsa_cfg_param(struct ucom_softc *ucom, struct termios *t) 452184610Salfred{ 453184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 454184610Salfred uint16_t value = 0; 455184610Salfred 456184610Salfred DPRINTF("sc = %p\n", sc); 457184610Salfred 458184610Salfred switch (t->c_ospeed) { 459184610Salfred case B0: 460184610Salfred ubsa_cfg_request(sc, UBSA_REG_FLOW_CTRL, 0); 461184610Salfred ubsa_cfg_set_dtr(&sc->sc_ucom, 0); 462184610Salfred ubsa_cfg_set_rts(&sc->sc_ucom, 0); 463184610Salfred break; 464184610Salfred case B300: 465184610Salfred case B600: 466184610Salfred case B1200: 467184610Salfred case B2400: 468184610Salfred case B4800: 469184610Salfred case B9600: 470184610Salfred case B19200: 471184610Salfred case B38400: 472184610Salfred case B57600: 473184610Salfred case B115200: 474184610Salfred case B230400: 475184610Salfred value = B230400 / t->c_ospeed; 476184610Salfred ubsa_cfg_request(sc, UBSA_REG_BAUDRATE, value); 477184610Salfred break; 478184610Salfred default: 479184610Salfred return; 480184610Salfred } 481184610Salfred 482184610Salfred if (t->c_cflag & PARENB) 483184610Salfred value = (t->c_cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN; 484184610Salfred else 485184610Salfred value = UBSA_PARITY_NONE; 486184610Salfred 487184610Salfred ubsa_cfg_request(sc, UBSA_REG_PARITY, value); 488184610Salfred 489184610Salfred switch (t->c_cflag & CSIZE) { 490184610Salfred case CS5: 491184610Salfred value = 0; 492184610Salfred break; 493184610Salfred case CS6: 494184610Salfred value = 1; 495184610Salfred break; 496184610Salfred case CS7: 497184610Salfred value = 2; 498184610Salfred break; 499184610Salfred default: 500184610Salfred case CS8: 501184610Salfred value = 3; 502184610Salfred break; 503184610Salfred } 504184610Salfred 505184610Salfred ubsa_cfg_request(sc, UBSA_REG_DATA_BITS, value); 506184610Salfred 507184610Salfred value = (t->c_cflag & CSTOPB) ? 1 : 0; 508184610Salfred 509184610Salfred ubsa_cfg_request(sc, UBSA_REG_STOP_BITS, value); 510184610Salfred 511184610Salfred value = 0; 512184610Salfred if (t->c_cflag & CRTSCTS) 513184610Salfred value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS; 514184610Salfred 515184610Salfred if (t->c_iflag & (IXON | IXOFF)) 516184610Salfred value |= UBSA_FLOW_OXON | UBSA_FLOW_IXON; 517184610Salfred 518184610Salfred ubsa_cfg_request(sc, UBSA_REG_FLOW_CTRL, value); 519184610Salfred} 520184610Salfred 521184610Salfredstatic void 522192984Sthompsaubsa_start_read(struct ucom_softc *ucom) 523184610Salfred{ 524184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 525184610Salfred 526184610Salfred /* start interrupt endpoint */ 527194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSA_INTR_DT_RD]); 528184610Salfred 529184610Salfred /* start read endpoint */ 530194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSA_BULK_DT_RD]); 531184610Salfred} 532184610Salfred 533184610Salfredstatic void 534192984Sthompsaubsa_stop_read(struct ucom_softc *ucom) 535184610Salfred{ 536184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 537184610Salfred 538184610Salfred /* stop interrupt endpoint */ 539194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UBSA_INTR_DT_RD]); 540184610Salfred 541184610Salfred /* stop read endpoint */ 542194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UBSA_BULK_DT_RD]); 543184610Salfred} 544184610Salfred 545184610Salfredstatic void 546192984Sthompsaubsa_start_write(struct ucom_softc *ucom) 547184610Salfred{ 548184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 549184610Salfred 550194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSA_BULK_DT_WR]); 551184610Salfred} 552184610Salfred 553184610Salfredstatic void 554192984Sthompsaubsa_stop_write(struct ucom_softc *ucom) 555184610Salfred{ 556184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 557184610Salfred 558194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UBSA_BULK_DT_WR]); 559184610Salfred} 560184610Salfred 561184610Salfredstatic void 562192984Sthompsaubsa_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 563184610Salfred{ 564184610Salfred struct ubsa_softc *sc = ucom->sc_parent; 565184610Salfred 566184610Salfred DPRINTF("\n"); 567184610Salfred 568184610Salfred *lsr = sc->sc_lsr; 569184610Salfred *msr = sc->sc_msr; 570184610Salfred} 571184610Salfred 572184610Salfredstatic void 573194677Sthompsaubsa_write_callback(struct usb_xfer *xfer, usb_error_t error) 574184610Salfred{ 575194677Sthompsa struct ubsa_softc *sc = usbd_xfer_softc(xfer); 576194677Sthompsa struct usb_page_cache *pc; 577184610Salfred uint32_t actlen; 578184610Salfred 579184610Salfred switch (USB_GET_STATE(xfer)) { 580184610Salfred case USB_ST_SETUP: 581184610Salfred case USB_ST_TRANSFERRED: 582188413Sthompsatr_setup: 583194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 584194677Sthompsa if (ucom_get_data(&sc->sc_ucom, pc, 0, 585184610Salfred UBSA_BSIZE, &actlen)) { 586184610Salfred 587194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen); 588194228Sthompsa usbd_transfer_submit(xfer); 589184610Salfred } 590184610Salfred return; 591184610Salfred 592184610Salfred default: /* Error */ 593194677Sthompsa if (error != USB_ERR_CANCELLED) { 594188413Sthompsa /* try to clear stall first */ 595194677Sthompsa usbd_xfer_set_stall(xfer); 596188413Sthompsa goto tr_setup; 597184610Salfred } 598184610Salfred return; 599184610Salfred 600184610Salfred } 601184610Salfred} 602184610Salfred 603184610Salfredstatic void 604194677Sthompsaubsa_read_callback(struct usb_xfer *xfer, usb_error_t error) 605184610Salfred{ 606194677Sthompsa struct ubsa_softc *sc = usbd_xfer_softc(xfer); 607194677Sthompsa struct usb_page_cache *pc; 608194677Sthompsa int actlen; 609184610Salfred 610194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 611194677Sthompsa 612184610Salfred switch (USB_GET_STATE(xfer)) { 613184610Salfred case USB_ST_TRANSFERRED: 614194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 615194677Sthompsa ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 616184610Salfred 617184610Salfred case USB_ST_SETUP: 618188413Sthompsatr_setup: 619194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 620194228Sthompsa usbd_transfer_submit(xfer); 621184610Salfred return; 622184610Salfred 623184610Salfred default: /* Error */ 624194677Sthompsa if (error != USB_ERR_CANCELLED) { 625188413Sthompsa /* try to clear stall first */ 626194677Sthompsa usbd_xfer_set_stall(xfer); 627188413Sthompsa goto tr_setup; 628184610Salfred } 629184610Salfred return; 630184610Salfred 631184610Salfred } 632184610Salfred} 633184610Salfred 634184610Salfredstatic void 635194677Sthompsaubsa_intr_callback(struct usb_xfer *xfer, usb_error_t error) 636184610Salfred{ 637194677Sthompsa struct ubsa_softc *sc = usbd_xfer_softc(xfer); 638194677Sthompsa struct usb_page_cache *pc; 639184610Salfred uint8_t buf[4]; 640194677Sthompsa int actlen; 641184610Salfred 642194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 643194677Sthompsa 644184610Salfred switch (USB_GET_STATE(xfer)) { 645184610Salfred case USB_ST_TRANSFERRED: 646184610Salfred 647233774Shselasky if (actlen >= (int)sizeof(buf)) { 648194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 649194677Sthompsa usbd_copy_out(pc, 0, buf, sizeof(buf)); 650184610Salfred 651184610Salfred /* 652184610Salfred * incidentally, Belkin adapter status bits match 653184610Salfred * UART 16550 bits 654184610Salfred */ 655184610Salfred sc->sc_lsr = buf[2]; 656184610Salfred sc->sc_msr = buf[3]; 657184610Salfred 658184610Salfred DPRINTF("lsr = 0x%02x, msr = 0x%02x\n", 659184610Salfred sc->sc_lsr, sc->sc_msr); 660184610Salfred 661194228Sthompsa ucom_status_change(&sc->sc_ucom); 662184610Salfred } else { 663194677Sthompsa DPRINTF("ignoring short packet, %d bytes\n", actlen); 664184610Salfred } 665184610Salfred 666184610Salfred case USB_ST_SETUP: 667188413Sthompsatr_setup: 668194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 669194228Sthompsa usbd_transfer_submit(xfer); 670184610Salfred return; 671184610Salfred 672184610Salfred default: /* Error */ 673194677Sthompsa if (error != USB_ERR_CANCELLED) { 674188413Sthompsa /* try to clear stall first */ 675194677Sthompsa usbd_xfer_set_stall(xfer); 676188413Sthompsa goto tr_setup; 677184610Salfred } 678184610Salfred return; 679184610Salfred 680184610Salfred } 681184610Salfred} 682197570Sthompsa 683197570Sthompsastatic void 684197570Sthompsaubsa_poll(struct ucom_softc *ucom) 685197570Sthompsa{ 686197570Sthompsa struct ubsa_softc *sc = ucom->sc_parent; 687197570Sthompsa usbd_transfer_poll(sc->sc_xfer, UBSA_N_TRANSFER); 688197570Sthompsa 689197570Sthompsa} 690