kernel: use ddi_msleep() instead of delay(drv_usectohz(x))
[unleashed.git] / usr / src / uts / common / io / usb / clients / usbser / usbsprl / pl2303_dsd.c
blobb3635e70da15fc38fcdabbd57f9a4c1efe815d32
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * USB Prolific PL2303 device-specific driver (DSD)
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/conf.h>
35 #include <sys/stream.h>
36 #include <sys/strsun.h>
37 #include <sys/termio.h>
38 #include <sys/termiox.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
42 #define USBDRV_MAJOR_VER 2
43 #define USBDRV_MINOR_VER 0
45 #include <sys/usb/usba.h>
46 #include <sys/usb/usba/usba_types.h>
47 #include <sys/usb/usba/usba_impl.h>
49 #include <sys/usb/clients/usbser/usbser_dsdi.h>
50 #include <sys/usb/clients/usbser/usbsprl/pl2303_var.h>
51 #include <sys/usb/clients/usbser/usbsprl/pl2303_vendor.h>
55 * DSD operations
57 static int pl2303_attach(ds_attach_info_t *);
58 static void pl2303_detach(ds_hdl_t);
59 static int pl2303_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
60 static void pl2303_unregister_cb(ds_hdl_t, uint_t);
61 static int pl2303_open_port(ds_hdl_t, uint_t);
62 static int pl2303_close_port(ds_hdl_t, uint_t);
64 /* power management */
65 static int pl2303_usb_power(ds_hdl_t, int, int, int *);
66 static int pl2303_suspend(ds_hdl_t);
67 static int pl2303_resume(ds_hdl_t);
68 static int pl2303_disconnect(ds_hdl_t);
69 static int pl2303_reconnect(ds_hdl_t);
71 /* standard UART operations */
72 static int pl2303_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
73 static int pl2303_set_modem_ctl(ds_hdl_t, uint_t, int, int);
74 static int pl2303_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
75 static int pl2303_break_ctl(ds_hdl_t, uint_t, int);
77 /* data xfer */
78 static int pl2303_tx(ds_hdl_t, uint_t, mblk_t *);
79 static mblk_t *pl2303_rx(ds_hdl_t, uint_t);
80 static void pl2303_stop(ds_hdl_t, uint_t, int);
81 static void pl2303_start(ds_hdl_t, uint_t, int);
82 static int pl2303_fifo_flush(ds_hdl_t, uint_t, int);
83 static int pl2303_fifo_drain(ds_hdl_t, uint_t, int);
85 /* polled I/O support */
86 static usb_pipe_handle_t pl2303_out_pipe(ds_hdl_t, uint_t);
87 static usb_pipe_handle_t pl2303_in_pipe(ds_hdl_t, uint_t);
90 * Sub-routines
93 /* configuration routines */
94 static void pl2303_cleanup(pl2303_state_t *, int);
95 static int pl2303_dev_attach(pl2303_state_t *);
96 static int pl2303_open_hw_port(pl2303_state_t *);
98 /* hotplug */
99 static int pl2303_restore_device_state(pl2303_state_t *);
100 static int pl2303_restore_port_state(pl2303_state_t *);
102 /* power management */
103 static int pl2303_create_pm_components(pl2303_state_t *);
104 static void pl2303_destroy_pm_components(pl2303_state_t *);
105 static int pl2303_pm_set_busy(pl2303_state_t *);
106 static void pl2303_pm_set_idle(pl2303_state_t *);
107 static int pl2303_pwrlvl0(pl2303_state_t *);
108 static int pl2303_pwrlvl1(pl2303_state_t *);
109 static int pl2303_pwrlvl2(pl2303_state_t *);
110 static int pl2303_pwrlvl3(pl2303_state_t *);
112 /* pipe operations */
113 static int pl2303_open_pipes(pl2303_state_t *);
114 static void pl2303_close_pipes(pl2303_state_t *);
115 static void pl2303_disconnect_pipes(pl2303_state_t *);
116 static int pl2303_reconnect_pipes(pl2303_state_t *);
118 /* pipe callbacks */
119 void pl2303_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
120 void pl2303_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
122 /* data transfer routines */
123 static int pl2303_rx_start(pl2303_state_t *);
124 static void pl2303_tx_start(pl2303_state_t *, int *);
125 static int pl2303_send_data(pl2303_state_t *, mblk_t *);
126 static int pl2303_wait_tx_drain(pl2303_state_t *, int);
128 /* vendor-specific commands */
129 static int pl2303_cmd_get_line(pl2303_state_t *, mblk_t **);
130 static int pl2303_cmd_set_line(pl2303_state_t *, mblk_t *);
131 static int pl2303_cmd_set_ctl(pl2303_state_t *, uint8_t);
132 static int pl2303_cmd_vendor_write0(pl2303_state_t *, uint16_t, int16_t);
133 static int pl2303_cmd_set_rtscts(pl2303_state_t *);
134 static int pl2303_cmd_break(pl2303_state_t *, int);
135 static void pl2303_mctl2reg(int mask, int val, uint8_t *);
136 static int pl2303_reg2mctl(uint8_t);
138 /* misc */
139 static void pl2303_put_tail(mblk_t **, mblk_t *);
140 static void pl2303_put_head(mblk_t **, mblk_t *);
144 * DSD ops structure
146 ds_ops_t pl2303_ds_ops = {
147 DS_OPS_VERSION,
148 pl2303_attach,
149 pl2303_detach,
150 pl2303_register_cb,
151 pl2303_unregister_cb,
152 pl2303_open_port,
153 pl2303_close_port,
154 pl2303_usb_power,
155 pl2303_suspend,
156 pl2303_resume,
157 pl2303_disconnect,
158 pl2303_reconnect,
159 pl2303_set_port_params,
160 pl2303_set_modem_ctl,
161 pl2303_get_modem_ctl,
162 pl2303_break_ctl,
163 NULL, /* HW don't support loopback */
164 pl2303_tx,
165 pl2303_rx,
166 pl2303_stop,
167 pl2303_start,
168 pl2303_fifo_flush,
169 pl2303_fifo_drain,
170 pl2303_out_pipe,
171 pl2303_in_pipe
176 * baud code into baud rate
177 * value 0 means not supported in hardware
180 static int pl2303_speedtab[] = {
181 0, /* B0 */
182 0, /* B50 */
183 75, /* B75 */
184 0, /* B110 */
185 0, /* B134 */
186 150, /* B150 */
187 0, /* B200 */
188 300, /* B300 */
189 600, /* B600 */
190 1200, /* B1200 */
191 1800, /* B1800 */
192 2400, /* B2400 */
193 4800, /* B4800 */
194 9600, /* B9600 */
195 19200, /* B19200 */
196 38400, /* B38400 */
197 57600, /* B57600 */
198 0, /* B76800 */
199 115200, /* B115200 */
200 0, /* B153600 */
201 230400, /* B230400 */
202 0, /* B307200 */
203 460800 /* B460800 */
207 /* debug support */
208 static uint_t pl2303_errlevel = USB_LOG_L4;
209 static uint_t pl2303_errmask = DPRINT_MASK_ALL;
210 static uint_t pl2303_instance_debug = (uint_t)-1;
214 * ds_attach
216 static int
217 pl2303_attach(ds_attach_info_t *aip)
219 pl2303_state_t *plp;
221 plp = (pl2303_state_t *)kmem_zalloc(sizeof (pl2303_state_t), KM_SLEEP);
222 plp->pl_dip = aip->ai_dip;
223 plp->pl_usb_events = aip->ai_usb_events;
224 *aip->ai_hdl = (ds_hdl_t)plp;
226 /* only one port */
227 *aip->ai_port_cnt = 1;
229 if (usb_client_attach(plp->pl_dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
230 pl2303_cleanup(plp, 1);
232 return (USB_FAILURE);
235 if (usb_get_dev_data(plp->pl_dip, &plp->pl_dev_data, USB_PARSE_LVL_IF,
236 0) != USB_SUCCESS) {
237 pl2303_cleanup(plp, 2);
239 return (USB_FAILURE);
242 mutex_init(&plp->pl_mutex, NULL, MUTEX_DRIVER,
243 plp->pl_dev_data->dev_iblock_cookie);
245 cv_init(&plp->pl_tx_cv, NULL, CV_DRIVER, NULL);
247 plp->pl_lh = usb_alloc_log_hdl(plp->pl_dip, "pl2303",
248 &pl2303_errlevel, &pl2303_errmask, &pl2303_instance_debug, 0);
251 * Check the chip type: pl2303_H, pl2303_X (or pl2303_HX(Chip A)),
252 * pl2303_HX(Chip D).
253 * pl2303_UNKNOWN means not supported chip type.
255 if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_H) {
256 mutex_enter(&plp->pl_mutex);
257 plp->pl_chiptype = pl2303_H;
258 mutex_exit(&plp->pl_mutex);
259 USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
260 "Chip Type: pl2303_H");
261 } else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_X) {
263 * pl2303_HX(Chip A)and pl2303_X devices have different
264 * hardware, but from the view of device driver, they have
265 * the same software interface.
267 * So "pl2303_X" will stand for both pl2303_HX(Chip A)and
268 * pl2303_X devices in this driver.
270 mutex_enter(&plp->pl_mutex);
271 plp->pl_chiptype = pl2303_X;
272 mutex_exit(&plp->pl_mutex);
273 USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
274 "Chip Type: pl2303_HX(Chip A) or pl2303_X");
275 } else if (plp->pl_dev_data->dev_descr->bcdDevice ==
276 PROLIFIC_REV_HX_CHIP_D) {
277 mutex_enter(&plp->pl_mutex);
278 plp->pl_chiptype = pl2303_HX_CHIP_D;
279 mutex_exit(&plp->pl_mutex);
280 USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
281 "Chip Type: pl2303_HX(Chip D)");
282 } else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_1) {
283 /* IO DATA USB-RSAQ3(usb67b,aaa2) uses pl2303_X chip */
284 mutex_enter(&plp->pl_mutex);
285 plp->pl_chiptype = pl2303_X;
286 mutex_exit(&plp->pl_mutex);
287 USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
288 "Chip Type: pl2303_X with revison number=1");
289 } else {
290 mutex_enter(&plp->pl_mutex);
291 plp->pl_chiptype = pl2303_UNKNOWN;
292 mutex_exit(&plp->pl_mutex);
293 USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
294 "Chip Type: Unknown");
297 plp->pl_def_ph = plp->pl_dev_data->dev_default_ph;
299 mutex_enter(&plp->pl_mutex);
300 plp->pl_dev_state = USB_DEV_ONLINE;
301 plp->pl_port_state = PL2303_PORT_CLOSED;
302 mutex_exit(&plp->pl_mutex);
304 if (pl2303_create_pm_components(plp) != USB_SUCCESS) {
305 pl2303_cleanup(plp, 3);
307 return (USB_FAILURE);
310 if (usb_register_event_cbs(plp->pl_dip, plp->pl_usb_events, 0)
311 != USB_SUCCESS) {
312 pl2303_cleanup(plp, 4);
314 return (USB_FAILURE);
317 if (usb_pipe_get_max_bulk_transfer_size(plp->pl_dip,
318 &plp->pl_xfer_sz) != USB_SUCCESS) {
319 pl2303_cleanup(plp, 5);
321 return (USB_FAILURE);
324 if (plp->pl_xfer_sz > PL2303_XFER_SZ_MAX) {
325 plp->pl_xfer_sz = PL2303_XFER_SZ_MAX;
328 if (pl2303_dev_attach(plp) != USB_SUCCESS) {
329 pl2303_cleanup(plp, 5);
331 return (USB_FAILURE);
334 return (USB_SUCCESS);
339 * ds_detach
341 static void
342 pl2303_detach(ds_hdl_t hdl)
344 pl2303_state_t *plp = (pl2303_state_t *)hdl;
346 pl2303_cleanup(plp, PL2303_CLEANUP_LEVEL_MAX);
351 * ds_register_cb
353 /*ARGSUSED*/
354 static int
355 pl2303_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
357 pl2303_state_t *plp = (pl2303_state_t *)hdl;
359 plp->pl_cb = *cb;
361 return (USB_SUCCESS);
366 * ds_unregister_cb
368 /*ARGSUSED*/
369 static void
370 pl2303_unregister_cb(ds_hdl_t hdl, uint_t port_num)
372 pl2303_state_t *plp = (pl2303_state_t *)hdl;
374 bzero(&plp->pl_cb, sizeof (plp->pl_cb));
379 * ds_open_port
381 /*ARGSUSED*/
382 static int
383 pl2303_open_port(ds_hdl_t hdl, uint_t port_num)
385 pl2303_state_t *plp = (pl2303_state_t *)hdl;
386 int rval = USB_FAILURE;
388 USB_DPRINTF_L4(DPRINT_OPEN, plp->pl_lh, "pl2303_open_port");
390 mutex_enter(&plp->pl_mutex);
391 if ((plp->pl_dev_state == USB_DEV_DISCONNECTED) ||
392 (plp->pl_port_state != PL2303_PORT_CLOSED)) {
393 mutex_exit(&plp->pl_mutex);
395 return (rval);
398 mutex_exit(&plp->pl_mutex);
400 if ((rval = pl2303_pm_set_busy(plp)) != USB_SUCCESS) {
402 return (rval);
405 /* initialize hardware serial port */
406 rval = pl2303_open_hw_port(plp);
408 if (rval == USB_SUCCESS) {
409 mutex_enter(&plp->pl_mutex);
411 /* start to receive data */
412 if (pl2303_rx_start(plp) != USB_SUCCESS) {
413 mutex_exit(&plp->pl_mutex);
415 return (USB_FAILURE);
417 plp->pl_port_state = PL2303_PORT_OPEN;
418 mutex_exit(&plp->pl_mutex);
419 } else {
420 pl2303_pm_set_idle(plp);
423 return (rval);
428 * ds_close_port
430 /*ARGSUSED*/
431 static int
432 pl2303_close_port(ds_hdl_t hdl, uint_t port_num)
434 pl2303_state_t *plp = (pl2303_state_t *)hdl;
436 USB_DPRINTF_L4(DPRINT_CLOSE, plp->pl_lh, "pl2303_close_port");
438 mutex_enter(&plp->pl_mutex);
440 /* free resources and finalize state */
441 if (plp->pl_rx_mp) {
442 freemsg(plp->pl_rx_mp);
443 plp->pl_rx_mp = NULL;
445 if (plp->pl_tx_mp) {
446 freemsg(plp->pl_tx_mp);
447 plp->pl_tx_mp = NULL;
450 plp->pl_port_state = PL2303_PORT_CLOSED;
451 mutex_exit(&plp->pl_mutex);
453 pl2303_pm_set_idle(plp);
455 return (USB_SUCCESS);
460 * power management
461 * ----------------
463 * ds_usb_power
465 /*ARGSUSED*/
466 static int
467 pl2303_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
469 pl2303_state_t *plp = (pl2303_state_t *)hdl;
470 pl2303_pm_t *pm = plp->pl_pm;
471 int rval;
473 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_usb_power");
475 if (!pm) {
477 return (USB_FAILURE);
480 mutex_enter(&plp->pl_mutex);
482 * check if we are transitioning to a legal power level
484 if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
485 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "pl2303_usb_power: "
486 "illegal power level %d, pwr_states=%x",
487 level, pm->pm_pwr_states);
488 mutex_exit(&plp->pl_mutex);
490 return (USB_FAILURE);
494 * if we are about to raise power and asked to lower power, fail
496 if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
497 mutex_exit(&plp->pl_mutex);
499 return (USB_FAILURE);
502 switch (level) {
503 case USB_DEV_OS_PWR_OFF:
504 rval = pl2303_pwrlvl0(plp);
506 break;
507 case USB_DEV_OS_PWR_1:
508 rval = pl2303_pwrlvl1(plp);
510 break;
511 case USB_DEV_OS_PWR_2:
512 rval = pl2303_pwrlvl2(plp);
514 break;
515 case USB_DEV_OS_FULL_PWR:
516 rval = pl2303_pwrlvl3(plp);
518 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
519 * that the usb serial device is disconnected/suspended while it
520 * is under power down state, now the device is powered up
521 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
522 * state to ONLINE, we need to set the dev state back to
523 * DISCONNECTED/SUSPENDED.
525 if ((rval == USB_SUCCESS) &&
526 ((*new_state == USB_DEV_DISCONNECTED) ||
527 (*new_state == USB_DEV_SUSPENDED))) {
528 plp->pl_dev_state = *new_state;
531 break;
532 default:
533 ASSERT(0); /* cannot happen */
536 *new_state = plp->pl_dev_state;
537 mutex_exit(&plp->pl_mutex);
539 return (rval);
544 * ds_suspend
546 static int
547 pl2303_suspend(ds_hdl_t hdl)
549 pl2303_state_t *plp = (pl2303_state_t *)hdl;
550 int state = USB_DEV_SUSPENDED;
552 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_suspend");
555 * If the device is suspended while it is under PWRED_DOWN state, we
556 * need to keep the PWRED_DOWN state so that it could be powered up
557 * later. In the mean while, usbser dev state will be changed to
558 * SUSPENDED state.
560 mutex_enter(&plp->pl_mutex);
561 if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
562 plp->pl_dev_state = USB_DEV_SUSPENDED;
564 mutex_exit(&plp->pl_mutex);
566 pl2303_disconnect_pipes(plp);
568 return (state);
573 * ds_resume
575 static int
576 pl2303_resume(ds_hdl_t hdl)
578 pl2303_state_t *plp = (pl2303_state_t *)hdl;
579 int current_state;
580 int rval;
582 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_resume");
584 mutex_enter(&plp->pl_mutex);
585 current_state = plp->pl_dev_state;
586 mutex_exit(&plp->pl_mutex);
588 if (current_state != USB_DEV_ONLINE) {
589 rval = pl2303_restore_device_state(plp);
590 } else {
591 rval = USB_SUCCESS;
594 return (rval);
599 * ds_disconnect
601 static int
602 pl2303_disconnect(ds_hdl_t hdl)
604 pl2303_state_t *plp = (pl2303_state_t *)hdl;
605 int state = USB_DEV_DISCONNECTED;
607 USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_disconnect");
610 * If the device is disconnected while it is under PWRED_DOWN state, we
611 * need to keep the PWRED_DOWN state so that it could be powered up
612 * later. In the mean while, usbser dev state will be changed to
613 * DISCONNECTED state.
615 mutex_enter(&plp->pl_mutex);
616 if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
617 plp->pl_dev_state = USB_DEV_DISCONNECTED;
619 mutex_exit(&plp->pl_mutex);
621 pl2303_disconnect_pipes(plp);
623 return (state);
628 * ds_reconnect
630 static int
631 pl2303_reconnect(ds_hdl_t hdl)
633 pl2303_state_t *plp = (pl2303_state_t *)hdl;
635 USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_reconnect");
637 return (pl2303_restore_device_state(plp));
642 * standard UART operations
643 * ------------------------
646 * ds_set_port_params
648 /*ARGSUSED*/
649 static int
650 pl2303_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
652 pl2303_state_t *plp = (pl2303_state_t *)hdl;
653 int rval = USB_FAILURE;
654 mblk_t *bp;
655 int i;
656 uint_t ui;
657 int baud;
658 int cnt;
659 ds_port_param_entry_t *pe;
660 uint16_t xonxoff_symbol;
661 uint8_t xon_char;
662 uint8_t xoff_char;
664 if (tp == NULL) {
666 return (rval);
669 cnt = tp->tp_cnt;
670 pe = tp->tp_entries;
672 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_port_params");
675 * get Line Coding Structure Request
676 * including: baud rate, stop bit, parity type and data bit
678 if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
680 return (rval);
683 /* translate parameters into device-specific bits */
684 for (i = 0; i < cnt; i++, pe++) {
685 switch (pe->param) {
686 case DS_PARAM_BAUD:
687 ui = pe->val.ui;
689 /* if we don't support this speed, return USB_FAILURE */
690 if ((ui >= NELEM(pl2303_speedtab)) ||
691 ((ui > 0) && (pl2303_speedtab[ui] == 0))) {
692 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh,
693 "pl2303_set_port_params: bad baud %d", ui);
695 freeb(bp);
697 return (USB_FAILURE);
700 baud = pl2303_speedtab[ui];
701 bp->b_rptr[0] = baud & 0xff;
702 bp->b_rptr[1] = (baud >> 8) & 0xff;
703 bp->b_rptr[2] = (baud >> 16) & 0xff;
704 bp->b_rptr[3] = (baud >> 24) & 0xff;
706 break;
707 case DS_PARAM_PARITY:
708 if (pe->val.ui & PARENB) {
709 if (pe->val.ui & PARODD) {
710 bp->b_rptr[5] = 1;
711 } else {
712 bp->b_rptr[5] = 2;
714 } else {
715 bp->b_rptr[5] = 0;
718 break;
719 case DS_PARAM_STOPB:
720 if (pe->val.ui & CSTOPB) {
721 bp->b_rptr[4] = 2;
722 } else {
723 bp->b_rptr[4] = 0;
726 break;
727 case DS_PARAM_CHARSZ:
728 switch (pe->val.ui) {
729 case CS5:
730 bp->b_rptr[6] = 5;
732 break;
733 case CS6:
734 bp->b_rptr[6] = 6;
736 break;
737 case CS7:
738 bp->b_rptr[6] = 7;
740 break;
741 case CS8:
742 default:
743 bp->b_rptr[6] = 8;
745 break;
748 break;
749 case DS_PARAM_XON_XOFF:
751 * Software flow control: XON/XOFF
752 * not supported by PL-2303H, HX chips
754 if (pe->val.ui & IXON || pe->val.ui & IXOFF) {
755 /* not supported by PL-2303H chip */
756 switch (plp->pl_chiptype) {
757 case pl2303_H:
759 break;
760 case pl2303_X:
761 case pl2303_HX_CHIP_D:
762 xon_char = pe->val.uc[0];
763 xoff_char = pe->val.uc[1];
764 xonxoff_symbol = (xoff_char << 8)
765 | xon_char;
767 rval = pl2303_cmd_vendor_write0(
768 plp, SET_XONXOFF,
769 xonxoff_symbol);
771 if (rval != USB_SUCCESS) {
772 USB_DPRINTF_L3(DPRINT_CTLOP,
773 plp->pl_lh,
774 "pl2303_set_port_params: "
775 "set XonXoff failed");
778 break;
779 case pl2303_UNKNOWN:
780 default:
782 break;
786 break;
787 case DS_PARAM_FLOW_CTL:
788 /* Hardware flow control */
789 if (pe->val.ui & CTSXON) {
790 if ((rval = pl2303_cmd_set_rtscts(plp))
791 != USB_SUCCESS) {
793 USB_DPRINTF_L3(DPRINT_CTLOP,
794 plp->pl_lh,
795 "pl2303_set_port_params: "
796 "pl2303_cmd_set_rtscts failed");
800 break;
801 default:
802 USB_DPRINTF_L2(DPRINT_CTLOP, plp->pl_lh,
803 "pl2303_set_port_params: bad param %d", pe->param);
805 break;
809 /* set new values for Line Coding Structure */
810 rval = pl2303_cmd_set_line(plp, bp);
812 freeb(bp);
814 if (rval != USB_SUCCESS) {
816 return (rval);
819 /* hardware need to get Line Coding Structure again */
820 if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
822 return (rval);
825 freeb(bp);
827 return (USB_SUCCESS);
832 * ds_set_modem_ctl
834 /*ARGSUSED*/
835 static int
836 pl2303_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
838 pl2303_state_t *plp = (pl2303_state_t *)hdl;
839 int rval = USB_FAILURE;
840 uint8_t new_mctl;
842 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_modem_ctl");
844 mutex_enter(&plp->pl_mutex);
845 new_mctl = plp->pl_mctl;
846 mutex_exit(&plp->pl_mutex);
848 /* set RTS and DTR */
849 pl2303_mctl2reg(mask, val, &new_mctl);
851 if ((rval = pl2303_cmd_set_ctl(plp, new_mctl)) == USB_SUCCESS) {
852 mutex_enter(&plp->pl_mutex);
853 plp->pl_mctl = new_mctl;
854 mutex_exit(&plp->pl_mutex);
857 return (rval);
862 * ds_get_modem_ctl
864 /*ARGSUSED*/
865 static int
866 pl2303_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
868 pl2303_state_t *plp = (pl2303_state_t *)hdl;
870 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_get_modem_ctl");
872 mutex_enter(&plp->pl_mutex);
874 /* get RTS and DTR */
875 *valp = pl2303_reg2mctl(plp->pl_mctl) & mask;
876 *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
877 mutex_exit(&plp->pl_mutex);
879 return (USB_SUCCESS);
884 * ds_break_ctl
886 /*ARGSUSED*/
887 static int
888 pl2303_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
890 pl2303_state_t *plp = (pl2303_state_t *)hdl;
892 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_break_ctl");
894 return (pl2303_cmd_break(plp, ctl));
899 * ds_tx
901 /*ARGSUSED*/
902 static int
903 pl2303_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
905 pl2303_state_t *plp = (pl2303_state_t *)hdl;
906 int xferd;
908 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx");
911 * sanity checks
913 if (mp == NULL) {
914 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: mp=NULL");
916 return (USB_SUCCESS);
918 if (MBLKL(mp) < 1) {
919 USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: len<=0");
920 freemsg(mp);
922 return (USB_SUCCESS);
925 mutex_enter(&plp->pl_mutex);
927 pl2303_put_tail(&plp->pl_tx_mp, mp); /* add to the chain */
929 pl2303_tx_start(plp, &xferd);
931 mutex_exit(&plp->pl_mutex);
933 return (USB_SUCCESS);
938 * ds_rx
939 * the real data receiving is in pl2303_open_port
941 /*ARGSUSED*/
942 static mblk_t *
943 pl2303_rx(ds_hdl_t hdl, uint_t port_num)
945 pl2303_state_t *plp = (pl2303_state_t *)hdl;
946 mblk_t *mp;
948 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_rx");
950 mutex_enter(&plp->pl_mutex);
951 mp = plp->pl_rx_mp;
952 plp->pl_rx_mp = NULL;
953 mutex_exit(&plp->pl_mutex);
955 return (mp);
960 * ds_stop
962 /*ARGSUSED*/
963 static void
964 pl2303_stop(ds_hdl_t hdl, uint_t port_num, int dir)
966 pl2303_state_t *plp = (pl2303_state_t *)hdl;
968 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_stop");
970 if (dir & DS_TX) {
971 mutex_enter(&plp->pl_mutex);
972 plp->pl_port_flags |= PL2303_PORT_TX_STOPPED;
973 mutex_exit(&plp->pl_mutex);
979 * ds_start
981 /*ARGSUSED*/
982 static void
983 pl2303_start(ds_hdl_t hdl, uint_t port_num, int dir)
985 pl2303_state_t *plp = (pl2303_state_t *)hdl;
987 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_start");
989 if (dir & DS_TX) {
990 mutex_enter(&plp->pl_mutex);
991 if (plp->pl_port_flags & PL2303_PORT_TX_STOPPED) {
992 plp->pl_port_flags &= ~PL2303_PORT_TX_STOPPED;
993 pl2303_tx_start(plp, NULL);
995 mutex_exit(&plp->pl_mutex);
1001 * ds_fifo_flush
1003 /*ARGSUSED*/
1004 static int
1005 pl2303_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
1007 pl2303_state_t *plp = (pl2303_state_t *)hdl;
1009 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_flush: dir=%x",
1010 dir);
1012 mutex_enter(&plp->pl_mutex);
1013 ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
1015 if ((dir & DS_TX) && plp->pl_tx_mp) {
1016 freemsg(plp->pl_tx_mp);
1017 plp->pl_tx_mp = NULL;
1019 if ((dir & DS_RX) && plp->pl_rx_mp) {
1020 freemsg(plp->pl_rx_mp);
1021 plp->pl_rx_mp = NULL;
1023 mutex_exit(&plp->pl_mutex);
1025 return (USB_SUCCESS);
1030 * ds_fifo_drain
1032 /*ARGSUSED*/
1033 static int
1034 pl2303_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
1036 pl2303_state_t *plp = (pl2303_state_t *)hdl;
1037 int rval = USB_SUCCESS;
1039 USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_drain");
1041 mutex_enter(&plp->pl_mutex);
1042 ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
1045 * for the reason of hardware, set timeout 0
1047 if (pl2303_wait_tx_drain(plp, 0) != USB_SUCCESS) {
1049 mutex_exit(&plp->pl_mutex);
1051 return (USB_FAILURE);
1054 mutex_exit(&plp->pl_mutex);
1056 /* wait 500 ms until hw fifo drains */
1057 ddi_msleep(500);
1059 return (rval);
1064 * configuration routines
1065 * ----------------------
1067 * clean up routine
1069 static void
1070 pl2303_cleanup(pl2303_state_t *plp, int level)
1072 ASSERT((level > 0) && (level <= PL2303_CLEANUP_LEVEL_MAX));
1074 switch (level) {
1075 default:
1076 pl2303_close_pipes(plp);
1077 /* FALLTHRU */
1078 case 5:
1079 usb_unregister_event_cbs(plp->pl_dip, plp->pl_usb_events);
1080 /* FALLTHRU */
1081 case 4:
1082 pl2303_destroy_pm_components(plp);
1083 /* FALLTHRU */
1084 case 3:
1085 mutex_destroy(&plp->pl_mutex);
1086 cv_destroy(&plp->pl_tx_cv);
1088 usb_free_log_hdl(plp->pl_lh);
1089 plp->pl_lh = NULL;
1091 usb_free_descr_tree(plp->pl_dip, plp->pl_dev_data);
1092 plp->pl_def_ph = NULL;
1093 /* FALLTHRU */
1094 case 2:
1095 usb_client_detach(plp->pl_dip, plp->pl_dev_data);
1096 /* FALLTHRU */
1097 case 1:
1098 kmem_free(plp, sizeof (pl2303_state_t));
1104 * device specific attach
1106 static int
1107 pl2303_dev_attach(pl2303_state_t *plp)
1109 if (pl2303_open_pipes(plp) != USB_SUCCESS) {
1110 return (USB_FAILURE);
1113 return (USB_SUCCESS);
1118 * hotplug
1119 * -------
1122 * restore device state after CPR resume or reconnect
1124 static int
1125 pl2303_restore_device_state(pl2303_state_t *plp)
1127 int state;
1129 mutex_enter(&plp->pl_mutex);
1130 state = plp->pl_dev_state;
1131 mutex_exit(&plp->pl_mutex);
1133 if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1135 return (state);
1138 if (usb_check_same_device(plp->pl_dip, plp->pl_lh, USB_LOG_L0,
1139 DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
1140 mutex_enter(&plp->pl_mutex);
1141 state = plp->pl_dev_state = USB_DEV_DISCONNECTED;
1142 mutex_exit(&plp->pl_mutex);
1144 return (state);
1147 if (state == USB_DEV_DISCONNECTED) {
1148 USB_DPRINTF_L0(DPRINT_HOTPLUG, plp->pl_lh,
1149 "Device has been reconnected but data may have been lost");
1152 if (pl2303_reconnect_pipes(plp) != USB_SUCCESS) {
1154 return (state);
1158 * init device state
1160 mutex_enter(&plp->pl_mutex);
1161 state = plp->pl_dev_state = USB_DEV_ONLINE;
1162 mutex_exit(&plp->pl_mutex);
1164 if ((pl2303_restore_port_state(plp) != USB_SUCCESS)) {
1165 USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
1166 "pl2303_restore_device_state: failed");
1169 return (state);
1174 * restore ports state after CPR resume or reconnect
1176 static int
1177 pl2303_restore_port_state(pl2303_state_t *plp)
1179 int rval;
1181 mutex_enter(&plp->pl_mutex);
1182 if (plp->pl_port_state != PL2303_PORT_OPEN) {
1183 mutex_exit(&plp->pl_mutex);
1185 return (USB_SUCCESS);
1187 mutex_exit(&plp->pl_mutex);
1189 /* open hardware serial port */
1190 if ((rval = pl2303_open_hw_port(plp)) != USB_SUCCESS) {
1191 USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
1192 "pl2303_restore_ports_state: failed");
1195 return (rval);
1200 * power management
1201 * ----------------
1204 * create PM components
1206 static int
1207 pl2303_create_pm_components(pl2303_state_t *plp)
1209 dev_info_t *dip = plp->pl_dip;
1210 pl2303_pm_t *pm;
1211 uint_t pwr_states;
1213 if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
1214 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1215 "pl2303_create_pm_components: failed");
1217 return (USB_SUCCESS);
1220 pm = plp->pl_pm = kmem_zalloc(sizeof (pl2303_pm_t), KM_SLEEP);
1222 pm->pm_pwr_states = (uint8_t)pwr_states;
1223 pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1224 pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
1225 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
1227 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1229 return (USB_SUCCESS);
1234 * destroy PM components
1236 static void
1237 pl2303_destroy_pm_components(pl2303_state_t *plp)
1239 pl2303_pm_t *pm = plp->pl_pm;
1240 dev_info_t *dip = plp->pl_dip;
1241 int rval;
1243 if (!pm)
1245 return;
1247 if (plp->pl_dev_state != USB_DEV_DISCONNECTED) {
1248 if (pm->pm_wakeup_enabled) {
1249 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1250 if (rval != DDI_SUCCESS) {
1251 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1252 "pl2303_destroy_pm_components:"
1253 "raising power failed, rval=%d", rval);
1256 rval = usb_handle_remote_wakeup(dip,
1257 USB_REMOTE_WAKEUP_DISABLE);
1258 if (rval != USB_SUCCESS) {
1259 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1260 "pl2303_destroy_pm_components: disable "
1261 "remote wakeup failed, rval=%d", rval);
1265 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1267 kmem_free(pm, sizeof (pl2303_pm_t));
1268 plp->pl_pm = NULL;
1273 * mark device busy and raise power
1275 static int
1276 pl2303_pm_set_busy(pl2303_state_t *plp)
1278 pl2303_pm_t *pm = plp->pl_pm;
1279 dev_info_t *dip = plp->pl_dip;
1280 int rval;
1282 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_busy");
1284 if (!pm) {
1286 return (USB_SUCCESS);
1289 mutex_enter(&plp->pl_mutex);
1290 /* if already marked busy, just increment the counter */
1291 if (pm->pm_busy_cnt++ > 0) {
1292 mutex_exit(&plp->pl_mutex);
1294 return (USB_SUCCESS);
1297 rval = pm_busy_component(dip, 0);
1298 ASSERT(rval == DDI_SUCCESS);
1300 if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
1301 mutex_exit(&plp->pl_mutex);
1303 return (USB_SUCCESS);
1306 /* need to raise power */
1307 pm->pm_raise_power = B_TRUE;
1308 mutex_exit(&plp->pl_mutex);
1310 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1311 if (rval != DDI_SUCCESS) {
1312 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "raising power failed");
1315 mutex_enter(&plp->pl_mutex);
1316 pm->pm_raise_power = B_FALSE;
1317 mutex_exit(&plp->pl_mutex);
1319 return (USB_SUCCESS);
1324 * mark device idle
1326 static void
1327 pl2303_pm_set_idle(pl2303_state_t *plp)
1329 pl2303_pm_t *pm = plp->pl_pm;
1330 dev_info_t *dip = plp->pl_dip;
1332 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_idle");
1334 if (!pm) {
1336 return;
1340 * if more ports use the device, do not mark as yet
1342 mutex_enter(&plp->pl_mutex);
1343 if (--pm->pm_busy_cnt > 0) {
1344 mutex_exit(&plp->pl_mutex);
1346 return;
1349 if (pm) {
1350 (void) pm_idle_component(dip, 0);
1352 mutex_exit(&plp->pl_mutex);
1357 * Functions to handle power transition for OS levels 0 -> 3
1358 * The same level as OS state, different from USB state
1360 static int
1361 pl2303_pwrlvl0(pl2303_state_t *plp)
1363 int rval;
1365 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl0");
1367 switch (plp->pl_dev_state) {
1368 case USB_DEV_ONLINE:
1369 /* issue USB D3 command to the device */
1370 rval = usb_set_device_pwrlvl3(plp->pl_dip);
1371 ASSERT(rval == USB_SUCCESS);
1373 plp->pl_dev_state = USB_DEV_PWRED_DOWN;
1374 plp->pl_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
1376 /* FALLTHRU */
1377 case USB_DEV_DISCONNECTED:
1378 case USB_DEV_SUSPENDED:
1379 /* allow a disconnect/cpr'ed device to go to lower power */
1381 return (USB_SUCCESS);
1382 case USB_DEV_PWRED_DOWN:
1383 default:
1384 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1385 "pl2303_pwrlvl0: illegal device state");
1387 return (USB_FAILURE);
1392 static int
1393 pl2303_pwrlvl1(pl2303_state_t *plp)
1395 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl1");
1397 /* issue USB D2 command to the device */
1398 (void) usb_set_device_pwrlvl2(plp->pl_dip);
1400 return (USB_FAILURE);
1404 static int
1405 pl2303_pwrlvl2(pl2303_state_t *plp)
1407 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl2");
1409 /* issue USB D1 command to the device */
1410 (void) usb_set_device_pwrlvl1(plp->pl_dip);
1412 return (USB_FAILURE);
1416 static int
1417 pl2303_pwrlvl3(pl2303_state_t *plp)
1419 int rval;
1421 USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl3");
1423 switch (plp->pl_dev_state) {
1424 case USB_DEV_PWRED_DOWN:
1425 /* Issue USB D0 command to the device here */
1426 rval = usb_set_device_pwrlvl0(plp->pl_dip);
1427 ASSERT(rval == USB_SUCCESS);
1429 plp->pl_dev_state = USB_DEV_ONLINE;
1430 plp->pl_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1432 /* FALLTHRU */
1433 case USB_DEV_ONLINE:
1434 /* we are already in full power */
1436 /* FALLTHRU */
1437 case USB_DEV_DISCONNECTED:
1438 case USB_DEV_SUSPENDED:
1440 return (USB_SUCCESS);
1441 default:
1442 USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1443 "pl2303_pwrlvl3: illegal device state");
1445 return (USB_FAILURE);
1451 * pipe operations
1452 * ---------------
1456 static int
1457 pl2303_open_pipes(pl2303_state_t *plp)
1459 int ifc, alt;
1460 usb_pipe_policy_t policy;
1461 usb_ep_data_t *in_data, *out_data;
1463 /* get ep data */
1464 ifc = plp->pl_dev_data->dev_curr_if;
1465 alt = 0;
1467 in_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
1468 0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
1470 out_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
1471 0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
1473 if ((in_data == NULL) || (out_data == NULL)) {
1474 USB_DPRINTF_L2(DPRINT_ATTACH, plp->pl_lh,
1475 "pl2303_open_pipes: can't get ep data");
1477 return (USB_FAILURE);
1480 /* open pipes */
1481 policy.pp_max_async_reqs = 2;
1483 if (usb_pipe_open(plp->pl_dip, &in_data->ep_descr, &policy,
1484 USB_FLAGS_SLEEP, &plp->pl_bulkin_ph) != USB_SUCCESS) {
1486 return (USB_FAILURE);
1489 if (usb_pipe_open(plp->pl_dip, &out_data->ep_descr, &policy,
1490 USB_FLAGS_SLEEP, &plp->pl_bulkout_ph) != USB_SUCCESS) {
1491 usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP,
1492 NULL, NULL);
1494 return (USB_FAILURE);
1497 mutex_enter(&plp->pl_mutex);
1498 plp->pl_bulkin_state = PL2303_PIPE_IDLE;
1499 plp->pl_bulkout_state = PL2303_PIPE_IDLE;
1500 mutex_exit(&plp->pl_mutex);
1502 return (USB_SUCCESS);
1506 static void
1507 pl2303_close_pipes(pl2303_state_t *plp)
1509 if (plp->pl_bulkin_ph) {
1510 usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph,
1511 USB_FLAGS_SLEEP, 0, 0);
1513 if (plp->pl_bulkout_ph) {
1514 usb_pipe_close(plp->pl_dip, plp->pl_bulkout_ph,
1515 USB_FLAGS_SLEEP, 0, 0);
1518 mutex_enter(&plp->pl_mutex);
1519 plp->pl_bulkin_state = PL2303_PIPE_CLOSED;
1520 plp->pl_bulkout_state = PL2303_PIPE_CLOSED;
1521 mutex_exit(&plp->pl_mutex);
1525 static void
1526 pl2303_disconnect_pipes(pl2303_state_t *plp)
1528 pl2303_close_pipes(plp);
1532 static int
1533 pl2303_reconnect_pipes(pl2303_state_t *plp)
1535 if ((pl2303_open_pipes(plp) != USB_SUCCESS)) {
1537 return (USB_FAILURE);
1540 return (USB_SUCCESS);
1545 * pipe callbacks
1546 * --------------
1549 * bulk in common and exeception callback
1552 /*ARGSUSED*/
1553 void
1554 pl2303_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1556 pl2303_state_t *plp = (pl2303_state_t *)req->bulk_client_private;
1557 mblk_t *data;
1558 int data_len;
1560 data = req->bulk_data;
1561 data_len = (data) ? MBLKL(data) : 0;
1563 USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh, "pl2303_bulkin_cb: "
1564 "cr=%d len=%d",
1565 req->bulk_completion_reason,
1566 data_len);
1568 /* save data and notify GSD */
1569 if ((plp->pl_port_state == PL2303_PORT_OPEN) && (data_len) &&
1570 (req->bulk_completion_reason == USB_CR_OK)) {
1571 req->bulk_data = NULL;
1572 pl2303_put_tail(&plp->pl_rx_mp, data);
1573 if (plp->pl_cb.cb_rx) {
1574 plp->pl_cb.cb_rx(plp->pl_cb.cb_arg);
1578 usb_free_bulk_req(req);
1580 /* receive more */
1581 mutex_enter(&plp->pl_mutex);
1582 plp->pl_bulkin_state = PL2303_PIPE_IDLE;
1583 if ((plp->pl_port_state == PL2303_PORT_OPEN) &&
1584 (plp->pl_dev_state == USB_DEV_ONLINE)) {
1585 if (pl2303_rx_start(plp) != USB_SUCCESS) {
1586 USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
1587 "pl2303_bulkin_cb: restart rx fail");
1590 mutex_exit(&plp->pl_mutex);
1595 * bulk out common and exeception callback
1597 /*ARGSUSED*/
1598 void
1599 pl2303_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1601 pl2303_state_t *plp = (pl2303_state_t *)req->bulk_client_private;
1602 int data_len;
1603 mblk_t *data = req->bulk_data;
1605 data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
1607 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
1608 "pl2303_bulkout_cb: cr=%d len=%d",
1609 req->bulk_completion_reason,
1610 data_len);
1612 /* Re-send data only when port is open */
1613 if ((plp->pl_port_state == PL2303_PORT_OPEN) &&
1614 req->bulk_completion_reason && (data_len > 0)) {
1615 pl2303_put_head(&plp->pl_tx_mp, data);
1616 req->bulk_data = NULL;
1619 usb_free_bulk_req(req);
1621 /* notify GSD */
1622 if (plp->pl_cb.cb_tx) {
1623 plp->pl_cb.cb_tx(plp->pl_cb.cb_arg);
1626 /* send more */
1627 mutex_enter(&plp->pl_mutex);
1628 plp->pl_bulkout_state = PL2303_PIPE_IDLE;
1629 if (plp->pl_tx_mp == NULL) {
1630 cv_broadcast(&plp->pl_tx_cv);
1631 } else {
1632 pl2303_tx_start(plp, NULL);
1634 mutex_exit(&plp->pl_mutex);
1639 * data transfer routines
1640 * ----------------------
1643 * start data receipt
1645 static int
1646 pl2303_rx_start(pl2303_state_t *plp)
1648 usb_bulk_req_t *br;
1649 int rval = USB_FAILURE;
1651 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_rx_start");
1653 ASSERT(mutex_owned(&plp->pl_mutex));
1655 plp->pl_bulkin_state = PL2303_PIPE_BUSY;
1656 mutex_exit(&plp->pl_mutex);
1658 br = usb_alloc_bulk_req(plp->pl_dip, plp->pl_xfer_sz, USB_FLAGS_SLEEP);
1659 br->bulk_len = plp->pl_xfer_sz;
1660 br->bulk_timeout = PL2303_BULKIN_TIMEOUT;
1661 br->bulk_cb = pl2303_bulkin_cb;
1662 br->bulk_exc_cb = pl2303_bulkin_cb;
1663 br->bulk_client_private = (usb_opaque_t)plp;
1664 br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
1666 rval = usb_pipe_bulk_xfer(plp->pl_bulkin_ph, br, 0);
1668 if (rval != USB_SUCCESS) {
1669 USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
1670 "pl2303_rx_start: xfer failed %d", rval);
1671 usb_free_bulk_req(br);
1674 mutex_enter(&plp->pl_mutex);
1675 if (rval != USB_SUCCESS) {
1676 plp->pl_bulkin_state = PL2303_PIPE_IDLE;
1679 return (rval);
1684 * start data transmit
1686 static void
1687 pl2303_tx_start(pl2303_state_t *plp, int *xferd)
1689 int len; /* bytes we can transmit */
1690 mblk_t *data; /* data to be transmitted */
1691 int data_len; /* bytes in 'data' */
1692 mblk_t *mp; /* current msgblk */
1693 int copylen; /* bytes copy from 'mp' to 'data' */
1694 int rval;
1696 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_tx_start");
1697 ASSERT(mutex_owned(&plp->pl_mutex));
1698 ASSERT(plp->pl_port_state != PL2303_PORT_CLOSED);
1700 if (xferd) {
1701 *xferd = 0;
1703 if ((plp->pl_port_flags & PL2303_PORT_TX_STOPPED) ||
1704 (plp->pl_tx_mp == NULL)) {
1706 return;
1708 if (plp->pl_bulkout_state != PL2303_PIPE_IDLE) {
1709 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
1710 "pl2303_tx_start: pipe busy");
1712 return;
1714 ASSERT(MBLKL(plp->pl_tx_mp) > 0);
1716 /* send as much data as port can receive */
1717 len = min(msgdsize(plp->pl_tx_mp), plp->pl_xfer_sz);
1719 if (len == 0) {
1721 return;
1724 if ((data = allocb(len, BPRI_LO)) == NULL) {
1726 return;
1730 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
1732 data_len = 0;
1734 while ((data_len < len) && plp->pl_tx_mp) {
1735 mp = plp->pl_tx_mp;
1736 copylen = min(MBLKL(mp), len - data_len);
1737 bcopy(mp->b_rptr, data->b_wptr, copylen);
1738 mp->b_rptr += copylen;
1739 data->b_wptr += copylen;
1740 data_len += copylen;
1742 if (MBLKL(mp) < 1) {
1743 plp->pl_tx_mp = unlinkb(mp);
1744 freeb(mp);
1745 } else {
1746 ASSERT(data_len == len);
1750 if (data_len <= 0) {
1751 USB_DPRINTF_L3(DPRINT_OUT_PIPE, plp->pl_lh,
1752 "pl2303_tx_start: copied zero bytes");
1753 freeb(data);
1755 return;
1758 plp->pl_bulkout_state = PL2303_PIPE_BUSY;
1759 mutex_exit(&plp->pl_mutex);
1761 rval = pl2303_send_data(plp, data);
1762 mutex_enter(&plp->pl_mutex);
1764 if (rval != USB_SUCCESS) {
1765 plp->pl_bulkout_state = PL2303_PIPE_IDLE;
1766 pl2303_put_head(&plp->pl_tx_mp, data);
1767 } else {
1768 if (xferd) {
1769 *xferd = data_len;
1775 static int
1776 pl2303_send_data(pl2303_state_t *plp, mblk_t *data)
1778 usb_bulk_req_t *br;
1779 int len = MBLKL(data);
1780 int rval;
1782 USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_send_data: %d "
1783 "%x %x %x", len, data->b_rptr[0],
1784 (len > 1) ? data->b_rptr[1] : 0,
1785 (len > 2) ? data->b_rptr[2] : 0);
1786 ASSERT(!mutex_owned(&plp->pl_mutex));
1788 br = usb_alloc_bulk_req(plp->pl_dip, 0, USB_FLAGS_SLEEP);
1789 br->bulk_data = data;
1790 br->bulk_len = len;
1791 br->bulk_timeout = PL2303_BULKOUT_TIMEOUT;
1792 br->bulk_cb = pl2303_bulkout_cb;
1793 br->bulk_exc_cb = pl2303_bulkout_cb;
1794 br->bulk_client_private = (usb_opaque_t)plp;
1795 br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1797 rval = usb_pipe_bulk_xfer(plp->pl_bulkout_ph, br, 0);
1799 if (rval != USB_SUCCESS) {
1800 USB_DPRINTF_L2(DPRINT_OUT_PIPE, plp->pl_lh,
1801 "pl2303_send_data: xfer failed %d", rval);
1803 br->bulk_data = NULL;
1804 usb_free_bulk_req(br);
1807 return (rval);
1812 * wait until local tx buffer drains.
1813 * 'timeout' is in seconds, zero means wait forever
1815 static int
1816 pl2303_wait_tx_drain(pl2303_state_t *plp, int timeout)
1818 clock_t until;
1819 int over = 0;
1821 until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
1823 while (plp->pl_tx_mp && !over) {
1824 if (timeout > 0) {
1825 /* whether timedout or signal pending */
1826 over = (cv_timedwait_sig(&plp->pl_tx_cv,
1827 &plp->pl_mutex, until) <= 0);
1828 } else {
1829 /* whether a signal is pending */
1830 over = (cv_wait_sig(&plp->pl_tx_cv,
1831 &plp->pl_mutex) == 0);
1835 return ((plp->pl_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
1840 * device operations
1841 * -----------------
1844 * initialize hardware serial port
1846 static int
1847 pl2303_open_hw_port(pl2303_state_t *plp)
1849 int rval = USB_SUCCESS;
1852 * initialize three Device Configuration Registers (DCR):
1853 * DCR0, DCR1, and DCR2
1856 switch (plp->pl_chiptype) {
1857 case (pl2303_H):
1858 /* Set DCR0 */
1859 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
1860 DCR0_INIT_H)) != USB_SUCCESS) {
1862 return (rval);
1865 /* Set DCR1 */
1866 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
1867 DCR1_INIT_H)) != USB_SUCCESS) {
1869 return (rval);
1872 /* Set DCR2 */
1873 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
1874 DCR2_INIT_H)) != USB_SUCCESS) {
1876 return (rval);
1879 break;
1880 case (pl2303_X):
1881 case (pl2303_HX_CHIP_D):
1883 /* Set DCR0 */
1884 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
1885 DCR0_INIT)) != USB_SUCCESS) {
1887 return (rval);
1890 /* Set DCR1 */
1891 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
1892 DCR1_INIT_X)) != USB_SUCCESS) {
1894 return (rval);
1897 /* Set DCR2 */
1898 if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
1899 DCR2_INIT_X)) != USB_SUCCESS) {
1901 return (rval);
1904 /* reset Downstream data pipes */
1905 if ((rval = pl2303_cmd_vendor_write0(plp,
1906 RESET_DOWNSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
1908 return (rval);
1911 /* reset Upstream data pipes */
1912 if ((rval = pl2303_cmd_vendor_write0(plp,
1913 RESET_UPSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
1915 return (rval);
1918 break;
1919 case (pl2303_UNKNOWN):
1920 default:
1921 USB_DPRINTF_L2(DPRINT_OPEN, plp->pl_lh,
1922 "pl2303_open_hw_port: unknown chiptype");
1924 rval = USB_FAILURE;
1927 return (rval);
1932 * vendor-specific commands
1933 * ------------------------
1936 * Get_Line_Coding Request
1938 static int
1939 pl2303_cmd_get_line(pl2303_state_t *plp, mblk_t **data)
1941 usb_ctrl_setup_t setup = { PL2303_GET_LINE_CODING_REQUEST_TYPE,
1942 PL2303_GET_LINE_CODING_REQUEST, 0, 0,
1943 PL2303_GET_LINE_CODING_LENGTH, 0 };
1944 usb_cb_flags_t cb_flags;
1945 usb_cr_t cr;
1946 int rval;
1948 *data = NULL;
1950 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, data,
1951 &cr, &cb_flags, 0);
1953 if ((rval == USB_SUCCESS) && (*data != NULL)) {
1954 USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
1955 "pl2303_cmd_get_line: %x %x %x %x %x %x %x",
1956 (*data)->b_rptr[0], (*data)->b_rptr[1], (*data)->b_rptr[2],
1957 (*data)->b_rptr[3], (*data)->b_rptr[4], (*data)->b_rptr[5],
1958 (*data)->b_rptr[6]);
1959 } else {
1960 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
1961 "pl2303_cmd_get_line: failed %d %d %x",
1962 rval, cr, cb_flags);
1964 if (*data != NULL) {
1965 freeb(*data);
1969 return (rval);
1974 * Set_Line_Coding Request
1976 static int
1977 pl2303_cmd_set_line(pl2303_state_t *plp, mblk_t *data)
1979 usb_ctrl_setup_t setup = { PL2303_SET_LINE_CODING_REQUEST_TYPE,
1980 PL2303_SET_LINE_CODING_REQUEST, 0, 0,
1981 PL2303_SET_LINE_CODING_LENGTH, 0 };
1982 usb_cb_flags_t cb_flags;
1983 usb_cr_t cr;
1984 int rval;
1986 USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
1987 "pl2303_cmd_set_line: %x %x %x %x %x %x %x",
1988 data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
1989 data->b_rptr[3], data->b_rptr[4], data->b_rptr[5], data->b_rptr[6]);
1991 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, &data,
1992 &cr, &cb_flags, 0);
1994 if (rval != USB_SUCCESS) {
1995 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
1996 "pl2303_cmd_set_line: failed %d %d %x",
1997 rval, cr, cb_flags);
2000 return (rval);
2005 * Set_Control_Line_State Request to RTS and DTR
2007 static int
2008 pl2303_cmd_set_ctl(pl2303_state_t *plp, uint8_t val)
2010 usb_ctrl_setup_t setup = { PL2303_SET_CONTROL_REQUEST_TYPE,
2011 PL2303_SET_CONTROL_REQUEST, 0, 0,
2012 PL2303_SET_CONTROL_LENGTH, 0 };
2013 usb_cb_flags_t cb_flags;
2014 usb_cr_t cr;
2015 int rval;
2017 setup.wValue = val;
2019 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2020 &cr, &cb_flags, 0);
2022 if (rval != USB_SUCCESS) {
2023 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2024 "pl2303_cmd_set_ctl: failed %d %d %x",
2025 rval, cr, cb_flags);
2028 return (rval);
2033 * Vendor_Specific_Write Request
2034 * wLength: 0
2036 static int
2037 pl2303_cmd_vendor_write0(pl2303_state_t *plp, uint16_t value, int16_t index)
2039 usb_ctrl_setup_t setup = { PL2303_VENDOR_WRITE_REQUEST_TYPE,
2040 PL2303_VENDOR_WRITE_REQUEST, 0, 0,
2041 PL2303_VENDOR_WRITE_LENGTH, 0 };
2042 usb_cb_flags_t cb_flags;
2043 usb_cr_t cr;
2044 int rval;
2046 setup.wValue = value;
2047 setup.wIndex = index;
2049 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2050 &cr, &cb_flags, 0);
2052 if (rval != USB_SUCCESS) {
2053 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2054 "pl2303_cmd_vendor_write0: %x %x failed %d %d %x",
2055 value, index, rval, cr, cb_flags);
2058 return (rval);
2063 * For Hardware flow control
2065 static int
2066 pl2303_cmd_set_rtscts(pl2303_state_t *plp)
2068 /* Set DCR0 */
2069 switch (plp->pl_chiptype) {
2070 case pl2303_H:
2072 return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_H));
2073 case pl2303_X:
2074 case pl2303_HX_CHIP_D:
2076 return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_X));
2077 case pl2303_UNKNOWN:
2078 default:
2080 return (USB_FAILURE);
2086 * Set TxD BREAK_ON or BREAK_OFF
2088 static int
2089 pl2303_cmd_break(pl2303_state_t *plp, int ctl)
2091 usb_ctrl_setup_t setup = { PL2303_BREAK_REQUEST_TYPE,
2092 PL2303_BREAK_REQUEST, 0, 0,
2093 PL2303_BREAK_LENGTH, 0 };
2094 usb_cb_flags_t cb_flags;
2095 usb_cr_t cr;
2096 int rval;
2098 setup.wValue = (ctl == DS_ON) ? PL2303_BREAK_ON : PL2303_BREAK_OFF;
2100 rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2101 &cr, &cb_flags, 0);
2103 if (rval != USB_SUCCESS) {
2104 USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2105 "pl2303_cmd_break: failed rval=%d,cr=%d,cb_flags=0x%x",
2106 rval, cr, cb_flags);
2109 return (rval);
2114 * for set_mod_ctl
2116 static void
2117 pl2303_mctl2reg(int mask, int val, uint8_t *line_ctl)
2119 if (mask & TIOCM_RTS) {
2120 if (val & TIOCM_RTS) {
2121 *line_ctl |= PL2303_CONTROL_RTS;
2122 } else {
2123 *line_ctl &= ~PL2303_CONTROL_RTS;
2126 if (mask & TIOCM_DTR) {
2127 if (val & TIOCM_DTR) {
2128 *line_ctl |= PL2303_CONTROL_DTR;
2129 } else {
2130 *line_ctl &= ~PL2303_CONTROL_DTR;
2137 * for get_mod_ctl
2139 static int
2140 pl2303_reg2mctl(uint8_t line_ctl)
2142 int val = 0;
2144 if (line_ctl & PL2303_CONTROL_RTS) {
2145 val |= TIOCM_RTS;
2147 if (line_ctl & PL2303_CONTROL_DTR) {
2148 val |= TIOCM_DTR;
2151 return (val);
2156 * misc routines
2157 * -------------
2162 * link a message block to tail of message
2163 * account for the case when message is null
2165 static void
2166 pl2303_put_tail(mblk_t **mpp, mblk_t *bp)
2168 if (*mpp) {
2169 linkb(*mpp, bp);
2170 } else {
2171 *mpp = bp;
2177 * put a message block at the head of the message
2178 * account for the case when message is null
2180 static void
2181 pl2303_put_head(mblk_t **mpp, mblk_t *bp)
2183 if (*mpp) {
2184 linkb(bp, *mpp);
2186 *mpp = bp;
2189 /*ARGSUSED*/
2190 static usb_pipe_handle_t
2191 pl2303_out_pipe(ds_hdl_t hdl, uint_t port_num)
2193 pl2303_state_t *plp = (pl2303_state_t *)hdl;
2195 return (plp->pl_bulkout_ph);
2198 /*ARGSUSED*/
2199 static usb_pipe_handle_t
2200 pl2303_in_pipe(ds_hdl_t hdl, uint_t port_num)
2202 pl2303_state_t *plp = (pl2303_state_t *)hdl;
2204 return (plp->pl_bulkin_ph);