uplcom.c revision 184610
1/* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */ 2 3#include <sys/cdefs.h> 4__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uplcom2.c 184610 2008-11-04 02:31:03Z alfred $"); 5 6/*- 7 * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/*- 33 * Copyright (c) 2001 The NetBSD Foundation, Inc. 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to The NetBSD Foundation 37 * by Ichiro FUKUHARA (ichiro@ichiro.org). 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the NetBSD 50 * Foundation, Inc. and its contributors. 51 * 4. Neither the name of The NetBSD Foundation nor the names of its 52 * contributors may be used to endorse or promote products derived 53 * from this software without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 * POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68/* 69 * This driver supports several USB-to-RS232 serial adapters driven by 70 * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232 71 * bridge chip. The adapters are sold under many different brand 72 * names. 73 * 74 * Datasheets are available at Prolific www site at 75 * http://www.prolific.com.tw. The datasheets don't contain full 76 * programming information for the chip. 77 * 78 * PL-2303HX is probably programmed the same as PL-2303X. 79 * 80 * There are several differences between PL-2303 and PL-2303(H)X. 81 * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_ 82 * different command for controlling CRTSCTS and needs special 83 * sequence of commands for initialization which aren't also 84 * documented in the datasheet. 85 */ 86 87#include <dev/usb2/include/usb2_devid.h> 88#include <dev/usb2/include/usb2_standard.h> 89#include <dev/usb2/include/usb2_mfunc.h> 90#include <dev/usb2/include/usb2_error.h> 91#include <dev/usb2/include/usb2_cdc.h> 92 93#define USB_DEBUG_VAR uplcom_debug 94 95#include <dev/usb2/core/usb2_core.h> 96#include <dev/usb2/core/usb2_debug.h> 97#include <dev/usb2/core/usb2_process.h> 98#include <dev/usb2/core/usb2_config_td.h> 99#include <dev/usb2/core/usb2_request.h> 100#include <dev/usb2/core/usb2_lookup.h> 101#include <dev/usb2/core/usb2_util.h> 102#include <dev/usb2/core/usb2_busdma.h> 103 104#include <dev/usb2/serial/usb2_serial.h> 105 106#if USB_DEBUG 107static int uplcom_debug = 0; 108 109SYSCTL_NODE(_hw_usb2, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom"); 110SYSCTL_INT(_hw_usb2_uplcom, OID_AUTO, debug, CTLFLAG_RW, 111 &uplcom_debug, 0, "Debug level"); 112#endif 113 114#define UPLCOM_MODVER 1 /* module version */ 115 116#define UPLCOM_CONFIG_INDEX 0 117#define UPLCOM_IFACE_INDEX 0 118#define UPLCOM_SECOND_IFACE_INDEX 1 119 120#ifndef UPLCOM_INTR_INTERVAL 121#define UPLCOM_INTR_INTERVAL 0 /* default */ 122#endif 123 124#define UPLCOM_BULK_BUF_SIZE 1024 /* bytes */ 125#define UPLCOM_N_TRANSFER 6 126 127#define UPLCOM_SET_REQUEST 0x01 128#define UPLCOM_SET_CRTSCTS 0x41 129#define UPLCOM_SET_CRTSCTS_PL2303X 0x61 130#define RSAQ_STATUS_CTS 0x80 131#define RSAQ_STATUS_DSR 0x02 132#define RSAQ_STATUS_DCD 0x01 133 134#define TYPE_PL2303 0 135#define TYPE_PL2303X 1 136 137struct uplcom_softc { 138 struct usb2_com_super_softc sc_super_ucom; 139 struct usb2_com_softc sc_ucom; 140 141 struct usb2_xfer *sc_xfer[UPLCOM_N_TRANSFER]; 142 struct usb2_device *sc_udev; 143 144 uint16_t sc_line; 145 146 uint8_t sc_flag; 147#define UPLCOM_FLAG_INTR_STALL 0x01 148#define UPLCOM_FLAG_READ_STALL 0x02 149#define UPLCOM_FLAG_WRITE_STALL 0x04 150 151 uint8_t sc_lsr; /* local status register */ 152 uint8_t sc_msr; /* uplcom status register */ 153 uint8_t sc_chiptype; /* type of chip */ 154 uint8_t sc_ctrl_iface_no; 155 uint8_t sc_data_iface_no; 156 uint8_t sc_iface_index[2]; 157}; 158 159/* prototypes */ 160 161static usb2_error_t uplcom_reset(struct uplcom_softc *sc, struct usb2_device *udev); 162static int uplcom_pl2303x_init(struct usb2_device *udev); 163static void uplcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff); 164static void uplcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff); 165static void uplcom_cfg_set_break(struct usb2_com_softc *sc, uint8_t onoff); 166static int uplcom_pre_param(struct usb2_com_softc *ucom, struct termios *t); 167static void uplcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t); 168static void uplcom_start_read(struct usb2_com_softc *ucom); 169static void uplcom_stop_read(struct usb2_com_softc *ucom); 170static void uplcom_start_write(struct usb2_com_softc *ucom); 171static void uplcom_stop_write(struct usb2_com_softc *ucom); 172static void uplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr); 173static int uplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag, struct thread *td); 174static void uplcom_cfg_do_request(struct uplcom_softc *sc, struct usb2_device_request *req, void *data); 175 176static device_probe_t uplcom_probe; 177static device_attach_t uplcom_attach; 178static device_detach_t uplcom_detach; 179 180static usb2_callback_t uplcom_intr_callback; 181static usb2_callback_t uplcom_intr_clear_stall_callback; 182static usb2_callback_t uplcom_write_callback; 183static usb2_callback_t uplcom_write_clear_stall_callback; 184static usb2_callback_t uplcom_read_callback; 185static usb2_callback_t uplcom_read_clear_stall_callback; 186 187static const struct usb2_config uplcom_config_data[UPLCOM_N_TRANSFER] = { 188 189 [0] = { 190 .type = UE_BULK, 191 .endpoint = UE_ADDR_ANY, 192 .direction = UE_DIR_OUT, 193 .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 194 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 195 .mh.callback = &uplcom_write_callback, 196 .if_index = 0, 197 }, 198 199 [1] = { 200 .type = UE_BULK, 201 .endpoint = UE_ADDR_ANY, 202 .direction = UE_DIR_IN, 203 .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 204 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 205 .mh.callback = &uplcom_read_callback, 206 .if_index = 0, 207 }, 208 209 [2] = { 210 .type = UE_CONTROL, 211 .endpoint = 0x00, /* Control pipe */ 212 .direction = UE_DIR_ANY, 213 .mh.bufsize = sizeof(struct usb2_device_request), 214 .mh.callback = &uplcom_write_clear_stall_callback, 215 .mh.timeout = 1000, /* 1 second */ 216 .mh.interval = 50, /* 50ms */ 217 .if_index = 0, 218 }, 219 220 [3] = { 221 .type = UE_CONTROL, 222 .endpoint = 0x00, /* Control pipe */ 223 .direction = UE_DIR_ANY, 224 .mh.bufsize = sizeof(struct usb2_device_request), 225 .mh.callback = &uplcom_read_clear_stall_callback, 226 .mh.timeout = 1000, /* 1 second */ 227 .mh.interval = 50, /* 50ms */ 228 .if_index = 0, 229 }, 230 231 [4] = { 232 .type = UE_INTERRUPT, 233 .endpoint = UE_ADDR_ANY, 234 .direction = UE_DIR_IN, 235 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 236 .mh.bufsize = 0, /* use wMaxPacketSize */ 237 .mh.callback = &uplcom_intr_callback, 238 .if_index = 1, 239 }, 240 241 [5] = { 242 .type = UE_CONTROL, 243 .endpoint = 0x00, /* Control pipe */ 244 .direction = UE_DIR_ANY, 245 .mh.bufsize = sizeof(struct usb2_device_request), 246 .mh.callback = &uplcom_intr_clear_stall_callback, 247 .mh.timeout = 1000, /* 1 second */ 248 .mh.interval = 50, /* 50ms */ 249 .if_index = 1, 250 }, 251}; 252 253struct usb2_com_callback uplcom_callback = { 254 .usb2_com_cfg_get_status = &uplcom_cfg_get_status, 255 .usb2_com_cfg_set_dtr = &uplcom_cfg_set_dtr, 256 .usb2_com_cfg_set_rts = &uplcom_cfg_set_rts, 257 .usb2_com_cfg_set_break = &uplcom_cfg_set_break, 258 .usb2_com_cfg_param = &uplcom_cfg_param, 259 .usb2_com_pre_param = &uplcom_pre_param, 260 .usb2_com_ioctl = &uplcom_ioctl, 261 .usb2_com_start_read = &uplcom_start_read, 262 .usb2_com_stop_read = &uplcom_stop_read, 263 .usb2_com_start_write = &uplcom_start_write, 264 .usb2_com_stop_write = &uplcom_stop_write, 265}; 266 267#define USB_UPL(v,p,rl,rh,t) \ 268 USB_VENDOR(v), USB_PRODUCT(p), USB_DEV_BCD_GTEQ(rl), \ 269 USB_DEV_BCD_LTEQ(rh), USB_DRIVER_INFO(t) 270 271static const struct usb2_device_id uplcom_devs[] = { 272 /* Belkin F5U257 */ 273 {USB_UPL(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257, 0, 0xFFFF, TYPE_PL2303X)}, 274 /* I/O DATA USB-RSAQ */ 275 {USB_UPL(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, 0, 0xFFFF, TYPE_PL2303)}, 276 /* I/O DATA USB-RSAQ2 */ 277 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, 0, 0xFFFF, TYPE_PL2303)}, 278 /* I/O DATA USB-RSAQ3 */ 279 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, 0, 0xFFFF, TYPE_PL2303X)}, 280 /* PLANEX USB-RS232 URS-03 */ 281 {USB_UPL(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, 0, 0xFFFF, TYPE_PL2303)}, 282 /* TrendNet TU-S9 */ 283 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0400, 0xFFFF, TYPE_PL2303X)}, 284 /* ST Lab USB-SERIAL-4 */ 285 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0300, 0x03FF, TYPE_PL2303X)}, 286 /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */ 287 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0, 0x02FF, TYPE_PL2303)}, 288 /* TDK USB-PHS Adapter UHA6400 */ 289 {USB_UPL(USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, 0, 0xFFFF, TYPE_PL2303)}, 290 /* RATOC REX-USB60 */ 291 {USB_UPL(USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, 0, 0xFFFF, TYPE_PL2303)}, 292 /* ELECOM UC-SGT */ 293 {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, 0, 0xFFFF, TYPE_PL2303)}, 294 {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, 0, 0xFFFF, TYPE_PL2303)}, 295 /* Sagem USB-Serial Controller */ 296 {USB_UPL(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_USBSERIAL, 0, 0xFFFF, TYPE_PL2303X)}, 297 /* Sony Ericsson USB Cable */ 298 {USB_UPL(USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10, 0, 0xFFFF, TYPE_PL2303)}, 299 /* SOURCENEXT KeikaiDenwa 8 */ 300 {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8, 0, 0xFFFF, TYPE_PL2303)}, 301 /* SOURCENEXT KeikaiDenwa 8 with charger */ 302 {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG, 0, 0, TYPE_PL2303)}, 303 /* HAL Corporation Crossam2+USB */ 304 {USB_UPL(USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, 0, 0xFFFF, TYPE_PL2303)}, 305 /* Sitecom USB to Serial */ 306 {USB_UPL(USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_SERIAL, 0, 0xFFFF, TYPE_PL2303)}, 307 /* Tripp-Lite U209-000-R */ 308 {USB_UPL(USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, 0, 0xFFFF, TYPE_PL2303X)}, 309 {USB_UPL(USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE, 0, 0xFFFF, TYPE_PL2303)}, 310 /* Prolific Pharos */ 311 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PHAROS, 0, 0xFFFF, TYPE_PL2303)}, 312 /* Willcom W-SIM */ 313 {USB_UPL(USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM, 0, 0xFFFF, TYPE_PL2303X)}, 314}; 315 316static device_method_t uplcom_methods[] = { 317 DEVMETHOD(device_probe, uplcom_probe), 318 DEVMETHOD(device_attach, uplcom_attach), 319 DEVMETHOD(device_detach, uplcom_detach), 320 {0, 0} 321}; 322 323static devclass_t uplcom_devclass; 324 325static driver_t uplcom_driver = { 326 .name = "uplcom", 327 .methods = uplcom_methods, 328 .size = sizeof(struct uplcom_softc), 329}; 330 331DRIVER_MODULE(uplcom, ushub, uplcom_driver, uplcom_devclass, NULL, 0); 332MODULE_DEPEND(uplcom, usb2_serial, 1, 1, 1); 333MODULE_DEPEND(uplcom, usb2_core, 1, 1, 1); 334MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER); 335MODULE_VERSION(uplcom, UPLCOM_MODVER); 336 337static int 338uplcom_probe(device_t dev) 339{ 340 struct usb2_attach_arg *uaa = device_get_ivars(dev); 341 342 DPRINTFN(11, "\n"); 343 344 if (uaa->usb2_mode != USB_MODE_HOST) { 345 return (ENXIO); 346 } 347 if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) { 348 return (ENXIO); 349 } 350 if (uaa->info.bIfaceIndex != UPLCOM_IFACE_INDEX) { 351 return (ENXIO); 352 } 353 return (usb2_lookup_id_by_uaa(uplcom_devs, sizeof(uplcom_devs), uaa)); 354} 355 356static int 357uplcom_attach(device_t dev) 358{ 359 struct usb2_attach_arg *uaa = device_get_ivars(dev); 360 struct uplcom_softc *sc = device_get_softc(dev); 361 struct usb2_interface *iface; 362 struct usb2_interface_descriptor *id; 363 int error; 364 365 DPRINTFN(11, "\n"); 366 367 if (sc == NULL) { 368 return (ENOMEM); 369 } 370 device_set_usb2_desc(dev); 371 372 DPRINTF("sc = %p\n", sc); 373 374 sc->sc_chiptype = USB_GET_DRIVER_INFO(uaa); 375 sc->sc_udev = uaa->device; 376 377 DPRINTF("chiptype: %s\n", 378 (sc->sc_chiptype == TYPE_PL2303X) ? 379 "2303X" : "2303"); 380 381 /* 382 * USB-RSAQ1 has two interface 383 * 384 * USB-RSAQ1 | USB-RSAQ2 385 * -----------------+----------------- 386 * Interface 0 |Interface 0 387 * Interrupt(0x81) | Interrupt(0x81) 388 * -----------------+ BulkIN(0x02) 389 * Interface 1 | BulkOUT(0x83) 390 * BulkIN(0x02) | 391 * BulkOUT(0x83) | 392 */ 393 394 sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; 395 sc->sc_iface_index[1] = UPLCOM_IFACE_INDEX; 396 397 iface = usb2_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX); 398 if (iface) { 399 id = usb2_get_interface_descriptor(iface); 400 if (id == NULL) { 401 device_printf(dev, "no interface descriptor (2)!\n"); 402 goto detach; 403 } 404 sc->sc_data_iface_no = id->bInterfaceNumber; 405 sc->sc_iface_index[0] = UPLCOM_SECOND_IFACE_INDEX; 406 usb2_set_parent_iface(uaa->device, 407 UPLCOM_SECOND_IFACE_INDEX, uaa->info.bIfaceIndex); 408 } else { 409 sc->sc_data_iface_no = sc->sc_ctrl_iface_no; 410 sc->sc_iface_index[0] = UPLCOM_IFACE_INDEX; 411 } 412 413 error = usb2_transfer_setup(uaa->device, 414 sc->sc_iface_index, sc->sc_xfer, uplcom_config_data, 415 UPLCOM_N_TRANSFER, sc, &Giant); 416 if (error) { 417 DPRINTF("one or more missing USB endpoints, " 418 "error=%s\n", usb2_errstr(error)); 419 goto detach; 420 } 421 error = uplcom_reset(sc, uaa->device); 422 if (error) { 423 device_printf(dev, "reset failed, error=%s\n", 424 usb2_errstr(error)); 425 goto detach; 426 } 427 /* clear stall at first run */ 428 sc->sc_flag |= (UPLCOM_FLAG_READ_STALL | 429 UPLCOM_FLAG_WRITE_STALL); 430 431 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 432 &uplcom_callback, &Giant); 433 if (error) { 434 goto detach; 435 } 436 /* 437 * do the initialization during attach so that the system does not 438 * sleep during open: 439 */ 440 if (sc->sc_chiptype == TYPE_PL2303X) { 441 if (uplcom_pl2303x_init(uaa->device)) { 442 device_printf(dev, "init failed!\n"); 443 goto detach; 444 } 445 } 446 return (0); 447 448detach: 449 uplcom_detach(dev); 450 return (ENXIO); 451} 452 453static int 454uplcom_detach(device_t dev) 455{ 456 struct uplcom_softc *sc = device_get_softc(dev); 457 458 DPRINTF("sc=%p\n", sc); 459 460 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 461 462 usb2_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER); 463 464 return (0); 465} 466 467static usb2_error_t 468uplcom_reset(struct uplcom_softc *sc, struct usb2_device *udev) 469{ 470 struct usb2_device_request req; 471 472 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 473 req.bRequest = UPLCOM_SET_REQUEST; 474 USETW(req.wValue, 0); 475 req.wIndex[0] = sc->sc_data_iface_no; 476 req.wIndex[1] = 0; 477 USETW(req.wLength, 0); 478 479 return (usb2_do_request(udev, &Giant, &req, NULL)); 480} 481 482struct pl2303x_init { 483 uint8_t req_type; 484 uint8_t request; 485 uint16_t value; 486 uint16_t index; 487 uint16_t length; 488}; 489 490static const struct pl2303x_init pl2303x[] = { 491 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 492 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0}, 493 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 494 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 495 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 496 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0}, 497 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 498 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 499 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0}, 500 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0}, 501 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0}, 502 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0}, 503 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0}, 504}; 505 506#define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) 507 508static int 509uplcom_pl2303x_init(struct usb2_device *udev) 510{ 511 struct usb2_device_request req; 512 usb2_error_t err; 513 uint8_t buf[4]; 514 uint8_t i; 515 516 for (i = 0; i != N_PL2302X_INIT; i++) { 517 req.bmRequestType = pl2303x[i].req_type; 518 req.bRequest = pl2303x[i].request; 519 USETW(req.wValue, pl2303x[i].value); 520 USETW(req.wIndex, pl2303x[i].index); 521 USETW(req.wLength, pl2303x[i].length); 522 523 err = usb2_do_request(udev, &Giant, &req, buf); 524 if (err) { 525 DPRINTF("error=%s\n", usb2_errstr(err)); 526 return (EIO); 527 } 528 } 529 return (0); 530} 531 532static void 533uplcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 534{ 535 struct uplcom_softc *sc = ucom->sc_parent; 536 struct usb2_device_request req; 537 538 DPRINTF("onoff = %d\n", onoff); 539 540 if (onoff) 541 sc->sc_line |= UCDC_LINE_DTR; 542 else 543 sc->sc_line &= ~UCDC_LINE_DTR; 544 545 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 546 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 547 USETW(req.wValue, sc->sc_line); 548 req.wIndex[0] = sc->sc_data_iface_no; 549 req.wIndex[1] = 0; 550 USETW(req.wLength, 0); 551 552 uplcom_cfg_do_request(sc, &req, NULL); 553 return; 554} 555 556static void 557uplcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 558{ 559 struct uplcom_softc *sc = ucom->sc_parent; 560 struct usb2_device_request req; 561 562 DPRINTF("onoff = %d\n", onoff); 563 564 if (onoff) 565 sc->sc_line |= UCDC_LINE_RTS; 566 else 567 sc->sc_line &= ~UCDC_LINE_RTS; 568 569 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 570 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 571 USETW(req.wValue, sc->sc_line); 572 req.wIndex[0] = sc->sc_data_iface_no; 573 req.wIndex[1] = 0; 574 USETW(req.wLength, 0); 575 576 uplcom_cfg_do_request(sc, &req, NULL); 577 return; 578} 579 580static void 581uplcom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 582{ 583 struct uplcom_softc *sc = ucom->sc_parent; 584 struct usb2_device_request req; 585 uint16_t temp; 586 587 DPRINTF("onoff = %d\n", onoff); 588 589 temp = (onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 590 591 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 592 req.bRequest = UCDC_SEND_BREAK; 593 USETW(req.wValue, temp); 594 req.wIndex[0] = sc->sc_data_iface_no; 595 req.wIndex[1] = 0; 596 USETW(req.wLength, 0); 597 598 uplcom_cfg_do_request(sc, &req, NULL); 599 return; 600} 601 602static const int32_t uplcom_rates[] = { 603 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 604 19200, 28800, 38400, 57600, 115200, 605 /* 606 * Higher speeds are probably possible. PL2303X supports up to 607 * 6Mb and can set any rate 608 */ 609 230400, 460800, 614400, 921600, 1228800 610}; 611 612#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0])) 613 614static int 615uplcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 616{ 617 uint8_t i; 618 619 DPRINTF("\n"); 620 621 /* check requested baud rate */ 622 623 for (i = 0;; i++) { 624 625 if (i != N_UPLCOM_RATES) { 626 if (uplcom_rates[i] == t->c_ospeed) { 627 break; 628 } 629 } else { 630 DPRINTF("invalid baud rate (%d)\n", t->c_ospeed); 631 return (EIO); 632 } 633 } 634 635 return (0); 636} 637 638static void 639uplcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 640{ 641 struct uplcom_softc *sc = ucom->sc_parent; 642 struct usb2_cdc_line_state ls; 643 struct usb2_device_request req; 644 645 DPRINTF("sc = %p\n", sc); 646 647 bzero(&ls, sizeof(ls)); 648 649 USETDW(ls.dwDTERate, t->c_ospeed); 650 651 if (t->c_cflag & CSTOPB) { 652 ls.bCharFormat = UCDC_STOP_BIT_2; 653 } else { 654 ls.bCharFormat = UCDC_STOP_BIT_1; 655 } 656 657 if (t->c_cflag & PARENB) { 658 if (t->c_cflag & PARODD) { 659 ls.bParityType = UCDC_PARITY_ODD; 660 } else { 661 ls.bParityType = UCDC_PARITY_EVEN; 662 } 663 } else { 664 ls.bParityType = UCDC_PARITY_NONE; 665 } 666 667 switch (t->c_cflag & CSIZE) { 668 case CS5: 669 ls.bDataBits = 5; 670 break; 671 case CS6: 672 ls.bDataBits = 6; 673 break; 674 case CS7: 675 ls.bDataBits = 7; 676 break; 677 case CS8: 678 ls.bDataBits = 8; 679 break; 680 } 681 682 DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", 683 UGETDW(ls.dwDTERate), ls.bCharFormat, 684 ls.bParityType, ls.bDataBits); 685 686 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 687 req.bRequest = UCDC_SET_LINE_CODING; 688 USETW(req.wValue, 0); 689 req.wIndex[0] = sc->sc_data_iface_no; 690 req.wIndex[1] = 0; 691 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 692 693 uplcom_cfg_do_request(sc, &req, &ls); 694 695 if (t->c_cflag & CRTSCTS) { 696 697 DPRINTF("crtscts = on\n"); 698 699 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 700 req.bRequest = UPLCOM_SET_REQUEST; 701 USETW(req.wValue, 0); 702 if (sc->sc_chiptype == TYPE_PL2303X) 703 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X); 704 else 705 USETW(req.wIndex, UPLCOM_SET_CRTSCTS); 706 USETW(req.wLength, 0); 707 708 uplcom_cfg_do_request(sc, &req, NULL); 709 } else { 710 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 711 req.bRequest = UPLCOM_SET_REQUEST; 712 USETW(req.wValue, 0); 713 USETW(req.wIndex, 0); 714 USETW(req.wLength, 0); 715 uplcom_cfg_do_request(sc, &req, NULL); 716 } 717 return; 718} 719 720static void 721uplcom_start_read(struct usb2_com_softc *ucom) 722{ 723 struct uplcom_softc *sc = ucom->sc_parent; 724 725 /* start interrupt endpoint */ 726 usb2_transfer_start(sc->sc_xfer[4]); 727 728 /* start read endpoint */ 729 usb2_transfer_start(sc->sc_xfer[1]); 730 return; 731} 732 733static void 734uplcom_stop_read(struct usb2_com_softc *ucom) 735{ 736 struct uplcom_softc *sc = ucom->sc_parent; 737 738 /* stop interrupt endpoint */ 739 usb2_transfer_stop(sc->sc_xfer[4]); 740 741 /* stop read endpoint */ 742 usb2_transfer_stop(sc->sc_xfer[3]); 743 usb2_transfer_stop(sc->sc_xfer[1]); 744 return; 745} 746 747static void 748uplcom_start_write(struct usb2_com_softc *ucom) 749{ 750 struct uplcom_softc *sc = ucom->sc_parent; 751 752 usb2_transfer_start(sc->sc_xfer[0]); 753 return; 754} 755 756static void 757uplcom_stop_write(struct usb2_com_softc *ucom) 758{ 759 struct uplcom_softc *sc = ucom->sc_parent; 760 761 usb2_transfer_stop(sc->sc_xfer[2]); 762 usb2_transfer_stop(sc->sc_xfer[0]); 763 return; 764} 765 766static void 767uplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 768{ 769 struct uplcom_softc *sc = ucom->sc_parent; 770 771 DPRINTF("\n"); 772 773 *lsr = sc->sc_lsr; 774 *msr = sc->sc_msr; 775 return; 776} 777 778static int 779uplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag, 780 struct thread *td) 781{ 782 return (ENOTTY); 783} 784 785static void 786uplcom_intr_callback(struct usb2_xfer *xfer) 787{ 788 struct uplcom_softc *sc = xfer->priv_sc; 789 uint8_t buf[9]; 790 791 switch (USB_GET_STATE(xfer)) { 792 case USB_ST_TRANSFERRED: 793 794 DPRINTF("actlen = %u\n", xfer->actlen); 795 796 if (xfer->actlen >= 9) { 797 798 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 799 800 DPRINTF("status = 0x%02x\n", buf[8]); 801 802 sc->sc_lsr = 0; 803 sc->sc_msr = 0; 804 805 if (buf[8] & RSAQ_STATUS_CTS) { 806 sc->sc_msr |= SER_CTS; 807 } 808 if (buf[8] & RSAQ_STATUS_DSR) { 809 sc->sc_msr |= SER_DSR; 810 } 811 if (buf[8] & RSAQ_STATUS_DCD) { 812 sc->sc_msr |= SER_DCD; 813 } 814 usb2_com_status_change(&sc->sc_ucom); 815 } 816 case USB_ST_SETUP: 817 if (sc->sc_flag & UPLCOM_FLAG_INTR_STALL) { 818 usb2_transfer_start(sc->sc_xfer[5]); 819 } else { 820 xfer->frlengths[0] = xfer->max_data_length; 821 usb2_start_hardware(xfer); 822 } 823 return; 824 825 default: /* Error */ 826 if (xfer->error != USB_ERR_CANCELLED) { 827 sc->sc_flag |= UPLCOM_FLAG_INTR_STALL; 828 usb2_transfer_start(sc->sc_xfer[5]); 829 } 830 return; 831 832 } 833} 834 835static void 836uplcom_intr_clear_stall_callback(struct usb2_xfer *xfer) 837{ 838 struct uplcom_softc *sc = xfer->priv_sc; 839 struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 840 841 if (usb2_clear_stall_callback(xfer, xfer_other)) { 842 DPRINTF("stall cleared\n"); 843 sc->sc_flag &= ~UPLCOM_FLAG_INTR_STALL; 844 usb2_transfer_start(xfer_other); 845 } 846 return; 847} 848 849static void 850uplcom_write_callback(struct usb2_xfer *xfer) 851{ 852 struct uplcom_softc *sc = xfer->priv_sc; 853 uint32_t actlen; 854 855 switch (USB_GET_STATE(xfer)) { 856 case USB_ST_SETUP: 857 case USB_ST_TRANSFERRED: 858 if (sc->sc_flag & UPLCOM_FLAG_WRITE_STALL) { 859 usb2_transfer_start(sc->sc_xfer[2]); 860 return; 861 } 862 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 863 UPLCOM_BULK_BUF_SIZE, &actlen)) { 864 865 DPRINTF("actlen = %d\n", actlen); 866 867 xfer->frlengths[0] = actlen; 868 usb2_start_hardware(xfer); 869 } 870 return; 871 872 default: /* Error */ 873 if (xfer->error != USB_ERR_CANCELLED) { 874 sc->sc_flag |= UPLCOM_FLAG_WRITE_STALL; 875 usb2_transfer_start(sc->sc_xfer[2]); 876 } 877 return; 878 879 } 880} 881 882static void 883uplcom_write_clear_stall_callback(struct usb2_xfer *xfer) 884{ 885 struct uplcom_softc *sc = xfer->priv_sc; 886 struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 887 888 if (usb2_clear_stall_callback(xfer, xfer_other)) { 889 DPRINTF("stall cleared\n"); 890 sc->sc_flag &= ~UPLCOM_FLAG_WRITE_STALL; 891 usb2_transfer_start(xfer_other); 892 } 893 return; 894} 895 896static void 897uplcom_read_callback(struct usb2_xfer *xfer) 898{ 899 struct uplcom_softc *sc = xfer->priv_sc; 900 901 switch (USB_GET_STATE(xfer)) { 902 case USB_ST_TRANSFERRED: 903 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 904 905 case USB_ST_SETUP: 906 if (sc->sc_flag & UPLCOM_FLAG_READ_STALL) { 907 usb2_transfer_start(sc->sc_xfer[3]); 908 } else { 909 xfer->frlengths[0] = xfer->max_data_length; 910 usb2_start_hardware(xfer); 911 } 912 return; 913 914 default: /* Error */ 915 if (xfer->error != USB_ERR_CANCELLED) { 916 sc->sc_flag |= UPLCOM_FLAG_READ_STALL; 917 usb2_transfer_start(sc->sc_xfer[3]); 918 } 919 return; 920 921 } 922} 923 924static void 925uplcom_read_clear_stall_callback(struct usb2_xfer *xfer) 926{ 927 struct uplcom_softc *sc = xfer->priv_sc; 928 struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 929 930 if (usb2_clear_stall_callback(xfer, xfer_other)) { 931 DPRINTF("stall cleared\n"); 932 sc->sc_flag &= ~UPLCOM_FLAG_READ_STALL; 933 usb2_transfer_start(xfer_other); 934 } 935 return; 936} 937 938static void 939uplcom_cfg_do_request(struct uplcom_softc *sc, struct usb2_device_request *req, 940 void *data) 941{ 942 uint16_t length; 943 usb2_error_t err; 944 945 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 946 goto error; 947 } 948 err = usb2_do_request_flags(sc->sc_udev, &Giant, req, 949 data, 0, NULL, 1000); 950 951 if (err) { 952 953 DPRINTFN(0, "device request failed, err=%s " 954 "(ignored)\n", usb2_errstr(err)); 955 956error: 957 length = UGETW(req->wLength); 958 959 if ((req->bmRequestType & UT_READ) && length) { 960 bzero(data, length); 961 } 962 } 963 return; 964} 965