uplcom.c revision 184610
1184610Salfred/* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */ 2184610Salfred 3184610Salfred#include <sys/cdefs.h> 4184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uplcom2.c 184610 2008-11-04 02:31:03Z alfred $"); 5184610Salfred 6184610Salfred/*- 7184610Salfred * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 8184610Salfred * All rights reserved. 9184610Salfred * 10184610Salfred * Redistribution and use in source and binary forms, with or without 11184610Salfred * modification, are permitted provided that the following conditions 12184610Salfred * are met: 13184610Salfred * 1. Redistributions of source code must retain the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer. 15184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 16184610Salfred * notice, this list of conditions and the following disclaimer in the 17184610Salfred * documentation and/or other materials provided with the distribution. 18184610Salfred * 19184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29184610Salfred * SUCH DAMAGE. 30184610Salfred */ 31184610Salfred 32184610Salfred/*- 33184610Salfred * Copyright (c) 2001 The NetBSD Foundation, Inc. 34184610Salfred * All rights reserved. 35184610Salfred * 36184610Salfred * This code is derived from software contributed to The NetBSD Foundation 37184610Salfred * by Ichiro FUKUHARA (ichiro@ichiro.org). 38184610Salfred * 39184610Salfred * Redistribution and use in source and binary forms, with or without 40184610Salfred * modification, are permitted provided that the following conditions 41184610Salfred * are met: 42184610Salfred * 1. Redistributions of source code must retain the above copyright 43184610Salfred * notice, this list of conditions and the following disclaimer. 44184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 45184610Salfred * notice, this list of conditions and the following disclaimer in the 46184610Salfred * documentation and/or other materials provided with the distribution. 47184610Salfred * 3. All advertising materials mentioning features or use of this software 48184610Salfred * must display the following acknowledgement: 49184610Salfred * This product includes software developed by the NetBSD 50184610Salfred * Foundation, Inc. and its contributors. 51184610Salfred * 4. Neither the name of The NetBSD Foundation nor the names of its 52184610Salfred * contributors may be used to endorse or promote products derived 53184610Salfred * from this software without specific prior written permission. 54184610Salfred * 55184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65184610Salfred * POSSIBILITY OF SUCH DAMAGE. 66184610Salfred */ 67184610Salfred 68184610Salfred/* 69184610Salfred * This driver supports several USB-to-RS232 serial adapters driven by 70184610Salfred * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232 71184610Salfred * bridge chip. The adapters are sold under many different brand 72184610Salfred * names. 73184610Salfred * 74184610Salfred * Datasheets are available at Prolific www site at 75184610Salfred * http://www.prolific.com.tw. The datasheets don't contain full 76184610Salfred * programming information for the chip. 77184610Salfred * 78184610Salfred * PL-2303HX is probably programmed the same as PL-2303X. 79184610Salfred * 80184610Salfred * There are several differences between PL-2303 and PL-2303(H)X. 81184610Salfred * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_ 82184610Salfred * different command for controlling CRTSCTS and needs special 83184610Salfred * sequence of commands for initialization which aren't also 84184610Salfred * documented in the datasheet. 85184610Salfred */ 86184610Salfred 87184610Salfred#include <dev/usb2/include/usb2_devid.h> 88184610Salfred#include <dev/usb2/include/usb2_standard.h> 89184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 90184610Salfred#include <dev/usb2/include/usb2_error.h> 91184610Salfred#include <dev/usb2/include/usb2_cdc.h> 92184610Salfred 93184610Salfred#define USB_DEBUG_VAR uplcom_debug 94184610Salfred 95184610Salfred#include <dev/usb2/core/usb2_core.h> 96184610Salfred#include <dev/usb2/core/usb2_debug.h> 97184610Salfred#include <dev/usb2/core/usb2_process.h> 98184610Salfred#include <dev/usb2/core/usb2_config_td.h> 99184610Salfred#include <dev/usb2/core/usb2_request.h> 100184610Salfred#include <dev/usb2/core/usb2_lookup.h> 101184610Salfred#include <dev/usb2/core/usb2_util.h> 102184610Salfred#include <dev/usb2/core/usb2_busdma.h> 103184610Salfred 104184610Salfred#include <dev/usb2/serial/usb2_serial.h> 105184610Salfred 106184610Salfred#if USB_DEBUG 107184610Salfredstatic int uplcom_debug = 0; 108184610Salfred 109184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom"); 110184610SalfredSYSCTL_INT(_hw_usb2_uplcom, OID_AUTO, debug, CTLFLAG_RW, 111184610Salfred &uplcom_debug, 0, "Debug level"); 112184610Salfred#endif 113184610Salfred 114184610Salfred#define UPLCOM_MODVER 1 /* module version */ 115184610Salfred 116184610Salfred#define UPLCOM_CONFIG_INDEX 0 117184610Salfred#define UPLCOM_IFACE_INDEX 0 118184610Salfred#define UPLCOM_SECOND_IFACE_INDEX 1 119184610Salfred 120184610Salfred#ifndef UPLCOM_INTR_INTERVAL 121184610Salfred#define UPLCOM_INTR_INTERVAL 0 /* default */ 122184610Salfred#endif 123184610Salfred 124184610Salfred#define UPLCOM_BULK_BUF_SIZE 1024 /* bytes */ 125184610Salfred#define UPLCOM_N_TRANSFER 6 126184610Salfred 127184610Salfred#define UPLCOM_SET_REQUEST 0x01 128184610Salfred#define UPLCOM_SET_CRTSCTS 0x41 129184610Salfred#define UPLCOM_SET_CRTSCTS_PL2303X 0x61 130184610Salfred#define RSAQ_STATUS_CTS 0x80 131184610Salfred#define RSAQ_STATUS_DSR 0x02 132184610Salfred#define RSAQ_STATUS_DCD 0x01 133184610Salfred 134184610Salfred#define TYPE_PL2303 0 135184610Salfred#define TYPE_PL2303X 1 136184610Salfred 137184610Salfredstruct uplcom_softc { 138184610Salfred struct usb2_com_super_softc sc_super_ucom; 139184610Salfred struct usb2_com_softc sc_ucom; 140184610Salfred 141184610Salfred struct usb2_xfer *sc_xfer[UPLCOM_N_TRANSFER]; 142184610Salfred struct usb2_device *sc_udev; 143184610Salfred 144184610Salfred uint16_t sc_line; 145184610Salfred 146184610Salfred uint8_t sc_flag; 147184610Salfred#define UPLCOM_FLAG_INTR_STALL 0x01 148184610Salfred#define UPLCOM_FLAG_READ_STALL 0x02 149184610Salfred#define UPLCOM_FLAG_WRITE_STALL 0x04 150184610Salfred 151184610Salfred uint8_t sc_lsr; /* local status register */ 152184610Salfred uint8_t sc_msr; /* uplcom status register */ 153184610Salfred uint8_t sc_chiptype; /* type of chip */ 154184610Salfred uint8_t sc_ctrl_iface_no; 155184610Salfred uint8_t sc_data_iface_no; 156184610Salfred uint8_t sc_iface_index[2]; 157184610Salfred}; 158184610Salfred 159184610Salfred/* prototypes */ 160184610Salfred 161184610Salfredstatic usb2_error_t uplcom_reset(struct uplcom_softc *sc, struct usb2_device *udev); 162184610Salfredstatic int uplcom_pl2303x_init(struct usb2_device *udev); 163184610Salfredstatic void uplcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff); 164184610Salfredstatic void uplcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff); 165184610Salfredstatic void uplcom_cfg_set_break(struct usb2_com_softc *sc, uint8_t onoff); 166184610Salfredstatic int uplcom_pre_param(struct usb2_com_softc *ucom, struct termios *t); 167184610Salfredstatic void uplcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t); 168184610Salfredstatic void uplcom_start_read(struct usb2_com_softc *ucom); 169184610Salfredstatic void uplcom_stop_read(struct usb2_com_softc *ucom); 170184610Salfredstatic void uplcom_start_write(struct usb2_com_softc *ucom); 171184610Salfredstatic void uplcom_stop_write(struct usb2_com_softc *ucom); 172184610Salfredstatic void uplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr); 173184610Salfredstatic int uplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag, struct thread *td); 174184610Salfredstatic void uplcom_cfg_do_request(struct uplcom_softc *sc, struct usb2_device_request *req, void *data); 175184610Salfred 176184610Salfredstatic device_probe_t uplcom_probe; 177184610Salfredstatic device_attach_t uplcom_attach; 178184610Salfredstatic device_detach_t uplcom_detach; 179184610Salfred 180184610Salfredstatic usb2_callback_t uplcom_intr_callback; 181184610Salfredstatic usb2_callback_t uplcom_intr_clear_stall_callback; 182184610Salfredstatic usb2_callback_t uplcom_write_callback; 183184610Salfredstatic usb2_callback_t uplcom_write_clear_stall_callback; 184184610Salfredstatic usb2_callback_t uplcom_read_callback; 185184610Salfredstatic usb2_callback_t uplcom_read_clear_stall_callback; 186184610Salfred 187184610Salfredstatic const struct usb2_config uplcom_config_data[UPLCOM_N_TRANSFER] = { 188184610Salfred 189184610Salfred [0] = { 190184610Salfred .type = UE_BULK, 191184610Salfred .endpoint = UE_ADDR_ANY, 192184610Salfred .direction = UE_DIR_OUT, 193184610Salfred .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 194184610Salfred .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 195184610Salfred .mh.callback = &uplcom_write_callback, 196184610Salfred .if_index = 0, 197184610Salfred }, 198184610Salfred 199184610Salfred [1] = { 200184610Salfred .type = UE_BULK, 201184610Salfred .endpoint = UE_ADDR_ANY, 202184610Salfred .direction = UE_DIR_IN, 203184610Salfred .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 204184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 205184610Salfred .mh.callback = &uplcom_read_callback, 206184610Salfred .if_index = 0, 207184610Salfred }, 208184610Salfred 209184610Salfred [2] = { 210184610Salfred .type = UE_CONTROL, 211184610Salfred .endpoint = 0x00, /* Control pipe */ 212184610Salfred .direction = UE_DIR_ANY, 213184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 214184610Salfred .mh.callback = &uplcom_write_clear_stall_callback, 215184610Salfred .mh.timeout = 1000, /* 1 second */ 216184610Salfred .mh.interval = 50, /* 50ms */ 217184610Salfred .if_index = 0, 218184610Salfred }, 219184610Salfred 220184610Salfred [3] = { 221184610Salfred .type = UE_CONTROL, 222184610Salfred .endpoint = 0x00, /* Control pipe */ 223184610Salfred .direction = UE_DIR_ANY, 224184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 225184610Salfred .mh.callback = &uplcom_read_clear_stall_callback, 226184610Salfred .mh.timeout = 1000, /* 1 second */ 227184610Salfred .mh.interval = 50, /* 50ms */ 228184610Salfred .if_index = 0, 229184610Salfred }, 230184610Salfred 231184610Salfred [4] = { 232184610Salfred .type = UE_INTERRUPT, 233184610Salfred .endpoint = UE_ADDR_ANY, 234184610Salfred .direction = UE_DIR_IN, 235184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 236184610Salfred .mh.bufsize = 0, /* use wMaxPacketSize */ 237184610Salfred .mh.callback = &uplcom_intr_callback, 238184610Salfred .if_index = 1, 239184610Salfred }, 240184610Salfred 241184610Salfred [5] = { 242184610Salfred .type = UE_CONTROL, 243184610Salfred .endpoint = 0x00, /* Control pipe */ 244184610Salfred .direction = UE_DIR_ANY, 245184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 246184610Salfred .mh.callback = &uplcom_intr_clear_stall_callback, 247184610Salfred .mh.timeout = 1000, /* 1 second */ 248184610Salfred .mh.interval = 50, /* 50ms */ 249184610Salfred .if_index = 1, 250184610Salfred }, 251184610Salfred}; 252184610Salfred 253184610Salfredstruct usb2_com_callback uplcom_callback = { 254184610Salfred .usb2_com_cfg_get_status = &uplcom_cfg_get_status, 255184610Salfred .usb2_com_cfg_set_dtr = &uplcom_cfg_set_dtr, 256184610Salfred .usb2_com_cfg_set_rts = &uplcom_cfg_set_rts, 257184610Salfred .usb2_com_cfg_set_break = &uplcom_cfg_set_break, 258184610Salfred .usb2_com_cfg_param = &uplcom_cfg_param, 259184610Salfred .usb2_com_pre_param = &uplcom_pre_param, 260184610Salfred .usb2_com_ioctl = &uplcom_ioctl, 261184610Salfred .usb2_com_start_read = &uplcom_start_read, 262184610Salfred .usb2_com_stop_read = &uplcom_stop_read, 263184610Salfred .usb2_com_start_write = &uplcom_start_write, 264184610Salfred .usb2_com_stop_write = &uplcom_stop_write, 265184610Salfred}; 266184610Salfred 267184610Salfred#define USB_UPL(v,p,rl,rh,t) \ 268184610Salfred USB_VENDOR(v), USB_PRODUCT(p), USB_DEV_BCD_GTEQ(rl), \ 269184610Salfred USB_DEV_BCD_LTEQ(rh), USB_DRIVER_INFO(t) 270184610Salfred 271184610Salfredstatic const struct usb2_device_id uplcom_devs[] = { 272184610Salfred /* Belkin F5U257 */ 273184610Salfred {USB_UPL(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257, 0, 0xFFFF, TYPE_PL2303X)}, 274184610Salfred /* I/O DATA USB-RSAQ */ 275184610Salfred {USB_UPL(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, 0, 0xFFFF, TYPE_PL2303)}, 276184610Salfred /* I/O DATA USB-RSAQ2 */ 277184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, 0, 0xFFFF, TYPE_PL2303)}, 278184610Salfred /* I/O DATA USB-RSAQ3 */ 279184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, 0, 0xFFFF, TYPE_PL2303X)}, 280184610Salfred /* PLANEX USB-RS232 URS-03 */ 281184610Salfred {USB_UPL(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, 0, 0xFFFF, TYPE_PL2303)}, 282184610Salfred /* TrendNet TU-S9 */ 283184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0400, 0xFFFF, TYPE_PL2303X)}, 284184610Salfred /* ST Lab USB-SERIAL-4 */ 285184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0300, 0x03FF, TYPE_PL2303X)}, 286184610Salfred /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */ 287184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0, 0x02FF, TYPE_PL2303)}, 288184610Salfred /* TDK USB-PHS Adapter UHA6400 */ 289184610Salfred {USB_UPL(USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, 0, 0xFFFF, TYPE_PL2303)}, 290184610Salfred /* RATOC REX-USB60 */ 291184610Salfred {USB_UPL(USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, 0, 0xFFFF, TYPE_PL2303)}, 292184610Salfred /* ELECOM UC-SGT */ 293184610Salfred {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, 0, 0xFFFF, TYPE_PL2303)}, 294184610Salfred {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, 0, 0xFFFF, TYPE_PL2303)}, 295184610Salfred /* Sagem USB-Serial Controller */ 296184610Salfred {USB_UPL(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_USBSERIAL, 0, 0xFFFF, TYPE_PL2303X)}, 297184610Salfred /* Sony Ericsson USB Cable */ 298184610Salfred {USB_UPL(USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10, 0, 0xFFFF, TYPE_PL2303)}, 299184610Salfred /* SOURCENEXT KeikaiDenwa 8 */ 300184610Salfred {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8, 0, 0xFFFF, TYPE_PL2303)}, 301184610Salfred /* SOURCENEXT KeikaiDenwa 8 with charger */ 302184610Salfred {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG, 0, 0, TYPE_PL2303)}, 303184610Salfred /* HAL Corporation Crossam2+USB */ 304184610Salfred {USB_UPL(USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, 0, 0xFFFF, TYPE_PL2303)}, 305184610Salfred /* Sitecom USB to Serial */ 306184610Salfred {USB_UPL(USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_SERIAL, 0, 0xFFFF, TYPE_PL2303)}, 307184610Salfred /* Tripp-Lite U209-000-R */ 308184610Salfred {USB_UPL(USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, 0, 0xFFFF, TYPE_PL2303X)}, 309184610Salfred {USB_UPL(USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE, 0, 0xFFFF, TYPE_PL2303)}, 310184610Salfred /* Prolific Pharos */ 311184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PHAROS, 0, 0xFFFF, TYPE_PL2303)}, 312184610Salfred /* Willcom W-SIM */ 313184610Salfred {USB_UPL(USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM, 0, 0xFFFF, TYPE_PL2303X)}, 314184610Salfred}; 315184610Salfred 316184610Salfredstatic device_method_t uplcom_methods[] = { 317184610Salfred DEVMETHOD(device_probe, uplcom_probe), 318184610Salfred DEVMETHOD(device_attach, uplcom_attach), 319184610Salfred DEVMETHOD(device_detach, uplcom_detach), 320184610Salfred {0, 0} 321184610Salfred}; 322184610Salfred 323184610Salfredstatic devclass_t uplcom_devclass; 324184610Salfred 325184610Salfredstatic driver_t uplcom_driver = { 326184610Salfred .name = "uplcom", 327184610Salfred .methods = uplcom_methods, 328184610Salfred .size = sizeof(struct uplcom_softc), 329184610Salfred}; 330184610Salfred 331184610SalfredDRIVER_MODULE(uplcom, ushub, uplcom_driver, uplcom_devclass, NULL, 0); 332184610SalfredMODULE_DEPEND(uplcom, usb2_serial, 1, 1, 1); 333184610SalfredMODULE_DEPEND(uplcom, usb2_core, 1, 1, 1); 334184610SalfredMODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER); 335184610SalfredMODULE_VERSION(uplcom, UPLCOM_MODVER); 336184610Salfred 337184610Salfredstatic int 338184610Salfreduplcom_probe(device_t dev) 339184610Salfred{ 340184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 341184610Salfred 342184610Salfred DPRINTFN(11, "\n"); 343184610Salfred 344184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 345184610Salfred return (ENXIO); 346184610Salfred } 347184610Salfred if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) { 348184610Salfred return (ENXIO); 349184610Salfred } 350184610Salfred if (uaa->info.bIfaceIndex != UPLCOM_IFACE_INDEX) { 351184610Salfred return (ENXIO); 352184610Salfred } 353184610Salfred return (usb2_lookup_id_by_uaa(uplcom_devs, sizeof(uplcom_devs), uaa)); 354184610Salfred} 355184610Salfred 356184610Salfredstatic int 357184610Salfreduplcom_attach(device_t dev) 358184610Salfred{ 359184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 360184610Salfred struct uplcom_softc *sc = device_get_softc(dev); 361184610Salfred struct usb2_interface *iface; 362184610Salfred struct usb2_interface_descriptor *id; 363184610Salfred int error; 364184610Salfred 365184610Salfred DPRINTFN(11, "\n"); 366184610Salfred 367184610Salfred if (sc == NULL) { 368184610Salfred return (ENOMEM); 369184610Salfred } 370184610Salfred device_set_usb2_desc(dev); 371184610Salfred 372184610Salfred DPRINTF("sc = %p\n", sc); 373184610Salfred 374184610Salfred sc->sc_chiptype = USB_GET_DRIVER_INFO(uaa); 375184610Salfred sc->sc_udev = uaa->device; 376184610Salfred 377184610Salfred DPRINTF("chiptype: %s\n", 378184610Salfred (sc->sc_chiptype == TYPE_PL2303X) ? 379184610Salfred "2303X" : "2303"); 380184610Salfred 381184610Salfred /* 382184610Salfred * USB-RSAQ1 has two interface 383184610Salfred * 384184610Salfred * USB-RSAQ1 | USB-RSAQ2 385184610Salfred * -----------------+----------------- 386184610Salfred * Interface 0 |Interface 0 387184610Salfred * Interrupt(0x81) | Interrupt(0x81) 388184610Salfred * -----------------+ BulkIN(0x02) 389184610Salfred * Interface 1 | BulkOUT(0x83) 390184610Salfred * BulkIN(0x02) | 391184610Salfred * BulkOUT(0x83) | 392184610Salfred */ 393184610Salfred 394184610Salfred sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; 395184610Salfred sc->sc_iface_index[1] = UPLCOM_IFACE_INDEX; 396184610Salfred 397184610Salfred iface = usb2_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX); 398184610Salfred if (iface) { 399184610Salfred id = usb2_get_interface_descriptor(iface); 400184610Salfred if (id == NULL) { 401184610Salfred device_printf(dev, "no interface descriptor (2)!\n"); 402184610Salfred goto detach; 403184610Salfred } 404184610Salfred sc->sc_data_iface_no = id->bInterfaceNumber; 405184610Salfred sc->sc_iface_index[0] = UPLCOM_SECOND_IFACE_INDEX; 406184610Salfred usb2_set_parent_iface(uaa->device, 407184610Salfred UPLCOM_SECOND_IFACE_INDEX, uaa->info.bIfaceIndex); 408184610Salfred } else { 409184610Salfred sc->sc_data_iface_no = sc->sc_ctrl_iface_no; 410184610Salfred sc->sc_iface_index[0] = UPLCOM_IFACE_INDEX; 411184610Salfred } 412184610Salfred 413184610Salfred error = usb2_transfer_setup(uaa->device, 414184610Salfred sc->sc_iface_index, sc->sc_xfer, uplcom_config_data, 415184610Salfred UPLCOM_N_TRANSFER, sc, &Giant); 416184610Salfred if (error) { 417184610Salfred DPRINTF("one or more missing USB endpoints, " 418184610Salfred "error=%s\n", usb2_errstr(error)); 419184610Salfred goto detach; 420184610Salfred } 421184610Salfred error = uplcom_reset(sc, uaa->device); 422184610Salfred if (error) { 423184610Salfred device_printf(dev, "reset failed, error=%s\n", 424184610Salfred usb2_errstr(error)); 425184610Salfred goto detach; 426184610Salfred } 427184610Salfred /* clear stall at first run */ 428184610Salfred sc->sc_flag |= (UPLCOM_FLAG_READ_STALL | 429184610Salfred UPLCOM_FLAG_WRITE_STALL); 430184610Salfred 431184610Salfred error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 432184610Salfred &uplcom_callback, &Giant); 433184610Salfred if (error) { 434184610Salfred goto detach; 435184610Salfred } 436184610Salfred /* 437184610Salfred * do the initialization during attach so that the system does not 438184610Salfred * sleep during open: 439184610Salfred */ 440184610Salfred if (sc->sc_chiptype == TYPE_PL2303X) { 441184610Salfred if (uplcom_pl2303x_init(uaa->device)) { 442184610Salfred device_printf(dev, "init failed!\n"); 443184610Salfred goto detach; 444184610Salfred } 445184610Salfred } 446184610Salfred return (0); 447184610Salfred 448184610Salfreddetach: 449184610Salfred uplcom_detach(dev); 450184610Salfred return (ENXIO); 451184610Salfred} 452184610Salfred 453184610Salfredstatic int 454184610Salfreduplcom_detach(device_t dev) 455184610Salfred{ 456184610Salfred struct uplcom_softc *sc = device_get_softc(dev); 457184610Salfred 458184610Salfred DPRINTF("sc=%p\n", sc); 459184610Salfred 460184610Salfred usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 461184610Salfred 462184610Salfred usb2_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER); 463184610Salfred 464184610Salfred return (0); 465184610Salfred} 466184610Salfred 467184610Salfredstatic usb2_error_t 468184610Salfreduplcom_reset(struct uplcom_softc *sc, struct usb2_device *udev) 469184610Salfred{ 470184610Salfred struct usb2_device_request req; 471184610Salfred 472184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 473184610Salfred req.bRequest = UPLCOM_SET_REQUEST; 474184610Salfred USETW(req.wValue, 0); 475184610Salfred req.wIndex[0] = sc->sc_data_iface_no; 476184610Salfred req.wIndex[1] = 0; 477184610Salfred USETW(req.wLength, 0); 478184610Salfred 479184610Salfred return (usb2_do_request(udev, &Giant, &req, NULL)); 480184610Salfred} 481184610Salfred 482184610Salfredstruct pl2303x_init { 483184610Salfred uint8_t req_type; 484184610Salfred uint8_t request; 485184610Salfred uint16_t value; 486184610Salfred uint16_t index; 487184610Salfred uint16_t length; 488184610Salfred}; 489184610Salfred 490184610Salfredstatic const struct pl2303x_init pl2303x[] = { 491184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 492184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0}, 493184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 494184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 495184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 496184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0}, 497184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 498184610Salfred {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 499184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0}, 500184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0}, 501184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0}, 502184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0}, 503184610Salfred {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0}, 504184610Salfred}; 505184610Salfred 506184610Salfred#define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) 507184610Salfred 508184610Salfredstatic int 509184610Salfreduplcom_pl2303x_init(struct usb2_device *udev) 510184610Salfred{ 511184610Salfred struct usb2_device_request req; 512184610Salfred usb2_error_t err; 513184610Salfred uint8_t buf[4]; 514184610Salfred uint8_t i; 515184610Salfred 516184610Salfred for (i = 0; i != N_PL2302X_INIT; i++) { 517184610Salfred req.bmRequestType = pl2303x[i].req_type; 518184610Salfred req.bRequest = pl2303x[i].request; 519184610Salfred USETW(req.wValue, pl2303x[i].value); 520184610Salfred USETW(req.wIndex, pl2303x[i].index); 521184610Salfred USETW(req.wLength, pl2303x[i].length); 522184610Salfred 523184610Salfred err = usb2_do_request(udev, &Giant, &req, buf); 524184610Salfred if (err) { 525184610Salfred DPRINTF("error=%s\n", usb2_errstr(err)); 526184610Salfred return (EIO); 527184610Salfred } 528184610Salfred } 529184610Salfred return (0); 530184610Salfred} 531184610Salfred 532184610Salfredstatic void 533184610Salfreduplcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 534184610Salfred{ 535184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 536184610Salfred struct usb2_device_request req; 537184610Salfred 538184610Salfred DPRINTF("onoff = %d\n", onoff); 539184610Salfred 540184610Salfred if (onoff) 541184610Salfred sc->sc_line |= UCDC_LINE_DTR; 542184610Salfred else 543184610Salfred sc->sc_line &= ~UCDC_LINE_DTR; 544184610Salfred 545184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 546184610Salfred req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 547184610Salfred USETW(req.wValue, sc->sc_line); 548184610Salfred req.wIndex[0] = sc->sc_data_iface_no; 549184610Salfred req.wIndex[1] = 0; 550184610Salfred USETW(req.wLength, 0); 551184610Salfred 552184610Salfred uplcom_cfg_do_request(sc, &req, NULL); 553184610Salfred return; 554184610Salfred} 555184610Salfred 556184610Salfredstatic void 557184610Salfreduplcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 558184610Salfred{ 559184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 560184610Salfred struct usb2_device_request req; 561184610Salfred 562184610Salfred DPRINTF("onoff = %d\n", onoff); 563184610Salfred 564184610Salfred if (onoff) 565184610Salfred sc->sc_line |= UCDC_LINE_RTS; 566184610Salfred else 567184610Salfred sc->sc_line &= ~UCDC_LINE_RTS; 568184610Salfred 569184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 570184610Salfred req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 571184610Salfred USETW(req.wValue, sc->sc_line); 572184610Salfred req.wIndex[0] = sc->sc_data_iface_no; 573184610Salfred req.wIndex[1] = 0; 574184610Salfred USETW(req.wLength, 0); 575184610Salfred 576184610Salfred uplcom_cfg_do_request(sc, &req, NULL); 577184610Salfred return; 578184610Salfred} 579184610Salfred 580184610Salfredstatic void 581184610Salfreduplcom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 582184610Salfred{ 583184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 584184610Salfred struct usb2_device_request req; 585184610Salfred uint16_t temp; 586184610Salfred 587184610Salfred DPRINTF("onoff = %d\n", onoff); 588184610Salfred 589184610Salfred temp = (onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 590184610Salfred 591184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 592184610Salfred req.bRequest = UCDC_SEND_BREAK; 593184610Salfred USETW(req.wValue, temp); 594184610Salfred req.wIndex[0] = sc->sc_data_iface_no; 595184610Salfred req.wIndex[1] = 0; 596184610Salfred USETW(req.wLength, 0); 597184610Salfred 598184610Salfred uplcom_cfg_do_request(sc, &req, NULL); 599184610Salfred return; 600184610Salfred} 601184610Salfred 602184610Salfredstatic const int32_t uplcom_rates[] = { 603184610Salfred 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 604184610Salfred 19200, 28800, 38400, 57600, 115200, 605184610Salfred /* 606184610Salfred * Higher speeds are probably possible. PL2303X supports up to 607184610Salfred * 6Mb and can set any rate 608184610Salfred */ 609184610Salfred 230400, 460800, 614400, 921600, 1228800 610184610Salfred}; 611184610Salfred 612184610Salfred#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0])) 613184610Salfred 614184610Salfredstatic int 615184610Salfreduplcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 616184610Salfred{ 617184610Salfred uint8_t i; 618184610Salfred 619184610Salfred DPRINTF("\n"); 620184610Salfred 621184610Salfred /* check requested baud rate */ 622184610Salfred 623184610Salfred for (i = 0;; i++) { 624184610Salfred 625184610Salfred if (i != N_UPLCOM_RATES) { 626184610Salfred if (uplcom_rates[i] == t->c_ospeed) { 627184610Salfred break; 628184610Salfred } 629184610Salfred } else { 630184610Salfred DPRINTF("invalid baud rate (%d)\n", t->c_ospeed); 631184610Salfred return (EIO); 632184610Salfred } 633184610Salfred } 634184610Salfred 635184610Salfred return (0); 636184610Salfred} 637184610Salfred 638184610Salfredstatic void 639184610Salfreduplcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 640184610Salfred{ 641184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 642184610Salfred struct usb2_cdc_line_state ls; 643184610Salfred struct usb2_device_request req; 644184610Salfred 645184610Salfred DPRINTF("sc = %p\n", sc); 646184610Salfred 647184610Salfred bzero(&ls, sizeof(ls)); 648184610Salfred 649184610Salfred USETDW(ls.dwDTERate, t->c_ospeed); 650184610Salfred 651184610Salfred if (t->c_cflag & CSTOPB) { 652184610Salfred ls.bCharFormat = UCDC_STOP_BIT_2; 653184610Salfred } else { 654184610Salfred ls.bCharFormat = UCDC_STOP_BIT_1; 655184610Salfred } 656184610Salfred 657184610Salfred if (t->c_cflag & PARENB) { 658184610Salfred if (t->c_cflag & PARODD) { 659184610Salfred ls.bParityType = UCDC_PARITY_ODD; 660184610Salfred } else { 661184610Salfred ls.bParityType = UCDC_PARITY_EVEN; 662184610Salfred } 663184610Salfred } else { 664184610Salfred ls.bParityType = UCDC_PARITY_NONE; 665184610Salfred } 666184610Salfred 667184610Salfred switch (t->c_cflag & CSIZE) { 668184610Salfred case CS5: 669184610Salfred ls.bDataBits = 5; 670184610Salfred break; 671184610Salfred case CS6: 672184610Salfred ls.bDataBits = 6; 673184610Salfred break; 674184610Salfred case CS7: 675184610Salfred ls.bDataBits = 7; 676184610Salfred break; 677184610Salfred case CS8: 678184610Salfred ls.bDataBits = 8; 679184610Salfred break; 680184610Salfred } 681184610Salfred 682184610Salfred DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", 683184610Salfred UGETDW(ls.dwDTERate), ls.bCharFormat, 684184610Salfred ls.bParityType, ls.bDataBits); 685184610Salfred 686184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 687184610Salfred req.bRequest = UCDC_SET_LINE_CODING; 688184610Salfred USETW(req.wValue, 0); 689184610Salfred req.wIndex[0] = sc->sc_data_iface_no; 690184610Salfred req.wIndex[1] = 0; 691184610Salfred USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 692184610Salfred 693184610Salfred uplcom_cfg_do_request(sc, &req, &ls); 694184610Salfred 695184610Salfred if (t->c_cflag & CRTSCTS) { 696184610Salfred 697184610Salfred DPRINTF("crtscts = on\n"); 698184610Salfred 699184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 700184610Salfred req.bRequest = UPLCOM_SET_REQUEST; 701184610Salfred USETW(req.wValue, 0); 702184610Salfred if (sc->sc_chiptype == TYPE_PL2303X) 703184610Salfred USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X); 704184610Salfred else 705184610Salfred USETW(req.wIndex, UPLCOM_SET_CRTSCTS); 706184610Salfred USETW(req.wLength, 0); 707184610Salfred 708184610Salfred uplcom_cfg_do_request(sc, &req, NULL); 709184610Salfred } else { 710184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 711184610Salfred req.bRequest = UPLCOM_SET_REQUEST; 712184610Salfred USETW(req.wValue, 0); 713184610Salfred USETW(req.wIndex, 0); 714184610Salfred USETW(req.wLength, 0); 715184610Salfred uplcom_cfg_do_request(sc, &req, NULL); 716184610Salfred } 717184610Salfred return; 718184610Salfred} 719184610Salfred 720184610Salfredstatic void 721184610Salfreduplcom_start_read(struct usb2_com_softc *ucom) 722184610Salfred{ 723184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 724184610Salfred 725184610Salfred /* start interrupt endpoint */ 726184610Salfred usb2_transfer_start(sc->sc_xfer[4]); 727184610Salfred 728184610Salfred /* start read endpoint */ 729184610Salfred usb2_transfer_start(sc->sc_xfer[1]); 730184610Salfred return; 731184610Salfred} 732184610Salfred 733184610Salfredstatic void 734184610Salfreduplcom_stop_read(struct usb2_com_softc *ucom) 735184610Salfred{ 736184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 737184610Salfred 738184610Salfred /* stop interrupt endpoint */ 739184610Salfred usb2_transfer_stop(sc->sc_xfer[4]); 740184610Salfred 741184610Salfred /* stop read endpoint */ 742184610Salfred usb2_transfer_stop(sc->sc_xfer[3]); 743184610Salfred usb2_transfer_stop(sc->sc_xfer[1]); 744184610Salfred return; 745184610Salfred} 746184610Salfred 747184610Salfredstatic void 748184610Salfreduplcom_start_write(struct usb2_com_softc *ucom) 749184610Salfred{ 750184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 751184610Salfred 752184610Salfred usb2_transfer_start(sc->sc_xfer[0]); 753184610Salfred return; 754184610Salfred} 755184610Salfred 756184610Salfredstatic void 757184610Salfreduplcom_stop_write(struct usb2_com_softc *ucom) 758184610Salfred{ 759184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 760184610Salfred 761184610Salfred usb2_transfer_stop(sc->sc_xfer[2]); 762184610Salfred usb2_transfer_stop(sc->sc_xfer[0]); 763184610Salfred return; 764184610Salfred} 765184610Salfred 766184610Salfredstatic void 767184610Salfreduplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 768184610Salfred{ 769184610Salfred struct uplcom_softc *sc = ucom->sc_parent; 770184610Salfred 771184610Salfred DPRINTF("\n"); 772184610Salfred 773184610Salfred *lsr = sc->sc_lsr; 774184610Salfred *msr = sc->sc_msr; 775184610Salfred return; 776184610Salfred} 777184610Salfred 778184610Salfredstatic int 779184610Salfreduplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag, 780184610Salfred struct thread *td) 781184610Salfred{ 782184610Salfred return (ENOTTY); 783184610Salfred} 784184610Salfred 785184610Salfredstatic void 786184610Salfreduplcom_intr_callback(struct usb2_xfer *xfer) 787184610Salfred{ 788184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 789184610Salfred uint8_t buf[9]; 790184610Salfred 791184610Salfred switch (USB_GET_STATE(xfer)) { 792184610Salfred case USB_ST_TRANSFERRED: 793184610Salfred 794184610Salfred DPRINTF("actlen = %u\n", xfer->actlen); 795184610Salfred 796184610Salfred if (xfer->actlen >= 9) { 797184610Salfred 798184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 799184610Salfred 800184610Salfred DPRINTF("status = 0x%02x\n", buf[8]); 801184610Salfred 802184610Salfred sc->sc_lsr = 0; 803184610Salfred sc->sc_msr = 0; 804184610Salfred 805184610Salfred if (buf[8] & RSAQ_STATUS_CTS) { 806184610Salfred sc->sc_msr |= SER_CTS; 807184610Salfred } 808184610Salfred if (buf[8] & RSAQ_STATUS_DSR) { 809184610Salfred sc->sc_msr |= SER_DSR; 810184610Salfred } 811184610Salfred if (buf[8] & RSAQ_STATUS_DCD) { 812184610Salfred sc->sc_msr |= SER_DCD; 813184610Salfred } 814184610Salfred usb2_com_status_change(&sc->sc_ucom); 815184610Salfred } 816184610Salfred case USB_ST_SETUP: 817184610Salfred if (sc->sc_flag & UPLCOM_FLAG_INTR_STALL) { 818184610Salfred usb2_transfer_start(sc->sc_xfer[5]); 819184610Salfred } else { 820184610Salfred xfer->frlengths[0] = xfer->max_data_length; 821184610Salfred usb2_start_hardware(xfer); 822184610Salfred } 823184610Salfred return; 824184610Salfred 825184610Salfred default: /* Error */ 826184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 827184610Salfred sc->sc_flag |= UPLCOM_FLAG_INTR_STALL; 828184610Salfred usb2_transfer_start(sc->sc_xfer[5]); 829184610Salfred } 830184610Salfred return; 831184610Salfred 832184610Salfred } 833184610Salfred} 834184610Salfred 835184610Salfredstatic void 836184610Salfreduplcom_intr_clear_stall_callback(struct usb2_xfer *xfer) 837184610Salfred{ 838184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 839184610Salfred struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 840184610Salfred 841184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 842184610Salfred DPRINTF("stall cleared\n"); 843184610Salfred sc->sc_flag &= ~UPLCOM_FLAG_INTR_STALL; 844184610Salfred usb2_transfer_start(xfer_other); 845184610Salfred } 846184610Salfred return; 847184610Salfred} 848184610Salfred 849184610Salfredstatic void 850184610Salfreduplcom_write_callback(struct usb2_xfer *xfer) 851184610Salfred{ 852184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 853184610Salfred uint32_t actlen; 854184610Salfred 855184610Salfred switch (USB_GET_STATE(xfer)) { 856184610Salfred case USB_ST_SETUP: 857184610Salfred case USB_ST_TRANSFERRED: 858184610Salfred if (sc->sc_flag & UPLCOM_FLAG_WRITE_STALL) { 859184610Salfred usb2_transfer_start(sc->sc_xfer[2]); 860184610Salfred return; 861184610Salfred } 862184610Salfred if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 863184610Salfred UPLCOM_BULK_BUF_SIZE, &actlen)) { 864184610Salfred 865184610Salfred DPRINTF("actlen = %d\n", actlen); 866184610Salfred 867184610Salfred xfer->frlengths[0] = actlen; 868184610Salfred usb2_start_hardware(xfer); 869184610Salfred } 870184610Salfred return; 871184610Salfred 872184610Salfred default: /* Error */ 873184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 874184610Salfred sc->sc_flag |= UPLCOM_FLAG_WRITE_STALL; 875184610Salfred usb2_transfer_start(sc->sc_xfer[2]); 876184610Salfred } 877184610Salfred return; 878184610Salfred 879184610Salfred } 880184610Salfred} 881184610Salfred 882184610Salfredstatic void 883184610Salfreduplcom_write_clear_stall_callback(struct usb2_xfer *xfer) 884184610Salfred{ 885184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 886184610Salfred struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 887184610Salfred 888184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 889184610Salfred DPRINTF("stall cleared\n"); 890184610Salfred sc->sc_flag &= ~UPLCOM_FLAG_WRITE_STALL; 891184610Salfred usb2_transfer_start(xfer_other); 892184610Salfred } 893184610Salfred return; 894184610Salfred} 895184610Salfred 896184610Salfredstatic void 897184610Salfreduplcom_read_callback(struct usb2_xfer *xfer) 898184610Salfred{ 899184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 900184610Salfred 901184610Salfred switch (USB_GET_STATE(xfer)) { 902184610Salfred case USB_ST_TRANSFERRED: 903184610Salfred usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 904184610Salfred 905184610Salfred case USB_ST_SETUP: 906184610Salfred if (sc->sc_flag & UPLCOM_FLAG_READ_STALL) { 907184610Salfred usb2_transfer_start(sc->sc_xfer[3]); 908184610Salfred } else { 909184610Salfred xfer->frlengths[0] = xfer->max_data_length; 910184610Salfred usb2_start_hardware(xfer); 911184610Salfred } 912184610Salfred return; 913184610Salfred 914184610Salfred default: /* Error */ 915184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 916184610Salfred sc->sc_flag |= UPLCOM_FLAG_READ_STALL; 917184610Salfred usb2_transfer_start(sc->sc_xfer[3]); 918184610Salfred } 919184610Salfred return; 920184610Salfred 921184610Salfred } 922184610Salfred} 923184610Salfred 924184610Salfredstatic void 925184610Salfreduplcom_read_clear_stall_callback(struct usb2_xfer *xfer) 926184610Salfred{ 927184610Salfred struct uplcom_softc *sc = xfer->priv_sc; 928184610Salfred struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 929184610Salfred 930184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 931184610Salfred DPRINTF("stall cleared\n"); 932184610Salfred sc->sc_flag &= ~UPLCOM_FLAG_READ_STALL; 933184610Salfred usb2_transfer_start(xfer_other); 934184610Salfred } 935184610Salfred return; 936184610Salfred} 937184610Salfred 938184610Salfredstatic void 939184610Salfreduplcom_cfg_do_request(struct uplcom_softc *sc, struct usb2_device_request *req, 940184610Salfred void *data) 941184610Salfred{ 942184610Salfred uint16_t length; 943184610Salfred usb2_error_t err; 944184610Salfred 945184610Salfred if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 946184610Salfred goto error; 947184610Salfred } 948184610Salfred err = usb2_do_request_flags(sc->sc_udev, &Giant, req, 949184610Salfred data, 0, NULL, 1000); 950184610Salfred 951184610Salfred if (err) { 952184610Salfred 953184610Salfred DPRINTFN(0, "device request failed, err=%s " 954184610Salfred "(ignored)\n", usb2_errstr(err)); 955184610Salfred 956184610Salfrederror: 957184610Salfred length = UGETW(req->wLength); 958184610Salfred 959184610Salfred if ((req->bmRequestType & UT_READ) && length) { 960184610Salfred bzero(data, length); 961184610Salfred } 962184610Salfred } 963184610Salfred return; 964184610Salfred} 965