1 /* $NetBSD: uplcom.c,v 1.50 2006/11/16 01:33:27 christos Exp $ */ 2 /* 3 * Copyright (c) 2001 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Ichiro FUKUHARA (ichiro@ichiro.org). 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * General information: http://www.prolific.com.tw/fr_pl2303.htm 40 * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.50 2006/11/16 01:33:27 christos Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/ioctl.h> 51 #include <sys/conf.h> 52 #include <sys/tty.h> 53 #include <sys/file.h> 54 #include <sys/select.h> 55 #include <sys/proc.h> 56 #include <sys/device.h> 57 #include <sys/poll.h> 58 59 #include <dev/usb/usb.h> 60 #include <dev/usb/usbcdc.h> 61 62 #include <dev/usb/usbdi.h> 63 #include <dev/usb/usbdi_util.h> 64 #include <dev/usb/usbdevs.h> 65 #include <dev/usb/usb_quirks.h> 66 67 #include <dev/usb/usbdevs.h> 68 #include <dev/usb/ucomvar.h> 69 70 #ifdef UPLCOM_DEBUG 71 #define DPRINTFN(n, x) if (uplcomdebug > (n)) logprintf x 72 int uplcomdebug = 0; 73 #else 74 #define DPRINTFN(n, x) 75 #endif 76 #define DPRINTF(x) DPRINTFN(0, x) 77 78 #define UPLCOM_CONFIG_INDEX 0 79 #define UPLCOM_IFACE_INDEX 0 80 #define UPLCOM_SECOND_IFACE_INDEX 1 81 82 #define UPLCOM_SET_REQUEST 0x01 83 #define UPLCOM_SET_CRTSCTS_0 0x41 84 #define UPLCOM_SET_CRTSCTS_HX 0x61 85 #define RSAQ_STATUS_DSR 0x02 86 #define RSAQ_STATUS_DCD 0x01 87 88 enum pl2303_type { 89 UPLCOM_TYPE_0, 90 UPLCOM_TYPE_HX, 91 }; 92 93 struct uplcom_softc { 94 USBBASEDEVICE sc_dev; /* base device */ 95 usbd_device_handle sc_udev; /* USB device */ 96 usbd_interface_handle sc_iface; /* interface */ 97 int sc_iface_number; /* interface number */ 98 99 usbd_interface_handle sc_intr_iface; /* interrupt interface */ 100 int sc_intr_number; /* interrupt number */ 101 usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */ 102 u_char *sc_intr_buf; /* interrupt buffer */ 103 int sc_isize; 104 105 usb_cdc_line_state_t sc_line_state; /* current line state */ 106 int sc_dtr; /* current DTR state */ 107 int sc_rts; /* current RTS state */ 108 109 device_ptr_t sc_subdev; /* ucom device */ 110 111 u_char sc_dying; /* disconnecting */ 112 113 u_char sc_lsr; /* Local status register */ 114 u_char sc_msr; /* uplcom status register */ 115 116 enum pl2303_type sc_type; /* PL2303 chip type */ 117 }; 118 119 /* 120 * These are the maximum number of bytes transferred per frame. 121 * The output buffer size cannot be increased due to the size encoding. 122 */ 123 #define UPLCOMIBUFSIZE 256 124 #define UPLCOMOBUFSIZE 256 125 126 Static usbd_status uplcom_reset(struct uplcom_softc *); 127 Static usbd_status uplcom_set_line_coding(struct uplcom_softc *sc, 128 usb_cdc_line_state_t *state); 129 Static usbd_status uplcom_set_crtscts(struct uplcom_softc *); 130 Static void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 131 132 Static void uplcom_set(void *, int, int, int); 133 Static void uplcom_dtr(struct uplcom_softc *, int); 134 Static void uplcom_rts(struct uplcom_softc *, int); 135 Static void uplcom_break(struct uplcom_softc *, int); 136 Static void uplcom_set_line_state(struct uplcom_softc *); 137 Static void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr); 138 #if TODO 139 Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr ); 140 #endif 141 Static int uplcom_param(void *, int, struct termios *); 142 Static int uplcom_open(void *, int); 143 Static void uplcom_close(void *, int); 144 Static usbd_status uplcom_vendor_control_write(usbd_device_handle, u_int16_t, u_int16_t); 145 146 struct ucom_methods uplcom_methods = { 147 uplcom_get_status, 148 uplcom_set, 149 uplcom_param, 150 NULL, /* uplcom_ioctl, TODO */ 151 uplcom_open, 152 uplcom_close, 153 NULL, 154 NULL, 155 }; 156 157 static const struct usb_devno uplcom_devs[] = { 158 /* I/O DATA USB-RSAQ2 */ 159 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 }, 160 /* I/O DATA USB-RSAQ3 */ 161 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 }, 162 /* I/O DATA USB-RSAQ */ 163 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ }, 164 /* PLANEX USB-RS232 URS-03 */ 165 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A }, 166 /* IOGEAR/ATEN UC-232A */ 167 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 }, 168 /* IOGEAR/ATENTRIPPLITE */ 169 { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 }, 170 /* ELECOM UC-SGT */ 171 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT }, 172 /* ELECOM UC-SGT0 */ 173 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 }, 174 /* Panasonic 50" Touch Panel */ 175 { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S }, 176 /* RATOC REX-USB60 */ 177 { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 }, 178 /* TDK USB-PHS Adapter UHA6400 */ 179 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 }, 180 /* TDK USB-PDC Adapter UPA9664 */ 181 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 }, 182 /* Sony Ericsson USB Cable */ 183 { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 }, 184 /* SOURCENEXT KeikaiDenwa 8 */ 185 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 }, 186 /* SOURCENEXT KeikaiDenwa 8 with charger */ 187 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG }, 188 /* HAL Corporation Crossam2+USB */ 189 { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 }, 190 /* Sitecom USB to serial cable */ 191 { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 }, 192 /* Pharos USB GPS - Microsoft version */ 193 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X }, 194 }; 195 #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p) 196 197 static const struct { 198 uint16_t vendor; 199 uint16_t product; 200 enum pl2303_type chiptype; 201 } uplcom_devs_ext[] = { 202 /* I/O DATA USB-RSAQ3 */ 203 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, UPLCOM_TYPE_HX }, 204 {0, 0, 0} 205 }; 206 207 208 USB_DECLARE_DRIVER(uplcom); 209 210 USB_MATCH(uplcom) 211 { 212 USB_MATCH_START(uplcom, uaa); 213 214 if (uaa->iface != NULL) 215 return (UMATCH_NONE); 216 217 return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ? 218 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 219 } 220 221 USB_ATTACH(uplcom) 222 { 223 USB_ATTACH_START(uplcom, sc, uaa); 224 usbd_device_handle dev = uaa->device; 225 usb_device_descriptor_t *ddesc; 226 usb_config_descriptor_t *cdesc; 227 usb_interface_descriptor_t *id; 228 usb_endpoint_descriptor_t *ed; 229 char *devinfop; 230 char *devname = USBDEVNAME(sc->sc_dev); 231 usbd_status err; 232 int i; 233 struct ucom_attach_args uca; 234 235 devinfop = usbd_devinfo_alloc(dev, 0); 236 USB_ATTACH_SETUP; 237 printf("%s: %s\n", devname, devinfop); 238 usbd_devinfo_free(devinfop); 239 240 sc->sc_udev = dev; 241 242 DPRINTF(("\n\nuplcom attach: sc=%p\n", sc)); 243 244 /* initialize endpoints */ 245 uca.bulkin = uca.bulkout = -1; 246 sc->sc_intr_number = -1; 247 sc->sc_intr_pipe = NULL; 248 249 /* Move the device into the configured state. */ 250 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1); 251 if (err) { 252 printf("\n%s: failed to set configuration, err=%s\n", 253 devname, usbd_errstr(err)); 254 sc->sc_dying = 1; 255 USB_ATTACH_ERROR_RETURN; 256 } 257 258 /* get the device descriptor */ 259 ddesc = usbd_get_device_descriptor(sc->sc_udev); 260 if (ddesc == NULL) { 261 printf("%s: failed to get device descriptor\n", 262 USBDEVNAME(sc->sc_dev)); 263 sc->sc_dying = 1; 264 USB_ATTACH_ERROR_RETURN; 265 } 266 267 /* determine chip type */ 268 for (i = 0; uplcom_devs_ext[i].vendor != 0; i++) { 269 if (uplcom_devs_ext[i].vendor == uaa->vendor && 270 uplcom_devs_ext[i].product == uaa->product) { 271 sc->sc_type = uplcom_devs_ext[i].chiptype; 272 goto chiptype_determined; 273 } 274 } 275 /* 276 * NOTE: The Linux driver distinguishes between UPLCOM_TYPE_0 277 * and UPLCOM_TYPE_1 type chips by testing other fields in the 278 * device descriptor. As far as the uplcom driver is 279 * concerned, both types are identical. 280 * The bcdDevice field should also distinguish these versions, 281 * but who knows. 282 */ 283 if (UGETW(ddesc->bcdDevice) == 0x0300) 284 sc->sc_type = UPLCOM_TYPE_HX; 285 else 286 sc->sc_type = UPLCOM_TYPE_0; 287 chiptype_determined: 288 289 /* get the config descriptor */ 290 cdesc = usbd_get_config_descriptor(sc->sc_udev); 291 292 if (cdesc == NULL) { 293 printf("%s: failed to get configuration descriptor\n", 294 USBDEVNAME(sc->sc_dev)); 295 sc->sc_dying = 1; 296 USB_ATTACH_ERROR_RETURN; 297 } 298 299 /* get the (first/common) interface */ 300 err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, 301 &sc->sc_iface); 302 if (err) { 303 printf("\n%s: failed to get interface, err=%s\n", 304 devname, usbd_errstr(err)); 305 sc->sc_dying = 1; 306 USB_ATTACH_ERROR_RETURN; 307 } 308 309 /* Find the interrupt endpoints */ 310 311 id = usbd_get_interface_descriptor(sc->sc_iface); 312 sc->sc_iface_number = id->bInterfaceNumber; 313 314 for (i = 0; i < id->bNumEndpoints; i++) { 315 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 316 if (ed == NULL) { 317 printf("%s: no endpoint descriptor for %d\n", 318 USBDEVNAME(sc->sc_dev), i); 319 sc->sc_dying = 1; 320 USB_ATTACH_ERROR_RETURN; 321 } 322 323 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 324 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 325 sc->sc_intr_number = ed->bEndpointAddress; 326 sc->sc_isize = UGETW(ed->wMaxPacketSize); 327 } 328 } 329 330 if (sc->sc_intr_number== -1) { 331 printf("%s: Could not find interrupt in\n", 332 USBDEVNAME(sc->sc_dev)); 333 sc->sc_dying = 1; 334 USB_ATTACH_ERROR_RETURN; 335 } 336 337 /* keep interface for interrupt */ 338 sc->sc_intr_iface = sc->sc_iface; 339 340 /* 341 * USB-RSAQ1 has two interface 342 * 343 * USB-RSAQ1 | USB-RSAQ2 344 * -----------------+----------------- 345 * Interface 0 |Interface 0 346 * Interrupt(0x81) | Interrupt(0x81) 347 * -----------------+ BulkIN(0x02) 348 * Interface 1 | BulkOUT(0x83) 349 * BulkIN(0x02) | 350 * BulkOUT(0x83) | 351 */ 352 if (cdesc->bNumInterface == 2) { 353 err = usbd_device2interface_handle(dev, 354 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface); 355 if (err) { 356 printf("\n%s: failed to get second interface, err=%s\n", 357 devname, usbd_errstr(err)); 358 sc->sc_dying = 1; 359 USB_ATTACH_ERROR_RETURN; 360 } 361 } 362 363 /* Find the bulk{in,out} endpoints */ 364 365 id = usbd_get_interface_descriptor(sc->sc_iface); 366 sc->sc_iface_number = id->bInterfaceNumber; 367 368 for (i = 0; i < id->bNumEndpoints; i++) { 369 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 370 if (ed == NULL) { 371 printf("%s: no endpoint descriptor for %d\n", 372 USBDEVNAME(sc->sc_dev), i); 373 sc->sc_dying = 1; 374 USB_ATTACH_ERROR_RETURN; 375 } 376 377 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 378 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 379 uca.bulkin = ed->bEndpointAddress; 380 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 381 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 382 uca.bulkout = ed->bEndpointAddress; 383 } 384 } 385 386 if (uca.bulkin == -1) { 387 printf("%s: Could not find data bulk in\n", 388 USBDEVNAME(sc->sc_dev)); 389 sc->sc_dying = 1; 390 USB_ATTACH_ERROR_RETURN; 391 } 392 393 if (uca.bulkout == -1) { 394 printf("%s: Could not find data bulk out\n", 395 USBDEVNAME(sc->sc_dev)); 396 sc->sc_dying = 1; 397 USB_ATTACH_ERROR_RETURN; 398 } 399 400 sc->sc_dtr = sc->sc_rts = -1; 401 uca.portno = UCOM_UNK_PORTNO; 402 /* bulkin, bulkout set above */ 403 uca.ibufsize = UPLCOMIBUFSIZE; 404 uca.obufsize = UPLCOMOBUFSIZE; 405 uca.ibufsizepad = UPLCOMIBUFSIZE; 406 uca.opkthdrlen = 0; 407 uca.device = dev; 408 uca.iface = sc->sc_iface; 409 uca.methods = &uplcom_methods; 410 uca.arg = sc; 411 uca.info = NULL; 412 413 err = uplcom_reset(sc); 414 415 if (err) { 416 printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev), 417 usbd_errstr(err)); 418 sc->sc_dying = 1; 419 USB_ATTACH_ERROR_RETURN; 420 } 421 422 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 423 USBDEV(sc->sc_dev)); 424 425 DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n", 426 uca.bulkin, uca.bulkout, sc->sc_intr_number )); 427 sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca, 428 ucomprint, ucomsubmatch); 429 430 USB_ATTACH_SUCCESS_RETURN; 431 } 432 433 USB_DETACH(uplcom) 434 { 435 USB_DETACH_START(uplcom, sc); 436 int rv = 0; 437 438 DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags)); 439 440 if (sc->sc_intr_pipe != NULL) { 441 usbd_abort_pipe(sc->sc_intr_pipe); 442 usbd_close_pipe(sc->sc_intr_pipe); 443 free(sc->sc_intr_buf, M_USBDEV); 444 sc->sc_intr_pipe = NULL; 445 } 446 447 sc->sc_dying = 1; 448 if (sc->sc_subdev != NULL) { 449 rv = config_detach(sc->sc_subdev, flags); 450 sc->sc_subdev = NULL; 451 } 452 453 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 454 USBDEV(sc->sc_dev)); 455 456 return (rv); 457 } 458 459 int 460 uplcom_activate(device_ptr_t self, enum devact act) 461 { 462 struct uplcom_softc *sc = (struct uplcom_softc *)self; 463 int rv = 0; 464 465 switch (act) { 466 case DVACT_ACTIVATE: 467 return (EOPNOTSUPP); 468 469 case DVACT_DEACTIVATE: 470 if (sc->sc_subdev != NULL) 471 rv = config_deactivate(sc->sc_subdev); 472 sc->sc_dying = 1; 473 break; 474 } 475 return (rv); 476 } 477 478 usbd_status 479 uplcom_reset(struct uplcom_softc *sc) 480 { 481 usb_device_request_t req; 482 usbd_status err; 483 484 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 485 req.bRequest = UPLCOM_SET_REQUEST; 486 USETW(req.wValue, 0); 487 USETW(req.wIndex, sc->sc_iface_number); 488 USETW(req.wLength, 0); 489 490 err = usbd_do_request(sc->sc_udev, &req, 0); 491 if (err) 492 return (EIO); 493 494 return (0); 495 } 496 497 void 498 uplcom_set_line_state(struct uplcom_softc *sc) 499 { 500 usb_device_request_t req; 501 int ls; 502 503 /* make sure we have initialized state for sc_dtr and sc_rts */ 504 if (sc->sc_dtr == -1) 505 sc->sc_dtr = 0; 506 if (sc->sc_rts == -1) 507 sc->sc_rts = 0; 508 509 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | 510 (sc->sc_rts ? UCDC_LINE_RTS : 0); 511 512 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 513 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 514 USETW(req.wValue, ls); 515 USETW(req.wIndex, sc->sc_iface_number); 516 USETW(req.wLength, 0); 517 518 (void)usbd_do_request(sc->sc_udev, &req, 0); 519 } 520 521 void 522 uplcom_set(void *addr, int portno, int reg, int onoff) 523 { 524 struct uplcom_softc *sc = addr; 525 526 switch (reg) { 527 case UCOM_SET_DTR: 528 uplcom_dtr(sc, onoff); 529 break; 530 case UCOM_SET_RTS: 531 uplcom_rts(sc, onoff); 532 break; 533 case UCOM_SET_BREAK: 534 uplcom_break(sc, onoff); 535 break; 536 default: 537 break; 538 } 539 } 540 541 void 542 uplcom_dtr(struct uplcom_softc *sc, int onoff) 543 { 544 545 DPRINTF(("uplcom_dtr: onoff=%d\n", onoff)); 546 547 if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff) 548 return; 549 550 sc->sc_dtr = !!onoff; 551 552 uplcom_set_line_state(sc); 553 } 554 555 void 556 uplcom_rts(struct uplcom_softc *sc, int onoff) 557 { 558 DPRINTF(("uplcom_rts: onoff=%d\n", onoff)); 559 560 if (sc->sc_rts != -1 && !sc->sc_rts == !onoff) 561 return; 562 563 sc->sc_rts = !!onoff; 564 565 uplcom_set_line_state(sc); 566 } 567 568 void 569 uplcom_break(struct uplcom_softc *sc, int onoff) 570 { 571 usb_device_request_t req; 572 573 DPRINTF(("uplcom_break: onoff=%d\n", onoff)); 574 575 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 576 req.bRequest = UCDC_SEND_BREAK; 577 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 578 USETW(req.wIndex, sc->sc_iface_number); 579 USETW(req.wLength, 0); 580 581 (void)usbd_do_request(sc->sc_udev, &req, 0); 582 } 583 584 usbd_status 585 uplcom_set_crtscts(struct uplcom_softc *sc) 586 { 587 usb_device_request_t req; 588 usbd_status err; 589 590 DPRINTF(("uplcom_set_crtscts: on\n")); 591 592 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 593 req.bRequest = UPLCOM_SET_REQUEST; 594 USETW(req.wValue, 0); 595 if (sc->sc_type == UPLCOM_TYPE_HX) 596 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_HX); 597 else 598 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_0); 599 USETW(req.wLength, 0); 600 601 err = usbd_do_request(sc->sc_udev, &req, 0); 602 if (err) { 603 DPRINTF(("uplcom_set_crtscts: failed, err=%s\n", 604 usbd_errstr(err))); 605 return (err); 606 } 607 608 return (USBD_NORMAL_COMPLETION); 609 } 610 611 usbd_status 612 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state) 613 { 614 usb_device_request_t req; 615 usbd_status err; 616 617 DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n", 618 UGETDW(state->dwDTERate), state->bCharFormat, 619 state->bParityType, state->bDataBits)); 620 621 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { 622 DPRINTF(("uplcom_set_line_coding: already set\n")); 623 return (USBD_NORMAL_COMPLETION); 624 } 625 626 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 627 req.bRequest = UCDC_SET_LINE_CODING; 628 USETW(req.wValue, 0); 629 USETW(req.wIndex, sc->sc_iface_number); 630 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 631 632 err = usbd_do_request(sc->sc_udev, &req, state); 633 if (err) { 634 DPRINTF(("uplcom_set_line_coding: failed, err=%s\n", 635 usbd_errstr(err))); 636 return (err); 637 } 638 639 sc->sc_line_state = *state; 640 641 return (USBD_NORMAL_COMPLETION); 642 } 643 644 int 645 uplcom_param(void *addr, int portno, struct termios *t) 646 { 647 struct uplcom_softc *sc = addr; 648 usbd_status err; 649 usb_cdc_line_state_t ls; 650 651 DPRINTF(("uplcom_param: sc=%p\n", sc)); 652 653 USETDW(ls.dwDTERate, t->c_ospeed); 654 if (ISSET(t->c_cflag, CSTOPB)) 655 ls.bCharFormat = UCDC_STOP_BIT_2; 656 else 657 ls.bCharFormat = UCDC_STOP_BIT_1; 658 if (ISSET(t->c_cflag, PARENB)) { 659 if (ISSET(t->c_cflag, PARODD)) 660 ls.bParityType = UCDC_PARITY_ODD; 661 else 662 ls.bParityType = UCDC_PARITY_EVEN; 663 } else 664 ls.bParityType = UCDC_PARITY_NONE; 665 switch (ISSET(t->c_cflag, CSIZE)) { 666 case CS5: 667 ls.bDataBits = 5; 668 break; 669 case CS6: 670 ls.bDataBits = 6; 671 break; 672 case CS7: 673 ls.bDataBits = 7; 674 break; 675 case CS8: 676 ls.bDataBits = 8; 677 break; 678 } 679 680 err = uplcom_set_line_coding(sc, &ls); 681 if (err) { 682 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err))); 683 return (EIO); 684 } 685 686 if (ISSET(t->c_cflag, CRTSCTS)) 687 uplcom_set_crtscts(sc); 688 689 if (sc->sc_rts == -1 || sc->sc_dtr == -1) 690 uplcom_set_line_state(sc); 691 692 if (err) { 693 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err))); 694 return (EIO); 695 } 696 697 return (0); 698 } 699 700 Static usbd_status 701 uplcom_vendor_control_write(usbd_device_handle dev, u_int16_t value, u_int16_t index) 702 { 703 usb_device_request_t req; 704 usbd_status err; 705 706 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 707 req.bRequest = UPLCOM_SET_REQUEST; 708 USETW(req.wValue, value); 709 USETW(req.wIndex, index); 710 USETW(req.wLength, 0); 711 712 err = usbd_do_request(dev, &req, NULL); 713 714 if (err) { 715 DPRINTF(("uplcom_open: vendor write failed, err=%s (%d)\n", 716 usbd_errstr(err), err)); 717 } 718 719 return err; 720 } 721 722 int 723 uplcom_open(void *addr, int portno) 724 { 725 struct uplcom_softc *sc = addr; 726 usbd_status err; 727 728 if (sc->sc_dying) 729 return (EIO); 730 731 DPRINTF(("uplcom_open: sc=%p\n", sc)); 732 733 /* Some unknown device frobbing. */ 734 if (sc->sc_type == UPLCOM_TYPE_HX) 735 uplcom_vendor_control_write(sc->sc_udev, 2, 0x44); 736 else 737 uplcom_vendor_control_write(sc->sc_udev, 2, 0x24); 738 739 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 740 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 741 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number, 742 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, 743 sc->sc_intr_buf, sc->sc_isize, 744 uplcom_intr, USBD_DEFAULT_INTERVAL); 745 if (err) { 746 DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n", 747 USBDEVNAME(sc->sc_dev), sc->sc_intr_number)); 748 return (EIO); 749 } 750 } 751 752 return (0); 753 } 754 755 void 756 uplcom_close(void *addr, int portno) 757 { 758 struct uplcom_softc *sc = addr; 759 int err; 760 761 if (sc->sc_dying) 762 return; 763 764 DPRINTF(("uplcom_close: close\n")); 765 766 if (sc->sc_intr_pipe != NULL) { 767 err = usbd_abort_pipe(sc->sc_intr_pipe); 768 if (err) 769 printf("%s: abort interrupt pipe failed: %s\n", 770 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 771 err = usbd_close_pipe(sc->sc_intr_pipe); 772 if (err) 773 printf("%s: close interrupt pipe failed: %s\n", 774 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 775 free(sc->sc_intr_buf, M_USBDEV); 776 sc->sc_intr_pipe = NULL; 777 } 778 } 779 780 void 781 uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 782 usbd_status status) 783 { 784 struct uplcom_softc *sc = priv; 785 u_char *buf = sc->sc_intr_buf; 786 u_char pstatus; 787 788 if (sc->sc_dying) 789 return; 790 791 if (status != USBD_NORMAL_COMPLETION) { 792 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 793 return; 794 795 DPRINTF(("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev), 796 usbd_errstr(status))); 797 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 798 return; 799 } 800 801 DPRINTF(("%s: uplcom status = %02x\n", USBDEVNAME(sc->sc_dev), buf[8])); 802 803 sc->sc_lsr = sc->sc_msr = 0; 804 pstatus = buf[8]; 805 if (ISSET(pstatus, RSAQ_STATUS_DSR)) 806 sc->sc_msr |= UMSR_DSR; 807 if (ISSET(pstatus, RSAQ_STATUS_DCD)) 808 sc->sc_msr |= UMSR_DCD; 809 ucom_status_change((struct ucom_softc *) sc->sc_subdev); 810 } 811 812 void 813 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 814 { 815 struct uplcom_softc *sc = addr; 816 817 DPRINTF(("uplcom_get_status:\n")); 818 819 if (lsr != NULL) 820 *lsr = sc->sc_lsr; 821 if (msr != NULL) 822 *msr = sc->sc_msr; 823 } 824 825 #if TODO 826 int 827 uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag, 828 usb_proc_ptr p) 829 { 830 struct uplcom_softc *sc = addr; 831 int error = 0; 832 833 if (sc->sc_dying) 834 return (EIO); 835 836 DPRINTF(("uplcom_ioctl: cmd=0x%08lx\n", cmd)); 837 838 switch (cmd) { 839 case TIOCNOTTY: 840 case TIOCMGET: 841 case TIOCMSET: 842 case USB_GET_CM_OVER_DATA: 843 case USB_SET_CM_OVER_DATA: 844 break; 845 846 default: 847 DPRINTF(("uplcom_ioctl: unknown\n")); 848 error = ENOTTY; 849 break; 850 } 851 852 return (error); 853 } 854 #endif 855