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