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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  *
29  * USB Prolific PL2303 device-specific driver (DSD)
30  *
31  */
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>
41 
42 #define	USBDRV_MAJOR_VER	2
43 #define	USBDRV_MINOR_VER	0
44 
45 #include <sys/usb/usba.h>
46 #include <sys/usb/usba/usba_types.h>
47 #include <sys/usb/usba/usba_impl.h>
48 
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>
52 
53 
54 /*
55  * DSD operations
56  */
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);
63 
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);
70 
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);
76 
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);
84 
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);
88 
89 /*
90  * Sub-routines
91  */
92 
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 *);
97 
98 /* hotplug */
99 static int	pl2303_restore_device_state(pl2303_state_t *);
100 static int	pl2303_restore_port_state(pl2303_state_t *);
101 
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 *);
111 
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 *);
117 
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 *);
121 
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);
127 
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);
137 
138 /* misc */
139 static void	pl2303_put_tail(mblk_t **, mblk_t *);
140 static void	pl2303_put_head(mblk_t **, mblk_t *);
141 
142 
143 /*
144  * DSD ops structure
145  */
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
172 };
173 
174 
175 /*
176  * baud code into baud rate
177  * value 0 means not supported in hardware
178  *
179  */
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 */
204 };
205 
206 
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;
211 
212 
213 /*
214  * ds_attach
215  */
216 static int
217 pl2303_attach(ds_attach_info_t *aip)
218 {
219 	pl2303_state_t	*plp;
220 
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;
225 
226 	/* only one port */
227 	*aip->ai_port_cnt = 1;
228 
229 	if (usb_client_attach(plp->pl_dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
230 		pl2303_cleanup(plp, 1);
231 
232 		return (USB_FAILURE);
233 	}
234 
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);
238 
239 		return (USB_FAILURE);
240 	}
241 
242 	mutex_init(&plp->pl_mutex, NULL, MUTEX_DRIVER,
243 	    plp->pl_dev_data->dev_iblock_cookie);
244 
245 	cv_init(&plp->pl_tx_cv, NULL, CV_DRIVER, NULL);
246 
247 	plp->pl_lh = usb_alloc_log_hdl(plp->pl_dip, "pl2303",
248 	    &pl2303_errlevel, &pl2303_errmask, &pl2303_instance_debug, 0);
249 
250 	/*
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.
254 	 */
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) {
262 		/*
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.
266 		 *
267 		 * So "pl2303_X" will stand for both pl2303_HX(Chip A)and
268 		 * pl2303_X devices in this driver.
269 		 */
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");
295 	}
296 
297 	plp->pl_def_ph = plp->pl_dev_data->dev_default_ph;
298 
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);
303 
304 	if (pl2303_create_pm_components(plp) != USB_SUCCESS) {
305 		pl2303_cleanup(plp, 3);
306 
307 		return (USB_FAILURE);
308 	}
309 
310 	if (usb_register_event_cbs(plp->pl_dip, plp->pl_usb_events, 0)
311 	    != USB_SUCCESS) {
312 		pl2303_cleanup(plp, 4);
313 
314 		return (USB_FAILURE);
315 	}
316 
317 	if (usb_pipe_get_max_bulk_transfer_size(plp->pl_dip,
318 	    &plp->pl_xfer_sz) != USB_SUCCESS) {
319 		pl2303_cleanup(plp, 5);
320 
321 		return (USB_FAILURE);
322 	}
323 
324 	if (plp->pl_xfer_sz > PL2303_XFER_SZ_MAX) {
325 		plp->pl_xfer_sz = PL2303_XFER_SZ_MAX;
326 	}
327 
328 	if (pl2303_dev_attach(plp) != USB_SUCCESS) {
329 		pl2303_cleanup(plp, 5);
330 
331 		return (USB_FAILURE);
332 	}
333 
334 	return (USB_SUCCESS);
335 }
336 
337 
338 /*
339  * ds_detach
340  */
341 static void
342 pl2303_detach(ds_hdl_t hdl)
343 {
344 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
345 
346 	pl2303_cleanup(plp, PL2303_CLEANUP_LEVEL_MAX);
347 }
348 
349 
350 /*
351  * ds_register_cb
352  */
353 /*ARGSUSED*/
354 static int
355 pl2303_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
356 {
357 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
358 
359 	plp->pl_cb = *cb;
360 
361 	return (USB_SUCCESS);
362 }
363 
364 
365 /*
366  * ds_unregister_cb
367  */
368 /*ARGSUSED*/
369 static void
370 pl2303_unregister_cb(ds_hdl_t hdl, uint_t port_num)
371 {
372 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
373 
374 	bzero(&plp->pl_cb, sizeof (plp->pl_cb));
375 }
376 
377 
378 /*
379  * ds_open_port
380  */
381 /*ARGSUSED*/
382 static int
383 pl2303_open_port(ds_hdl_t hdl, uint_t port_num)
384 {
385 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
386 	int		rval = USB_FAILURE;
387 
388 	USB_DPRINTF_L4(DPRINT_OPEN, plp->pl_lh, "pl2303_open_port");
389 
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);
394 
395 		return (rval);
396 	}
397 
398 	mutex_exit(&plp->pl_mutex);
399 
400 	if ((rval = pl2303_pm_set_busy(plp)) != USB_SUCCESS) {
401 
402 		return (rval);
403 	}
404 
405 	/* initialize hardware serial port */
406 	rval = pl2303_open_hw_port(plp);
407 
408 	if (rval == USB_SUCCESS) {
409 		mutex_enter(&plp->pl_mutex);
410 
411 		/* start to receive data */
412 		if (pl2303_rx_start(plp) != USB_SUCCESS) {
413 			mutex_exit(&plp->pl_mutex);
414 
415 			return (USB_FAILURE);
416 		}
417 		plp->pl_port_state = PL2303_PORT_OPEN;
418 		mutex_exit(&plp->pl_mutex);
419 	} else {
420 		pl2303_pm_set_idle(plp);
421 	}
422 
423 	return (rval);
424 }
425 
426 
427 /*
428  * ds_close_port
429  */
430 /*ARGSUSED*/
431 static int
432 pl2303_close_port(ds_hdl_t hdl, uint_t port_num)
433 {
434 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
435 
436 	USB_DPRINTF_L4(DPRINT_CLOSE, plp->pl_lh, "pl2303_close_port");
437 
438 	mutex_enter(&plp->pl_mutex);
439 
440 	/* free resources and finalize state */
441 	if (plp->pl_rx_mp) {
442 		freemsg(plp->pl_rx_mp);
443 		plp->pl_rx_mp = NULL;
444 	}
445 	if (plp->pl_tx_mp) {
446 		freemsg(plp->pl_tx_mp);
447 		plp->pl_tx_mp = NULL;
448 	}
449 
450 	plp->pl_port_state = PL2303_PORT_CLOSED;
451 	mutex_exit(&plp->pl_mutex);
452 
453 	pl2303_pm_set_idle(plp);
454 
455 	return (USB_SUCCESS);
456 }
457 
458 
459 /*
460  * power management
461  * ----------------
462  *
463  * ds_usb_power
464  */
465 /*ARGSUSED*/
466 static int
467 pl2303_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
468 {
469 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
470 	pl2303_pm_t	*pm = plp->pl_pm;
471 	int		rval;
472 
473 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_usb_power");
474 
475 	if (!pm) {
476 
477 		return (USB_FAILURE);
478 	}
479 
480 	mutex_enter(&plp->pl_mutex);
481 	/*
482 	 * check if we are transitioning to a legal power level
483 	 */
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);
489 
490 		return (USB_FAILURE);
491 	}
492 
493 	/*
494 	 * if we are about to raise power and asked to lower power, fail
495 	 */
496 	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
497 		mutex_exit(&plp->pl_mutex);
498 
499 		return (USB_FAILURE);
500 	}
501 
502 	switch (level) {
503 	case USB_DEV_OS_PWR_OFF:
504 		rval = pl2303_pwrlvl0(plp);
505 
506 		break;
507 	case USB_DEV_OS_PWR_1:
508 		rval = pl2303_pwrlvl1(plp);
509 
510 		break;
511 	case USB_DEV_OS_PWR_2:
512 		rval = pl2303_pwrlvl2(plp);
513 
514 		break;
515 	case USB_DEV_OS_FULL_PWR:
516 		rval = pl2303_pwrlvl3(plp);
517 		/*
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.
524 		 */
525 		if ((rval == USB_SUCCESS) &&
526 		    ((*new_state == USB_DEV_DISCONNECTED) ||
527 		    (*new_state == USB_DEV_SUSPENDED))) {
528 			plp->pl_dev_state = *new_state;
529 		}
530 
531 		break;
532 	default:
533 		ASSERT(0);	/* cannot happen */
534 	}
535 
536 	*new_state = plp->pl_dev_state;
537 	mutex_exit(&plp->pl_mutex);
538 
539 	return (rval);
540 }
541 
542 
543 /*
544  * ds_suspend
545  */
546 static int
547 pl2303_suspend(ds_hdl_t hdl)
548 {
549 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
550 	int		state = USB_DEV_SUSPENDED;
551 
552 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_suspend");
553 
554 	/*
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.
559 	 */
560 	mutex_enter(&plp->pl_mutex);
561 	if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
562 		plp->pl_dev_state = USB_DEV_SUSPENDED;
563 	}
564 	mutex_exit(&plp->pl_mutex);
565 
566 	pl2303_disconnect_pipes(plp);
567 
568 	return (state);
569 }
570 
571 
572 /*
573  * ds_resume
574  */
575 static int
576 pl2303_resume(ds_hdl_t hdl)
577 {
578 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
579 	int		current_state;
580 	int		rval;
581 
582 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_resume");
583 
584 	mutex_enter(&plp->pl_mutex);
585 	current_state = plp->pl_dev_state;
586 	mutex_exit(&plp->pl_mutex);
587 
588 	if (current_state != USB_DEV_ONLINE) {
589 		rval = pl2303_restore_device_state(plp);
590 	} else {
591 		rval = USB_SUCCESS;
592 	}
593 
594 	return (rval);
595 }
596 
597 
598 /*
599  * ds_disconnect
600  */
601 static int
602 pl2303_disconnect(ds_hdl_t hdl)
603 {
604 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
605 	int		state = USB_DEV_DISCONNECTED;
606 
607 	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_disconnect");
608 
609 	/*
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.
614 	 */
615 	mutex_enter(&plp->pl_mutex);
616 	if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
617 		plp->pl_dev_state = USB_DEV_DISCONNECTED;
618 	}
619 	mutex_exit(&plp->pl_mutex);
620 
621 	pl2303_disconnect_pipes(plp);
622 
623 	return (state);
624 }
625 
626 
627 /*
628  * ds_reconnect
629  */
630 static int
631 pl2303_reconnect(ds_hdl_t hdl)
632 {
633 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
634 
635 	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_reconnect");
636 
637 	return (pl2303_restore_device_state(plp));
638 }
639 
640 
641 /*
642  * standard UART operations
643  * ------------------------
644  *
645  *
646  * ds_set_port_params
647  */
648 /*ARGSUSED*/
649 static int
650 pl2303_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
651 {
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;
663 
664 	if (tp == NULL) {
665 
666 		return (rval);
667 	}
668 
669 	cnt = tp->tp_cnt;
670 	pe = tp->tp_entries;
671 
672 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_port_params");
673 
674 	/*
675 	 * get Line Coding Structure Request
676 	 * including: baud rate, stop bit, parity type and data bit
677 	 */
678 	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
679 
680 		return (rval);
681 	}
682 
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;
688 
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);
694 
695 				freeb(bp);
696 
697 				return (USB_FAILURE);
698 			}
699 
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;
705 
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;
713 				}
714 			} else {
715 				bp->b_rptr[5] = 0;
716 			}
717 
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;
724 			}
725 
726 			break;
727 		case DS_PARAM_CHARSZ:
728 			switch (pe->val.ui) {
729 			case CS5:
730 				bp->b_rptr[6] = 5;
731 
732 				break;
733 			case CS6:
734 				bp->b_rptr[6] = 6;
735 
736 				break;
737 			case CS7:
738 				bp->b_rptr[6] = 7;
739 
740 				break;
741 			case CS8:
742 			default:
743 				bp->b_rptr[6] = 8;
744 
745 				break;
746 			}
747 
748 			break;
749 		case DS_PARAM_XON_XOFF:
750 			/*
751 			 * Software flow control: XON/XOFF
752 			 * not supported by PL-2303H, HX chips
753 			 */
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:
758 
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;
766 
767 					rval =	pl2303_cmd_vendor_write0(
768 					    plp, SET_XONXOFF,
769 					    xonxoff_symbol);
770 
771 					if (rval != USB_SUCCESS) {
772 						USB_DPRINTF_L3(DPRINT_CTLOP,
773 						    plp->pl_lh,
774 						    "pl2303_set_port_params: "
775 						    "set XonXoff failed");
776 					}
777 
778 					break;
779 				case pl2303_UNKNOWN:
780 				default:
781 
782 					break;
783 				}
784 			}
785 
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) {
792 
793 					USB_DPRINTF_L3(DPRINT_CTLOP,
794 					    plp->pl_lh,
795 					    "pl2303_set_port_params: "
796 					    "pl2303_cmd_set_rtscts failed");
797 				}
798 			}
799 
800 			break;
801 		default:
802 			USB_DPRINTF_L2(DPRINT_CTLOP, plp->pl_lh,
803 			    "pl2303_set_port_params: bad param %d", pe->param);
804 
805 			break;
806 		}
807 	}
808 
809 	/* set new values for Line Coding Structure */
810 	rval = pl2303_cmd_set_line(plp, bp);
811 
812 	freeb(bp);
813 
814 	if (rval != USB_SUCCESS) {
815 
816 		return (rval);
817 	}
818 
819 	/* hardware need to get Line Coding Structure again */
820 	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
821 
822 		return (rval);
823 	}
824 
825 	freeb(bp);
826 
827 	return (USB_SUCCESS);
828 }
829 
830 
831 /*
832  * ds_set_modem_ctl
833  */
834 /*ARGSUSED*/
835 static int
836 pl2303_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
837 {
838 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
839 	int		rval = USB_FAILURE;
840 	uint8_t		new_mctl;
841 
842 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_modem_ctl");
843 
844 	mutex_enter(&plp->pl_mutex);
845 	new_mctl = plp->pl_mctl;
846 	mutex_exit(&plp->pl_mutex);
847 
848 	/* set RTS and DTR */
849 	pl2303_mctl2reg(mask, val, &new_mctl);
850 
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);
855 	}
856 
857 	return (rval);
858 }
859 
860 
861 /*
862  * ds_get_modem_ctl
863  */
864 /*ARGSUSED*/
865 static int
866 pl2303_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
867 {
868 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
869 
870 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_get_modem_ctl");
871 
872 	mutex_enter(&plp->pl_mutex);
873 
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);
878 
879 	return (USB_SUCCESS);
880 }
881 
882 
883 /*
884  * ds_break_ctl
885  */
886 /*ARGSUSED*/
887 static int
888 pl2303_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
889 {
890 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
891 
892 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_break_ctl");
893 
894 	return (pl2303_cmd_break(plp, ctl));
895 }
896 
897 
898 /*
899  * ds_tx
900  */
901 /*ARGSUSED*/
902 static int
903 pl2303_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
904 {
905 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
906 	int		xferd;
907 
908 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx");
909 
910 	/*
911 	 * sanity checks
912 	 */
913 	if (mp == NULL) {
914 		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: mp=NULL");
915 
916 		return (USB_SUCCESS);
917 	}
918 	if (MBLKL(mp) < 1) {
919 		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: len<=0");
920 		freemsg(mp);
921 
922 		return (USB_SUCCESS);
923 	}
924 
925 	mutex_enter(&plp->pl_mutex);
926 
927 	pl2303_put_tail(&plp->pl_tx_mp, mp);	/* add to the chain */
928 
929 	pl2303_tx_start(plp, &xferd);
930 
931 	mutex_exit(&plp->pl_mutex);
932 
933 	return (USB_SUCCESS);
934 }
935 
936 
937 /*
938  * ds_rx
939  * the real data receiving is in pl2303_open_port
940  */
941 /*ARGSUSED*/
942 static mblk_t *
943 pl2303_rx(ds_hdl_t hdl, uint_t port_num)
944 {
945 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
946 	mblk_t		*mp;
947 
948 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_rx");
949 
950 	mutex_enter(&plp->pl_mutex);
951 	mp = plp->pl_rx_mp;
952 	plp->pl_rx_mp = NULL;
953 	mutex_exit(&plp->pl_mutex);
954 
955 	return (mp);
956 }
957 
958 
959 /*
960  * ds_stop
961  */
962 /*ARGSUSED*/
963 static void
964 pl2303_stop(ds_hdl_t hdl, uint_t port_num, int dir)
965 {
966 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
967 
968 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_stop");
969 
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);
974 	}
975 }
976 
977 
978 /*
979  * ds_start
980  */
981 /*ARGSUSED*/
982 static void
983 pl2303_start(ds_hdl_t hdl, uint_t port_num, int dir)
984 {
985 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
986 
987 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_start");
988 
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);
994 		}
995 		mutex_exit(&plp->pl_mutex);
996 	}
997 }
998 
999 
1000 /*
1001  * ds_fifo_flush
1002  */
1003 /*ARGSUSED*/
1004 static int
1005 pl2303_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
1006 {
1007 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
1008 
1009 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_flush: dir=%x",
1010 	    dir);
1011 
1012 	mutex_enter(&plp->pl_mutex);
1013 	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
1014 
1015 	if ((dir & DS_TX) && plp->pl_tx_mp) {
1016 		freemsg(plp->pl_tx_mp);
1017 		plp->pl_tx_mp = NULL;
1018 	}
1019 	if ((dir & DS_RX) && plp->pl_rx_mp) {
1020 		freemsg(plp->pl_rx_mp);
1021 		plp->pl_rx_mp = NULL;
1022 	}
1023 	mutex_exit(&plp->pl_mutex);
1024 
1025 	return (USB_SUCCESS);
1026 }
1027 
1028 
1029 /*
1030  * ds_fifo_drain
1031  */
1032 /*ARGSUSED*/
1033 static int
1034 pl2303_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
1035 {
1036 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
1037 	int		rval = USB_SUCCESS;
1038 
1039 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_drain");
1040 
1041 	mutex_enter(&plp->pl_mutex);
1042 	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
1043 
1044 	/*
1045 	 * for the reason of hardware, set timeout 0
1046 	 */
1047 	if (pl2303_wait_tx_drain(plp, 0) != USB_SUCCESS) {
1048 
1049 		mutex_exit(&plp->pl_mutex);
1050 
1051 		return (USB_FAILURE);
1052 	}
1053 
1054 	mutex_exit(&plp->pl_mutex);
1055 
1056 	/* wait 500 ms until hw fifo drains */
1057 	delay(drv_usectohz(500*1000));
1058 
1059 	return (rval);
1060 }
1061 
1062 
1063 /*
1064  * configuration routines
1065  * ----------------------
1066  *
1067  * clean up routine
1068  */
1069 static void
1070 pl2303_cleanup(pl2303_state_t *plp, int level)
1071 {
1072 	ASSERT((level > 0) && (level <= PL2303_CLEANUP_LEVEL_MAX));
1073 
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);
1087 
1088 		usb_free_log_hdl(plp->pl_lh);
1089 		plp->pl_lh = NULL;
1090 
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));
1099 	}
1100 }
1101 
1102 
1103 /*
1104  * device specific attach
1105  */
1106 static int
1107 pl2303_dev_attach(pl2303_state_t *plp)
1108 {
1109 	if (pl2303_open_pipes(plp) != USB_SUCCESS) {
1110 		return (USB_FAILURE);
1111 	}
1112 
1113 	return (USB_SUCCESS);
1114 }
1115 
1116 
1117 /*
1118  * hotplug
1119  * -------
1120  *
1121  *
1122  * restore device state after CPR resume or reconnect
1123  */
1124 static int
1125 pl2303_restore_device_state(pl2303_state_t *plp)
1126 {
1127 	int	state;
1128 
1129 	mutex_enter(&plp->pl_mutex);
1130 	state = plp->pl_dev_state;
1131 	mutex_exit(&plp->pl_mutex);
1132 
1133 	if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1134 
1135 		return (state);
1136 	}
1137 
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);
1143 
1144 		return (state);
1145 	}
1146 
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");
1150 	}
1151 
1152 	if (pl2303_reconnect_pipes(plp) != USB_SUCCESS) {
1153 
1154 		return (state);
1155 	}
1156 
1157 	/*
1158 	 * init device state
1159 	 */
1160 	mutex_enter(&plp->pl_mutex);
1161 	state = plp->pl_dev_state = USB_DEV_ONLINE;
1162 	mutex_exit(&plp->pl_mutex);
1163 
1164 	if ((pl2303_restore_port_state(plp) != USB_SUCCESS)) {
1165 		USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
1166 		    "pl2303_restore_device_state: failed");
1167 	}
1168 
1169 	return (state);
1170 }
1171 
1172 
1173 /*
1174  * restore ports state after CPR resume or reconnect
1175  */
1176 static int
1177 pl2303_restore_port_state(pl2303_state_t *plp)
1178 {
1179 	int		rval;
1180 
1181 	mutex_enter(&plp->pl_mutex);
1182 	if (plp->pl_port_state != PL2303_PORT_OPEN) {
1183 		mutex_exit(&plp->pl_mutex);
1184 
1185 		return (USB_SUCCESS);
1186 	}
1187 	mutex_exit(&plp->pl_mutex);
1188 
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");
1193 	}
1194 
1195 	return (rval);
1196 }
1197 
1198 
1199 /*
1200  * power management
1201  * ----------------
1202  *
1203  *
1204  * create PM components
1205  */
1206 static int
1207 pl2303_create_pm_components(pl2303_state_t *plp)
1208 {
1209 	dev_info_t	*dip = plp->pl_dip;
1210 	pl2303_pm_t	*pm;
1211 	uint_t		pwr_states;
1212 
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");
1216 
1217 		return (USB_SUCCESS);
1218 	}
1219 
1220 	pm = plp->pl_pm = kmem_zalloc(sizeof (pl2303_pm_t), KM_SLEEP);
1221 
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);
1226 
1227 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1228 
1229 	return (USB_SUCCESS);
1230 }
1231 
1232 
1233 /*
1234  * destroy PM components
1235  */
1236 static void
1237 pl2303_destroy_pm_components(pl2303_state_t *plp)
1238 {
1239 	pl2303_pm_t	*pm = plp->pl_pm;
1240 	dev_info_t	*dip = plp->pl_dip;
1241 	int		rval;
1242 
1243 	if (!pm)
1244 
1245 		return;
1246 
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);
1254 			}
1255 
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);
1262 			}
1263 		}
1264 
1265 		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1266 	}
1267 	kmem_free(pm, sizeof (pl2303_pm_t));
1268 	plp->pl_pm = NULL;
1269 }
1270 
1271 
1272 /*
1273  * mark device busy and raise power
1274  */
1275 static int
1276 pl2303_pm_set_busy(pl2303_state_t *plp)
1277 {
1278 	pl2303_pm_t	*pm = plp->pl_pm;
1279 	dev_info_t	*dip = plp->pl_dip;
1280 	int		rval;
1281 
1282 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_busy");
1283 
1284 	if (!pm) {
1285 
1286 		return (USB_SUCCESS);
1287 	}
1288 
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);
1293 
1294 		return (USB_SUCCESS);
1295 	}
1296 
1297 	rval = pm_busy_component(dip, 0);
1298 	ASSERT(rval == DDI_SUCCESS);
1299 
1300 	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
1301 		mutex_exit(&plp->pl_mutex);
1302 
1303 		return (USB_SUCCESS);
1304 	}
1305 
1306 	/* need to raise power	*/
1307 	pm->pm_raise_power = B_TRUE;
1308 	mutex_exit(&plp->pl_mutex);
1309 
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");
1313 	}
1314 
1315 	mutex_enter(&plp->pl_mutex);
1316 	pm->pm_raise_power = B_FALSE;
1317 	mutex_exit(&plp->pl_mutex);
1318 
1319 	return (USB_SUCCESS);
1320 }
1321 
1322 
1323 /*
1324  * mark device idle
1325  */
1326 static void
1327 pl2303_pm_set_idle(pl2303_state_t *plp)
1328 {
1329 	pl2303_pm_t	*pm = plp->pl_pm;
1330 	dev_info_t	*dip = plp->pl_dip;
1331 
1332 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_idle");
1333 
1334 	if (!pm) {
1335 
1336 		return;
1337 	}
1338 
1339 	/*
1340 	 * if more ports use the device, do not mark as yet
1341 	 */
1342 	mutex_enter(&plp->pl_mutex);
1343 	if (--pm->pm_busy_cnt > 0) {
1344 		mutex_exit(&plp->pl_mutex);
1345 
1346 		return;
1347 	}
1348 
1349 	if (pm) {
1350 		(void) pm_idle_component(dip, 0);
1351 	}
1352 	mutex_exit(&plp->pl_mutex);
1353 }
1354 
1355 
1356 /*
1357  * Functions to handle power transition for OS levels 0 -> 3
1358  * The same level as OS state, different from USB state
1359  */
1360 static int
1361 pl2303_pwrlvl0(pl2303_state_t *plp)
1362 {
1363 	int	rval;
1364 
1365 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl0");
1366 
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);
1372 
1373 		plp->pl_dev_state = USB_DEV_PWRED_DOWN;
1374 		plp->pl_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
1375 
1376 		/* FALLTHRU */
1377 	case USB_DEV_DISCONNECTED:
1378 	case USB_DEV_SUSPENDED:
1379 		/* allow a disconnect/cpr'ed device to go to lower power */
1380 
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");
1386 
1387 		return (USB_FAILURE);
1388 	}
1389 }
1390 
1391 
1392 static int
1393 pl2303_pwrlvl1(pl2303_state_t *plp)
1394 {
1395 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl1");
1396 
1397 	/* issue USB D2 command to the device */
1398 	(void) usb_set_device_pwrlvl2(plp->pl_dip);
1399 
1400 	return (USB_FAILURE);
1401 }
1402 
1403 
1404 static int
1405 pl2303_pwrlvl2(pl2303_state_t *plp)
1406 {
1407 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl2");
1408 
1409 	/* issue USB D1 command to the device */
1410 	(void) usb_set_device_pwrlvl1(plp->pl_dip);
1411 
1412 	return (USB_FAILURE);
1413 }
1414 
1415 
1416 static int
1417 pl2303_pwrlvl3(pl2303_state_t *plp)
1418 {
1419 	int	rval;
1420 
1421 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl3");
1422 
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);
1428 
1429 		plp->pl_dev_state = USB_DEV_ONLINE;
1430 		plp->pl_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1431 
1432 		/* FALLTHRU */
1433 	case USB_DEV_ONLINE:
1434 		/* we are already in full power */
1435 
1436 		/* FALLTHRU */
1437 	case USB_DEV_DISCONNECTED:
1438 	case USB_DEV_SUSPENDED:
1439 
1440 		return (USB_SUCCESS);
1441 	default:
1442 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
1443 		    "pl2303_pwrlvl3: illegal device state");
1444 
1445 		return (USB_FAILURE);
1446 	}
1447 }
1448 
1449 
1450 /*
1451  * pipe operations
1452  * ---------------
1453  *
1454  *
1455  */
1456 static int
1457 pl2303_open_pipes(pl2303_state_t *plp)
1458 {
1459 	int		ifc, alt;
1460 	usb_pipe_policy_t policy;
1461 	usb_ep_data_t	*in_data, *out_data;
1462 
1463 	/* get ep data */
1464 	ifc = plp->pl_dev_data->dev_curr_if;
1465 	alt = 0;
1466 
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);
1469 
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);
1472 
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");
1476 
1477 		return (USB_FAILURE);
1478 	}
1479 
1480 	/* open pipes */
1481 	policy.pp_max_async_reqs = 2;
1482 
1483 	if (usb_pipe_open(plp->pl_dip, &in_data->ep_descr, &policy,
1484 	    USB_FLAGS_SLEEP, &plp->pl_bulkin_ph) != USB_SUCCESS) {
1485 
1486 		return (USB_FAILURE);
1487 	}
1488 
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);
1493 
1494 		return (USB_FAILURE);
1495 	}
1496 
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);
1501 
1502 	return (USB_SUCCESS);
1503 }
1504 
1505 
1506 static void
1507 pl2303_close_pipes(pl2303_state_t *plp)
1508 {
1509 	if (plp->pl_bulkin_ph) {
1510 		usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph,
1511 		    USB_FLAGS_SLEEP, 0, 0);
1512 	}
1513 	if (plp->pl_bulkout_ph) {
1514 		usb_pipe_close(plp->pl_dip, plp->pl_bulkout_ph,
1515 		    USB_FLAGS_SLEEP, 0, 0);
1516 	}
1517 
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);
1522 }
1523 
1524 
1525 static void
1526 pl2303_disconnect_pipes(pl2303_state_t *plp)
1527 {
1528 	pl2303_close_pipes(plp);
1529 }
1530 
1531 
1532 static int
1533 pl2303_reconnect_pipes(pl2303_state_t *plp)
1534 {
1535 	if ((pl2303_open_pipes(plp) != USB_SUCCESS)) {
1536 
1537 		return (USB_FAILURE);
1538 	}
1539 
1540 	return (USB_SUCCESS);
1541 }
1542 
1543 
1544 /*
1545  * pipe callbacks
1546  * --------------
1547  *
1548  *
1549  * bulk in common and exeception callback
1550  *
1551  */
1552 /*ARGSUSED*/
1553 void
1554 pl2303_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1555 {
1556 	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
1557 	mblk_t		*data;
1558 	int		data_len;
1559 
1560 	data = req->bulk_data;
1561 	data_len = (data) ? MBLKL(data) : 0;
1562 
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);
1567 
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);
1575 		}
1576 	}
1577 
1578 	usb_free_bulk_req(req);
1579 
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");
1588 		}
1589 	}
1590 	mutex_exit(&plp->pl_mutex);
1591 }
1592 
1593 
1594 /*
1595  * bulk out common and exeception callback
1596  */
1597 /*ARGSUSED*/
1598 void
1599 pl2303_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1600 {
1601 	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
1602 	int		data_len;
1603 	mblk_t		*data = req->bulk_data;
1604 
1605 	data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
1606 
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);
1611 
1612 	if (req->bulk_completion_reason && (data_len > 0)) {
1613 		pl2303_put_head(&plp->pl_tx_mp, data);
1614 		req->bulk_data = NULL;
1615 	}
1616 
1617 	usb_free_bulk_req(req);
1618 
1619 	/* notify GSD */
1620 	if (plp->pl_cb.cb_tx) {
1621 		plp->pl_cb.cb_tx(plp->pl_cb.cb_arg);
1622 	}
1623 
1624 	/* send more */
1625 	mutex_enter(&plp->pl_mutex);
1626 	plp->pl_bulkout_state = PL2303_PIPE_IDLE;
1627 	if (plp->pl_tx_mp == NULL) {
1628 		cv_broadcast(&plp->pl_tx_cv);
1629 	} else {
1630 		pl2303_tx_start(plp, NULL);
1631 	}
1632 	mutex_exit(&plp->pl_mutex);
1633 }
1634 
1635 
1636 /*
1637  * data transfer routines
1638  * ----------------------
1639  *
1640  *
1641  * start data receipt
1642  */
1643 static int
1644 pl2303_rx_start(pl2303_state_t *plp)
1645 {
1646 	usb_bulk_req_t	*br;
1647 	int		rval = USB_FAILURE;
1648 
1649 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_rx_start");
1650 
1651 	ASSERT(mutex_owned(&plp->pl_mutex));
1652 
1653 	plp->pl_bulkin_state = PL2303_PIPE_BUSY;
1654 	mutex_exit(&plp->pl_mutex);
1655 
1656 	br = usb_alloc_bulk_req(plp->pl_dip, plp->pl_xfer_sz, USB_FLAGS_SLEEP);
1657 	br->bulk_len = plp->pl_xfer_sz;
1658 	br->bulk_timeout = PL2303_BULKIN_TIMEOUT;
1659 	br->bulk_cb = pl2303_bulkin_cb;
1660 	br->bulk_exc_cb = pl2303_bulkin_cb;
1661 	br->bulk_client_private = (usb_opaque_t)plp;
1662 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
1663 
1664 	rval = usb_pipe_bulk_xfer(plp->pl_bulkin_ph, br, 0);
1665 
1666 	if (rval != USB_SUCCESS) {
1667 		USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
1668 		    "pl2303_rx_start: xfer failed %d", rval);
1669 		usb_free_bulk_req(br);
1670 	}
1671 
1672 	mutex_enter(&plp->pl_mutex);
1673 	if (rval != USB_SUCCESS) {
1674 		plp->pl_bulkin_state = PL2303_PIPE_IDLE;
1675 	}
1676 
1677 	return (rval);
1678 }
1679 
1680 
1681 /*
1682  * start data transmit
1683  */
1684 static void
1685 pl2303_tx_start(pl2303_state_t *plp, int *xferd)
1686 {
1687 	int		len;		/* bytes we can transmit */
1688 	mblk_t		*data;		/* data to be transmitted */
1689 	int		data_len;	/* bytes in 'data' */
1690 	mblk_t		*mp;		/* current msgblk */
1691 	int		copylen;	/* bytes copy from 'mp' to 'data' */
1692 	int		rval;
1693 
1694 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_tx_start");
1695 	ASSERT(mutex_owned(&plp->pl_mutex));
1696 	ASSERT(plp->pl_port_state != PL2303_PORT_CLOSED);
1697 
1698 	if (xferd) {
1699 		*xferd = 0;
1700 	}
1701 	if ((plp->pl_port_flags & PL2303_PORT_TX_STOPPED) ||
1702 	    (plp->pl_tx_mp == NULL)) {
1703 
1704 		return;
1705 	}
1706 	if (plp->pl_bulkout_state != PL2303_PIPE_IDLE) {
1707 		USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
1708 		    "pl2303_tx_start: pipe busy");
1709 
1710 		return;
1711 	}
1712 	ASSERT(MBLKL(plp->pl_tx_mp) > 0);
1713 
1714 	/* send as much data as port can receive */
1715 	len = min(msgdsize(plp->pl_tx_mp), plp->pl_xfer_sz);
1716 
1717 	if (len == 0) {
1718 
1719 		return;
1720 	}
1721 
1722 	if ((data = allocb(len, BPRI_LO)) == NULL) {
1723 
1724 		return;
1725 	}
1726 
1727 	/*
1728 	 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
1729 	 */
1730 	data_len = 0;
1731 
1732 	while ((data_len < len) && plp->pl_tx_mp) {
1733 		mp = plp->pl_tx_mp;
1734 		copylen = min(MBLKL(mp), len - data_len);
1735 		bcopy(mp->b_rptr, data->b_wptr, copylen);
1736 		mp->b_rptr += copylen;
1737 		data->b_wptr += copylen;
1738 		data_len += copylen;
1739 
1740 		if (MBLKL(mp) < 1) {
1741 			plp->pl_tx_mp = unlinkb(mp);
1742 			freeb(mp);
1743 		} else {
1744 			ASSERT(data_len == len);
1745 		}
1746 	}
1747 
1748 	if (data_len <= 0) {
1749 		USB_DPRINTF_L3(DPRINT_OUT_PIPE, plp->pl_lh,
1750 		    "pl2303_tx_start: copied zero bytes");
1751 		freeb(data);
1752 
1753 		return;
1754 	}
1755 
1756 	plp->pl_bulkout_state = PL2303_PIPE_BUSY;
1757 	mutex_exit(&plp->pl_mutex);
1758 
1759 	rval = pl2303_send_data(plp, data);
1760 	mutex_enter(&plp->pl_mutex);
1761 
1762 	if (rval != USB_SUCCESS) {
1763 		plp->pl_bulkout_state = PL2303_PIPE_IDLE;
1764 		pl2303_put_head(&plp->pl_tx_mp, data);
1765 	} else {
1766 		if (xferd) {
1767 			*xferd = data_len;
1768 		}
1769 	}
1770 }
1771 
1772 
1773 static int
1774 pl2303_send_data(pl2303_state_t *plp, mblk_t *data)
1775 {
1776 	usb_bulk_req_t	*br;
1777 	int		len = MBLKL(data);
1778 	int		rval;
1779 
1780 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_send_data: %d "
1781 	    "%x %x %x", len, data->b_rptr[0],
1782 	    (len > 1) ? data->b_rptr[1] : 0,
1783 	    (len > 2) ? data->b_rptr[2] : 0);
1784 	ASSERT(!mutex_owned(&plp->pl_mutex));
1785 
1786 	br = usb_alloc_bulk_req(plp->pl_dip, 0, USB_FLAGS_SLEEP);
1787 	br->bulk_data = data;
1788 	br->bulk_len = len;
1789 	br->bulk_timeout = PL2303_BULKOUT_TIMEOUT;
1790 	br->bulk_cb = pl2303_bulkout_cb;
1791 	br->bulk_exc_cb = pl2303_bulkout_cb;
1792 	br->bulk_client_private = (usb_opaque_t)plp;
1793 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1794 
1795 	rval = usb_pipe_bulk_xfer(plp->pl_bulkout_ph, br, 0);
1796 
1797 	if (rval != USB_SUCCESS) {
1798 		USB_DPRINTF_L2(DPRINT_OUT_PIPE, plp->pl_lh,
1799 		    "pl2303_send_data: xfer failed %d", rval);
1800 
1801 		br->bulk_data = NULL;
1802 		usb_free_bulk_req(br);
1803 	}
1804 
1805 	return (rval);
1806 }
1807 
1808 
1809 /*
1810  * wait until local tx buffer drains.
1811  * 'timeout' is in seconds, zero means wait forever
1812  */
1813 static int
1814 pl2303_wait_tx_drain(pl2303_state_t *plp, int timeout)
1815 {
1816 	clock_t	until;
1817 	int	over = 0;
1818 
1819 	until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
1820 
1821 	while (plp->pl_tx_mp && !over) {
1822 		if (timeout > 0) {
1823 			/* whether timedout or signal pending */
1824 			over = (cv_timedwait_sig(&plp->pl_tx_cv,
1825 			    &plp->pl_mutex, until) <= 0);
1826 		} else {
1827 			/* whether a signal is pending */
1828 			over = (cv_wait_sig(&plp->pl_tx_cv,
1829 			    &plp->pl_mutex) == 0);
1830 		}
1831 	}
1832 
1833 	return ((plp->pl_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
1834 }
1835 
1836 
1837 /*
1838  * device operations
1839  * -----------------
1840  *
1841  *
1842  * initialize hardware serial port
1843  */
1844 static int
1845 pl2303_open_hw_port(pl2303_state_t *plp)
1846 {
1847 	int		rval = USB_SUCCESS;
1848 
1849 	/*
1850 	 * initialize three Device Configuration Registers (DCR):
1851 	 * DCR0, DCR1, and DCR2
1852 	 */
1853 
1854 	switch (plp->pl_chiptype) {
1855 	case (pl2303_H):
1856 		/* Set DCR0 */
1857 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
1858 		    DCR0_INIT_H)) != USB_SUCCESS) {
1859 
1860 			return (rval);
1861 		}
1862 
1863 		/* Set DCR1 */
1864 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
1865 		    DCR1_INIT_H)) != USB_SUCCESS) {
1866 
1867 			return (rval);
1868 		}
1869 
1870 		/* Set DCR2 */
1871 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
1872 		    DCR2_INIT_H)) != USB_SUCCESS) {
1873 
1874 			return (rval);
1875 		}
1876 
1877 		break;
1878 	case (pl2303_X):
1879 	case (pl2303_HX_CHIP_D):
1880 
1881 		/* Set DCR0 */
1882 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
1883 		    DCR0_INIT)) != USB_SUCCESS) {
1884 
1885 			return (rval);
1886 		}
1887 
1888 		/* Set DCR1 */
1889 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
1890 		    DCR1_INIT_X)) != USB_SUCCESS) {
1891 
1892 			return (rval);
1893 		}
1894 
1895 		/* Set DCR2 */
1896 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
1897 		    DCR2_INIT_X)) != USB_SUCCESS) {
1898 
1899 			return (rval);
1900 		}
1901 
1902 		/* reset Downstream data pipes */
1903 		if ((rval = pl2303_cmd_vendor_write0(plp,
1904 		    RESET_DOWNSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
1905 
1906 			return (rval);
1907 		}
1908 
1909 		/* reset Upstream data pipes */
1910 		if ((rval = pl2303_cmd_vendor_write0(plp,
1911 		    RESET_UPSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
1912 
1913 			return (rval);
1914 		}
1915 
1916 		break;
1917 	case (pl2303_UNKNOWN):
1918 	default:
1919 		USB_DPRINTF_L2(DPRINT_OPEN, plp->pl_lh,
1920 		    "pl2303_open_hw_port: unknown chiptype");
1921 
1922 		rval = USB_FAILURE;
1923 	}
1924 
1925 	return (rval);
1926 }
1927 
1928 
1929 /*
1930  * vendor-specific commands
1931  * ------------------------
1932  *
1933  *
1934  * Get_Line_Coding Request
1935  */
1936 static int
1937 pl2303_cmd_get_line(pl2303_state_t *plp, mblk_t **data)
1938 {
1939 	usb_ctrl_setup_t setup = { PL2303_GET_LINE_CODING_REQUEST_TYPE,
1940 	    PL2303_GET_LINE_CODING_REQUEST, 0, 0,
1941 	    PL2303_GET_LINE_CODING_LENGTH, 0 };
1942 	usb_cb_flags_t	cb_flags;
1943 	usb_cr_t	cr;
1944 	int		rval;
1945 
1946 	*data = NULL;
1947 
1948 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, data,
1949 	    &cr, &cb_flags, 0);
1950 
1951 	if ((rval == USB_SUCCESS) && (*data != NULL)) {
1952 		USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
1953 		    "pl2303_cmd_get_line: %x %x %x %x %x %x %x",
1954 		    (*data)->b_rptr[0], (*data)->b_rptr[1], (*data)->b_rptr[2],
1955 		    (*data)->b_rptr[3], (*data)->b_rptr[4], (*data)->b_rptr[5],
1956 		    (*data)->b_rptr[6]);
1957 	} else {
1958 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
1959 		    "pl2303_cmd_get_line: failed %d %d %x",
1960 		    rval, cr, cb_flags);
1961 
1962 		if (*data != NULL) {
1963 			freeb(*data);
1964 		}
1965 	}
1966 
1967 	return (rval);
1968 }
1969 
1970 
1971 /*
1972  * Set_Line_Coding Request
1973  */
1974 static int
1975 pl2303_cmd_set_line(pl2303_state_t *plp, mblk_t *data)
1976 {
1977 	usb_ctrl_setup_t setup = { PL2303_SET_LINE_CODING_REQUEST_TYPE,
1978 	    PL2303_SET_LINE_CODING_REQUEST, 0, 0,
1979 	    PL2303_SET_LINE_CODING_LENGTH, 0 };
1980 	usb_cb_flags_t	cb_flags;
1981 	usb_cr_t	cr;
1982 	int		rval;
1983 
1984 	USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
1985 	    "pl2303_cmd_set_line: %x %x %x %x %x %x %x",
1986 	    data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
1987 	    data->b_rptr[3], data->b_rptr[4], data->b_rptr[5], data->b_rptr[6]);
1988 
1989 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, &data,
1990 	    &cr, &cb_flags, 0);
1991 
1992 	if (rval != USB_SUCCESS) {
1993 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
1994 		    "pl2303_cmd_set_line: failed %d %d %x",
1995 		    rval, cr, cb_flags);
1996 	}
1997 
1998 	return (rval);
1999 }
2000 
2001 
2002 /*
2003  * Set_Control_Line_State Request to RTS and DTR
2004  */
2005 static int
2006 pl2303_cmd_set_ctl(pl2303_state_t *plp, uint8_t val)
2007 {
2008 	usb_ctrl_setup_t setup = { PL2303_SET_CONTROL_REQUEST_TYPE,
2009 	    PL2303_SET_CONTROL_REQUEST, 0, 0,
2010 	    PL2303_SET_CONTROL_LENGTH, 0 };
2011 	usb_cb_flags_t	cb_flags;
2012 	usb_cr_t	cr;
2013 	int		rval;
2014 
2015 	setup.wValue = val;
2016 
2017 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2018 	    &cr, &cb_flags, 0);
2019 
2020 	if (rval != USB_SUCCESS) {
2021 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2022 		    "pl2303_cmd_set_ctl: failed %d %d %x",
2023 		    rval, cr, cb_flags);
2024 	}
2025 
2026 	return (rval);
2027 }
2028 
2029 
2030 /*
2031  * Vendor_Specific_Write Request
2032  * wLength: 0
2033  */
2034 static int
2035 pl2303_cmd_vendor_write0(pl2303_state_t *plp, uint16_t value, int16_t index)
2036 {
2037 	usb_ctrl_setup_t setup = { PL2303_VENDOR_WRITE_REQUEST_TYPE,
2038 	    PL2303_VENDOR_WRITE_REQUEST, 0, 0,
2039 	    PL2303_VENDOR_WRITE_LENGTH, 0 };
2040 	usb_cb_flags_t	cb_flags;
2041 	usb_cr_t	cr;
2042 	int		rval;
2043 
2044 	setup.wValue = value;
2045 	setup.wIndex = index;
2046 
2047 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2048 	    &cr, &cb_flags, 0);
2049 
2050 	if (rval != USB_SUCCESS) {
2051 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2052 		    "pl2303_cmd_vendor_write0: %x %x failed %d %d %x",
2053 		    value, index, rval, cr, cb_flags);
2054 	}
2055 
2056 	return (rval);
2057 }
2058 
2059 
2060 /*
2061  * For Hardware flow control
2062  */
2063 static int
2064 pl2303_cmd_set_rtscts(pl2303_state_t *plp)
2065 {
2066 	/* Set DCR0 */
2067 	switch (plp->pl_chiptype) {
2068 	case pl2303_H:
2069 
2070 		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_H));
2071 	case pl2303_X:
2072 	case pl2303_HX_CHIP_D:
2073 
2074 		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_X));
2075 	case pl2303_UNKNOWN:
2076 	default:
2077 
2078 		return (USB_FAILURE);
2079 	}
2080 }
2081 
2082 
2083 /*
2084  * Set TxD BREAK_ON or BREAK_OFF
2085  */
2086 static int
2087 pl2303_cmd_break(pl2303_state_t *plp, int ctl)
2088 {
2089 	usb_ctrl_setup_t setup = { PL2303_BREAK_REQUEST_TYPE,
2090 	    PL2303_BREAK_REQUEST, 0, 0,
2091 	    PL2303_BREAK_LENGTH, 0 };
2092 	usb_cb_flags_t	cb_flags;
2093 	usb_cr_t	cr;
2094 	int		rval;
2095 
2096 	setup.wValue = (ctl == DS_ON) ? PL2303_BREAK_ON : PL2303_BREAK_OFF;
2097 
2098 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
2099 	    &cr, &cb_flags, 0);
2100 
2101 	if (rval != USB_SUCCESS) {
2102 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
2103 		    "pl2303_cmd_break: failed rval=%d,cr=%d,cb_flags=0x%x",
2104 		    rval, cr, cb_flags);
2105 	}
2106 
2107 	return (rval);
2108 }
2109 
2110 
2111 /*
2112  * for set_mod_ctl
2113  */
2114 static void
2115 pl2303_mctl2reg(int mask, int val, uint8_t *line_ctl)
2116 {
2117 	if (mask & TIOCM_RTS) {
2118 		if (val & TIOCM_RTS) {
2119 			*line_ctl |= PL2303_CONTROL_RTS;
2120 		} else {
2121 			*line_ctl &= ~PL2303_CONTROL_RTS;
2122 		}
2123 	}
2124 	if (mask & TIOCM_DTR) {
2125 		if (val & TIOCM_DTR) {
2126 			*line_ctl |= PL2303_CONTROL_DTR;
2127 		} else {
2128 			*line_ctl &= ~PL2303_CONTROL_DTR;
2129 		}
2130 	}
2131 }
2132 
2133 
2134 /*
2135  * for get_mod_ctl
2136  */
2137 static int
2138 pl2303_reg2mctl(uint8_t line_ctl)
2139 {
2140 	int	val = 0;
2141 
2142 	if (line_ctl & PL2303_CONTROL_RTS) {
2143 		val |= TIOCM_RTS;
2144 	}
2145 	if (line_ctl & PL2303_CONTROL_DTR) {
2146 		val |= TIOCM_DTR;
2147 	}
2148 
2149 	return (val);
2150 }
2151 
2152 
2153 /*
2154  * misc routines
2155  * -------------
2156  *
2157  */
2158 
2159 /*
2160  * link a message block to tail of message
2161  * account for the case when message is null
2162  */
2163 static void
2164 pl2303_put_tail(mblk_t **mpp, mblk_t *bp)
2165 {
2166 	if (*mpp) {
2167 		linkb(*mpp, bp);
2168 	} else {
2169 		*mpp = bp;
2170 	}
2171 }
2172 
2173 
2174 /*
2175  * put a message block at the head of the message
2176  * account for the case when message is null
2177  */
2178 static void
2179 pl2303_put_head(mblk_t **mpp, mblk_t *bp)
2180 {
2181 	if (*mpp) {
2182 		linkb(bp, *mpp);
2183 	}
2184 	*mpp = bp;
2185 }
2186 
2187 /*ARGSUSED*/
2188 static usb_pipe_handle_t
2189 pl2303_out_pipe(ds_hdl_t hdl, uint_t port_num)
2190 {
2191 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
2192 
2193 	return (plp->pl_bulkout_ph);
2194 }
2195 
2196 /*ARGSUSED*/
2197 static usb_pipe_handle_t
2198 pl2303_in_pipe(ds_hdl_t hdl, uint_t port_num)
2199 {
2200 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
2201 
2202 	return (plp->pl_bulkin_ph);
2203 }
2204