1 /* $NetBSD: uplcom.c,v 1.89 2020/03/14 03:01:36 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Ichiro FUKUHARA (ichiro@ichiro.org). 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * General information: http://www.prolific.com.tw/fr_pl2303.htm 34 * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.89 2020/03/14 03:01:36 christos Exp $"); 39 40 #ifdef _KERNEL_OPT 41 #include "opt_usb.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/kmem.h> 48 #include <sys/ioctl.h> 49 #include <sys/conf.h> 50 #include <sys/tty.h> 51 #include <sys/file.h> 52 #include <sys/select.h> 53 #include <sys/proc.h> 54 #include <sys/device.h> 55 #include <sys/poll.h> 56 #include <sys/sysctl.h> 57 58 #include <dev/usb/usb.h> 59 #include <dev/usb/usbcdc.h> 60 61 #include <dev/usb/usbdi.h> 62 #include <dev/usb/usbdi_util.h> 63 #include <dev/usb/usbdevs.h> 64 #include <dev/usb/usb_quirks.h> 65 #include <dev/usb/usbhist.h> 66 67 #include <dev/usb/ucomvar.h> 68 69 #ifdef USB_DEBUG 70 #ifndef UPLCOM_DEBUG 71 #define uplcomdebug 0 72 #else 73 int uplcomdebug = 0; 74 75 SYSCTL_SETUP(sysctl_hw_uplcom_setup, "sysctl hw.uplcom setup") 76 { 77 int err; 78 const struct sysctlnode *rnode; 79 const struct sysctlnode *cnode; 80 81 err = sysctl_createv(clog, 0, NULL, &rnode, 82 CTLFLAG_PERMANENT, CTLTYPE_NODE, "uplcom", 83 SYSCTL_DESCR("uplcom global controls"), 84 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 85 86 if (err) 87 goto fail; 88 89 /* control debugging printfs */ 90 err = sysctl_createv(clog, 0, &rnode, &cnode, 91 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 92 "debug", SYSCTL_DESCR("Enable debugging output"), 93 NULL, 0, &uplcomdebug, sizeof(uplcomdebug), CTL_CREATE, CTL_EOL); 94 if (err) 95 goto fail; 96 97 return; 98 fail: 99 aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); 100 } 101 102 #endif /* UCOM_DEBUG */ 103 #endif /* USB_DEBUG */ 104 105 106 #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(uplcomdebug,1,FMT,A,B,C,D) 107 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(uplcomdebug,N,FMT,A,B,C,D) 108 #define UPLCOMHIST_FUNC() USBHIST_FUNC() 109 #define UPLCOMHIST_CALLED(name) USBHIST_CALLED(uplcomdebug) 110 111 #define UPLCOM_CONFIG_INDEX 0 112 #define UPLCOM_IFACE_INDEX 0 113 #define UPLCOM_SECOND_IFACE_INDEX 1 114 115 #define UPLCOM_SET_REQUEST 0x01 116 #define UPLCOM_SET_CRTSCTS_0 0x41 117 #define UPLCOM_SET_CRTSCTS_HX 0x61 118 119 #define UPLCOM_N_SERIAL_CTS 0x80 120 121 enum pl2303_type { 122 UPLCOM_TYPE_0, /* we use this for all non-HX variants */ 123 UPLCOM_TYPE_HX, 124 }; 125 126 struct uplcom_softc { 127 device_t sc_dev; /* base device */ 128 struct usbd_device * sc_udev; /* USB device */ 129 struct usbd_interface * sc_iface; /* interface */ 130 int sc_iface_number; /* interface number */ 131 132 struct usbd_interface * sc_intr_iface; /* interrupt interface */ 133 int sc_intr_number; /* interrupt number */ 134 struct usbd_pipe * sc_intr_pipe; /* interrupt pipe */ 135 u_char *sc_intr_buf; /* interrupt buffer */ 136 int sc_isize; 137 138 usb_cdc_line_state_t sc_line_state; /* current line state */ 139 int sc_dtr; /* current DTR state */ 140 int sc_rts; /* current RTS state */ 141 142 device_t sc_subdev; /* ucom device */ 143 144 bool sc_dying; /* disconnecting */ 145 146 u_char sc_lsr; /* Local status register */ 147 u_char sc_msr; /* uplcom status register */ 148 149 enum pl2303_type sc_type; /* PL2303 chip type */ 150 }; 151 152 /* 153 * These are the maximum number of bytes transferred per frame. 154 * The output buffer size cannot be increased due to the size encoding. 155 */ 156 #define UPLCOMIBUFSIZE 256 157 #define UPLCOMOBUFSIZE 256 158 159 static usbd_status uplcom_reset(struct uplcom_softc *); 160 static usbd_status uplcom_set_line_coding(struct uplcom_softc *, 161 usb_cdc_line_state_t *); 162 static usbd_status uplcom_set_crtscts(struct uplcom_softc *); 163 static void uplcom_intr(struct usbd_xfer *, void *, usbd_status); 164 165 static void uplcom_set(void *, int, int, int); 166 static void uplcom_dtr(struct uplcom_softc *, int); 167 static void uplcom_rts(struct uplcom_softc *, int); 168 static void uplcom_break(struct uplcom_softc *, int); 169 static void uplcom_set_line_state(struct uplcom_softc *); 170 static void uplcom_get_status(void *, int, u_char *, u_char *); 171 #if TODO 172 static int uplcom_ioctl(void *, int, u_long, void *, int, proc_t *); 173 #endif 174 static int uplcom_param(void *, int, struct termios *); 175 static int uplcom_open(void *, int); 176 static void uplcom_close(void *, int); 177 static usbd_status uplcom_vendor_control_write(struct usbd_device *, uint16_t, uint16_t); 178 static void uplcom_close_pipe(struct uplcom_softc *); 179 180 static const struct ucom_methods uplcom_methods = { 181 .ucom_get_status = uplcom_get_status, 182 .ucom_set = uplcom_set, 183 .ucom_param = uplcom_param, 184 .ucom_ioctl = NULL, /* TODO */ 185 .ucom_open = uplcom_open, 186 .ucom_close = uplcom_close, 187 }; 188 189 static const struct usb_devno uplcom_devs[] = { 190 /* I/O DATA USB-RSAQ2 */ 191 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 }, 192 /* I/O DATA USB-RSAQ3 */ 193 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 }, 194 /* I/O DATA USB-RSAQ */ 195 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ }, 196 /* I/O DATA USB-RSAQ5 */ 197 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 }, 198 /* PLANEX USB-RS232 URS-03 */ 199 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A }, 200 /* various */ 201 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 }, 202 /* SMART Technologies USB to serial */ 203 { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 }, 204 /* IOGEAR/ATENTRIPPLITE */ 205 { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 }, 206 /* ELECOM UC-SGT */ 207 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT }, 208 /* ELECOM UC-SGT0 */ 209 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 }, 210 /* Panasonic 50" Touch Panel */ 211 { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S }, 212 /* RATOC REX-USB60 */ 213 { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 }, 214 /* TDK USB-PHS Adapter UHA6400 */ 215 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 }, 216 /* TDK USB-PDC Adapter UPA9664 */ 217 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 }, 218 /* Sony Ericsson USB Cable */ 219 { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 }, 220 /* SOURCENEXT KeikaiDenwa 8 */ 221 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 }, 222 /* SOURCENEXT KeikaiDenwa 8 with charger */ 223 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG }, 224 /* HAL Corporation Crossam2+USB */ 225 { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 }, 226 /* Sitecom USB to serial cable */ 227 { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 }, 228 /* Pharos USB GPS - Microsoft version */ 229 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X }, 230 /* Willcom WS002IN (DD) */ 231 { USB_VENDOR_NETINDEX, USB_PRODUCT_NETINDEX_WS002IN }, 232 /* COREGA CG-USBRS232R */ 233 { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGUSBRS232R }, 234 /* Sharp CE-175TU (USB to Zaurus option port 15 adapter) */ 235 { USB_VENDOR_SHARP, USB_PRODUCT_SHARP_CE175TU }, 236 }; 237 #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p) 238 239 static int uplcom_match(device_t, cfdata_t, void *); 240 static void uplcom_attach(device_t, device_t, void *); 241 static void uplcom_childdet(device_t, device_t); 242 static int uplcom_detach(device_t, int); 243 244 CFATTACH_DECL2_NEW(uplcom, sizeof(struct uplcom_softc), uplcom_match, 245 uplcom_attach, uplcom_detach, NULL, NULL, uplcom_childdet); 246 247 static int 248 uplcom_match(device_t parent, cfdata_t match, void *aux) 249 { 250 struct usb_attach_arg *uaa = aux; 251 252 return uplcom_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? 253 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 254 } 255 256 static void 257 uplcom_attach(device_t parent, device_t self, void *aux) 258 { 259 struct uplcom_softc *sc = device_private(self); 260 struct usb_attach_arg *uaa = aux; 261 struct usbd_device *dev = uaa->uaa_device; 262 usb_device_descriptor_t *ddesc; 263 usb_config_descriptor_t *cdesc; 264 usb_interface_descriptor_t *id; 265 usb_endpoint_descriptor_t *ed; 266 char *devinfop; 267 const char *devname = device_xname(self); 268 usbd_status err; 269 int i; 270 struct ucom_attach_args ucaa; 271 272 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 273 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 274 275 sc->sc_dev = self; 276 sc->sc_dying = false; 277 278 aprint_naive("\n"); 279 aprint_normal("\n"); 280 281 devinfop = usbd_devinfo_alloc(dev, 0); 282 aprint_normal_dev(self, "%s\n", devinfop); 283 usbd_devinfo_free(devinfop); 284 285 sc->sc_udev = dev; 286 287 /* initialize endpoints */ 288 ucaa.ucaa_bulkin = ucaa.ucaa_bulkout = -1; 289 sc->sc_intr_number = -1; 290 sc->sc_intr_pipe = NULL; 291 292 /* Move the device into the configured state. */ 293 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1); 294 if (err) { 295 aprint_error("\n%s: failed to set configuration, err=%s\n", 296 devname, usbd_errstr(err)); 297 sc->sc_dying = true; 298 return; 299 } 300 301 /* determine chip type */ 302 ddesc = usbd_get_device_descriptor(dev); 303 if (ddesc->bDeviceClass != UDCLASS_COMM && 304 ddesc->bMaxPacketSize == 0x40) 305 sc->sc_type = UPLCOM_TYPE_HX; 306 307 #ifdef UPLCOM_DEBUG 308 /* print the chip type */ 309 if (sc->sc_type == UPLCOM_TYPE_HX) { 310 DPRINTF("chiptype HX", 0, 0, 0, 0); 311 } else { 312 DPRINTF("chiptype 0", 0, 0, 0, 0); 313 } 314 #endif 315 316 /* Move the device into the configured state. */ 317 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1); 318 if (err) { 319 aprint_error_dev(self, "failed to set configuration: %s\n", 320 usbd_errstr(err)); 321 sc->sc_dying = true; 322 return; 323 } 324 325 /* get the config descriptor */ 326 cdesc = usbd_get_config_descriptor(sc->sc_udev); 327 328 if (cdesc == NULL) { 329 aprint_error_dev(self, 330 "failed to get configuration descriptor\n"); 331 sc->sc_dying = true; 332 return; 333 } 334 335 /* get the (first/common) interface */ 336 err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, 337 &sc->sc_iface); 338 if (err) { 339 aprint_error("\n%s: failed to get interface, err=%s\n", 340 devname, usbd_errstr(err)); 341 sc->sc_dying = true; 342 return; 343 } 344 345 /* Find the interrupt endpoints */ 346 347 id = usbd_get_interface_descriptor(sc->sc_iface); 348 sc->sc_iface_number = id->bInterfaceNumber; 349 350 for (i = 0; i < id->bNumEndpoints; i++) { 351 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 352 if (ed == NULL) { 353 aprint_error_dev(self, 354 "no endpoint descriptor for %d\n", i); 355 sc->sc_dying = true; 356 return; 357 } 358 359 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 360 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 361 sc->sc_intr_number = ed->bEndpointAddress; 362 sc->sc_isize = UGETW(ed->wMaxPacketSize); 363 } 364 } 365 366 if (sc->sc_intr_number== -1) { 367 aprint_error_dev(self, "Could not find interrupt in\n"); 368 sc->sc_dying = true; 369 return; 370 } 371 372 /* keep interface for interrupt */ 373 sc->sc_intr_iface = sc->sc_iface; 374 375 /* 376 * USB-RSAQ1 has two interface 377 * 378 * USB-RSAQ1 | USB-RSAQ2 379 * -----------------+----------------- 380 * Interface 0 |Interface 0 381 * Interrupt(0x81) | Interrupt(0x81) 382 * -----------------+ BulkIN(0x02) 383 * Interface 1 | BulkOUT(0x83) 384 * BulkIN(0x02) | 385 * BulkOUT(0x83) | 386 */ 387 if (cdesc->bNumInterface == 2) { 388 err = usbd_device2interface_handle(dev, 389 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface); 390 if (err) { 391 aprint_error("\n%s: failed to get second interface, " 392 "err=%s\n", devname, usbd_errstr(err)); 393 sc->sc_dying = true; 394 return; 395 } 396 } 397 398 /* Find the bulk{in,out} endpoints */ 399 400 id = usbd_get_interface_descriptor(sc->sc_iface); 401 sc->sc_iface_number = id->bInterfaceNumber; 402 403 for (i = 0; i < id->bNumEndpoints; i++) { 404 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 405 if (ed == NULL) { 406 aprint_error_dev(self, 407 "no endpoint descriptor for %d\n", i); 408 sc->sc_dying = true; 409 return; 410 } 411 412 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 413 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 414 ucaa.ucaa_bulkin = ed->bEndpointAddress; 415 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 416 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 417 ucaa.ucaa_bulkout = ed->bEndpointAddress; 418 } 419 } 420 421 if (ucaa.ucaa_bulkin == -1) { 422 aprint_error_dev(self, "Could not find data bulk in\n"); 423 sc->sc_dying = true; 424 return; 425 } 426 427 if (ucaa.ucaa_bulkout == -1) { 428 aprint_error_dev(self, "Could not find data bulk out\n"); 429 sc->sc_dying = true; 430 return; 431 } 432 433 sc->sc_dtr = sc->sc_rts = -1; 434 ucaa.ucaa_portno = UCOM_UNK_PORTNO; 435 /* ucaa_bulkin, ucaa_bulkout set above */ 436 ucaa.ucaa_ibufsize = UPLCOMIBUFSIZE; 437 ucaa.ucaa_obufsize = UPLCOMOBUFSIZE; 438 ucaa.ucaa_ibufsizepad = UPLCOMIBUFSIZE; 439 ucaa.ucaa_opkthdrlen = 0; 440 ucaa.ucaa_device = dev; 441 ucaa.ucaa_iface = sc->sc_iface; 442 ucaa.ucaa_methods = &uplcom_methods; 443 ucaa.ucaa_arg = sc; 444 ucaa.ucaa_info = NULL; 445 446 err = uplcom_reset(sc); 447 448 if (err) { 449 aprint_error_dev(self, "reset failed, %s\n", usbd_errstr(err)); 450 sc->sc_dying = true; 451 return; 452 } 453 454 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); 455 456 DPRINTF("in=%#jx out=%#jx intr=%#jx", 457 ucaa.ucaa_bulkin, ucaa.ucaa_bulkout, sc->sc_intr_number, 0); 458 sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &ucaa, 459 ucomprint, ucomsubmatch); 460 461 if (!pmf_device_register(self, NULL, NULL)) 462 aprint_error_dev(self, "couldn't establish power handler\n"); 463 464 return; 465 } 466 467 static void 468 uplcom_childdet(device_t self, device_t child) 469 { 470 struct uplcom_softc *sc = device_private(self); 471 472 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 473 474 KASSERT(sc->sc_subdev == child); 475 sc->sc_subdev = NULL; 476 } 477 478 static void 479 uplcom_close_pipe(struct uplcom_softc *sc) 480 { 481 482 if (sc->sc_intr_pipe != NULL) { 483 usbd_abort_pipe(sc->sc_intr_pipe); 484 usbd_close_pipe(sc->sc_intr_pipe); 485 sc->sc_intr_pipe = NULL; 486 } 487 if (sc->sc_intr_buf != NULL) { 488 kmem_free(sc->sc_intr_buf, sc->sc_isize); 489 sc->sc_intr_buf = NULL; 490 } 491 } 492 493 static int 494 uplcom_detach(device_t self, int flags) 495 { 496 struct uplcom_softc *sc = device_private(self); 497 int rv = 0; 498 499 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 500 DPRINTF("sc=%#jx flags=%jd", (uintptr_t)sc, flags, 0, 0); 501 502 sc->sc_dying = true; 503 504 uplcom_close_pipe(sc); 505 506 if (sc->sc_subdev != NULL) { 507 rv = config_detach(sc->sc_subdev, flags); 508 sc->sc_subdev = NULL; 509 } 510 511 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); 512 513 pmf_device_deregister(self); 514 515 return rv; 516 } 517 518 usbd_status 519 uplcom_reset(struct uplcom_softc *sc) 520 { 521 usb_device_request_t req; 522 usbd_status err; 523 524 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 525 req.bRequest = UPLCOM_SET_REQUEST; 526 USETW(req.wValue, 0); 527 USETW(req.wIndex, sc->sc_iface_number); 528 USETW(req.wLength, 0); 529 530 err = usbd_do_request(sc->sc_udev, &req, 0); 531 if (err) 532 return EIO; 533 534 return 0; 535 } 536 537 struct pl2303x_init { 538 uint8_t req_type; 539 uint8_t request; 540 uint16_t value; 541 uint16_t index; 542 }; 543 544 static const struct pl2303x_init pl2303x[] = { 545 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 546 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0 }, 547 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 548 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0 }, 549 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 550 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1 }, 551 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 552 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0 }, 553 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1 }, 554 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0 }, 555 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44 } 556 }; 557 #define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) 558 559 static usbd_status 560 uplcom_pl2303x_init(struct uplcom_softc *sc) 561 { 562 usb_device_request_t req; 563 usbd_status err; 564 int i; 565 566 for (i = 0; i < N_PL2302X_INIT; i++) { 567 char buf[1]; 568 void *b; 569 570 req.bmRequestType = pl2303x[i].req_type; 571 req.bRequest = pl2303x[i].request; 572 USETW(req.wValue, pl2303x[i].value); 573 USETW(req.wIndex, pl2303x[i].index); 574 if (UT_GET_DIR(req.bmRequestType) == UT_READ) { 575 b = buf; 576 USETW(req.wLength, sizeof(buf)); 577 } else { 578 b = NULL; 579 USETW(req.wLength, 0); 580 } 581 582 err = usbd_do_request(sc->sc_udev, &req, b); 583 if (err) { 584 aprint_error_dev(sc->sc_dev, 585 "uplcom_pl2303x_init failed: %s\n", 586 usbd_errstr(err)); 587 return EIO; 588 } 589 } 590 591 return 0; 592 } 593 594 static void 595 uplcom_set_line_state(struct uplcom_softc *sc) 596 { 597 usb_device_request_t req; 598 int ls; 599 600 /* make sure we have initialized state for sc_dtr and sc_rts */ 601 if (sc->sc_dtr == -1) 602 sc->sc_dtr = 0; 603 if (sc->sc_rts == -1) 604 sc->sc_rts = 0; 605 606 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | 607 (sc->sc_rts ? UCDC_LINE_RTS : 0); 608 609 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 610 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 611 USETW(req.wValue, ls); 612 USETW(req.wIndex, sc->sc_iface_number); 613 USETW(req.wLength, 0); 614 615 (void)usbd_do_request(sc->sc_udev, &req, 0); 616 } 617 618 static void 619 uplcom_set(void *addr, int portno, int reg, int onoff) 620 { 621 struct uplcom_softc *sc = addr; 622 623 if (sc->sc_dying) 624 return; 625 626 switch (reg) { 627 case UCOM_SET_DTR: 628 uplcom_dtr(sc, onoff); 629 break; 630 case UCOM_SET_RTS: 631 uplcom_rts(sc, onoff); 632 break; 633 case UCOM_SET_BREAK: 634 uplcom_break(sc, onoff); 635 break; 636 default: 637 break; 638 } 639 } 640 641 static void 642 uplcom_dtr(struct uplcom_softc *sc, int onoff) 643 { 644 645 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 646 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 647 648 if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff) 649 return; 650 651 sc->sc_dtr = !!onoff; 652 653 uplcom_set_line_state(sc); 654 } 655 656 static void 657 uplcom_rts(struct uplcom_softc *sc, int onoff) 658 { 659 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 660 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 661 662 if (sc->sc_rts != -1 && !sc->sc_rts == !onoff) 663 return; 664 665 sc->sc_rts = !!onoff; 666 667 uplcom_set_line_state(sc); 668 } 669 670 static void 671 uplcom_break(struct uplcom_softc *sc, int onoff) 672 { 673 usb_device_request_t req; 674 675 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 676 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 677 678 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 679 req.bRequest = UCDC_SEND_BREAK; 680 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 681 USETW(req.wIndex, sc->sc_iface_number); 682 USETW(req.wLength, 0); 683 684 (void)usbd_do_request(sc->sc_udev, &req, 0); 685 } 686 687 static usbd_status 688 uplcom_set_crtscts(struct uplcom_softc *sc) 689 { 690 usb_device_request_t req; 691 usbd_status err; 692 693 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 694 695 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 696 req.bRequest = UPLCOM_SET_REQUEST; 697 USETW(req.wValue, 0); 698 if (sc->sc_type == UPLCOM_TYPE_HX) 699 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_HX); 700 else 701 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_0); 702 USETW(req.wLength, 0); 703 704 err = usbd_do_request(sc->sc_udev, &req, 0); 705 if (err) { 706 DPRINTF("failed, err=%jd", err, 0, 0, 0); 707 return err; 708 } 709 710 return USBD_NORMAL_COMPLETION; 711 } 712 713 static usbd_status 714 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state) 715 { 716 usb_device_request_t req; 717 usbd_status err; 718 719 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 720 721 DPRINTF("rate=%jd fmt=%jd parity=%jd bits=%jd", 722 UGETDW(state->dwDTERate), state->bCharFormat, 723 state->bParityType, state->bDataBits); 724 725 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { 726 DPRINTF("already set", 0, 0, 0, 0); 727 return USBD_NORMAL_COMPLETION; 728 } 729 730 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 731 req.bRequest = UCDC_SET_LINE_CODING; 732 USETW(req.wValue, 0); 733 USETW(req.wIndex, sc->sc_iface_number); 734 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 735 736 err = usbd_do_request(sc->sc_udev, &req, state); 737 if (err) { 738 DPRINTF("failed, err=%ju", err, 0, 0, 0); 739 return err; 740 } 741 742 sc->sc_line_state = *state; 743 744 return USBD_NORMAL_COMPLETION; 745 } 746 747 static int 748 uplcom_param(void *addr, int portno, struct termios *t) 749 { 750 struct uplcom_softc *sc = addr; 751 usbd_status err; 752 usb_cdc_line_state_t ls; 753 754 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 755 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 756 757 if (sc->sc_dying) 758 return EIO; 759 760 USETDW(ls.dwDTERate, t->c_ospeed); 761 if (ISSET(t->c_cflag, CSTOPB)) 762 ls.bCharFormat = UCDC_STOP_BIT_2; 763 else 764 ls.bCharFormat = UCDC_STOP_BIT_1; 765 if (ISSET(t->c_cflag, PARENB)) { 766 if (ISSET(t->c_cflag, PARODD)) 767 ls.bParityType = UCDC_PARITY_ODD; 768 else 769 ls.bParityType = UCDC_PARITY_EVEN; 770 } else 771 ls.bParityType = UCDC_PARITY_NONE; 772 switch (ISSET(t->c_cflag, CSIZE)) { 773 case CS5: 774 ls.bDataBits = 5; 775 break; 776 case CS6: 777 ls.bDataBits = 6; 778 break; 779 case CS7: 780 ls.bDataBits = 7; 781 break; 782 case CS8: 783 ls.bDataBits = 8; 784 break; 785 } 786 787 err = uplcom_set_line_coding(sc, &ls); 788 if (err) { 789 DPRINTF("err=%jd", err, 0, 0, 0); 790 return EIO; 791 } 792 793 if (ISSET(t->c_cflag, CRTSCTS)) 794 uplcom_set_crtscts(sc); 795 796 if (sc->sc_rts == -1 || sc->sc_dtr == -1) 797 uplcom_set_line_state(sc); 798 799 if (err) { 800 DPRINTF("err=%jd", err, 0, 0, 0); 801 return EIO; 802 } 803 804 return 0; 805 } 806 807 static usbd_status 808 uplcom_vendor_control_write(struct usbd_device *dev, uint16_t value, 809 uint16_t index) 810 { 811 usb_device_request_t req; 812 usbd_status err; 813 814 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 815 816 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 817 req.bRequest = UPLCOM_SET_REQUEST; 818 USETW(req.wValue, value); 819 USETW(req.wIndex, index); 820 USETW(req.wLength, 0); 821 822 err = usbd_do_request(dev, &req, NULL); 823 824 if (err) { 825 DPRINTF("vendor write failed, err=%jd", err, 0, 0, 0); 826 } 827 828 return err; 829 } 830 831 static int 832 uplcom_open(void *addr, int portno) 833 { 834 struct uplcom_softc *sc = addr; 835 usbd_status err = 0; 836 837 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 838 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 839 840 if (sc->sc_dying) 841 return EIO; 842 843 /* Some unknown device frobbing. */ 844 if (sc->sc_type == UPLCOM_TYPE_HX) 845 uplcom_vendor_control_write(sc->sc_udev, 2, 0x44); 846 else 847 uplcom_vendor_control_write(sc->sc_udev, 2, 0x24); 848 849 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 850 sc->sc_intr_buf = kmem_alloc(sc->sc_isize, KM_SLEEP); 851 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number, 852 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, 853 sc->sc_intr_buf, sc->sc_isize, 854 uplcom_intr, USBD_DEFAULT_INTERVAL); 855 if (err) { 856 DPRINTF("cannot open interrupt pipe (addr %jd)", 857 sc->sc_intr_number, 0, 0, 0); 858 } 859 } 860 861 if (err == 0 && sc->sc_type == UPLCOM_TYPE_HX) 862 err = uplcom_pl2303x_init(sc); 863 864 return err; 865 } 866 867 static void 868 uplcom_close(void *addr, int portno) 869 { 870 struct uplcom_softc *sc = addr; 871 872 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 873 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 874 875 if (sc->sc_dying) 876 return; 877 878 uplcom_close_pipe(sc); 879 } 880 881 static void 882 uplcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 883 { 884 struct uplcom_softc *sc = priv; 885 u_char *buf = sc->sc_intr_buf; 886 u_char pstatus; 887 888 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 889 890 if (sc->sc_dying) 891 return; 892 893 if (status != USBD_NORMAL_COMPLETION) { 894 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 895 return; 896 897 DPRINTF("abnormal status: %ju", status, 0, 0, 0); 898 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 899 return; 900 } 901 902 DPRINTF("uplcom status = %02jx", buf[8], 0, 0, 0); 903 904 sc->sc_lsr = sc->sc_msr = 0; 905 pstatus = buf[8]; 906 if (ISSET(pstatus, UPLCOM_N_SERIAL_CTS)) 907 sc->sc_msr |= UMSR_CTS; 908 if (ISSET(pstatus, UCDC_N_SERIAL_RI)) 909 sc->sc_msr |= UMSR_RI; 910 if (ISSET(pstatus, UCDC_N_SERIAL_DSR)) 911 sc->sc_msr |= UMSR_DSR; 912 if (ISSET(pstatus, UCDC_N_SERIAL_DCD)) 913 sc->sc_msr |= UMSR_DCD; 914 ucom_status_change(device_private(sc->sc_subdev)); 915 } 916 917 static void 918 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 919 { 920 struct uplcom_softc *sc = addr; 921 922 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 923 924 if (sc->sc_dying) 925 return; 926 927 *lsr = sc->sc_lsr; 928 *msr = sc->sc_msr; 929 } 930 931 #if TODO 932 static int 933 uplcom_ioctl(void *addr, int portno, u_long cmd, void *data, int flag, 934 proc_t *p) 935 { 936 struct uplcom_softc *sc = addr; 937 int error = 0; 938 939 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 940 941 if (sc->sc_dying) 942 return EIO; 943 944 DPRINTF("cmd=0x%08lx", cmd, 0, 0, 0); 945 946 switch (cmd) { 947 case TIOCNOTTY: 948 case TIOCMGET: 949 case TIOCMSET: 950 case USB_GET_CM_OVER_DATA: 951 case USB_SET_CM_OVER_DATA: 952 break; 953 954 default: 955 DPRINTF("unknown", 0, 0, 0, 0); 956 error = ENOTTY; 957 break; 958 } 959 960 return error; 961 } 962 #endif 963