uplcom.c revision 185948
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 185948 2008-12-11 23:13:02Z thompsa $"); 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 *, struct usb2_device *); 162static int uplcom_pl2303x_init(struct usb2_device *); 163static void uplcom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 164static void uplcom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 165static void uplcom_cfg_set_break(struct usb2_com_softc *, uint8_t); 166static int uplcom_pre_param(struct usb2_com_softc *, struct termios *); 167static void uplcom_cfg_param(struct usb2_com_softc *, struct termios *); 168static void uplcom_start_read(struct usb2_com_softc *); 169static void uplcom_stop_read(struct usb2_com_softc *); 170static void uplcom_start_write(struct usb2_com_softc *); 171static void uplcom_stop_write(struct usb2_com_softc *); 172static void uplcom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 173 uint8_t *); 174static int uplcom_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int, 175 struct thread *); 176static void uplcom_cfg_do_request(struct uplcom_softc *, 177 struct usb2_device_request *, void *); 178 179static device_probe_t uplcom_probe; 180static device_attach_t uplcom_attach; 181static device_detach_t uplcom_detach; 182 183static usb2_callback_t uplcom_intr_callback; 184static usb2_callback_t uplcom_intr_clear_stall_callback; 185static usb2_callback_t uplcom_write_callback; 186static usb2_callback_t uplcom_write_clear_stall_callback; 187static usb2_callback_t uplcom_read_callback; 188static usb2_callback_t uplcom_read_clear_stall_callback; 189 190static const struct usb2_config uplcom_config_data[UPLCOM_N_TRANSFER] = { 191 192 [0] = { 193 .type = UE_BULK, 194 .endpoint = UE_ADDR_ANY, 195 .direction = UE_DIR_OUT, 196 .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 197 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 198 .mh.callback = &uplcom_write_callback, 199 .if_index = 0, 200 }, 201 202 [1] = { 203 .type = UE_BULK, 204 .endpoint = UE_ADDR_ANY, 205 .direction = UE_DIR_IN, 206 .mh.bufsize = UPLCOM_BULK_BUF_SIZE, 207 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 208 .mh.callback = &uplcom_read_callback, 209 .if_index = 0, 210 }, 211 212 [2] = { 213 .type = UE_CONTROL, 214 .endpoint = 0x00, /* Control pipe */ 215 .direction = UE_DIR_ANY, 216 .mh.bufsize = sizeof(struct usb2_device_request), 217 .mh.callback = &uplcom_write_clear_stall_callback, 218 .mh.timeout = 1000, /* 1 second */ 219 .mh.interval = 50, /* 50ms */ 220 .if_index = 0, 221 }, 222 223 [3] = { 224 .type = UE_CONTROL, 225 .endpoint = 0x00, /* Control pipe */ 226 .direction = UE_DIR_ANY, 227 .mh.bufsize = sizeof(struct usb2_device_request), 228 .mh.callback = &uplcom_read_clear_stall_callback, 229 .mh.timeout = 1000, /* 1 second */ 230 .mh.interval = 50, /* 50ms */ 231 .if_index = 0, 232 }, 233 234 [4] = { 235 .type = UE_INTERRUPT, 236 .endpoint = UE_ADDR_ANY, 237 .direction = UE_DIR_IN, 238 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 239 .mh.bufsize = 0, /* use wMaxPacketSize */ 240 .mh.callback = &uplcom_intr_callback, 241 .if_index = 1, 242 }, 243 244 [5] = { 245 .type = UE_CONTROL, 246 .endpoint = 0x00, /* Control pipe */ 247 .direction = UE_DIR_ANY, 248 .mh.bufsize = sizeof(struct usb2_device_request), 249 .mh.callback = &uplcom_intr_clear_stall_callback, 250 .mh.timeout = 1000, /* 1 second */ 251 .mh.interval = 50, /* 50ms */ 252 .if_index = 1, 253 }, 254}; 255 256struct usb2_com_callback uplcom_callback = { 257 .usb2_com_cfg_get_status = &uplcom_cfg_get_status, 258 .usb2_com_cfg_set_dtr = &uplcom_cfg_set_dtr, 259 .usb2_com_cfg_set_rts = &uplcom_cfg_set_rts, 260 .usb2_com_cfg_set_break = &uplcom_cfg_set_break, 261 .usb2_com_cfg_param = &uplcom_cfg_param, 262 .usb2_com_pre_param = &uplcom_pre_param, 263 .usb2_com_ioctl = &uplcom_ioctl, 264 .usb2_com_start_read = &uplcom_start_read, 265 .usb2_com_stop_read = &uplcom_stop_read, 266 .usb2_com_start_write = &uplcom_start_write, 267 .usb2_com_stop_write = &uplcom_stop_write, 268}; 269 270#define USB_UPL(v,p,rl,rh,t) \ 271 USB_VENDOR(v), USB_PRODUCT(p), USB_DEV_BCD_GTEQ(rl), \ 272 USB_DEV_BCD_LTEQ(rh), USB_DRIVER_INFO(t) 273 274static const struct usb2_device_id uplcom_devs[] = { 275 /* Belkin F5U257 */ 276 {USB_UPL(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257, 0, 0xFFFF, TYPE_PL2303X)}, 277 /* I/O DATA USB-RSAQ */ 278 {USB_UPL(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, 0, 0xFFFF, TYPE_PL2303)}, 279 /* I/O DATA USB-RSAQ2 */ 280 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, 0, 0xFFFF, TYPE_PL2303)}, 281 /* I/O DATA USB-RSAQ3 */ 282 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, 0, 0xFFFF, TYPE_PL2303X)}, 283 /* PLANEX USB-RS232 URS-03 */ 284 {USB_UPL(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, 0, 0xFFFF, TYPE_PL2303)}, 285 /* TrendNet TU-S9 */ 286 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0400, 0xFFFF, TYPE_PL2303X)}, 287 /* ST Lab USB-SERIAL-4 */ 288 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0300, 0x03FF, TYPE_PL2303X)}, 289 /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */ 290 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0, 0x02FF, TYPE_PL2303)}, 291 /* TDK USB-PHS Adapter UHA6400 */ 292 {USB_UPL(USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, 0, 0xFFFF, TYPE_PL2303)}, 293 /* RATOC REX-USB60 */ 294 {USB_UPL(USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, 0, 0xFFFF, TYPE_PL2303)}, 295 /* ELECOM UC-SGT */ 296 {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, 0, 0xFFFF, TYPE_PL2303)}, 297 {USB_UPL(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, 0, 0xFFFF, TYPE_PL2303)}, 298 /* Sagem USB-Serial Controller */ 299 {USB_UPL(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_USBSERIAL, 0, 0xFFFF, TYPE_PL2303X)}, 300 /* Sony Ericsson USB Cable */ 301 {USB_UPL(USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10, 0, 0xFFFF, TYPE_PL2303)}, 302 /* SOURCENEXT KeikaiDenwa 8 */ 303 {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8, 0, 0xFFFF, TYPE_PL2303)}, 304 /* SOURCENEXT KeikaiDenwa 8 with charger */ 305 {USB_UPL(USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG, 0, 0, TYPE_PL2303)}, 306 /* HAL Corporation Crossam2+USB */ 307 {USB_UPL(USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, 0, 0xFFFF, TYPE_PL2303)}, 308 /* Sitecom USB to Serial */ 309 {USB_UPL(USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_SERIAL, 0, 0xFFFF, TYPE_PL2303)}, 310 /* Tripp-Lite U209-000-R */ 311 {USB_UPL(USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, 0, 0xFFFF, TYPE_PL2303X)}, 312 {USB_UPL(USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE, 0, 0xFFFF, TYPE_PL2303)}, 313 /* Prolific Pharos */ 314 {USB_UPL(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PHAROS, 0, 0xFFFF, TYPE_PL2303)}, 315 /* Willcom W-SIM */ 316 {USB_UPL(USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM, 0, 0xFFFF, TYPE_PL2303X)}, 317}; 318 319static device_method_t uplcom_methods[] = { 320 DEVMETHOD(device_probe, uplcom_probe), 321 DEVMETHOD(device_attach, uplcom_attach), 322 DEVMETHOD(device_detach, uplcom_detach), 323 {0, 0} 324}; 325 326static devclass_t uplcom_devclass; 327 328static driver_t uplcom_driver = { 329 .name = "uplcom", 330 .methods = uplcom_methods, 331 .size = sizeof(struct uplcom_softc), 332}; 333 334DRIVER_MODULE(uplcom, ushub, uplcom_driver, uplcom_devclass, NULL, 0); 335MODULE_DEPEND(uplcom, usb2_serial, 1, 1, 1); 336MODULE_DEPEND(uplcom, usb2_core, 1, 1, 1); 337MODULE_VERSION(uplcom, UPLCOM_MODVER); 338 339static int 340uplcom_probe(device_t dev) 341{ 342 struct usb2_attach_arg *uaa = device_get_ivars(dev); 343 344 DPRINTFN(11, "\n"); 345 346 if (uaa->usb2_mode != USB_MODE_HOST) { 347 return (ENXIO); 348 } 349 if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) { 350 return (ENXIO); 351 } 352 if (uaa->info.bIfaceIndex != UPLCOM_IFACE_INDEX) { 353 return (ENXIO); 354 } 355 return (usb2_lookup_id_by_uaa(uplcom_devs, sizeof(uplcom_devs), uaa)); 356} 357 358static int 359uplcom_attach(device_t dev) 360{ 361 struct usb2_attach_arg *uaa = device_get_ivars(dev); 362 struct uplcom_softc *sc = device_get_softc(dev); 363 struct usb2_interface *iface; 364 struct usb2_interface_descriptor *id; 365 int error; 366 367 DPRINTFN(11, "\n"); 368 369 if (sc == NULL) { 370 return (ENOMEM); 371 } 372 device_set_usb2_desc(dev); 373 374 DPRINTF("sc = %p\n", sc); 375 376 sc->sc_chiptype = USB_GET_DRIVER_INFO(uaa); 377 sc->sc_udev = uaa->device; 378 379 DPRINTF("chiptype: %s\n", 380 (sc->sc_chiptype == TYPE_PL2303X) ? 381 "2303X" : "2303"); 382 383 /* 384 * USB-RSAQ1 has two interface 385 * 386 * USB-RSAQ1 | USB-RSAQ2 387 * -----------------+----------------- 388 * Interface 0 |Interface 0 389 * Interrupt(0x81) | Interrupt(0x81) 390 * -----------------+ BulkIN(0x02) 391 * Interface 1 | BulkOUT(0x83) 392 * BulkIN(0x02) | 393 * BulkOUT(0x83) | 394 */ 395 396 sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; 397 sc->sc_iface_index[1] = UPLCOM_IFACE_INDEX; 398 399 iface = usb2_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX); 400 if (iface) { 401 id = usb2_get_interface_descriptor(iface); 402 if (id == NULL) { 403 device_printf(dev, "no interface descriptor (2)!\n"); 404 goto detach; 405 } 406 sc->sc_data_iface_no = id->bInterfaceNumber; 407 sc->sc_iface_index[0] = UPLCOM_SECOND_IFACE_INDEX; 408 usb2_set_parent_iface(uaa->device, 409 UPLCOM_SECOND_IFACE_INDEX, uaa->info.bIfaceIndex); 410 } else { 411 sc->sc_data_iface_no = sc->sc_ctrl_iface_no; 412 sc->sc_iface_index[0] = UPLCOM_IFACE_INDEX; 413 } 414 415 error = usb2_transfer_setup(uaa->device, 416 sc->sc_iface_index, sc->sc_xfer, uplcom_config_data, 417 UPLCOM_N_TRANSFER, sc, &Giant); 418 if (error) { 419 DPRINTF("one or more missing USB endpoints, " 420 "error=%s\n", usb2_errstr(error)); 421 goto detach; 422 } 423 error = uplcom_reset(sc, uaa->device); 424 if (error) { 425 device_printf(dev, "reset failed, error=%s\n", 426 usb2_errstr(error)); 427 goto detach; 428 } 429 /* clear stall at first run */ 430 sc->sc_flag |= (UPLCOM_FLAG_READ_STALL | 431 UPLCOM_FLAG_WRITE_STALL); 432 433 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 434 &uplcom_callback, &Giant); 435 if (error) { 436 goto detach; 437 } 438 /* 439 * do the initialization during attach so that the system does not 440 * sleep during open: 441 */ 442 if (sc->sc_chiptype == TYPE_PL2303X) { 443 if (uplcom_pl2303x_init(uaa->device)) { 444 device_printf(dev, "init failed!\n"); 445 goto detach; 446 } 447 } 448 return (0); 449 450detach: 451 uplcom_detach(dev); 452 return (ENXIO); 453} 454 455static int 456uplcom_detach(device_t dev) 457{ 458 struct uplcom_softc *sc = device_get_softc(dev); 459 460 DPRINTF("sc=%p\n", sc); 461 462 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 463 464 usb2_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER); 465 466 return (0); 467} 468 469static usb2_error_t 470uplcom_reset(struct uplcom_softc *sc, struct usb2_device *udev) 471{ 472 struct usb2_device_request req; 473 474 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 475 req.bRequest = UPLCOM_SET_REQUEST; 476 USETW(req.wValue, 0); 477 req.wIndex[0] = sc->sc_data_iface_no; 478 req.wIndex[1] = 0; 479 USETW(req.wLength, 0); 480 481 return (usb2_do_request(udev, &Giant, &req, NULL)); 482} 483 484struct pl2303x_init { 485 uint8_t req_type; 486 uint8_t request; 487 uint16_t value; 488 uint16_t index; 489 uint16_t length; 490}; 491 492static const struct pl2303x_init pl2303x[] = { 493 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 494 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0}, 495 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 496 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 497 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 498 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0}, 499 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1}, 500 {UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1}, 501 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0}, 502 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0}, 503 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0}, 504 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0}, 505 {UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0}, 506}; 507 508#define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) 509 510static int 511uplcom_pl2303x_init(struct usb2_device *udev) 512{ 513 struct usb2_device_request req; 514 usb2_error_t err; 515 uint8_t buf[4]; 516 uint8_t i; 517 518 for (i = 0; i != N_PL2302X_INIT; i++) { 519 req.bmRequestType = pl2303x[i].req_type; 520 req.bRequest = pl2303x[i].request; 521 USETW(req.wValue, pl2303x[i].value); 522 USETW(req.wIndex, pl2303x[i].index); 523 USETW(req.wLength, pl2303x[i].length); 524 525 err = usb2_do_request(udev, &Giant, &req, buf); 526 if (err) { 527 DPRINTF("error=%s\n", usb2_errstr(err)); 528 return (EIO); 529 } 530 } 531 return (0); 532} 533 534static void 535uplcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 536{ 537 struct uplcom_softc *sc = ucom->sc_parent; 538 struct usb2_device_request req; 539 540 DPRINTF("onoff = %d\n", onoff); 541 542 if (onoff) 543 sc->sc_line |= UCDC_LINE_DTR; 544 else 545 sc->sc_line &= ~UCDC_LINE_DTR; 546 547 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 548 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 549 USETW(req.wValue, sc->sc_line); 550 req.wIndex[0] = sc->sc_data_iface_no; 551 req.wIndex[1] = 0; 552 USETW(req.wLength, 0); 553 554 uplcom_cfg_do_request(sc, &req, NULL); 555 return; 556} 557 558static void 559uplcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 560{ 561 struct uplcom_softc *sc = ucom->sc_parent; 562 struct usb2_device_request req; 563 564 DPRINTF("onoff = %d\n", onoff); 565 566 if (onoff) 567 sc->sc_line |= UCDC_LINE_RTS; 568 else 569 sc->sc_line &= ~UCDC_LINE_RTS; 570 571 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 572 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 573 USETW(req.wValue, sc->sc_line); 574 req.wIndex[0] = sc->sc_data_iface_no; 575 req.wIndex[1] = 0; 576 USETW(req.wLength, 0); 577 578 uplcom_cfg_do_request(sc, &req, NULL); 579 return; 580} 581 582static void 583uplcom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 584{ 585 struct uplcom_softc *sc = ucom->sc_parent; 586 struct usb2_device_request req; 587 uint16_t temp; 588 589 DPRINTF("onoff = %d\n", onoff); 590 591 temp = (onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 592 593 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 594 req.bRequest = UCDC_SEND_BREAK; 595 USETW(req.wValue, temp); 596 req.wIndex[0] = sc->sc_data_iface_no; 597 req.wIndex[1] = 0; 598 USETW(req.wLength, 0); 599 600 uplcom_cfg_do_request(sc, &req, NULL); 601 return; 602} 603 604static const int32_t uplcom_rates[] = { 605 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 606 19200, 28800, 38400, 57600, 115200, 607 /* 608 * Higher speeds are probably possible. PL2303X supports up to 609 * 6Mb and can set any rate 610 */ 611 230400, 460800, 614400, 921600, 1228800 612}; 613 614#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0])) 615 616static int 617uplcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 618{ 619 uint8_t i; 620 621 DPRINTF("\n"); 622 623 /* check requested baud rate */ 624 625 for (i = 0;; i++) { 626 627 if (i != N_UPLCOM_RATES) { 628 if (uplcom_rates[i] == t->c_ospeed) { 629 break; 630 } 631 } else { 632 DPRINTF("invalid baud rate (%d)\n", t->c_ospeed); 633 return (EIO); 634 } 635 } 636 637 return (0); 638} 639 640static void 641uplcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 642{ 643 struct uplcom_softc *sc = ucom->sc_parent; 644 struct usb2_cdc_line_state ls; 645 struct usb2_device_request req; 646 647 DPRINTF("sc = %p\n", sc); 648 649 bzero(&ls, sizeof(ls)); 650 651 USETDW(ls.dwDTERate, t->c_ospeed); 652 653 if (t->c_cflag & CSTOPB) { 654 ls.bCharFormat = UCDC_STOP_BIT_2; 655 } else { 656 ls.bCharFormat = UCDC_STOP_BIT_1; 657 } 658 659 if (t->c_cflag & PARENB) { 660 if (t->c_cflag & PARODD) { 661 ls.bParityType = UCDC_PARITY_ODD; 662 } else { 663 ls.bParityType = UCDC_PARITY_EVEN; 664 } 665 } else { 666 ls.bParityType = UCDC_PARITY_NONE; 667 } 668 669 switch (t->c_cflag & CSIZE) { 670 case CS5: 671 ls.bDataBits = 5; 672 break; 673 case CS6: 674 ls.bDataBits = 6; 675 break; 676 case CS7: 677 ls.bDataBits = 7; 678 break; 679 case CS8: 680 ls.bDataBits = 8; 681 break; 682 } 683 684 DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", 685 UGETDW(ls.dwDTERate), ls.bCharFormat, 686 ls.bParityType, ls.bDataBits); 687 688 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 689 req.bRequest = UCDC_SET_LINE_CODING; 690 USETW(req.wValue, 0); 691 req.wIndex[0] = sc->sc_data_iface_no; 692 req.wIndex[1] = 0; 693 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 694 695 uplcom_cfg_do_request(sc, &req, &ls); 696 697 if (t->c_cflag & CRTSCTS) { 698 699 DPRINTF("crtscts = on\n"); 700 701 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 702 req.bRequest = UPLCOM_SET_REQUEST; 703 USETW(req.wValue, 0); 704 if (sc->sc_chiptype == TYPE_PL2303X) 705 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X); 706 else 707 USETW(req.wIndex, UPLCOM_SET_CRTSCTS); 708 USETW(req.wLength, 0); 709 710 uplcom_cfg_do_request(sc, &req, NULL); 711 } else { 712 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 713 req.bRequest = UPLCOM_SET_REQUEST; 714 USETW(req.wValue, 0); 715 USETW(req.wIndex, 0); 716 USETW(req.wLength, 0); 717 uplcom_cfg_do_request(sc, &req, NULL); 718 } 719 return; 720} 721 722static void 723uplcom_start_read(struct usb2_com_softc *ucom) 724{ 725 struct uplcom_softc *sc = ucom->sc_parent; 726 727 /* start interrupt endpoint */ 728 usb2_transfer_start(sc->sc_xfer[4]); 729 730 /* start read endpoint */ 731 usb2_transfer_start(sc->sc_xfer[1]); 732 return; 733} 734 735static void 736uplcom_stop_read(struct usb2_com_softc *ucom) 737{ 738 struct uplcom_softc *sc = ucom->sc_parent; 739 740 /* stop interrupt endpoint */ 741 usb2_transfer_stop(sc->sc_xfer[4]); 742 743 /* stop read endpoint */ 744 usb2_transfer_stop(sc->sc_xfer[3]); 745 usb2_transfer_stop(sc->sc_xfer[1]); 746 return; 747} 748 749static void 750uplcom_start_write(struct usb2_com_softc *ucom) 751{ 752 struct uplcom_softc *sc = ucom->sc_parent; 753 754 usb2_transfer_start(sc->sc_xfer[0]); 755 return; 756} 757 758static void 759uplcom_stop_write(struct usb2_com_softc *ucom) 760{ 761 struct uplcom_softc *sc = ucom->sc_parent; 762 763 usb2_transfer_stop(sc->sc_xfer[2]); 764 usb2_transfer_stop(sc->sc_xfer[0]); 765 return; 766} 767 768static void 769uplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 770{ 771 struct uplcom_softc *sc = ucom->sc_parent; 772 773 DPRINTF("\n"); 774 775 *lsr = sc->sc_lsr; 776 *msr = sc->sc_msr; 777 return; 778} 779 780static int 781uplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag, 782 struct thread *td) 783{ 784 return (ENOTTY); 785} 786 787static void 788uplcom_intr_callback(struct usb2_xfer *xfer) 789{ 790 struct uplcom_softc *sc = xfer->priv_sc; 791 uint8_t buf[9]; 792 793 switch (USB_GET_STATE(xfer)) { 794 case USB_ST_TRANSFERRED: 795 796 DPRINTF("actlen = %u\n", xfer->actlen); 797 798 if (xfer->actlen >= 9) { 799 800 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 801 802 DPRINTF("status = 0x%02x\n", buf[8]); 803 804 sc->sc_lsr = 0; 805 sc->sc_msr = 0; 806 807 if (buf[8] & RSAQ_STATUS_CTS) { 808 sc->sc_msr |= SER_CTS; 809 } 810 if (buf[8] & RSAQ_STATUS_DSR) { 811 sc->sc_msr |= SER_DSR; 812 } 813 if (buf[8] & RSAQ_STATUS_DCD) { 814 sc->sc_msr |= SER_DCD; 815 } 816 usb2_com_status_change(&sc->sc_ucom); 817 } 818 case USB_ST_SETUP: 819 if (sc->sc_flag & UPLCOM_FLAG_INTR_STALL) { 820 usb2_transfer_start(sc->sc_xfer[5]); 821 } else { 822 xfer->frlengths[0] = xfer->max_data_length; 823 usb2_start_hardware(xfer); 824 } 825 return; 826 827 default: /* Error */ 828 if (xfer->error != USB_ERR_CANCELLED) { 829 sc->sc_flag |= UPLCOM_FLAG_INTR_STALL; 830 usb2_transfer_start(sc->sc_xfer[5]); 831 } 832 return; 833 834 } 835} 836 837static void 838uplcom_intr_clear_stall_callback(struct usb2_xfer *xfer) 839{ 840 struct uplcom_softc *sc = xfer->priv_sc; 841 struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 842 843 if (usb2_clear_stall_callback(xfer, xfer_other)) { 844 DPRINTF("stall cleared\n"); 845 sc->sc_flag &= ~UPLCOM_FLAG_INTR_STALL; 846 usb2_transfer_start(xfer_other); 847 } 848 return; 849} 850 851static void 852uplcom_write_callback(struct usb2_xfer *xfer) 853{ 854 struct uplcom_softc *sc = xfer->priv_sc; 855 uint32_t actlen; 856 857 switch (USB_GET_STATE(xfer)) { 858 case USB_ST_SETUP: 859 case USB_ST_TRANSFERRED: 860 if (sc->sc_flag & UPLCOM_FLAG_WRITE_STALL) { 861 usb2_transfer_start(sc->sc_xfer[2]); 862 return; 863 } 864 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 865 UPLCOM_BULK_BUF_SIZE, &actlen)) { 866 867 DPRINTF("actlen = %d\n", actlen); 868 869 xfer->frlengths[0] = actlen; 870 usb2_start_hardware(xfer); 871 } 872 return; 873 874 default: /* Error */ 875 if (xfer->error != USB_ERR_CANCELLED) { 876 sc->sc_flag |= UPLCOM_FLAG_WRITE_STALL; 877 usb2_transfer_start(sc->sc_xfer[2]); 878 } 879 return; 880 881 } 882} 883 884static void 885uplcom_write_clear_stall_callback(struct usb2_xfer *xfer) 886{ 887 struct uplcom_softc *sc = xfer->priv_sc; 888 struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 889 890 if (usb2_clear_stall_callback(xfer, xfer_other)) { 891 DPRINTF("stall cleared\n"); 892 sc->sc_flag &= ~UPLCOM_FLAG_WRITE_STALL; 893 usb2_transfer_start(xfer_other); 894 } 895 return; 896} 897 898static void 899uplcom_read_callback(struct usb2_xfer *xfer) 900{ 901 struct uplcom_softc *sc = xfer->priv_sc; 902 903 switch (USB_GET_STATE(xfer)) { 904 case USB_ST_TRANSFERRED: 905 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 906 907 case USB_ST_SETUP: 908 if (sc->sc_flag & UPLCOM_FLAG_READ_STALL) { 909 usb2_transfer_start(sc->sc_xfer[3]); 910 } else { 911 xfer->frlengths[0] = xfer->max_data_length; 912 usb2_start_hardware(xfer); 913 } 914 return; 915 916 default: /* Error */ 917 if (xfer->error != USB_ERR_CANCELLED) { 918 sc->sc_flag |= UPLCOM_FLAG_READ_STALL; 919 usb2_transfer_start(sc->sc_xfer[3]); 920 } 921 return; 922 923 } 924} 925 926static void 927uplcom_read_clear_stall_callback(struct usb2_xfer *xfer) 928{ 929 struct uplcom_softc *sc = xfer->priv_sc; 930 struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 931 932 if (usb2_clear_stall_callback(xfer, xfer_other)) { 933 DPRINTF("stall cleared\n"); 934 sc->sc_flag &= ~UPLCOM_FLAG_READ_STALL; 935 usb2_transfer_start(xfer_other); 936 } 937 return; 938} 939 940static void 941uplcom_cfg_do_request(struct uplcom_softc *sc, struct usb2_device_request *req, 942 void *data) 943{ 944 uint16_t length; 945 usb2_error_t err; 946 947 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 948 goto error; 949 } 950 err = usb2_do_request_flags(sc->sc_udev, &Giant, req, 951 data, 0, NULL, 1000); 952 953 if (err) { 954 955 DPRINTFN(0, "device request failed, err=%s " 956 "(ignored)\n", usb2_errstr(err)); 957 958error: 959 length = UGETW(req->wLength); 960 961 if ((req->bmRequestType & UT_READ) && length) { 962 bzero(data, length); 963 } 964 } 965 return; 966} 967