uvscom.c revision 186730
1/* $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $ */ 2 3#include <sys/cdefs.h> 4__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uvscom2.c 186730 2009-01-04 00:12:01Z alfred $"); 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/* 34 * uvscom: SUNTAC Slipper U VS-10U driver. 35 * Slipper U is a PC Card to USB converter for data communication card 36 * adapter. It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in, 37 * P-in m@ater and various data communication card adapters. 38 */ 39 40#include <dev/usb2/include/usb2_devid.h> 41#include <dev/usb2/include/usb2_standard.h> 42#include <dev/usb2/include/usb2_mfunc.h> 43#include <dev/usb2/include/usb2_error.h> 44#include <dev/usb2/include/usb2_cdc.h> 45 46#define USB_DEBUG_VAR uvscom_debug 47 48#include <dev/usb2/core/usb2_core.h> 49#include <dev/usb2/core/usb2_debug.h> 50#include <dev/usb2/core/usb2_process.h> 51#include <dev/usb2/core/usb2_config_td.h> 52#include <dev/usb2/core/usb2_request.h> 53#include <dev/usb2/core/usb2_lookup.h> 54#include <dev/usb2/core/usb2_util.h> 55#include <dev/usb2/core/usb2_busdma.h> 56 57#include <dev/usb2/serial/usb2_serial.h> 58 59#if USB_DEBUG 60static int uvscom_debug = 0; 61 62SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom"); 63SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW, 64 &uvscom_debug, 0, "Debug level"); 65#endif 66 67#define UVSCOM_MODVER 1 /* module version */ 68 69#define UVSCOM_CONFIG_INDEX 0 70#define UVSCOM_IFACE_INDEX 0 71 72/* Request */ 73#define UVSCOM_SET_SPEED 0x10 74#define UVSCOM_LINE_CTL 0x11 75#define UVSCOM_SET_PARAM 0x12 76#define UVSCOM_READ_STATUS 0xd0 77#define UVSCOM_SHUTDOWN 0xe0 78 79/* UVSCOM_SET_SPEED parameters */ 80#define UVSCOM_SPEED_150BPS 0x00 81#define UVSCOM_SPEED_300BPS 0x01 82#define UVSCOM_SPEED_600BPS 0x02 83#define UVSCOM_SPEED_1200BPS 0x03 84#define UVSCOM_SPEED_2400BPS 0x04 85#define UVSCOM_SPEED_4800BPS 0x05 86#define UVSCOM_SPEED_9600BPS 0x06 87#define UVSCOM_SPEED_19200BPS 0x07 88#define UVSCOM_SPEED_38400BPS 0x08 89#define UVSCOM_SPEED_57600BPS 0x09 90#define UVSCOM_SPEED_115200BPS 0x0a 91 92/* UVSCOM_LINE_CTL parameters */ 93#define UVSCOM_BREAK 0x40 94#define UVSCOM_RTS 0x02 95#define UVSCOM_DTR 0x01 96#define UVSCOM_LINE_INIT 0x08 97 98/* UVSCOM_SET_PARAM parameters */ 99#define UVSCOM_DATA_MASK 0x03 100#define UVSCOM_DATA_BIT_8 0x03 101#define UVSCOM_DATA_BIT_7 0x02 102#define UVSCOM_DATA_BIT_6 0x01 103#define UVSCOM_DATA_BIT_5 0x00 104 105#define UVSCOM_STOP_MASK 0x04 106#define UVSCOM_STOP_BIT_2 0x04 107#define UVSCOM_STOP_BIT_1 0x00 108 109#define UVSCOM_PARITY_MASK 0x18 110#define UVSCOM_PARITY_EVEN 0x18 111#define UVSCOM_PARITY_ODD 0x08 112#define UVSCOM_PARITY_NONE 0x00 113 114/* Status bits */ 115#define UVSCOM_TXRDY 0x04 116#define UVSCOM_RXRDY 0x01 117 118#define UVSCOM_DCD 0x08 119#define UVSCOM_NOCARD 0x04 120#define UVSCOM_DSR 0x02 121#define UVSCOM_CTS 0x01 122#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS) 123 124#define UVSCOM_BULK_BUF_SIZE 1024 /* bytes */ 125 126#define UVSCOM_N_TRANSFER 6 /* units */ 127 128struct uvscom_softc { 129 struct usb2_com_super_softc sc_super_ucom; 130 struct usb2_com_softc sc_ucom; 131 132 struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER]; 133 struct usb2_device *sc_udev; 134 135 uint16_t sc_line; /* line control register */ 136 137 uint8_t sc_flag; 138#define UVSCOM_FLAG_WRITE_STALL 0x0001 139#define UVSCOM_FLAG_READ_STALL 0x0002 140#define UVSCOM_FLAG_INTR_STALL 0x0004 141 uint8_t sc_iface_no; /* interface number */ 142 uint8_t sc_iface_index; /* interface index */ 143 uint8_t sc_lsr; /* local status register */ 144 uint8_t sc_msr; /* uvscom status register */ 145 uint8_t sc_unit_status; /* unit status */ 146}; 147 148/* prototypes */ 149 150static device_probe_t uvscom_probe; 151static device_attach_t uvscom_attach; 152static device_detach_t uvscom_detach; 153 154static usb2_callback_t uvscom_write_callback; 155static usb2_callback_t uvscom_write_clear_stall_callback; 156static usb2_callback_t uvscom_read_callback; 157static usb2_callback_t uvscom_read_clear_stall_callback; 158static usb2_callback_t uvscom_intr_callback; 159static usb2_callback_t uvscom_intr_clear_stall_callback; 160 161static void uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 162static void uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 163static void uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t); 164static int uvscom_pre_param(struct usb2_com_softc *, struct termios *); 165static void uvscom_cfg_param(struct usb2_com_softc *, struct termios *); 166static int uvscom_pre_open(struct usb2_com_softc *); 167static void uvscom_cfg_open(struct usb2_com_softc *); 168static void uvscom_cfg_close(struct usb2_com_softc *); 169static void uvscom_start_read(struct usb2_com_softc *); 170static void uvscom_stop_read(struct usb2_com_softc *); 171static void uvscom_start_write(struct usb2_com_softc *); 172static void uvscom_stop_write(struct usb2_com_softc *); 173static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 174 uint8_t *); 175static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t); 176static uint16_t uvscom_cfg_read_status(struct uvscom_softc *); 177 178static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = { 179 180 [0] = { 181 .type = UE_BULK, 182 .endpoint = UE_ADDR_ANY, 183 .direction = UE_DIR_OUT, 184 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 185 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 186 .mh.callback = &uvscom_write_callback, 187 }, 188 189 [1] = { 190 .type = UE_BULK, 191 .endpoint = UE_ADDR_ANY, 192 .direction = UE_DIR_IN, 193 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 194 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 195 .mh.callback = &uvscom_read_callback, 196 }, 197 198 [2] = { 199 .type = UE_CONTROL, 200 .endpoint = 0x00, /* Control pipe */ 201 .direction = UE_DIR_ANY, 202 .mh.bufsize = sizeof(struct usb2_device_request), 203 .mh.callback = &uvscom_write_clear_stall_callback, 204 .mh.timeout = 1000, /* 1 second */ 205 .mh.interval = 50, /* 50ms */ 206 }, 207 208 [3] = { 209 .type = UE_CONTROL, 210 .endpoint = 0x00, /* Control pipe */ 211 .direction = UE_DIR_ANY, 212 .mh.bufsize = sizeof(struct usb2_device_request), 213 .mh.callback = &uvscom_read_clear_stall_callback, 214 .mh.timeout = 1000, /* 1 second */ 215 .mh.interval = 50, /* 50ms */ 216 }, 217 218 [4] = { 219 .type = UE_INTERRUPT, 220 .endpoint = UE_ADDR_ANY, 221 .direction = UE_DIR_IN, 222 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 223 .mh.bufsize = 0, /* use wMaxPacketSize */ 224 .mh.callback = &uvscom_intr_callback, 225 }, 226 227 [5] = { 228 .type = UE_CONTROL, 229 .endpoint = 0x00, /* Control pipe */ 230 .direction = UE_DIR_ANY, 231 .mh.bufsize = sizeof(struct usb2_device_request), 232 .mh.callback = &uvscom_intr_clear_stall_callback, 233 .mh.timeout = 1000, /* 1 second */ 234 .mh.interval = 50, /* 50ms */ 235 }, 236}; 237 238static const struct usb2_com_callback uvscom_callback = { 239 .usb2_com_cfg_get_status = &uvscom_cfg_get_status, 240 .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr, 241 .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts, 242 .usb2_com_cfg_set_break = &uvscom_cfg_set_break, 243 .usb2_com_cfg_param = &uvscom_cfg_param, 244 .usb2_com_cfg_open = &uvscom_cfg_open, 245 .usb2_com_cfg_close = &uvscom_cfg_close, 246 .usb2_com_pre_open = &uvscom_pre_open, 247 .usb2_com_pre_param = &uvscom_pre_param, 248 .usb2_com_start_read = &uvscom_start_read, 249 .usb2_com_stop_read = &uvscom_stop_read, 250 .usb2_com_start_write = &uvscom_start_write, 251 .usb2_com_stop_write = &uvscom_stop_write, 252}; 253 254static const struct usb2_device_id uvscom_devs[] = { 255 /* SUNTAC U-Cable type A4 */ 256 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)}, 257 /* SUNTAC U-Cable type D2 */ 258 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)}, 259 /* SUNTAC Ir-Trinity */ 260 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)}, 261 /* SUNTAC U-Cable type P1 */ 262 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)}, 263 /* SUNTAC Slipper U */ 264 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)}, 265}; 266 267static device_method_t uvscom_methods[] = { 268 DEVMETHOD(device_probe, uvscom_probe), 269 DEVMETHOD(device_attach, uvscom_attach), 270 DEVMETHOD(device_detach, uvscom_detach), 271 {0, 0} 272}; 273 274static devclass_t uvscom_devclass; 275 276static driver_t uvscom_driver = { 277 .name = "uvscom", 278 .methods = uvscom_methods, 279 .size = sizeof(struct uvscom_softc), 280}; 281 282DRIVER_MODULE(uvscom, ushub, uvscom_driver, uvscom_devclass, NULL, 0); 283MODULE_DEPEND(uvscom, usb2_serial, 1, 1, 1); 284MODULE_DEPEND(uvscom, usb2_core, 1, 1, 1); 285MODULE_VERSION(uvscom, UVSCOM_MODVER); 286 287static int 288uvscom_probe(device_t dev) 289{ 290 struct usb2_attach_arg *uaa = device_get_ivars(dev); 291 292 if (uaa->usb2_mode != USB_MODE_HOST) { 293 return (ENXIO); 294 } 295 if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) { 296 return (ENXIO); 297 } 298 if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) { 299 return (ENXIO); 300 } 301 return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa)); 302} 303 304static int 305uvscom_attach(device_t dev) 306{ 307 struct usb2_attach_arg *uaa = device_get_ivars(dev); 308 struct uvscom_softc *sc = device_get_softc(dev); 309 int error; 310 311 if (sc == NULL) { 312 return (ENOMEM); 313 } 314 device_set_usb2_desc(dev); 315 316 sc->sc_udev = uaa->device; 317 318 DPRINTF("sc=%p\n", sc); 319 320 sc->sc_iface_no = uaa->info.bIfaceNum; 321 sc->sc_iface_index = UVSCOM_IFACE_INDEX; 322 323 error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index, 324 sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &Giant); 325 326 if (error) { 327 DPRINTF("could not allocate all USB transfers!\n"); 328 goto detach; 329 } 330 sc->sc_line = UVSCOM_LINE_INIT; 331 332 /* clear stall at first run */ 333 sc->sc_flag |= (UVSCOM_FLAG_WRITE_STALL | 334 UVSCOM_FLAG_READ_STALL); 335 336 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 337 &uvscom_callback, &Giant); 338 if (error) { 339 goto detach; 340 } 341 /* start interrupt pipe */ 342 USB_XFER_LOCK(sc->sc_xfer[4]); 343 usb2_transfer_start(sc->sc_xfer[4]); 344 USB_XFER_UNLOCK(sc->sc_xfer[4]); 345 346 return (0); 347 348detach: 349 uvscom_detach(dev); 350 return (ENXIO); 351} 352 353static int 354uvscom_detach(device_t dev) 355{ 356 struct uvscom_softc *sc = device_get_softc(dev); 357 358 DPRINTF("sc=%p\n", sc); 359 360 /* stop interrupt pipe */ 361 362 if (sc->sc_xfer[4]) { 363 usb2_transfer_stop(sc->sc_xfer[4]); 364 } 365 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 366 367 usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER); 368 369 return (0); 370} 371 372static void 373uvscom_write_callback(struct usb2_xfer *xfer) 374{ 375 struct uvscom_softc *sc = xfer->priv_sc; 376 uint32_t actlen; 377 378 switch (USB_GET_STATE(xfer)) { 379 case USB_ST_SETUP: 380 case USB_ST_TRANSFERRED: 381 if (sc->sc_flag & UVSCOM_FLAG_WRITE_STALL) { 382 usb2_transfer_start(sc->sc_xfer[2]); 383 return; 384 } 385 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 386 UVSCOM_BULK_BUF_SIZE, &actlen)) { 387 388 xfer->frlengths[0] = actlen; 389 usb2_start_hardware(xfer); 390 } 391 return; 392 393 default: /* Error */ 394 if (xfer->error != USB_ERR_CANCELLED) { 395 sc->sc_flag |= UVSCOM_FLAG_WRITE_STALL; 396 usb2_transfer_start(sc->sc_xfer[2]); 397 } 398 return; 399 400 } 401} 402 403static void 404uvscom_write_clear_stall_callback(struct usb2_xfer *xfer) 405{ 406 struct uvscom_softc *sc = xfer->priv_sc; 407 struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 408 409 if (usb2_clear_stall_callback(xfer, xfer_other)) { 410 DPRINTF("stall cleared\n"); 411 sc->sc_flag &= ~UVSCOM_FLAG_WRITE_STALL; 412 usb2_transfer_start(xfer_other); 413 } 414} 415 416static void 417uvscom_read_callback(struct usb2_xfer *xfer) 418{ 419 struct uvscom_softc *sc = xfer->priv_sc; 420 421 switch (USB_GET_STATE(xfer)) { 422 case USB_ST_TRANSFERRED: 423 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 424 425 case USB_ST_SETUP: 426 if (sc->sc_flag & UVSCOM_FLAG_READ_STALL) { 427 usb2_transfer_start(sc->sc_xfer[3]); 428 } else { 429 xfer->frlengths[0] = xfer->max_data_length; 430 usb2_start_hardware(xfer); 431 } 432 return; 433 434 default: /* Error */ 435 if (xfer->error != USB_ERR_CANCELLED) { 436 sc->sc_flag |= UVSCOM_FLAG_READ_STALL; 437 usb2_transfer_start(sc->sc_xfer[3]); 438 } 439 return; 440 441 } 442} 443 444static void 445uvscom_read_clear_stall_callback(struct usb2_xfer *xfer) 446{ 447 struct uvscom_softc *sc = xfer->priv_sc; 448 struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 449 450 if (usb2_clear_stall_callback(xfer, xfer_other)) { 451 DPRINTF("stall cleared\n"); 452 sc->sc_flag &= ~UVSCOM_FLAG_READ_STALL; 453 usb2_transfer_start(xfer_other); 454 } 455} 456 457static void 458uvscom_intr_callback(struct usb2_xfer *xfer) 459{ 460 struct uvscom_softc *sc = xfer->priv_sc; 461 uint8_t buf[2]; 462 463 switch (USB_GET_STATE(xfer)) { 464 case USB_ST_TRANSFERRED: 465 if (xfer->actlen >= 2) { 466 467 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 468 469 sc->sc_lsr = 0; 470 sc->sc_msr = 0; 471 sc->sc_unit_status = buf[1]; 472 473 if (buf[0] & UVSCOM_TXRDY) { 474 sc->sc_lsr |= ULSR_TXRDY; 475 } 476 if (buf[0] & UVSCOM_RXRDY) { 477 sc->sc_lsr |= ULSR_RXRDY; 478 } 479 if (buf[1] & UVSCOM_CTS) { 480 sc->sc_msr |= SER_CTS; 481 } 482 if (buf[1] & UVSCOM_DSR) { 483 sc->sc_msr |= SER_DSR; 484 } 485 if (buf[1] & UVSCOM_DCD) { 486 sc->sc_msr |= SER_DCD; 487 } 488 /* 489 * the UCOM layer will ignore this call if the TTY 490 * device is closed! 491 */ 492 usb2_com_status_change(&sc->sc_ucom); 493 } 494 case USB_ST_SETUP: 495 if (sc->sc_flag & UVSCOM_FLAG_INTR_STALL) { 496 usb2_transfer_start(sc->sc_xfer[5]); 497 } else { 498 xfer->frlengths[0] = xfer->max_data_length; 499 usb2_start_hardware(xfer); 500 } 501 return; 502 503 default: /* Error */ 504 if (xfer->error != USB_ERR_CANCELLED) { 505 sc->sc_flag |= UVSCOM_FLAG_INTR_STALL; 506 usb2_transfer_start(sc->sc_xfer[5]); 507 } 508 return; 509 510 } 511} 512 513static void 514uvscom_intr_clear_stall_callback(struct usb2_xfer *xfer) 515{ 516 struct uvscom_softc *sc = xfer->priv_sc; 517 struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 518 519 if (usb2_clear_stall_callback(xfer, xfer_other)) { 520 DPRINTF("stall cleared\n"); 521 sc->sc_flag &= ~UVSCOM_FLAG_INTR_STALL; 522 usb2_transfer_start(xfer_other); 523 } 524} 525 526static void 527uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 528{ 529 struct uvscom_softc *sc = ucom->sc_parent; 530 531 DPRINTF("onoff = %d\n", onoff); 532 533 if (onoff) 534 sc->sc_line |= UVSCOM_DTR; 535 else 536 sc->sc_line &= ~UVSCOM_DTR; 537 538 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 539} 540 541static void 542uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 543{ 544 struct uvscom_softc *sc = ucom->sc_parent; 545 546 DPRINTF("onoff = %d\n", onoff); 547 548 if (onoff) 549 sc->sc_line |= UVSCOM_RTS; 550 else 551 sc->sc_line &= ~UVSCOM_RTS; 552 553 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 554} 555 556static void 557uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 558{ 559 struct uvscom_softc *sc = ucom->sc_parent; 560 561 DPRINTF("onoff = %d\n", onoff); 562 563 if (onoff) 564 sc->sc_line |= UVSCOM_BREAK; 565 else 566 sc->sc_line &= ~UVSCOM_BREAK; 567 568 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 569} 570 571static int 572uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 573{ 574 switch (t->c_ospeed) { 575 case B150: 576 case B300: 577 case B600: 578 case B1200: 579 case B2400: 580 case B4800: 581 case B9600: 582 case B19200: 583 case B38400: 584 case B57600: 585 case B115200: 586 default: 587 return (EINVAL); 588 } 589 return (0); 590} 591 592static void 593uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 594{ 595 struct uvscom_softc *sc = ucom->sc_parent; 596 uint16_t value; 597 598 DPRINTF("\n"); 599 600 switch (t->c_ospeed) { 601 case B150: 602 value = UVSCOM_SPEED_150BPS; 603 break; 604 case B300: 605 value = UVSCOM_SPEED_300BPS; 606 break; 607 case B600: 608 value = UVSCOM_SPEED_600BPS; 609 break; 610 case B1200: 611 value = UVSCOM_SPEED_1200BPS; 612 break; 613 case B2400: 614 value = UVSCOM_SPEED_2400BPS; 615 break; 616 case B4800: 617 value = UVSCOM_SPEED_4800BPS; 618 break; 619 case B9600: 620 value = UVSCOM_SPEED_9600BPS; 621 break; 622 case B19200: 623 value = UVSCOM_SPEED_19200BPS; 624 break; 625 case B38400: 626 value = UVSCOM_SPEED_38400BPS; 627 break; 628 case B57600: 629 value = UVSCOM_SPEED_57600BPS; 630 break; 631 case B115200: 632 value = UVSCOM_SPEED_115200BPS; 633 break; 634 default: 635 return; 636 } 637 638 uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value); 639 640 value = 0; 641 642 if (t->c_cflag & CSTOPB) { 643 value |= UVSCOM_STOP_BIT_2; 644 } 645 if (t->c_cflag & PARENB) { 646 if (t->c_cflag & PARODD) { 647 value |= UVSCOM_PARITY_ODD; 648 } else { 649 value |= UVSCOM_PARITY_EVEN; 650 } 651 } else { 652 value |= UVSCOM_PARITY_NONE; 653 } 654 655 switch (t->c_cflag & CSIZE) { 656 case CS5: 657 value |= UVSCOM_DATA_BIT_5; 658 break; 659 case CS6: 660 value |= UVSCOM_DATA_BIT_6; 661 break; 662 case CS7: 663 value |= UVSCOM_DATA_BIT_7; 664 break; 665 default: 666 case CS8: 667 value |= UVSCOM_DATA_BIT_8; 668 break; 669 } 670 671 uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value); 672} 673 674static int 675uvscom_pre_open(struct usb2_com_softc *ucom) 676{ 677 struct uvscom_softc *sc = ucom->sc_parent; 678 679 DPRINTF("sc = %p\n", sc); 680 681 /* check if PC card was inserted */ 682 683 if (sc->sc_unit_status & UVSCOM_NOCARD) { 684 DPRINTF("no PC card!\n"); 685 return (ENXIO); 686 } 687 return (0); 688} 689 690static void 691uvscom_cfg_open(struct usb2_com_softc *ucom) 692{ 693 struct uvscom_softc *sc = ucom->sc_parent; 694 695 DPRINTF("sc = %p\n", sc); 696 697 uvscom_cfg_read_status(sc); 698} 699 700static void 701uvscom_cfg_close(struct usb2_com_softc *ucom) 702{ 703 struct uvscom_softc *sc = ucom->sc_parent; 704 705 DPRINTF("sc=%p\n", sc); 706 707 uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0); 708} 709 710static void 711uvscom_start_read(struct usb2_com_softc *ucom) 712{ 713 struct uvscom_softc *sc = ucom->sc_parent; 714 715 usb2_transfer_start(sc->sc_xfer[1]); 716} 717 718static void 719uvscom_stop_read(struct usb2_com_softc *ucom) 720{ 721 struct uvscom_softc *sc = ucom->sc_parent; 722 723 usb2_transfer_stop(sc->sc_xfer[3]); 724 usb2_transfer_stop(sc->sc_xfer[1]); 725} 726 727static void 728uvscom_start_write(struct usb2_com_softc *ucom) 729{ 730 struct uvscom_softc *sc = ucom->sc_parent; 731 732 usb2_transfer_start(sc->sc_xfer[0]); 733} 734 735static void 736uvscom_stop_write(struct usb2_com_softc *ucom) 737{ 738 struct uvscom_softc *sc = ucom->sc_parent; 739 740 usb2_transfer_stop(sc->sc_xfer[2]); 741 usb2_transfer_stop(sc->sc_xfer[0]); 742} 743 744static void 745uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 746{ 747 struct uvscom_softc *sc = ucom->sc_parent; 748 749 *lsr = sc->sc_lsr; 750 *msr = sc->sc_msr; 751} 752 753static void 754uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value) 755{ 756 struct usb2_device_request req; 757 usb2_error_t err; 758 759 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 760 return; 761 } 762 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 763 req.bRequest = index; 764 USETW(req.wValue, value); 765 USETW(req.wIndex, 0); 766 USETW(req.wLength, 0); 767 768 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 769 NULL, 0, NULL, 1000); 770 if (err) { 771 DPRINTFN(0, "device request failed, err=%s " 772 "(ignored)\n", usb2_errstr(err)); 773 } 774} 775 776static uint16_t 777uvscom_cfg_read_status(struct uvscom_softc *sc) 778{ 779 struct usb2_device_request req; 780 usb2_error_t err; 781 uint8_t data[2]; 782 783 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 784 return (0); 785 } 786 req.bmRequestType = UT_READ_VENDOR_DEVICE; 787 req.bRequest = UVSCOM_READ_STATUS; 788 USETW(req.wValue, 0); 789 USETW(req.wIndex, 0); 790 USETW(req.wLength, 2); 791 792 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 793 data, 0, NULL, 1000); 794 if (err) { 795 DPRINTFN(0, "device request failed, err=%s " 796 "(ignored)\n", usb2_errstr(err)); 797 data[0] = 0; 798 data[1] = 0; 799 } 800 return (data[0] | (data[1] << 8)); 801} 802