pl2303_dsd.c revision 903:a9ef93192894
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29/* 30 * 31 * USB Prolific PL2303 device-specific driver (DSD) 32 * 33 */ 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/conf.h> 37#include <sys/stream.h> 38#include <sys/strsun.h> 39#include <sys/termio.h> 40#include <sys/termiox.h> 41#include <sys/ddi.h> 42#include <sys/sunddi.h> 43 44#define USBDRV_MAJOR_VER 2 45#define USBDRV_MINOR_VER 0 46 47#include <sys/usb/usba.h> 48#include <sys/usb/usba/usba_types.h> 49#include <sys/usb/usba/usba_impl.h> 50 51#include <sys/usb/clients/usbser/usbser_dsdi.h> 52#include <sys/usb/clients/usbser/usbsprl/pl2303_var.h> 53#include <sys/usb/clients/usbser/usbsprl/pl2303_vendor.h> 54 55 56/* 57 * DSD operations 58 */ 59static int pl2303_attach(ds_attach_info_t *); 60static void pl2303_detach(ds_hdl_t); 61static int pl2303_register_cb(ds_hdl_t, uint_t, ds_cb_t *); 62static void pl2303_unregister_cb(ds_hdl_t, uint_t); 63static int pl2303_open_port(ds_hdl_t, uint_t); 64static int pl2303_close_port(ds_hdl_t, uint_t); 65 66/* power management */ 67static int pl2303_usb_power(ds_hdl_t, int, int, int *); 68static int pl2303_suspend(ds_hdl_t); 69static int pl2303_resume(ds_hdl_t); 70static int pl2303_disconnect(ds_hdl_t); 71static int pl2303_reconnect(ds_hdl_t); 72 73/* standard UART operations */ 74static int pl2303_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *); 75static int pl2303_set_modem_ctl(ds_hdl_t, uint_t, int, int); 76static int pl2303_get_modem_ctl(ds_hdl_t, uint_t, int, int *); 77static int pl2303_break_ctl(ds_hdl_t, uint_t, int); 78 79/* data xfer */ 80static int pl2303_tx(ds_hdl_t, uint_t, mblk_t *); 81static mblk_t *pl2303_rx(ds_hdl_t, uint_t); 82static void pl2303_stop(ds_hdl_t, uint_t, int); 83static void pl2303_start(ds_hdl_t, uint_t, int); 84static int pl2303_fifo_flush(ds_hdl_t, uint_t, int); 85static int pl2303_fifo_drain(ds_hdl_t, uint_t, int); 86 87 88/* 89 * Sub-routines 90 */ 91 92/* configuration routines */ 93static void pl2303_cleanup(pl2303_state_t *, int); 94static int pl2303_dev_attach(pl2303_state_t *); 95static int pl2303_open_hw_port(pl2303_state_t *); 96 97/* hotplug */ 98static int pl2303_restore_device_state(pl2303_state_t *); 99static int pl2303_restore_port_state(pl2303_state_t *); 100 101/* power management */ 102static int pl2303_create_pm_components(pl2303_state_t *); 103static void pl2303_destroy_pm_components(pl2303_state_t *); 104static int pl2303_pm_set_busy(pl2303_state_t *); 105static void pl2303_pm_set_idle(pl2303_state_t *); 106static int pl2303_pwrlvl0(pl2303_state_t *); 107static int pl2303_pwrlvl1(pl2303_state_t *); 108static int pl2303_pwrlvl2(pl2303_state_t *); 109static int pl2303_pwrlvl3(pl2303_state_t *); 110 111/* pipe operations */ 112static int pl2303_open_pipes(pl2303_state_t *); 113static void pl2303_close_pipes(pl2303_state_t *); 114static void pl2303_disconnect_pipes(pl2303_state_t *); 115static int pl2303_reconnect_pipes(pl2303_state_t *); 116 117/* pipe callbacks */ 118void pl2303_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *); 119void pl2303_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *); 120 121/* data transfer routines */ 122static int pl2303_rx_start(pl2303_state_t *); 123static void pl2303_tx_start(pl2303_state_t *, int *); 124static int pl2303_send_data(pl2303_state_t *, mblk_t *); 125static int pl2303_wait_tx_drain(pl2303_state_t *, int); 126 127/* vendor-specific commands */ 128static int pl2303_cmd_get_line(pl2303_state_t *, mblk_t **); 129static int pl2303_cmd_set_line(pl2303_state_t *, mblk_t *); 130static int pl2303_cmd_set_ctl(pl2303_state_t *, uint8_t); 131static int pl2303_cmd_vendor_write0(pl2303_state_t *, uint16_t, int16_t); 132static int pl2303_cmd_set_rtscts(pl2303_state_t *); 133static int pl2303_cmd_break(pl2303_state_t *, int); 134static void pl2303_mctl2reg(int mask, int val, uint8_t *); 135static int pl2303_reg2mctl(uint8_t); 136 137/* misc */ 138static void pl2303_put_tail(mblk_t **, mblk_t *); 139static void pl2303_put_head(mblk_t **, mblk_t *); 140 141 142/* 143 * DSD ops structure 144 */ 145ds_ops_t ds_ops = { 146 DS_OPS_VERSION, 147 pl2303_attach, 148 pl2303_detach, 149 pl2303_register_cb, 150 pl2303_unregister_cb, 151 pl2303_open_port, 152 pl2303_close_port, 153 pl2303_usb_power, 154 pl2303_suspend, 155 pl2303_resume, 156 pl2303_disconnect, 157 pl2303_reconnect, 158 pl2303_set_port_params, 159 pl2303_set_modem_ctl, 160 pl2303_get_modem_ctl, 161 pl2303_break_ctl, 162 NULL, /* HW don't support loopback */ 163 pl2303_tx, 164 pl2303_rx, 165 pl2303_stop, 166 pl2303_start, 167 pl2303_fifo_flush, 168 pl2303_fifo_drain 169}; 170 171 172/* 173 * baud code into baud rate 174 * value 0 means not supported in hardware 175 * 176 */ 177static int pl2303_speedtab[] = { 178 0, /* B0 */ 179 0, /* B50 */ 180 75, /* B75 */ 181 0, /* B110 */ 182 0, /* B134 */ 183 150, /* B150 */ 184 0, /* B200 */ 185 300, /* B300 */ 186 600, /* B600 */ 187 1200, /* B1200 */ 188 1800, /* B1800 */ 189 2400, /* B2400 */ 190 4800, /* B4800 */ 191 9600, /* B9600 */ 192 19200, /* B19200 */ 193 38400, /* B38400 */ 194 57600, /* B57600 */ 195 0, /* B76800 */ 196 115200, /* B115200 */ 197 0, /* B153600 */ 198 230400, /* B230400 */ 199 0, /* B307200 */ 200 460800 /* B460800 */ 201}; 202 203 204/* debug support */ 205static uint_t pl2303_errlevel = USB_LOG_L4; 206static uint_t pl2303_errmask = DPRINT_MASK_ALL; 207static uint_t pl2303_instance_debug = (uint_t)-1; 208 209 210/* 211 * ds_attach 212 */ 213static int 214pl2303_attach(ds_attach_info_t *aip) 215{ 216 pl2303_state_t *plp; 217 218 plp = (pl2303_state_t *)kmem_zalloc(sizeof (pl2303_state_t), KM_SLEEP); 219 plp->pl_dip = aip->ai_dip; 220 plp->pl_usb_events = aip->ai_usb_events; 221 *aip->ai_hdl = (ds_hdl_t)plp; 222 223 /* only one port */ 224 *aip->ai_port_cnt = 1; 225 226 if (usb_client_attach(plp->pl_dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 227 pl2303_cleanup(plp, 1); 228 229 return (USB_FAILURE); 230 } 231 232 if (usb_get_dev_data(plp->pl_dip, &plp->pl_dev_data, USB_PARSE_LVL_IF, 233 0) != USB_SUCCESS) { 234 pl2303_cleanup(plp, 2); 235 236 return (USB_FAILURE); 237 } 238 239 /* 240 * check the chip type: pl2303_H, pl2303_X (or pl2303_HX) 241 * pl2303_UNKNOWN means not supported chip type 242 */ 243 if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_H) { 244 mutex_enter(&plp->pl_mutex); 245 plp->pl_chiptype = pl2303_H; 246 mutex_exit(&plp->pl_mutex); 247 USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh, 248 "Chip Type: pl2303_H"); 249 } else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_X) { 250 /* 251 * pl2303_HX and pl2303_X devices have different hardware, 252 * but from the view of device driver, they have the same 253 * software interface. 254 * 255 * so "pl2303_X" will stand for both pl2303_HX and pl2303_X 256 * devices in this driver 257 */ 258 mutex_enter(&plp->pl_mutex); 259 plp->pl_chiptype = pl2303_X; 260 mutex_exit(&plp->pl_mutex); 261 USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh, 262 "Chip Type: pl2303_HX or pl2303_X"); 263 } else { 264 mutex_enter(&plp->pl_mutex); 265 plp->pl_chiptype = pl2303_UNKNOWN; 266 mutex_exit(&plp->pl_mutex); 267 USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh, 268 "Chip Type: Unknown"); 269 } 270 271 plp->pl_lh = usb_alloc_log_hdl(plp->pl_dip, "pl2303", 272 &pl2303_errlevel, &pl2303_errmask, &pl2303_instance_debug, 0); 273 274 plp->pl_def_ph = plp->pl_dev_data->dev_default_ph; 275 276 mutex_init(&plp->pl_mutex, NULL, MUTEX_DRIVER, 277 plp->pl_dev_data->dev_iblock_cookie); 278 279 cv_init(&plp->pl_tx_cv, NULL, CV_DRIVER, NULL); 280 cv_init(&plp->pl_rx_cv, NULL, CV_DRIVER, NULL); 281 282 mutex_enter(&plp->pl_mutex); 283 plp->pl_dev_state = USB_DEV_ONLINE; 284 plp->pl_port_state = PL2303_PORT_CLOSED; 285 mutex_exit(&plp->pl_mutex); 286 287 if (pl2303_create_pm_components(plp) != USB_SUCCESS) { 288 pl2303_cleanup(plp, 2); 289 290 return (USB_FAILURE); 291 } 292 293 if (usb_register_event_cbs(plp->pl_dip, plp->pl_usb_events, 0) 294 != USB_SUCCESS) { 295 pl2303_cleanup(plp, 3); 296 297 return (USB_FAILURE); 298 } 299 300 if (usb_pipe_get_max_bulk_transfer_size(plp->pl_dip, 301 &plp->pl_xfer_sz) != USB_SUCCESS) { 302 pl2303_cleanup(plp, 4); 303 304 return (USB_FAILURE); 305 } 306 307 if (plp->pl_xfer_sz > PL2303_XFER_SZ_MAX) { 308 plp->pl_xfer_sz = PL2303_XFER_SZ_MAX; 309 } 310 311 if (pl2303_dev_attach(plp) != USB_SUCCESS) { 312 pl2303_cleanup(plp, 4); 313 314 return (USB_FAILURE); 315 } 316 317 return (USB_SUCCESS); 318} 319 320 321/* 322 * ds_detach 323 */ 324static void 325pl2303_detach(ds_hdl_t hdl) 326{ 327 pl2303_state_t *plp = (pl2303_state_t *)hdl; 328 329 pl2303_cleanup(plp, PL2303_CLEANUP_LEVEL_MAX); 330} 331 332 333/* 334 * ds_register_cb 335 */ 336/*ARGSUSED*/ 337static int 338pl2303_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb) 339{ 340 pl2303_state_t *plp = (pl2303_state_t *)hdl; 341 342 plp->pl_cb = *cb; 343 344 return (USB_SUCCESS); 345} 346 347 348/* 349 * ds_unregister_cb 350 */ 351/*ARGSUSED*/ 352static void 353pl2303_unregister_cb(ds_hdl_t hdl, uint_t port_num) 354{ 355 pl2303_state_t *plp = (pl2303_state_t *)hdl; 356 357 bzero(&plp->pl_cb, sizeof (plp->pl_cb)); 358} 359 360 361/* 362 * ds_open_port 363 */ 364/*ARGSUSED*/ 365static int 366pl2303_open_port(ds_hdl_t hdl, uint_t port_num) 367{ 368 pl2303_state_t *plp = (pl2303_state_t *)hdl; 369 int rval = USB_FAILURE; 370 371 USB_DPRINTF_L4(DPRINT_OPEN, plp->pl_lh, "pl2303_open_port"); 372 373 mutex_enter(&plp->pl_mutex); 374 if ((plp->pl_dev_state == USB_DEV_DISCONNECTED) || 375 (plp->pl_port_state != PL2303_PORT_CLOSED)) { 376 mutex_exit(&plp->pl_mutex); 377 378 return (rval); 379 } 380 381 mutex_exit(&plp->pl_mutex); 382 383 if ((rval = pl2303_pm_set_busy(plp)) != USB_SUCCESS) { 384 385 return (rval); 386 } 387 388 /* initialize hardware serial port */ 389 rval = pl2303_open_hw_port(plp); 390 391 if (rval == USB_SUCCESS) { 392 mutex_enter(&plp->pl_mutex); 393 plp->pl_port_state = PL2303_PORT_OPEN; 394 395 /* start to receive data */ 396 (void) pl2303_rx_start(plp); 397 mutex_exit(&plp->pl_mutex); 398 } else { 399 pl2303_pm_set_idle(plp); 400 } 401 402 return (rval); 403} 404 405 406/* 407 * ds_close_port 408 */ 409/*ARGSUSED*/ 410static int 411pl2303_close_port(ds_hdl_t hdl, uint_t port_num) 412{ 413 pl2303_state_t *plp = (pl2303_state_t *)hdl; 414 415 USB_DPRINTF_L4(DPRINT_CLOSE, plp->pl_lh, "pl2303_close_port"); 416 417 mutex_enter(&plp->pl_mutex); 418 419 /* free resources and finalize state */ 420 if (plp->pl_rx_mp) { 421 freemsg(plp->pl_rx_mp); 422 plp->pl_rx_mp = NULL; 423 } 424 if (plp->pl_tx_mp) { 425 freemsg(plp->pl_tx_mp); 426 plp->pl_tx_mp = NULL; 427 } 428 429 plp->pl_port_state = PL2303_PORT_CLOSED; 430 mutex_exit(&plp->pl_mutex); 431 432 pl2303_pm_set_idle(plp); 433 434 return (USB_SUCCESS); 435} 436 437 438/* 439 * power management 440 * ---------------- 441 * 442 * ds_usb_power 443 */ 444/*ARGSUSED*/ 445static int 446pl2303_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state) 447{ 448 pl2303_state_t *plp = (pl2303_state_t *)hdl; 449 pl2303_pm_t *pm = plp->pl_pm; 450 int rval; 451 452 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_usb_power"); 453 454 if (!pm) { 455 456 return (USB_FAILURE); 457 } 458 459 mutex_enter(&plp->pl_mutex); 460 /* 461 * check if we are transitioning to a legal power level 462 */ 463 if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) { 464 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "pl2303_usb_power: " 465 "illegal power level %d, pwr_states=%x", 466 level, pm->pm_pwr_states); 467 mutex_exit(&plp->pl_mutex); 468 469 return (USB_FAILURE); 470 } 471 472 /* 473 * if we are about to raise power and asked to lower power, fail 474 */ 475 if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) { 476 mutex_exit(&plp->pl_mutex); 477 478 return (USB_FAILURE); 479 } 480 481 switch (level) { 482 case USB_DEV_OS_PWR_OFF: 483 rval = pl2303_pwrlvl0(plp); 484 485 break; 486 case USB_DEV_OS_PWR_1: 487 rval = pl2303_pwrlvl1(plp); 488 489 break; 490 case USB_DEV_OS_PWR_2: 491 rval = pl2303_pwrlvl2(plp); 492 493 break; 494 case USB_DEV_OS_FULL_PWR: 495 rval = pl2303_pwrlvl3(plp); 496 497 break; 498 default: 499 ASSERT(0); /* cannot happen */ 500 } 501 502 *new_state = plp->pl_dev_state; 503 mutex_exit(&plp->pl_mutex); 504 505 return (rval); 506} 507 508 509/* 510 * ds_suspend 511 */ 512static int 513pl2303_suspend(ds_hdl_t hdl) 514{ 515 pl2303_state_t *plp = (pl2303_state_t *)hdl; 516 int state; 517 518 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_suspend"); 519 520 mutex_enter(&plp->pl_mutex); 521 state = plp->pl_dev_state = USB_DEV_SUSPENDED; 522 mutex_exit(&plp->pl_mutex); 523 524 pl2303_disconnect_pipes(plp); 525 526 return (state); 527} 528 529 530/* 531 * ds_resume 532 */ 533static int 534pl2303_resume(ds_hdl_t hdl) 535{ 536 pl2303_state_t *plp = (pl2303_state_t *)hdl; 537 int current_state; 538 int rval; 539 540 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_resume"); 541 542 (void) pm_busy_component(plp->pl_dip, 0); 543 (void) pm_raise_power(plp->pl_dip, 0, USB_DEV_OS_FULL_PWR); 544 545 mutex_enter(&plp->pl_mutex); 546 current_state = plp->pl_dev_state; 547 mutex_exit(&plp->pl_mutex); 548 549 if (current_state != USB_DEV_ONLINE) { 550 rval = pl2303_restore_device_state(plp); 551 } else { 552 rval = USB_SUCCESS; 553 } 554 555 (void) pm_idle_component(plp->pl_dip, 0); 556 557 return (rval); 558} 559 560 561/* 562 * ds_disconnect 563 */ 564static int 565pl2303_disconnect(ds_hdl_t hdl) 566{ 567 pl2303_state_t *plp = (pl2303_state_t *)hdl; 568 int state; 569 570 USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_disconnect"); 571 572 mutex_enter(&plp->pl_mutex); 573 state = plp->pl_dev_state = USB_DEV_DISCONNECTED; 574 mutex_exit(&plp->pl_mutex); 575 576 pl2303_disconnect_pipes(plp); 577 578 return (state); 579} 580 581 582/* 583 * ds_reconnect 584 */ 585static int 586pl2303_reconnect(ds_hdl_t hdl) 587{ 588 pl2303_state_t *plp = (pl2303_state_t *)hdl; 589 590 USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_reconnect"); 591 592 return (pl2303_restore_device_state(plp)); 593} 594 595 596/* 597 * standard UART operations 598 * ------------------------ 599 * 600 * 601 * ds_set_port_params 602 */ 603/*ARGSUSED*/ 604static int 605pl2303_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp) 606{ 607 pl2303_state_t *plp = (pl2303_state_t *)hdl; 608 int rval = USB_FAILURE; 609 mblk_t *bp; 610 int i; 611 uint_t ui; 612 int baud; 613 int cnt; 614 ds_port_param_entry_t *pe; 615 uint16_t xonxoff_symbol; 616 uint8_t xon_char; 617 uint8_t xoff_char; 618 619 if (tp == NULL) { 620 621 return (rval); 622 } 623 624 cnt = tp->tp_cnt; 625 pe = tp->tp_entries; 626 627 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_port_params"); 628 629 /* 630 * get Line Coding Structure Request 631 * including: baud rate, stop bit, parity type and data bit 632 */ 633 if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) { 634 635 return (rval); 636 } 637 638 /* translate parameters into device-specific bits */ 639 for (i = 0; i < cnt; i++, pe++) { 640 switch (pe->param) { 641 case DS_PARAM_BAUD: 642 ui = pe->val.ui; 643 644 /* if we don't support this speed, return USB_FAILURE */ 645 if ((ui >= NELEM(pl2303_speedtab)) || 646 ((ui > 0) && (pl2303_speedtab[ui] == 0))) { 647 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, 648 "pl2303_set_port_params: bad baud %d", ui); 649 650 return (USB_FAILURE); 651 } 652 653 baud = pl2303_speedtab[ui]; 654 bp->b_rptr[0] = baud & 0xff; 655 bp->b_rptr[1] = (baud >> 8) & 0xff; 656 bp->b_rptr[2] = (baud >> 16) & 0xff; 657 bp->b_rptr[3] = (baud >> 24) & 0xff; 658 659 break; 660 case DS_PARAM_PARITY: 661 if (pe->val.ui & PARENB) { 662 if (pe->val.ui & PARODD) { 663 bp->b_rptr[5] = 1; 664 } else { 665 bp->b_rptr[5] = 2; 666 } 667 } else { 668 bp->b_rptr[5] = 0; 669 } 670 671 break; 672 case DS_PARAM_STOPB: 673 if (pe->val.ui & CSTOPB) { 674 bp->b_rptr[4] = 2; 675 } else { 676 bp->b_rptr[4] = 0; 677 } 678 679 break; 680 case DS_PARAM_CHARSZ: 681 switch (pe->val.ui) { 682 case CS5: 683 bp->b_rptr[6] = 5; 684 685 break; 686 case CS6: 687 bp->b_rptr[6] = 6; 688 689 break; 690 case CS7: 691 bp->b_rptr[6] = 7; 692 693 break; 694 case CS8: 695 default: 696 bp->b_rptr[6] = 8; 697 698 break; 699 } 700 701 break; 702 case DS_PARAM_XON_XOFF: 703 /* 704 * Software flow control: XON/XOFF 705 * not supported by PL-2303H, HX chips 706 */ 707 if (pe->val.ui & IXON || pe->val.ui & IXOFF) { 708 /* not supported by PL-2303H chip */ 709 switch (plp->pl_chiptype) { 710 case pl2303_H: 711 712 break; 713 case pl2303_X: 714 xon_char = pe->val.uc[0]; 715 xoff_char = pe->val.uc[1]; 716 xonxoff_symbol = (xoff_char << 8) 717 | xon_char; 718 719 rval = pl2303_cmd_vendor_write0( 720 plp, SET_XONXOFF, 721 xonxoff_symbol); 722 723 if (rval != USB_SUCCESS) { 724 USB_DPRINTF_L3(DPRINT_CTLOP, 725 plp->pl_lh, 726 "pl2303_set_port_params: " 727 "set XonXoff failed"); 728 } 729 730 break; 731 case pl2303_UNKNOWN: 732 default: 733 734 break; 735 } 736 } 737 738 break; 739 case DS_PARAM_FLOW_CTL: 740 /* Hardware flow control */ 741 if (pe->val.ui & CTSXON) { 742 if ((rval = pl2303_cmd_set_rtscts(plp)) 743 != USB_SUCCESS) { 744 745 USB_DPRINTF_L3(DPRINT_CTLOP, 746 plp->pl_lh, 747 "pl2303_set_port_params: " 748 "pl2303_cmd_set_rtscts failed"); 749 } 750 } 751 752 break; 753 default: 754 USB_DPRINTF_L2(DPRINT_CTLOP, plp->pl_lh, 755 "pl2303_set_port_params: bad param %d", pe->param); 756 757 break; 758 } 759 } 760 761 /* set new values for Line Coding Structure */ 762 if ((rval = pl2303_cmd_set_line(plp, bp)) != USB_SUCCESS) { 763 764 return (rval); 765 } 766 767 freeb(bp); 768 bp = NULL; 769 770 /* hardware need to get Line Coding Structure again */ 771 if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) { 772 773 if (bp != NULL) { 774 freeb(bp); 775 } 776 777 return (rval); 778 } 779 780 if (bp != NULL) { 781 freeb(bp); 782 } 783 784 return (USB_SUCCESS); 785} 786 787 788/* 789 * ds_set_modem_ctl 790 */ 791/*ARGSUSED*/ 792static int 793pl2303_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val) 794{ 795 pl2303_state_t *plp = (pl2303_state_t *)hdl; 796 int rval = USB_FAILURE; 797 uint8_t new_mctl; 798 799 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_modem_ctl"); 800 801 mutex_enter(&plp->pl_mutex); 802 new_mctl = plp->pl_mctl; 803 mutex_exit(&plp->pl_mutex); 804 805 /* set RTS and DTR */ 806 pl2303_mctl2reg(mask, val, &new_mctl); 807 808 if ((rval = pl2303_cmd_set_ctl(plp, new_mctl)) == USB_SUCCESS) { 809 mutex_enter(&plp->pl_mutex); 810 plp->pl_mctl = new_mctl; 811 mutex_exit(&plp->pl_mutex); 812 } 813 814 return (rval); 815} 816 817 818/* 819 * ds_get_modem_ctl 820 */ 821/*ARGSUSED*/ 822static int 823pl2303_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp) 824{ 825 pl2303_state_t *plp = (pl2303_state_t *)hdl; 826 827 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_get_modem_ctl"); 828 829 mutex_enter(&plp->pl_mutex); 830 831 /* get RTS and DTR */ 832 *valp = pl2303_reg2mctl(plp->pl_mctl) & mask; 833 *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI)); 834 mutex_exit(&plp->pl_mutex); 835 836 return (USB_SUCCESS); 837} 838 839 840/* 841 * ds_break_ctl 842 */ 843/*ARGSUSED*/ 844static int 845pl2303_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl) 846{ 847 pl2303_state_t *plp = (pl2303_state_t *)hdl; 848 849 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_break_ctl"); 850 851 return (pl2303_cmd_break(plp, ctl)); 852} 853 854 855/* 856 * ds_tx 857 */ 858/*ARGSUSED*/ 859static int 860pl2303_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp) 861{ 862 pl2303_state_t *plp = (pl2303_state_t *)hdl; 863 int xferd; 864 865 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx"); 866 867 /* 868 * sanity checks 869 */ 870 if (mp == NULL) { 871 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: mp=NULL"); 872 873 return (USB_SUCCESS); 874 } 875 if (MBLKL(mp) <= 0) { 876 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: len<=0"); 877 freemsg(mp); 878 879 return (USB_SUCCESS); 880 } 881 882 mutex_enter(&plp->pl_mutex); 883 884 pl2303_put_tail(&plp->pl_tx_mp, mp); /* add to the chain */ 885 886 pl2303_tx_start(plp, &xferd); 887 888 mutex_exit(&plp->pl_mutex); 889 890 return (USB_SUCCESS); 891} 892 893 894/* 895 * ds_rx 896 * the real data receiving is in pl2303_open_port 897 */ 898/*ARGSUSED*/ 899static mblk_t * 900pl2303_rx(ds_hdl_t hdl, uint_t port_num) 901{ 902 pl2303_state_t *plp = (pl2303_state_t *)hdl; 903 mblk_t *mp; 904 905 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_rx"); 906 907 mutex_enter(&plp->pl_mutex); 908 mp = plp->pl_rx_mp; 909 plp->pl_rx_mp = NULL; 910 mutex_exit(&plp->pl_mutex); 911 912 return (mp); 913} 914 915 916/* 917 * ds_stop 918 */ 919/*ARGSUSED*/ 920static void 921pl2303_stop(ds_hdl_t hdl, uint_t port_num, int dir) 922{ 923 pl2303_state_t *plp = (pl2303_state_t *)hdl; 924 925 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_stop"); 926 927 if (dir & DS_TX) { 928 mutex_enter(&plp->pl_mutex); 929 plp->pl_port_flags |= PL2303_PORT_TX_STOPPED; 930 mutex_exit(&plp->pl_mutex); 931 } 932} 933 934 935/* 936 * ds_start 937 */ 938/*ARGSUSED*/ 939static void 940pl2303_start(ds_hdl_t hdl, uint_t port_num, int dir) 941{ 942 pl2303_state_t *plp = (pl2303_state_t *)hdl; 943 944 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_start"); 945 946 if (dir & DS_TX) { 947 mutex_enter(&plp->pl_mutex); 948 if (plp->pl_port_flags & PL2303_PORT_TX_STOPPED) { 949 plp->pl_port_flags &= ~PL2303_PORT_TX_STOPPED; 950 pl2303_tx_start(plp, NULL); 951 } 952 mutex_exit(&plp->pl_mutex); 953 } 954} 955 956 957/* 958 * ds_fifo_flush 959 */ 960/*ARGSUSED*/ 961static int 962pl2303_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir) 963{ 964 pl2303_state_t *plp = (pl2303_state_t *)hdl; 965 966 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_flush: dir=%x", 967 dir); 968 969 mutex_enter(&plp->pl_mutex); 970 ASSERT(plp->pl_port_state == PL2303_PORT_OPEN); 971 972 if ((dir & DS_TX) && plp->pl_tx_mp) { 973 freemsg(plp->pl_tx_mp); 974 plp->pl_tx_mp = NULL; 975 } 976 if ((dir & DS_RX) && plp->pl_rx_mp) { 977 freemsg(plp->pl_rx_mp); 978 plp->pl_rx_mp = NULL; 979 } 980 mutex_exit(&plp->pl_mutex); 981 982 return (USB_SUCCESS); 983} 984 985 986/* 987 * ds_fifo_drain 988 */ 989/*ARGSUSED*/ 990static int 991pl2303_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout) 992{ 993 pl2303_state_t *plp = (pl2303_state_t *)hdl; 994 int rval = USB_SUCCESS; 995 996 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_drain"); 997 998 mutex_enter(&plp->pl_mutex); 999 ASSERT(plp->pl_port_state == PL2303_PORT_OPEN); 1000 1001 /* 1002 * for the reason of hardware, set timeout 0 1003 */ 1004 if (pl2303_wait_tx_drain(plp, 0) != USB_SUCCESS) { 1005 1006 mutex_exit(&plp->pl_mutex); 1007 1008 return (USB_FAILURE); 1009 } 1010 1011 mutex_exit(&plp->pl_mutex); 1012 1013 /* wait 500 ms until hw fifo drains */ 1014 delay(drv_usectohz(500*1000)); 1015 1016 return (rval); 1017} 1018 1019 1020/* 1021 * configuration routines 1022 * ---------------------- 1023 * 1024 * clean up routine 1025 */ 1026static void 1027pl2303_cleanup(pl2303_state_t *plp, int level) 1028{ 1029 ASSERT((level > 0) && (level <= PL2303_CLEANUP_LEVEL_MAX)); 1030 1031 switch (level) { 1032 default: 1033 pl2303_close_pipes(plp); 1034 /* FALLTHRU */ 1035 case 4: 1036 usb_unregister_event_cbs(plp->pl_dip, plp->pl_usb_events); 1037 /* FALLTHRU */ 1038 case 3: 1039 pl2303_destroy_pm_components(plp); 1040 mutex_destroy(&plp->pl_mutex); 1041 cv_destroy(&plp->pl_tx_cv); 1042 cv_destroy(&plp->pl_rx_cv); 1043 1044 usb_free_log_hdl(plp->pl_lh); 1045 plp->pl_lh = NULL; 1046 1047 usb_free_descr_tree(plp->pl_dip, plp->pl_dev_data); 1048 plp->pl_def_ph = NULL; 1049 /* FALLTHRU */ 1050 case 2: 1051 usb_client_detach(plp->pl_dip, plp->pl_dev_data); 1052 /* FALLTHRU */ 1053 case 1: 1054 kmem_free(plp, sizeof (pl2303_state_t)); 1055 } 1056} 1057 1058 1059/* 1060 * device specific attach 1061 */ 1062static int 1063pl2303_dev_attach(pl2303_state_t *plp) 1064{ 1065 if (pl2303_open_pipes(plp) != USB_SUCCESS) { 1066 return (USB_FAILURE); 1067 } 1068 1069 return (USB_SUCCESS); 1070} 1071 1072 1073/* 1074 * hotplug 1075 * ------- 1076 * 1077 * 1078 * restore device state after CPR resume or reconnect 1079 */ 1080static int 1081pl2303_restore_device_state(pl2303_state_t *plp) 1082{ 1083 int state; 1084 1085 mutex_enter(&plp->pl_mutex); 1086 state = plp->pl_dev_state; 1087 mutex_exit(&plp->pl_mutex); 1088 1089 if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) { 1090 1091 return (state); 1092 } 1093 1094 if (usb_check_same_device(plp->pl_dip, plp->pl_lh, USB_LOG_L2, 1095 DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) { 1096 mutex_enter(&plp->pl_mutex); 1097 state = plp->pl_dev_state = USB_DEV_DISCONNECTED; 1098 mutex_exit(&plp->pl_mutex); 1099 1100 return (state); 1101 } 1102 1103 if (state == USB_DEV_DISCONNECTED) { 1104 USB_DPRINTF_L0(DPRINT_HOTPLUG, plp->pl_lh, 1105 "Device has been reconnected but data may have been lost"); 1106 } 1107 1108 if (pl2303_reconnect_pipes(plp) != USB_SUCCESS) { 1109 1110 return (state); 1111 } 1112 1113 /* 1114 * init device state 1115 */ 1116 mutex_enter(&plp->pl_mutex); 1117 state = plp->pl_dev_state = USB_DEV_ONLINE; 1118 mutex_exit(&plp->pl_mutex); 1119 1120 if ((pl2303_restore_port_state(plp) != USB_SUCCESS)) { 1121 USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh, 1122 "pl2303_restore_device_state: failed"); 1123 } 1124 1125 return (state); 1126} 1127 1128 1129/* 1130 * restore ports state after CPR resume or reconnect 1131 */ 1132static int 1133pl2303_restore_port_state(pl2303_state_t *plp) 1134{ 1135 int rval; 1136 1137 mutex_enter(&plp->pl_mutex); 1138 if (plp->pl_port_state != PL2303_PORT_OPEN) { 1139 mutex_exit(&plp->pl_mutex); 1140 1141 return (USB_SUCCESS); 1142 } 1143 mutex_exit(&plp->pl_mutex); 1144 1145 /* open hardware serial port */ 1146 if ((rval = pl2303_open_hw_port(plp)) != USB_SUCCESS) { 1147 USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh, 1148 "pl2303_restore_ports_state: failed"); 1149 } 1150 1151 return (rval); 1152} 1153 1154 1155/* 1156 * power management 1157 * ---------------- 1158 * 1159 * 1160 * create PM components 1161 */ 1162static int 1163pl2303_create_pm_components(pl2303_state_t *plp) 1164{ 1165 dev_info_t *dip = plp->pl_dip; 1166 pl2303_pm_t *pm; 1167 uint_t pwr_states; 1168 1169 if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) { 1170 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, 1171 "pl2303_create_pm_components: failed"); 1172 1173 return (USB_SUCCESS); 1174 } 1175 1176 pm = plp->pl_pm = kmem_zalloc(sizeof (pl2303_pm_t), KM_SLEEP); 1177 1178 pm->pm_pwr_states = (uint8_t)pwr_states; 1179 pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 1180 pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip, 1181 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS); 1182 1183 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1184 1185 return (USB_SUCCESS); 1186} 1187 1188 1189/* 1190 * destroy PM components 1191 */ 1192static void 1193pl2303_destroy_pm_components(pl2303_state_t *plp) 1194{ 1195 pl2303_pm_t *pm = plp->pl_pm; 1196 dev_info_t *dip = plp->pl_dip; 1197 int rval; 1198 1199 if (!pm) 1200 1201 return; 1202 1203 if (plp->pl_dev_state != USB_DEV_DISCONNECTED) { 1204 if (pm->pm_wakeup_enabled) { 1205 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1206 if (rval != DDI_SUCCESS) { 1207 USB_DPRINTF_L1(DPRINT_PM, plp->pl_lh, 1208 "pl2303_destroy_pm_components:" 1209 "raising power failed, rval=%d", rval); 1210 } 1211 1212 rval = usb_handle_remote_wakeup(dip, 1213 USB_REMOTE_WAKEUP_DISABLE); 1214 if (rval != USB_SUCCESS) { 1215 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, 1216 "pl2303_destroy_pm_components: disable " 1217 "remote wakeup failed, rval=%d", rval); 1218 } 1219 } 1220 1221 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 1222 } 1223 kmem_free(pm, sizeof (pl2303_pm_t)); 1224 plp->pl_pm = NULL; 1225} 1226 1227 1228/* 1229 * mark device busy and raise power 1230 */ 1231static int 1232pl2303_pm_set_busy(pl2303_state_t *plp) 1233{ 1234 pl2303_pm_t *pm = plp->pl_pm; 1235 dev_info_t *dip = plp->pl_dip; 1236 int rval; 1237 1238 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_busy"); 1239 1240 if (!pm) { 1241 1242 return (USB_SUCCESS); 1243 } 1244 1245 mutex_enter(&plp->pl_mutex); 1246 /* if already marked busy, just increment the counter */ 1247 if (pm->pm_busy_cnt++ > 0) { 1248 mutex_exit(&plp->pl_mutex); 1249 1250 return (USB_SUCCESS); 1251 } 1252 1253 rval = pm_busy_component(dip, 0); 1254 ASSERT(rval == DDI_SUCCESS); 1255 1256 if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) { 1257 mutex_exit(&plp->pl_mutex); 1258 1259 return (USB_SUCCESS); 1260 } 1261 1262 /* need to raise power */ 1263 pm->pm_raise_power = B_TRUE; 1264 mutex_exit(&plp->pl_mutex); 1265 1266 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1267 if (rval != DDI_SUCCESS) { 1268 USB_DPRINTF_L1(DPRINT_PM, plp->pl_lh, "raising power failed"); 1269 } 1270 1271 mutex_enter(&plp->pl_mutex); 1272 pm->pm_raise_power = B_FALSE; 1273 mutex_exit(&plp->pl_mutex); 1274 1275 return (USB_SUCCESS); 1276} 1277 1278 1279/* 1280 * mark device idle 1281 */ 1282static void 1283pl2303_pm_set_idle(pl2303_state_t *plp) 1284{ 1285 pl2303_pm_t *pm = plp->pl_pm; 1286 dev_info_t *dip = plp->pl_dip; 1287 1288 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_idle"); 1289 1290 if (!pm) { 1291 1292 return; 1293 } 1294 1295 /* 1296 * if more ports use the device, do not mark as yet 1297 */ 1298 mutex_enter(&plp->pl_mutex); 1299 if (--pm->pm_busy_cnt > 0) { 1300 mutex_exit(&plp->pl_mutex); 1301 1302 return; 1303 } 1304 1305 if (pm) { 1306 (void) pm_idle_component(dip, 0); 1307 } 1308 mutex_exit(&plp->pl_mutex); 1309} 1310 1311 1312/* 1313 * Functions to handle power transition for OS levels 0 -> 3 1314 * The same level as OS state, different from USB state 1315 */ 1316static int 1317pl2303_pwrlvl0(pl2303_state_t *plp) 1318{ 1319 int rval; 1320 1321 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl0"); 1322 1323 switch (plp->pl_dev_state) { 1324 case USB_DEV_ONLINE: 1325 /* issue USB D3 command to the device */ 1326 rval = usb_set_device_pwrlvl3(plp->pl_dip); 1327 ASSERT(rval == USB_SUCCESS); 1328 1329 plp->pl_dev_state = USB_DEV_PWRED_DOWN; 1330 plp->pl_pm->pm_cur_power = USB_DEV_OS_PWR_OFF; 1331 1332 /* FALLTHRU */ 1333 case USB_DEV_DISCONNECTED: 1334 case USB_DEV_SUSPENDED: 1335 /* allow a disconnect/cpr'ed device to go to lower power */ 1336 1337 return (USB_SUCCESS); 1338 case USB_DEV_PWRED_DOWN: 1339 default: 1340 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, 1341 "pl2303_pwrlvl0: illegal device state"); 1342 1343 return (USB_FAILURE); 1344 } 1345} 1346 1347 1348static int 1349pl2303_pwrlvl1(pl2303_state_t *plp) 1350{ 1351 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl1"); 1352 1353 /* issue USB D2 command to the device */ 1354 (void) usb_set_device_pwrlvl2(plp->pl_dip); 1355 1356 return (USB_FAILURE); 1357} 1358 1359 1360static int 1361pl2303_pwrlvl2(pl2303_state_t *plp) 1362{ 1363 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl2"); 1364 1365 /* issue USB D1 command to the device */ 1366 (void) usb_set_device_pwrlvl1(plp->pl_dip); 1367 1368 return (USB_FAILURE); 1369} 1370 1371 1372static int 1373pl2303_pwrlvl3(pl2303_state_t *plp) 1374{ 1375 int rval; 1376 1377 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl3"); 1378 1379 switch (plp->pl_dev_state) { 1380 case USB_DEV_PWRED_DOWN: 1381 /* Issue USB D0 command to the device here */ 1382 rval = usb_set_device_pwrlvl0(plp->pl_dip); 1383 ASSERT(rval == USB_SUCCESS); 1384 1385 plp->pl_dev_state = USB_DEV_ONLINE; 1386 plp->pl_pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 1387 1388 /* FALLTHRU */ 1389 case USB_DEV_ONLINE: 1390 /* we are already in full power */ 1391 1392 /* FALLTHRU */ 1393 case USB_DEV_DISCONNECTED: 1394 case USB_DEV_SUSPENDED: 1395 1396 return (USB_SUCCESS); 1397 default: 1398 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, 1399 "pl2303_pwrlvl3: illegal device state"); 1400 1401 return (USB_FAILURE); 1402 } 1403} 1404 1405 1406/* 1407 * pipe operations 1408 * --------------- 1409 * 1410 * 1411 */ 1412static int 1413pl2303_open_pipes(pl2303_state_t *plp) 1414{ 1415 int ifc, alt; 1416 usb_pipe_policy_t policy; 1417 usb_ep_data_t *in_data, *out_data; 1418 1419 /* get ep data */ 1420 ifc = plp->pl_dev_data->dev_curr_if; 1421 alt = 0; 1422 1423 in_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt, 1424 0, USB_EP_ATTR_BULK, USB_EP_DIR_IN); 1425 1426 out_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt, 1427 0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 1428 1429 if ((in_data == NULL) || (out_data == NULL)) { 1430 USB_DPRINTF_L2(DPRINT_ATTACH, plp->pl_lh, 1431 "pl2303_open_pipes: can't get ep data"); 1432 1433 return (USB_FAILURE); 1434 } 1435 1436 /* open pipes */ 1437 policy.pp_max_async_reqs = 2; 1438 1439 if (usb_pipe_open(plp->pl_dip, &in_data->ep_descr, &policy, 1440 USB_FLAGS_SLEEP, &plp->pl_bulkin_ph) != USB_SUCCESS) { 1441 1442 return (USB_FAILURE); 1443 } 1444 1445 if (usb_pipe_open(plp->pl_dip, &out_data->ep_descr, &policy, 1446 USB_FLAGS_SLEEP, &plp->pl_bulkout_ph) != USB_SUCCESS) { 1447 usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP, 1448 NULL, NULL); 1449 1450 return (USB_FAILURE); 1451 } 1452 1453 mutex_enter(&plp->pl_mutex); 1454 plp->pl_bulkin_state = PL2303_PIPE_IDLE; 1455 plp->pl_bulkout_state = PL2303_PIPE_IDLE; 1456 mutex_exit(&plp->pl_mutex); 1457 1458 return (USB_SUCCESS); 1459} 1460 1461 1462static void 1463pl2303_close_pipes(pl2303_state_t *plp) 1464{ 1465 mutex_enter(&plp->pl_mutex); 1466 if (plp->pl_dev_state == USB_DEV_ONLINE) { 1467 USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh, 1468 "pl2303_close_pipes: waiting for idle bulkin\n"); 1469 while (plp->pl_bulkin_state != PL2303_PIPE_IDLE) { 1470 cv_wait(&plp->pl_rx_cv, &plp->pl_mutex); 1471 } 1472 } 1473 mutex_exit(&plp->pl_mutex); 1474 1475 usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP, 0, 0); 1476 usb_pipe_close(plp->pl_dip, plp->pl_bulkout_ph, USB_FLAGS_SLEEP, 0, 0); 1477 1478 mutex_enter(&plp->pl_mutex); 1479 plp->pl_bulkin_state = PL2303_PIPE_CLOSED; 1480 plp->pl_bulkout_state = PL2303_PIPE_CLOSED; 1481 mutex_exit(&plp->pl_mutex); 1482} 1483 1484 1485static void 1486pl2303_disconnect_pipes(pl2303_state_t *plp) 1487{ 1488 pl2303_close_pipes(plp); 1489} 1490 1491 1492static int 1493pl2303_reconnect_pipes(pl2303_state_t *plp) 1494{ 1495 if ((pl2303_open_pipes(plp) != USB_SUCCESS)) { 1496 1497 return (USB_FAILURE); 1498 } 1499 1500 return (USB_SUCCESS); 1501} 1502 1503 1504/* 1505 * pipe callbacks 1506 * -------------- 1507 * 1508 * 1509 * bulk in common and exeception callback 1510 * 1511 */ 1512/*ARGSUSED*/ 1513void 1514pl2303_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 1515{ 1516 pl2303_state_t *plp = (pl2303_state_t *)req->bulk_client_private; 1517 mblk_t *data; 1518 int data_len; 1519 1520 data = req->bulk_data; 1521 data_len = (data) ? MBLKL(data) : 0; 1522 1523 USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh, "pl2303_bulkin_cb: " 1524 "cr=%d len=%d", 1525 req->bulk_completion_reason, 1526 data_len); 1527 1528 /* save data and notify GSD */ 1529 if ((plp->pl_port_state == PL2303_PORT_OPEN) && (data_len) && 1530 (req->bulk_completion_reason == USB_CR_OK)) { 1531 req->bulk_data = NULL; 1532 pl2303_put_tail(&plp->pl_rx_mp, data); 1533 if (plp->pl_cb.cb_rx) { 1534 plp->pl_cb.cb_rx(plp->pl_cb.cb_arg); 1535 } 1536 } 1537 1538 usb_free_bulk_req(req); 1539 1540 /* receive more */ 1541 mutex_enter(&plp->pl_mutex); 1542 plp->pl_bulkin_state = PL2303_PIPE_IDLE; 1543 if (plp->pl_port_state == PL2303_PORT_OPEN) { 1544 (void) pl2303_rx_start(plp); 1545 } else { 1546 plp->pl_bulkin_state = PL2303_PIPE_IDLE; 1547 cv_broadcast(&plp->pl_rx_cv); 1548 } 1549 mutex_exit(&plp->pl_mutex); 1550} 1551 1552 1553/* 1554 * bulk out common and exeception callback 1555 */ 1556/*ARGSUSED*/ 1557void 1558pl2303_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 1559{ 1560 pl2303_state_t *plp = (pl2303_state_t *)req->bulk_client_private; 1561 int data_len; 1562 mblk_t *data = req->bulk_data; 1563 1564 data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0; 1565 1566 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, 1567 "pl2303_bulkout_cb: cr=%d len=%d", 1568 req->bulk_completion_reason, 1569 data_len); 1570 1571 if (req->bulk_completion_reason && (data_len > 0)) { 1572 pl2303_put_head(&plp->pl_tx_mp, data); 1573 req->bulk_data = NULL; 1574 } 1575 1576 usb_free_bulk_req(req); 1577 1578 /* notify GSD */ 1579 if (plp->pl_cb.cb_tx) { 1580 plp->pl_cb.cb_tx(plp->pl_cb.cb_arg); 1581 } 1582 1583 /* send more */ 1584 mutex_enter(&plp->pl_mutex); 1585 plp->pl_bulkout_state = PL2303_PIPE_IDLE; 1586 if (plp->pl_tx_mp == NULL) { 1587 cv_broadcast(&plp->pl_tx_cv); 1588 } else { 1589 pl2303_tx_start(plp, NULL); 1590 } 1591 mutex_exit(&plp->pl_mutex); 1592} 1593 1594 1595/* 1596 * data transfer routines 1597 * ---------------------- 1598 * 1599 * 1600 * start data receipt 1601 */ 1602static int 1603pl2303_rx_start(pl2303_state_t *plp) 1604{ 1605 usb_bulk_req_t *br; 1606 int rval = USB_FAILURE; 1607 1608 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_rx_start"); 1609 1610 ASSERT(mutex_owned(&plp->pl_mutex)); 1611 1612 plp->pl_bulkin_state = PL2303_PIPE_BUSY; 1613 mutex_exit(&plp->pl_mutex); 1614 1615 br = usb_alloc_bulk_req(plp->pl_dip, plp->pl_xfer_sz, USB_FLAGS_SLEEP); 1616 br->bulk_len = plp->pl_xfer_sz; 1617 br->bulk_timeout = PL2303_BULKIN_TIMEOUT; 1618 br->bulk_cb = pl2303_bulkin_cb; 1619 br->bulk_exc_cb = pl2303_bulkin_cb; 1620 br->bulk_client_private = (usb_opaque_t)plp; 1621 br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK; 1622 1623 rval = usb_pipe_bulk_xfer(plp->pl_bulkin_ph, br, 0); 1624 1625 if (rval != USB_SUCCESS) { 1626 USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh, 1627 "pl2303_rx_start: xfer failed %d", rval); 1628 usb_free_bulk_req(br); 1629 } 1630 1631 mutex_enter(&plp->pl_mutex); 1632 if (rval != USB_SUCCESS) { 1633 plp->pl_bulkin_state = PL2303_PIPE_IDLE; 1634 } 1635 1636 return (rval); 1637} 1638 1639 1640/* 1641 * start data transmit 1642 */ 1643static void 1644pl2303_tx_start(pl2303_state_t *plp, int *xferd) 1645{ 1646 int len; /* bytes we can transmit */ 1647 mblk_t *data; /* data to be transmitted */ 1648 int data_len; /* bytes in 'data' */ 1649 mblk_t *mp; /* current msgblk */ 1650 int copylen; /* bytes copy from 'mp' to 'data' */ 1651 int rval; 1652 1653 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_tx_start"); 1654 ASSERT(mutex_owned(&plp->pl_mutex)); 1655 ASSERT(plp->pl_port_state != PL2303_PORT_CLOSED); 1656 1657 if (xferd) { 1658 *xferd = 0; 1659 } 1660 if ((plp->pl_port_flags & PL2303_PORT_TX_STOPPED) || 1661 (plp->pl_tx_mp == NULL)) { 1662 1663 return; 1664 } 1665 if (plp->pl_bulkout_state != PL2303_PIPE_IDLE) { 1666 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, 1667 "pl2303_tx_start: pipe busy"); 1668 1669 return; 1670 } 1671 ASSERT(MBLKL(plp->pl_tx_mp) > 0); 1672 1673 /* send as much data as port can receive */ 1674 len = min(msgdsize(plp->pl_tx_mp), plp->pl_xfer_sz); 1675 1676 if (len == 0) { 1677 1678 return; 1679 } 1680 1681 if ((data = allocb(len, BPRI_LO)) == NULL) { 1682 1683 return; 1684 } 1685 1686 /* 1687 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data' 1688 */ 1689 data_len = 0; 1690 1691 while ((data_len < len) && plp->pl_tx_mp) { 1692 mp = plp->pl_tx_mp; 1693 copylen = min(MBLKL(mp), len - data_len); 1694 bcopy(mp->b_rptr, data->b_wptr, copylen); 1695 mp->b_rptr += copylen; 1696 data->b_wptr += copylen; 1697 data_len += copylen; 1698 1699 if (MBLKL(mp) <= 0) { 1700 plp->pl_tx_mp = unlinkb(mp); 1701 freeb(mp); 1702 } else { 1703 ASSERT(data_len == len); 1704 } 1705 } 1706 1707 if (data_len <= 0) { 1708 USB_DPRINTF_L3(DPRINT_OUT_PIPE, plp->pl_lh, 1709 "pl2303_tx_start: copied zero bytes"); 1710 freeb(data); 1711 1712 return; 1713 } 1714 1715 plp->pl_bulkout_state = PL2303_PIPE_BUSY; 1716 mutex_exit(&plp->pl_mutex); 1717 1718 rval = pl2303_send_data(plp, data); 1719 mutex_enter(&plp->pl_mutex); 1720 1721 if (rval != USB_SUCCESS) { 1722 plp->pl_bulkout_state = PL2303_PIPE_IDLE; 1723 if (plp->pl_tx_mp == NULL) { 1724 plp->pl_tx_mp = data; 1725 } 1726 1727 } else { 1728 if (xferd) { 1729 *xferd = data_len; 1730 } 1731 } 1732} 1733 1734 1735static int 1736pl2303_send_data(pl2303_state_t *plp, mblk_t *data) 1737{ 1738 usb_bulk_req_t *br; 1739 int len = MBLKL(data); 1740 int rval; 1741 1742 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_send_data: %d " 1743 "%x %x %x", len, data->b_rptr[0], 1744 (len > 1) ? data->b_rptr[1] : 0, 1745 (len > 2) ? data->b_rptr[2] : 0); 1746 ASSERT(!mutex_owned(&plp->pl_mutex)); 1747 1748 br = usb_alloc_bulk_req(plp->pl_dip, 0, USB_FLAGS_SLEEP); 1749 br->bulk_data = data; 1750 br->bulk_len = len; 1751 br->bulk_timeout = PL2303_BULKOUT_TIMEOUT; 1752 br->bulk_cb = pl2303_bulkout_cb; 1753 br->bulk_exc_cb = pl2303_bulkout_cb; 1754 br->bulk_client_private = (usb_opaque_t)plp; 1755 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 1756 1757 rval = usb_pipe_bulk_xfer(plp->pl_bulkout_ph, br, 0); 1758 1759 if (rval != USB_SUCCESS) { 1760 USB_DPRINTF_L2(DPRINT_OUT_PIPE, plp->pl_lh, 1761 "pl2303_send_data: xfer failed %d", rval); 1762 usb_free_bulk_req(br); 1763 } 1764 1765 return (rval); 1766} 1767 1768 1769/* 1770 * wait until local tx buffer drains. 1771 * 'timeout' is in seconds, zero means wait forever 1772 */ 1773static int 1774pl2303_wait_tx_drain(pl2303_state_t *plp, int timeout) 1775{ 1776 clock_t until; 1777 int over = 0; 1778 1779 until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout); 1780 1781 while (plp->pl_tx_mp && !over) { 1782 if (timeout > 0) { 1783 /* whether timedout or signal pending */ 1784 over = (cv_timedwait_sig(&plp->pl_tx_cv, 1785 &plp->pl_mutex, until) <= 0); 1786 } else { 1787 /* whether a signal is pending */ 1788 over = (cv_wait_sig(&plp->pl_tx_cv, 1789 &plp->pl_mutex) == 0); 1790 } 1791 } 1792 1793 return ((plp->pl_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE); 1794} 1795 1796 1797/* 1798 * device operations 1799 * ----------------- 1800 * 1801 * 1802 * initialize hardware serial port 1803 */ 1804static int 1805pl2303_open_hw_port(pl2303_state_t *plp) 1806{ 1807 int rval = USB_SUCCESS; 1808 1809 /* 1810 * initialize three Device Configuration Registers (DCR): 1811 * DCR0, DCR1, and DCR2 1812 */ 1813 1814 switch (plp->pl_chiptype) { 1815 case (pl2303_H): 1816 /* Set DCR0 */ 1817 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0, 1818 DCR0_INIT_H)) != USB_SUCCESS) { 1819 1820 return (rval); 1821 } 1822 1823 /* Set DCR1 */ 1824 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1, 1825 DCR1_INIT_H)) != USB_SUCCESS) { 1826 1827 return (rval); 1828 } 1829 1830 /* Set DCR2 */ 1831 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2, 1832 DCR2_INIT_H)) != USB_SUCCESS) { 1833 1834 return (rval); 1835 } 1836 1837 break; 1838 case (pl2303_X): 1839 1840 /* Set DCR0 */ 1841 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0, 1842 DCR0_INIT)) != USB_SUCCESS) { 1843 1844 return (rval); 1845 } 1846 1847 /* Set DCR1 */ 1848 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1, 1849 DCR1_INIT_X)) != USB_SUCCESS) { 1850 1851 return (rval); 1852 } 1853 1854 /* Set DCR2 */ 1855 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2, 1856 DCR2_INIT_X)) != USB_SUCCESS) { 1857 1858 return (rval); 1859 } 1860 1861 /* reset Downstream data pipes */ 1862 if ((rval = pl2303_cmd_vendor_write0(plp, 1863 RESET_DOWNSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) { 1864 1865 return (rval); 1866 } 1867 1868 /* reset Upstream data pipes */ 1869 if ((rval = pl2303_cmd_vendor_write0(plp, 1870 RESET_UPSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) { 1871 1872 return (rval); 1873 } 1874 1875 break; 1876 case (pl2303_UNKNOWN): 1877 default: 1878 USB_DPRINTF_L2(DPRINT_OPEN, plp->pl_lh, 1879 "pl2303_open_hw_port: unknown chiptype"); 1880 1881 rval = USB_FAILURE; 1882 } 1883 1884 return (rval); 1885} 1886 1887 1888/* 1889 * vendor-specific commands 1890 * ------------------------ 1891 * 1892 * 1893 * Get_Line_Coding Request 1894 */ 1895static int 1896pl2303_cmd_get_line(pl2303_state_t *plp, mblk_t **data) 1897{ 1898 usb_ctrl_setup_t setup = { PL2303_GET_LINE_CODING_REQUEST_TYPE, 1899 PL2303_GET_LINE_CODING_REQUEST, 0, 0, 1900 PL2303_GET_LINE_CODING_LENGTH, 0 }; 1901 usb_cb_flags_t cb_flags; 1902 usb_cr_t cr; 1903 int rval; 1904 1905 *data = NULL; 1906 1907 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, data, 1908 &cr, &cb_flags, 0); 1909 1910 if ((rval == USB_SUCCESS) && (*data != NULL)) { 1911 USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh, 1912 "pl2303_cmd_get_line: %x %x %x %x %x %x %x", 1913 (*data)->b_rptr[0], (*data)->b_rptr[1], (*data)->b_rptr[2], 1914 (*data)->b_rptr[3], (*data)->b_rptr[4], (*data)->b_rptr[5], 1915 (*data)->b_rptr[6]); 1916 } else { 1917 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh, 1918 "pl2303_cmd_get_line: failed %d %d %x", 1919 rval, cr, cb_flags); 1920 } 1921 1922 return (rval); 1923} 1924 1925 1926/* 1927 * Set_Line_Coding Request 1928 */ 1929static int 1930pl2303_cmd_set_line(pl2303_state_t *plp, mblk_t *data) 1931{ 1932 usb_ctrl_setup_t setup = { PL2303_SET_LINE_CODING_REQUEST_TYPE, 1933 PL2303_SET_LINE_CODING_REQUEST, 0, 0, 1934 PL2303_SET_LINE_CODING_LENGTH, 0 }; 1935 usb_cb_flags_t cb_flags; 1936 usb_cr_t cr; 1937 int rval; 1938 1939 USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh, 1940 "pl2303_cmd_set_line: %x %x %x %x %x %x %x", 1941 data->b_rptr[0], data->b_rptr[1], data->b_rptr[2], 1942 data->b_rptr[3], data->b_rptr[4], data->b_rptr[5], data->b_rptr[6]); 1943 1944 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, &data, 1945 &cr, &cb_flags, 0); 1946 1947 if (rval != USB_SUCCESS) { 1948 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh, 1949 "pl2303_cmd_set_line: failed %d %d %x", 1950 rval, cr, cb_flags); 1951 } 1952 1953 return (rval); 1954} 1955 1956 1957/* 1958 * Set_Control_Line_State Request to RTS and DTR 1959 */ 1960static int 1961pl2303_cmd_set_ctl(pl2303_state_t *plp, uint8_t val) 1962{ 1963 usb_ctrl_setup_t setup = { PL2303_SET_CONTROL_REQUEST_TYPE, 1964 PL2303_SET_CONTROL_REQUEST, 0, 0, 1965 PL2303_SET_CONTROL_LENGTH, 0 }; 1966 usb_cb_flags_t cb_flags; 1967 usb_cr_t cr; 1968 int rval; 1969 1970 setup.wValue = val; 1971 1972 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL, 1973 &cr, &cb_flags, 0); 1974 1975 if (rval != USB_SUCCESS) { 1976 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh, 1977 "pl2303_cmd_set_ctl: failed %d %d %x", 1978 rval, cr, cb_flags); 1979 } 1980 1981 return (rval); 1982} 1983 1984 1985/* 1986 * Vendor_Specific_Write Request 1987 * wLength: 0 1988 */ 1989static int 1990pl2303_cmd_vendor_write0(pl2303_state_t *plp, uint16_t value, int16_t index) 1991{ 1992 usb_ctrl_setup_t setup = { PL2303_VENDOR_WRITE_REQUEST_TYPE, 1993 PL2303_VENDOR_WRITE_REQUEST, 0, 0, 1994 PL2303_VENDOR_WRITE_LENGTH, 0 }; 1995 usb_cb_flags_t cb_flags; 1996 usb_cr_t cr; 1997 int rval; 1998 1999 setup.wValue = value; 2000 setup.wIndex = index; 2001 2002 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL, 2003 &cr, &cb_flags, 0); 2004 2005 if (rval != USB_SUCCESS) { 2006 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh, 2007 "pl2303_cmd_vendor_write0: %x %x failed %d %d %x", 2008 value, index, rval, cr, cb_flags); 2009 } 2010 2011 return (rval); 2012} 2013 2014 2015/* 2016 * For Hardware flow control 2017 */ 2018static int 2019pl2303_cmd_set_rtscts(pl2303_state_t *plp) 2020{ 2021 /* Set DCR0 */ 2022 switch (plp->pl_chiptype) { 2023 case pl2303_H: 2024 2025 return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_H)); 2026 case pl2303_X: 2027 2028 return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_X)); 2029 case pl2303_UNKNOWN: 2030 default: 2031 2032 return (USB_FAILURE); 2033 } 2034} 2035 2036 2037/* 2038 * Set TxD BREAK_ON or BREAK_OFF 2039 */ 2040static int 2041pl2303_cmd_break(pl2303_state_t *plp, int ctl) 2042{ 2043 usb_ctrl_setup_t setup = { PL2303_BREAK_REQUEST_TYPE, 2044 PL2303_BREAK_REQUEST, 0, 0, 2045 PL2303_BREAK_LENGTH, 0 }; 2046 usb_cb_flags_t cb_flags; 2047 usb_cr_t cr; 2048 int rval; 2049 2050 setup.wValue = (ctl == DS_ON) ? PL2303_BREAK_ON : PL2303_BREAK_OFF; 2051 2052 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL, 2053 &cr, &cb_flags, 0); 2054 2055 if (rval != USB_SUCCESS) { 2056 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh, 2057 "pl2303_cmd_break: failed rval=%d,cr=%d,cb_flags=0x%x", 2058 rval, cr, cb_flags); 2059 } 2060 2061 return (rval); 2062} 2063 2064 2065/* 2066 * for set_mod_ctl 2067 */ 2068static void 2069pl2303_mctl2reg(int mask, int val, uint8_t *line_ctl) 2070{ 2071 if (mask & TIOCM_RTS) { 2072 if (val & TIOCM_RTS) { 2073 *line_ctl |= PL2303_CONTROL_RTS; 2074 } else { 2075 *line_ctl &= ~PL2303_CONTROL_RTS; 2076 } 2077 } 2078 if (mask & TIOCM_DTR) { 2079 if (val & TIOCM_DTR) { 2080 *line_ctl |= PL2303_CONTROL_DTR; 2081 } else { 2082 *line_ctl &= ~PL2303_CONTROL_DTR; 2083 } 2084 } 2085} 2086 2087 2088/* 2089 * for get_mod_ctl 2090 */ 2091static int 2092pl2303_reg2mctl(uint8_t line_ctl) 2093{ 2094 int val = 0; 2095 2096 if (line_ctl & PL2303_CONTROL_RTS) { 2097 val |= TIOCM_RTS; 2098 } 2099 if (line_ctl & PL2303_CONTROL_DTR) { 2100 val |= TIOCM_DTR; 2101 } 2102 2103 return (val); 2104} 2105 2106 2107/* 2108 * misc routines 2109 * ------------- 2110 * 2111 */ 2112 2113/* 2114 * link a message block to tail of message 2115 * account for the case when message is null 2116 */ 2117static void 2118pl2303_put_tail(mblk_t **mpp, mblk_t *bp) 2119{ 2120 if (*mpp) { 2121 linkb(*mpp, bp); 2122 } else { 2123 *mpp = bp; 2124 } 2125} 2126 2127 2128/* 2129 * put a message block at the head of the message 2130 * account for the case when message is null 2131 */ 2132static void 2133pl2303_put_head(mblk_t **mpp, mblk_t *bp) 2134{ 2135 if (*mpp) { 2136 linkb(bp, *mpp); 2137 } 2138 *mpp = bp; 2139} 2140