1/* $OpenBSD: uvscom.c,v 1.43 2024/05/23 03:21:09 jsg Exp $ */ 2/* $NetBSD: uvscom.c,v 1.9 2003/02/12 15:36:20 ichiro Exp $ */ 3/*- 4 * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/dev/usb/uvscom.c,v 1.1 2002/03/18 18:23:39 joe Exp $ 29 */ 30 31/* 32 * uvscom: SUNTAC Slipper U VS-10U driver. 33 * Slipper U is a PC card to USB converter for data communication card 34 * adapter. It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in, 35 * P-in m@ater and various data communication card adapters. 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/malloc.h> 41#include <sys/tty.h> 42#include <sys/device.h> 43 44#include <dev/usb/usb.h> 45#include <dev/usb/usbdi.h> 46#include <dev/usb/usbdevs.h> 47 48#include <dev/usb/ucomvar.h> 49 50#ifdef UVSCOM_DEBUG 51static int uvscomdebug = 1; 52 53#define DPRINTFN(n, x) do { if (uvscomdebug > (n)) printf x; } while (0) 54#else 55#define DPRINTFN(n, x) 56#endif 57#define DPRINTF(x) DPRINTFN(0, x) 58 59#define UVSCOM_IFACE_INDEX 0 60 61#define UVSCOM_INTR_INTERVAL 100 /* mS */ 62 63#define UVSCOM_UNIT_WAIT 5 64 65/* Request */ 66#define UVSCOM_SET_SPEED 0x10 67#define UVSCOM_LINE_CTL 0x11 68#define UVSCOM_SET_PARAM 0x12 69#define UVSCOM_READ_STATUS 0xd0 70#define UVSCOM_SHUTDOWN 0xe0 71 72/* UVSCOM_SET_SPEED parameters */ 73#define UVSCOM_SPEED_150BPS 0x00 74#define UVSCOM_SPEED_300BPS 0x01 75#define UVSCOM_SPEED_600BPS 0x02 76#define UVSCOM_SPEED_1200BPS 0x03 77#define UVSCOM_SPEED_2400BPS 0x04 78#define UVSCOM_SPEED_4800BPS 0x05 79#define UVSCOM_SPEED_9600BPS 0x06 80#define UVSCOM_SPEED_19200BPS 0x07 81#define UVSCOM_SPEED_38400BPS 0x08 82#define UVSCOM_SPEED_57600BPS 0x09 83#define UVSCOM_SPEED_115200BPS 0x0a 84 85/* UVSCOM_LINE_CTL parameters */ 86#define UVSCOM_BREAK 0x40 87#define UVSCOM_RTS 0x02 88#define UVSCOM_DTR 0x01 89#define UVSCOM_LINE_INIT 0x08 90 91/* UVSCOM_SET_PARAM parameters */ 92#define UVSCOM_DATA_MASK 0x03 93#define UVSCOM_DATA_BIT_8 0x03 94#define UVSCOM_DATA_BIT_7 0x02 95#define UVSCOM_DATA_BIT_6 0x01 96#define UVSCOM_DATA_BIT_5 0x00 97 98#define UVSCOM_STOP_MASK 0x04 99#define UVSCOM_STOP_BIT_2 0x04 100#define UVSCOM_STOP_BIT_1 0x00 101 102#define UVSCOM_PARITY_MASK 0x18 103#define UVSCOM_PARITY_EVEN 0x18 104#if 0 105#define UVSCOM_PARITY_UNK 0x10 106#endif 107#define UVSCOM_PARITY_ODD 0x08 108#define UVSCOM_PARITY_NONE 0x00 109 110/* Status bits */ 111#define UVSCOM_TXRDY 0x04 112#define UVSCOM_RXRDY 0x01 113 114#define UVSCOM_DCD 0x08 115#define UVSCOM_NOCARD 0x04 116#define UVSCOM_DSR 0x02 117#define UVSCOM_CTS 0x01 118#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS) 119 120struct uvscom_softc { 121 struct device sc_dev; /* base device */ 122 struct usbd_device *sc_udev; /* USB device */ 123 struct usbd_interface *sc_iface; /* interface */ 124 125 struct usbd_interface *sc_intr_iface; /* interrupt interface */ 126 int sc_intr_number; /* interrupt number */ 127 struct usbd_pipe *sc_intr_pipe; /* interrupt pipe */ 128 u_char *sc_intr_buf; /* interrupt buffer */ 129 int sc_isize; 130 131 u_char sc_dtr; /* current DTR state */ 132 u_char sc_rts; /* current RTS state */ 133 134 u_char sc_lsr; /* Local status register */ 135 u_char sc_msr; /* uvscom status register */ 136 137 uint16_t sc_lcr; /* Line control */ 138 u_char sc_usr; /* unit status */ 139 140 struct device *sc_subdev; /* ucom device */ 141}; 142 143/* 144 * These are the maximum number of bytes transferred per frame. 145 * The output buffer size cannot be increased due to the size encoding. 146 */ 147#define UVSCOMIBUFSIZE 512 148#define UVSCOMOBUFSIZE 64 149 150usbd_status uvscom_readstat(struct uvscom_softc *); 151usbd_status uvscom_shutdown(struct uvscom_softc *); 152usbd_status uvscom_reset(struct uvscom_softc *); 153usbd_status uvscom_set_line_coding(struct uvscom_softc *, 154 uint16_t, uint16_t); 155usbd_status uvscom_set_line(struct uvscom_softc *, uint16_t); 156usbd_status uvscom_set_crtscts(struct uvscom_softc *); 157void uvscom_get_status(void *, int, u_char *, u_char *); 158void uvscom_dtr(struct uvscom_softc *, int); 159void uvscom_rts(struct uvscom_softc *, int); 160void uvscom_break(struct uvscom_softc *, int); 161 162void uvscom_set(void *, int, int, int); 163void uvscom_intr(struct usbd_xfer *, void *, usbd_status); 164int uvscom_param(void *, int, struct termios *); 165int uvscom_open(void *, int); 166void uvscom_close(void *, int); 167 168const struct ucom_methods uvscom_methods = { 169 uvscom_get_status, 170 uvscom_set, 171 uvscom_param, 172 NULL, /* uvscom_ioctl, TODO */ 173 uvscom_open, 174 uvscom_close, 175 NULL, 176 NULL 177}; 178 179static const struct usb_devno uvscom_devs [] = { 180 /* SUNTAC U-Cable type A3 */ 181 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS64LX }, 182 /* SUNTAC U-Cable type A4 */ 183 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4 }, 184 /* SUNTAC U-Cable type D2 */ 185 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L }, 186 /* SUNTAC U-Cable type P1 */ 187 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1 }, 188 /* SUNTAC Slipper U */ 189 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U }, 190 /* SUNTAC Ir-Trinity */ 191 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U }, 192}; 193 194int uvscom_match(struct device *, void *, void *); 195void uvscom_attach(struct device *, struct device *, void *); 196int uvscom_detach(struct device *, int); 197 198struct cfdriver uvscom_cd = { 199 NULL, "uvscom", DV_DULL 200}; 201 202const struct cfattach uvscom_ca = { 203 sizeof(struct uvscom_softc), uvscom_match, uvscom_attach, uvscom_detach 204}; 205 206int 207uvscom_match(struct device *parent, void *match, void *aux) 208{ 209 struct usb_attach_arg *uaa = aux; 210 211 if (uaa->iface == NULL) 212 return (UMATCH_NONE); 213 214 return (usb_lookup(uvscom_devs, uaa->vendor, uaa->product) != NULL ? 215 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 216} 217 218void 219uvscom_attach(struct device *parent, struct device *self, void *aux) 220{ 221 struct uvscom_softc *sc = (struct uvscom_softc *)self; 222 struct usb_attach_arg *uaa = aux; 223 struct usbd_device *dev = uaa->device; 224 usb_config_descriptor_t *cdesc; 225 usb_interface_descriptor_t *id; 226 usb_endpoint_descriptor_t *ed; 227 const char *devname = sc->sc_dev.dv_xname; 228 usbd_status err; 229 int i; 230 struct ucom_attach_args uca; 231 232 sc->sc_udev = dev; 233 234 DPRINTF(("uvscom attach: sc = %p\n", sc)); 235 236 /* initialize endpoints */ 237 uca.bulkin = uca.bulkout = -1; 238 sc->sc_intr_number = -1; 239 sc->sc_intr_pipe = NULL; 240 241 /* get the config descriptor */ 242 cdesc = usbd_get_config_descriptor(sc->sc_udev); 243 244 if (cdesc == NULL) { 245 printf("%s: failed to get configuration descriptor\n", 246 sc->sc_dev.dv_xname); 247 usbd_deactivate(sc->sc_udev); 248 return; 249 } 250 251 /* get the common interface */ 252 err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX, 253 &sc->sc_iface); 254 if (err) { 255 printf("%s: failed to get interface, err=%s\n", 256 devname, usbd_errstr(err)); 257 usbd_deactivate(sc->sc_udev); 258 return; 259 } 260 261 id = usbd_get_interface_descriptor(sc->sc_iface); 262 263 /* Find endpoints */ 264 for (i = 0; i < id->bNumEndpoints; i++) { 265 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 266 if (ed == NULL) { 267 printf("%s: no endpoint descriptor for %d\n", 268 sc->sc_dev.dv_xname, i); 269 usbd_deactivate(sc->sc_udev); 270 return; 271 } 272 273 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 274 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 275 uca.bulkin = ed->bEndpointAddress; 276 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 277 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 278 uca.bulkout = ed->bEndpointAddress; 279 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 280 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 281 sc->sc_intr_number = ed->bEndpointAddress; 282 sc->sc_isize = UGETW(ed->wMaxPacketSize); 283 } 284 } 285 286 if (uca.bulkin == -1) { 287 printf("%s: Could not find data bulk in\n", 288 sc->sc_dev.dv_xname); 289 usbd_deactivate(sc->sc_udev); 290 return; 291 } 292 if (uca.bulkout == -1) { 293 printf("%s: Could not find data bulk out\n", 294 sc->sc_dev.dv_xname); 295 usbd_deactivate(sc->sc_udev); 296 return; 297 } 298 if (sc->sc_intr_number == -1) { 299 printf("%s: Could not find interrupt in\n", 300 sc->sc_dev.dv_xname); 301 usbd_deactivate(sc->sc_udev); 302 return; 303 } 304 305 sc->sc_dtr = sc->sc_rts = 0; 306 sc->sc_lcr = UVSCOM_LINE_INIT; 307 308 uca.portno = UCOM_UNK_PORTNO; 309 /* bulkin, bulkout set above */ 310 uca.ibufsize = UVSCOMIBUFSIZE; 311 uca.obufsize = UVSCOMOBUFSIZE; 312 uca.ibufsizepad = UVSCOMIBUFSIZE; 313 uca.opkthdrlen = 0; 314 uca.device = dev; 315 uca.iface = sc->sc_iface; 316 uca.methods = &uvscom_methods; 317 uca.arg = sc; 318 uca.info = NULL; 319 320 err = uvscom_reset(sc); 321 322 if (err) { 323 printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname, 324 usbd_errstr(err)); 325 usbd_deactivate(sc->sc_udev); 326 return; 327 } 328 329 DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n", 330 ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number)); 331 332 DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n", 333 uca.bulkin, uca.bulkout, sc->sc_intr_number )); 334 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 335} 336 337int 338uvscom_detach(struct device *self, int flags) 339{ 340 struct uvscom_softc *sc = (struct uvscom_softc *)self; 341 int rv = 0; 342 343 DPRINTF(("uvscom_detach: sc = %p\n", sc)); 344 345 if (sc->sc_intr_pipe != NULL) { 346 usbd_close_pipe(sc->sc_intr_pipe); 347 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize); 348 sc->sc_intr_pipe = NULL; 349 } 350 351 if (sc->sc_subdev != NULL) { 352 rv = config_detach(sc->sc_subdev, flags); 353 sc->sc_subdev = NULL; 354 } 355 356 return (rv); 357} 358 359usbd_status 360uvscom_readstat(struct uvscom_softc *sc) 361{ 362 usb_device_request_t req; 363 usbd_status err; 364 uint16_t r; 365 366 DPRINTF(("%s: send readstat\n", sc->sc_dev.dv_xname)); 367 368 req.bmRequestType = UT_READ_VENDOR_DEVICE; 369 req.bRequest = UVSCOM_READ_STATUS; 370 USETW(req.wValue, 0); 371 USETW(req.wIndex, 0); 372 USETW(req.wLength, 2); 373 374 err = usbd_do_request(sc->sc_udev, &req, &r); 375 if (err) { 376 printf("%s: uvscom_readstat: %s\n", 377 sc->sc_dev.dv_xname, usbd_errstr(err)); 378 return (err); 379 } 380 381 DPRINTF(("%s: uvscom_readstat: r = %d\n", 382 sc->sc_dev.dv_xname, r)); 383 384 return (USBD_NORMAL_COMPLETION); 385} 386 387usbd_status 388uvscom_shutdown(struct uvscom_softc *sc) 389{ 390 usb_device_request_t req; 391 usbd_status err; 392 393 DPRINTF(("%s: send shutdown\n", sc->sc_dev.dv_xname)); 394 395 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 396 req.bRequest = UVSCOM_SHUTDOWN; 397 USETW(req.wValue, 0); 398 USETW(req.wIndex, 0); 399 USETW(req.wLength, 0); 400 401 err = usbd_do_request(sc->sc_udev, &req, NULL); 402 if (err) { 403 printf("%s: uvscom_shutdown: %s\n", 404 sc->sc_dev.dv_xname, usbd_errstr(err)); 405 return (err); 406 } 407 408 return (USBD_NORMAL_COMPLETION); 409} 410 411usbd_status 412uvscom_reset(struct uvscom_softc *sc) 413{ 414 DPRINTF(("%s: uvscom_reset\n", sc->sc_dev.dv_xname)); 415 416 return (USBD_NORMAL_COMPLETION); 417} 418 419usbd_status 420uvscom_set_crtscts(struct uvscom_softc *sc) 421{ 422 DPRINTF(("%s: uvscom_set_crtscts\n", sc->sc_dev.dv_xname)); 423 424 return (USBD_NORMAL_COMPLETION); 425} 426 427usbd_status 428uvscom_set_line(struct uvscom_softc *sc, uint16_t line) 429{ 430 usb_device_request_t req; 431 usbd_status err; 432 433 DPRINTF(("%s: uvscom_set_line: %04x\n", 434 sc->sc_dev.dv_xname, line)); 435 436 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 437 req.bRequest = UVSCOM_LINE_CTL; 438 USETW(req.wValue, line); 439 USETW(req.wIndex, 0); 440 USETW(req.wLength, 0); 441 442 err = usbd_do_request(sc->sc_udev, &req, NULL); 443 if (err) { 444 printf("%s: uvscom_set_line: %s\n", 445 sc->sc_dev.dv_xname, usbd_errstr(err)); 446 return (err); 447 } 448 449 return (USBD_NORMAL_COMPLETION); 450} 451 452usbd_status 453uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls) 454{ 455 usb_device_request_t req; 456 usbd_status err; 457 458 DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n", 459 sc->sc_dev.dv_xname, lsp, ls)); 460 461 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 462 req.bRequest = UVSCOM_SET_SPEED; 463 USETW(req.wValue, lsp); 464 USETW(req.wIndex, 0); 465 USETW(req.wLength, 0); 466 467 err = usbd_do_request(sc->sc_udev, &req, NULL); 468 if (err) { 469 printf("%s: uvscom_set_line_coding: %s\n", 470 sc->sc_dev.dv_xname, usbd_errstr(err)); 471 return (err); 472 } 473 474 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 475 req.bRequest = UVSCOM_SET_PARAM; 476 USETW(req.wValue, ls); 477 USETW(req.wIndex, 0); 478 USETW(req.wLength, 0); 479 480 err = usbd_do_request(sc->sc_udev, &req, NULL); 481 if (err) { 482 printf("%s: uvscom_set_line_coding: %s\n", 483 sc->sc_dev.dv_xname, usbd_errstr(err)); 484 return (err); 485 } 486 487 return (USBD_NORMAL_COMPLETION); 488} 489 490void 491uvscom_dtr(struct uvscom_softc *sc, int onoff) 492{ 493 DPRINTF(("%s: uvscom_dtr: onoff = %d\n", 494 sc->sc_dev.dv_xname, onoff)); 495 496 if (sc->sc_dtr == onoff) 497 return; /* no change */ 498 499 sc->sc_dtr = onoff; 500 501 if (onoff) 502 SET(sc->sc_lcr, UVSCOM_DTR); 503 else 504 CLR(sc->sc_lcr, UVSCOM_DTR); 505 506 uvscom_set_line(sc, sc->sc_lcr); 507} 508 509void 510uvscom_rts(struct uvscom_softc *sc, int onoff) 511{ 512 DPRINTF(("%s: uvscom_rts: onoff = %d\n", 513 sc->sc_dev.dv_xname, onoff)); 514 515 if (sc->sc_rts == onoff) 516 return; /* no change */ 517 518 sc->sc_rts = onoff; 519 520 if (onoff) 521 SET(sc->sc_lcr, UVSCOM_RTS); 522 else 523 CLR(sc->sc_lcr, UVSCOM_RTS); 524 525 uvscom_set_line(sc, sc->sc_lcr); 526} 527 528void 529uvscom_break(struct uvscom_softc *sc, int onoff) 530{ 531 DPRINTF(("%s: uvscom_break: onoff = %d\n", 532 sc->sc_dev.dv_xname, onoff)); 533 534 if (onoff) 535 uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK)); 536} 537 538void 539uvscom_set(void *addr, int portno, int reg, int onoff) 540{ 541 struct uvscom_softc *sc = addr; 542 543 switch (reg) { 544 case UCOM_SET_DTR: 545 uvscom_dtr(sc, onoff); 546 break; 547 case UCOM_SET_RTS: 548 uvscom_rts(sc, onoff); 549 break; 550 case UCOM_SET_BREAK: 551 uvscom_break(sc, onoff); 552 break; 553 default: 554 break; 555 } 556} 557 558int 559uvscom_param(void *addr, int portno, struct termios *t) 560{ 561 struct uvscom_softc *sc = addr; 562 usbd_status err; 563 uint16_t lsp; 564 uint16_t ls; 565 566 DPRINTF(("%s: uvscom_param: sc = %p\n", 567 sc->sc_dev.dv_xname, sc)); 568 569 ls = 0; 570 571 switch (t->c_ospeed) { 572 case B150: 573 lsp = UVSCOM_SPEED_150BPS; 574 break; 575 case B300: 576 lsp = UVSCOM_SPEED_300BPS; 577 break; 578 case B600: 579 lsp = UVSCOM_SPEED_600BPS; 580 break; 581 case B1200: 582 lsp = UVSCOM_SPEED_1200BPS; 583 break; 584 case B2400: 585 lsp = UVSCOM_SPEED_2400BPS; 586 break; 587 case B4800: 588 lsp = UVSCOM_SPEED_4800BPS; 589 break; 590 case B9600: 591 lsp = UVSCOM_SPEED_9600BPS; 592 break; 593 case B19200: 594 lsp = UVSCOM_SPEED_19200BPS; 595 break; 596 case B38400: 597 lsp = UVSCOM_SPEED_38400BPS; 598 break; 599 case B57600: 600 lsp = UVSCOM_SPEED_57600BPS; 601 break; 602 case B115200: 603 lsp = UVSCOM_SPEED_115200BPS; 604 break; 605 default: 606 return (EIO); 607 } 608 609 if (ISSET(t->c_cflag, CSTOPB)) 610 SET(ls, UVSCOM_STOP_BIT_2); 611 else 612 SET(ls, UVSCOM_STOP_BIT_1); 613 614 if (ISSET(t->c_cflag, PARENB)) { 615 if (ISSET(t->c_cflag, PARODD)) 616 SET(ls, UVSCOM_PARITY_ODD); 617 else 618 SET(ls, UVSCOM_PARITY_EVEN); 619 } else 620 SET(ls, UVSCOM_PARITY_NONE); 621 622 switch (ISSET(t->c_cflag, CSIZE)) { 623 case CS5: 624 SET(ls, UVSCOM_DATA_BIT_5); 625 break; 626 case CS6: 627 SET(ls, UVSCOM_DATA_BIT_6); 628 break; 629 case CS7: 630 SET(ls, UVSCOM_DATA_BIT_7); 631 break; 632 case CS8: 633 SET(ls, UVSCOM_DATA_BIT_8); 634 break; 635 default: 636 return (EIO); 637 } 638 639 err = uvscom_set_line_coding(sc, lsp, ls); 640 if (err) 641 return (EIO); 642 643 if (ISSET(t->c_cflag, CRTSCTS)) { 644 err = uvscom_set_crtscts(sc); 645 if (err) 646 return (EIO); 647 } 648 649 return (0); 650} 651 652int 653uvscom_open(void *addr, int portno) 654{ 655 struct uvscom_softc *sc = addr; 656 int err; 657 int i; 658 659 if (usbd_is_dying(sc->sc_udev)) 660 return (EIO); 661 662 DPRINTF(("uvscom_open: sc = %p\n", sc)); 663 664 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 665 DPRINTF(("uvscom_open: open interrupt pipe.\n")); 666 667 sc->sc_usr = 0; /* clear unit status */ 668 669 err = uvscom_readstat(sc); 670 if (err) { 671 DPRINTF(("%s: uvscom_open: readstat failed\n", 672 sc->sc_dev.dv_xname)); 673 return (EIO); 674 } 675 676 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 677 err = usbd_open_pipe_intr(sc->sc_iface, 678 sc->sc_intr_number, 679 USBD_SHORT_XFER_OK, 680 &sc->sc_intr_pipe, 681 sc, 682 sc->sc_intr_buf, 683 sc->sc_isize, 684 uvscom_intr, 685 UVSCOM_INTR_INTERVAL); 686 if (err) { 687 printf("%s: cannot open interrupt pipe (addr %d)\n", 688 sc->sc_dev.dv_xname, 689 sc->sc_intr_number); 690 return (EIO); 691 } 692 } else { 693 DPRINTF(("uvscom_open: did not open interrupt pipe.\n")); 694 } 695 696 if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) { 697 /* unit is not ready */ 698 699 for (i = UVSCOM_UNIT_WAIT; i > 0; --i) { 700 tsleep_nsec(&err, TTIPRI, "uvsop", SEC_TO_NSEC(1)); 701 if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK)) 702 break; 703 } 704 if (i == 0) { 705 DPRINTF(("%s: unit is not ready\n", 706 sc->sc_dev.dv_xname)); 707 return (EIO); 708 } 709 710 /* check PC card was inserted */ 711 if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) { 712 DPRINTF(("%s: no card\n", 713 sc->sc_dev.dv_xname)); 714 return (EIO); 715 } 716 } 717 718 return (0); 719} 720 721void 722uvscom_close(void *addr, int portno) 723{ 724 struct uvscom_softc *sc = addr; 725 int err; 726 727 if (usbd_is_dying(sc->sc_udev)) 728 return; 729 730 DPRINTF(("uvscom_close: close\n")); 731 732 uvscom_shutdown(sc); 733 734 if (sc->sc_intr_pipe != NULL) { 735 err = usbd_close_pipe(sc->sc_intr_pipe); 736 if (err) 737 printf("%s: close interrupt pipe failed: %s\n", 738 sc->sc_dev.dv_xname, 739 usbd_errstr(err)); 740 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize); 741 sc->sc_intr_pipe = NULL; 742 } 743} 744 745void 746uvscom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 747{ 748 struct uvscom_softc *sc = priv; 749 u_char *buf = sc->sc_intr_buf; 750 u_char pstatus; 751 752 if (usbd_is_dying(sc->sc_udev)) 753 return; 754 755 if (status != USBD_NORMAL_COMPLETION) { 756 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 757 return; 758 759 printf("%s: uvscom_intr: abnormal status: %s\n", 760 sc->sc_dev.dv_xname, 761 usbd_errstr(status)); 762 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 763 return; 764 } 765 766 DPRINTFN(2, ("%s: uvscom status = %02x %02x\n", 767 sc->sc_dev.dv_xname, buf[0], buf[1])); 768 769 sc->sc_lsr = sc->sc_msr = 0; 770 sc->sc_usr = buf[1]; 771 772 pstatus = buf[0]; 773 if (ISSET(pstatus, UVSCOM_TXRDY)) 774 SET(sc->sc_lsr, ULSR_TXRDY); 775 if (ISSET(pstatus, UVSCOM_RXRDY)) 776 SET(sc->sc_lsr, ULSR_RXRDY); 777 778 pstatus = buf[1]; 779 if (ISSET(pstatus, UVSCOM_CTS)) 780 SET(sc->sc_msr, UMSR_CTS); 781 if (ISSET(pstatus, UVSCOM_DSR)) 782 SET(sc->sc_msr, UMSR_DSR); 783 if (ISSET(pstatus, UVSCOM_DCD)) 784 SET(sc->sc_msr, UMSR_DCD); 785 786 ucom_status_change((struct ucom_softc *) sc->sc_subdev); 787} 788 789void 790uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 791{ 792 struct uvscom_softc *sc = addr; 793 794 if (lsr != NULL) 795 *lsr = sc->sc_lsr; 796 if (msr != NULL) 797 *msr = sc->sc_msr; 798} 799