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