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