14de26129Sxs /*
24de26129Sxs  * CDDL HEADER START
34de26129Sxs  *
44de26129Sxs  * The contents of this file are subject to the terms of the
528cdc3d7Sszhou  * Common Development and Distribution License (the "License").
628cdc3d7Sszhou  * You may not use this file except in compliance with the License.
74de26129Sxs  *
84de26129Sxs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94de26129Sxs  * or http://www.opensolaris.org/os/licensing.
104de26129Sxs  * See the License for the specific language governing permissions
114de26129Sxs  * and limitations under the License.
124de26129Sxs  *
134de26129Sxs  * When distributing Covered Code, include this CDDL HEADER in each
144de26129Sxs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154de26129Sxs  * If applicable, add the following below this CDDL HEADER, with the
164de26129Sxs  * fields enclosed by brackets "[]" replaced with your own identifying
174de26129Sxs  * information: Portions Copyright [yyyy] [name of copyright owner]
184de26129Sxs  *
194de26129Sxs  * CDDL HEADER END
204de26129Sxs  */
214de26129Sxs /*
2222eb7cb5Sgd  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
234de26129Sxs  * Use is subject to license terms.
244de26129Sxs  */
254de26129Sxs 
264de26129Sxs 
274de26129Sxs /*
284de26129Sxs  *
294de26129Sxs  * USB Prolific PL2303 device-specific driver (DSD)
304de26129Sxs  *
314de26129Sxs  */
324de26129Sxs #include <sys/types.h>
334de26129Sxs #include <sys/param.h>
344de26129Sxs #include <sys/conf.h>
354de26129Sxs #include <sys/stream.h>
364de26129Sxs #include <sys/strsun.h>
374de26129Sxs #include <sys/termio.h>
384de26129Sxs #include <sys/termiox.h>
394de26129Sxs #include <sys/ddi.h>
404de26129Sxs #include <sys/sunddi.h>
414de26129Sxs 
424de26129Sxs #define	USBDRV_MAJOR_VER	2
434de26129Sxs #define	USBDRV_MINOR_VER	0
444de26129Sxs 
454de26129Sxs #include <sys/usb/usba.h>
464de26129Sxs #include <sys/usb/usba/usba_types.h>
474de26129Sxs #include <sys/usb/usba/usba_impl.h>
484de26129Sxs 
494de26129Sxs #include <sys/usb/clients/usbser/usbser_dsdi.h>
504de26129Sxs #include <sys/usb/clients/usbser/usbsprl/pl2303_var.h>
514de26129Sxs #include <sys/usb/clients/usbser/usbsprl/pl2303_vendor.h>
524de26129Sxs 
534de26129Sxs 
544de26129Sxs /*
554de26129Sxs  * DSD operations
564de26129Sxs  */
574de26129Sxs static int	pl2303_attach(ds_attach_info_t *);
584de26129Sxs static void	pl2303_detach(ds_hdl_t);
594de26129Sxs static int	pl2303_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
604de26129Sxs static void	pl2303_unregister_cb(ds_hdl_t, uint_t);
614de26129Sxs static int	pl2303_open_port(ds_hdl_t, uint_t);
624de26129Sxs static int	pl2303_close_port(ds_hdl_t, uint_t);
634de26129Sxs 
644de26129Sxs /* power management */
654de26129Sxs static int	pl2303_usb_power(ds_hdl_t, int, int, int *);
664de26129Sxs static int	pl2303_suspend(ds_hdl_t);
674de26129Sxs static int	pl2303_resume(ds_hdl_t);
684de26129Sxs static int	pl2303_disconnect(ds_hdl_t);
694de26129Sxs static int	pl2303_reconnect(ds_hdl_t);
704de26129Sxs 
714de26129Sxs /* standard UART operations */
724de26129Sxs static int	pl2303_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
734de26129Sxs static int	pl2303_set_modem_ctl(ds_hdl_t, uint_t, int, int);
744de26129Sxs static int	pl2303_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
754de26129Sxs static int	pl2303_break_ctl(ds_hdl_t, uint_t, int);
764de26129Sxs 
774de26129Sxs /* data xfer */
784de26129Sxs static int	pl2303_tx(ds_hdl_t, uint_t, mblk_t *);
794de26129Sxs static mblk_t	*pl2303_rx(ds_hdl_t, uint_t);
804de26129Sxs static void	pl2303_stop(ds_hdl_t, uint_t, int);
814de26129Sxs static void	pl2303_start(ds_hdl_t, uint_t, int);
824de26129Sxs static int	pl2303_fifo_flush(ds_hdl_t, uint_t, int);
834de26129Sxs static int	pl2303_fifo_drain(ds_hdl_t, uint_t, int);
844de26129Sxs 
8528cdc3d7Sszhou /* polled I/O support */
8628cdc3d7Sszhou static usb_pipe_handle_t pl2303_out_pipe(ds_hdl_t, uint_t);
8728cdc3d7Sszhou static usb_pipe_handle_t pl2303_in_pipe(ds_hdl_t, uint_t);
884de26129Sxs 
894de26129Sxs /*
904de26129Sxs  * Sub-routines
914de26129Sxs  */
924de26129Sxs 
934de26129Sxs /* configuration routines */
944de26129Sxs static void	pl2303_cleanup(pl2303_state_t *, int);
954de26129Sxs static int	pl2303_dev_attach(pl2303_state_t *);
964de26129Sxs static int	pl2303_open_hw_port(pl2303_state_t *);
974de26129Sxs 
984de26129Sxs /* hotplug */
994de26129Sxs static int	pl2303_restore_device_state(pl2303_state_t *);
1004de26129Sxs static int	pl2303_restore_port_state(pl2303_state_t *);
1014de26129Sxs 
1024de26129Sxs /* power management */
1034de26129Sxs static int	pl2303_create_pm_components(pl2303_state_t *);
1044de26129Sxs static void	pl2303_destroy_pm_components(pl2303_state_t *);
1054de26129Sxs static int	pl2303_pm_set_busy(pl2303_state_t *);
1064de26129Sxs static void	pl2303_pm_set_idle(pl2303_state_t *);
1074de26129Sxs static int	pl2303_pwrlvl0(pl2303_state_t *);
1084de26129Sxs static int	pl2303_pwrlvl1(pl2303_state_t *);
1094de26129Sxs static int	pl2303_pwrlvl2(pl2303_state_t *);
1104de26129Sxs static int	pl2303_pwrlvl3(pl2303_state_t *);
1114de26129Sxs 
1124de26129Sxs /* pipe operations */
1134de26129Sxs static int	pl2303_open_pipes(pl2303_state_t *);
1144de26129Sxs static void	pl2303_close_pipes(pl2303_state_t *);
1154de26129Sxs static void	pl2303_disconnect_pipes(pl2303_state_t *);
1164de26129Sxs static int	pl2303_reconnect_pipes(pl2303_state_t *);
1174de26129Sxs 
1184de26129Sxs /* pipe callbacks */
1194de26129Sxs void		pl2303_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
1204de26129Sxs void		pl2303_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
1214de26129Sxs 
1224de26129Sxs /* data transfer routines */
1234de26129Sxs static int	pl2303_rx_start(pl2303_state_t *);
1244de26129Sxs static void	pl2303_tx_start(pl2303_state_t *, int *);
1254de26129Sxs static int	pl2303_send_data(pl2303_state_t *, mblk_t *);
1264de26129Sxs static int	pl2303_wait_tx_drain(pl2303_state_t *, int);
1274de26129Sxs 
1284de26129Sxs /* vendor-specific commands */
1294de26129Sxs static int	pl2303_cmd_get_line(pl2303_state_t *, mblk_t **);
1304de26129Sxs static int	pl2303_cmd_set_line(pl2303_state_t *, mblk_t *);
1314de26129Sxs static int	pl2303_cmd_set_ctl(pl2303_state_t *, uint8_t);
1324de26129Sxs static int	pl2303_cmd_vendor_write0(pl2303_state_t *, uint16_t, int16_t);
1334de26129Sxs static int	pl2303_cmd_set_rtscts(pl2303_state_t *);
1344de26129Sxs static int	pl2303_cmd_break(pl2303_state_t *, int);
1354de26129Sxs static void	pl2303_mctl2reg(int mask, int val, uint8_t *);
1364de26129Sxs static int	pl2303_reg2mctl(uint8_t);
1374de26129Sxs 
1384de26129Sxs /* misc */
1394de26129Sxs static void	pl2303_put_tail(mblk_t **, mblk_t *);
1404de26129Sxs static void	pl2303_put_head(mblk_t **, mblk_t *);
1414de26129Sxs 
1424de26129Sxs 
1434de26129Sxs /*
1444de26129Sxs  * DSD ops structure
1454de26129Sxs  */
146e8ed0869SJohn Beck ds_ops_t pl2303_ds_ops = {
1474de26129Sxs 	DS_OPS_VERSION,
1484de26129Sxs 	pl2303_attach,
1494de26129Sxs 	pl2303_detach,
1504de26129Sxs 	pl2303_register_cb,
1514de26129Sxs 	pl2303_unregister_cb,
1524de26129Sxs 	pl2303_open_port,
1534de26129Sxs 	pl2303_close_port,
1544de26129Sxs 	pl2303_usb_power,
1554de26129Sxs 	pl2303_suspend,
1564de26129Sxs 	pl2303_resume,
1574de26129Sxs 	pl2303_disconnect,
1584de26129Sxs 	pl2303_reconnect,
1594de26129Sxs 	pl2303_set_port_params,
1604de26129Sxs 	pl2303_set_modem_ctl,
1614de26129Sxs 	pl2303_get_modem_ctl,
1624de26129Sxs 	pl2303_break_ctl,
1634de26129Sxs 	NULL,			/* HW don't support loopback */
1644de26129Sxs 	pl2303_tx,
1654de26129Sxs 	pl2303_rx,
1664de26129Sxs 	pl2303_stop,
1674de26129Sxs 	pl2303_start,
1684de26129Sxs 	pl2303_fifo_flush,
16928cdc3d7Sszhou 	pl2303_fifo_drain,
17028cdc3d7Sszhou 	pl2303_out_pipe,
17128cdc3d7Sszhou 	pl2303_in_pipe
1724de26129Sxs };
1734de26129Sxs 
1744de26129Sxs 
1754de26129Sxs /*
1764de26129Sxs  * baud code into baud rate
1774de26129Sxs  * value 0 means not supported in hardware
1784de26129Sxs  *
1794de26129Sxs  */
1804de26129Sxs static int pl2303_speedtab[] = {
1814de26129Sxs 	0,	/* B0 */
1824de26129Sxs 	0,	/* B50 */
1834de26129Sxs 	75,	/* B75 */
1844de26129Sxs 	0,	/* B110 */
1854de26129Sxs 	0,	/* B134 */
1864de26129Sxs 	150,	/* B150 */
1874de26129Sxs 	0,	/* B200 */
1884de26129Sxs 	300,	/* B300 */
1894de26129Sxs 	600,	/* B600 */
1904de26129Sxs 	1200,	/* B1200 */
1914de26129Sxs 	1800,	/* B1800 */
1924de26129Sxs 	2400,	/* B2400 */
1934de26129Sxs 	4800,	/* B4800 */
1944de26129Sxs 	9600,	/* B9600 */
1954de26129Sxs 	19200,	/* B19200 */
1964de26129Sxs 	38400,	/* B38400 */
1974de26129Sxs 	57600,	/* B57600 */
1984de26129Sxs 	0,	/* B76800 */
1994de26129Sxs 	115200,	/* B115200 */
2004de26129Sxs 	0,	/* B153600 */
2014de26129Sxs 	230400,	/* B230400 */
2024de26129Sxs 	0,	/* B307200 */
2034de26129Sxs 	460800	/* B460800 */
2044de26129Sxs };
2054de26129Sxs 
2064de26129Sxs 
2074de26129Sxs /* debug support */
2086918308bSyz static uint_t	pl2303_errlevel = USB_LOG_L4;
2096918308bSyz static uint_t	pl2303_errmask = DPRINT_MASK_ALL;
2106918308bSyz static uint_t	pl2303_instance_debug = (uint_t)-1;
2114de26129Sxs 
2124de26129Sxs 
2134de26129Sxs /*
2144de26129Sxs  * ds_attach
2154de26129Sxs  */
2164de26129Sxs static int
pl2303_attach(ds_attach_info_t * aip)2174de26129Sxs pl2303_attach(ds_attach_info_t *aip)
2184de26129Sxs {
2194de26129Sxs 	pl2303_state_t	*plp;
2204de26129Sxs 
2214de26129Sxs 	plp = (pl2303_state_t *)kmem_zalloc(sizeof (pl2303_state_t), KM_SLEEP);
2224de26129Sxs 	plp->pl_dip = aip->ai_dip;
2234de26129Sxs 	plp->pl_usb_events = aip->ai_usb_events;
2244de26129Sxs 	*aip->ai_hdl = (ds_hdl_t)plp;
2254de26129Sxs 
2264de26129Sxs 	/* only one port */
2274de26129Sxs 	*aip->ai_port_cnt = 1;
2284de26129Sxs 
2294de26129Sxs 	if (usb_client_attach(plp->pl_dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
2304de26129Sxs 		pl2303_cleanup(plp, 1);
2314de26129Sxs 
2324de26129Sxs 		return (USB_FAILURE);
2334de26129Sxs 	}
2344de26129Sxs 
2354de26129Sxs 	if (usb_get_dev_data(plp->pl_dip, &plp->pl_dev_data,  USB_PARSE_LVL_IF,
2364de26129Sxs 	    0) != USB_SUCCESS) {
2374de26129Sxs 		pl2303_cleanup(plp, 2);
2384de26129Sxs 
2394de26129Sxs 		return (USB_FAILURE);
2404de26129Sxs 	}
2414de26129Sxs 
2426918308bSyz 	mutex_init(&plp->pl_mutex, NULL, MUTEX_DRIVER,
243b0fe7b8fSlg 	    plp->pl_dev_data->dev_iblock_cookie);
2446918308bSyz 
2456918308bSyz 	cv_init(&plp->pl_tx_cv, NULL, CV_DRIVER, NULL);
2466918308bSyz 
2476918308bSyz 	plp->pl_lh = usb_alloc_log_hdl(plp->pl_dip, "pl2303",
2486918308bSyz 	    &pl2303_errlevel, &pl2303_errmask, &pl2303_instance_debug, 0);
2496918308bSyz 
2504de26129Sxs 	/*
251cbab2b26Slg 	 * Check the chip type: pl2303_H, pl2303_X (or pl2303_HX(Chip A)),
252cbab2b26Slg 	 * pl2303_HX(Chip D).
253cbab2b26Slg 	 * pl2303_UNKNOWN means not supported chip type.
2544de26129Sxs 	 */
2554de26129Sxs 	if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_H) {
2564de26129Sxs 		mutex_enter(&plp->pl_mutex);
2574de26129Sxs 		plp->pl_chiptype = pl2303_H;
2584de26129Sxs 		mutex_exit(&plp->pl_mutex);
259cbab2b26Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
260b0fe7b8fSlg 		    "Chip Type: pl2303_H");
2614de26129Sxs 	} else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_X) {
2624de26129Sxs 		/*
263cbab2b26Slg 		 * pl2303_HX(Chip A)and pl2303_X devices have different
264cbab2b26Slg 		 * hardware, but from the view of device driver, they have
265cbab2b26Slg 		 * the same software interface.
2664de26129Sxs 		 *
267cbab2b26Slg 		 * So "pl2303_X" will stand for both pl2303_HX(Chip A)and
268cbab2b26Slg 		 * pl2303_X devices in this driver.
2694de26129Sxs 		 */
2704de26129Sxs 		mutex_enter(&plp->pl_mutex);
2714de26129Sxs 		plp->pl_chiptype = pl2303_X;
2724de26129Sxs 		mutex_exit(&plp->pl_mutex);
273cbab2b26Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
274b0fe7b8fSlg 		    "Chip Type: pl2303_HX(Chip A) or pl2303_X");
275cbab2b26Slg 	} else if (plp->pl_dev_data->dev_descr->bcdDevice ==
276b0fe7b8fSlg 	    PROLIFIC_REV_HX_CHIP_D) {
277cbab2b26Slg 		mutex_enter(&plp->pl_mutex);
278cbab2b26Slg 		plp->pl_chiptype = pl2303_HX_CHIP_D;
279cbab2b26Slg 		mutex_exit(&plp->pl_mutex);
280cbab2b26Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
281b0fe7b8fSlg 		    "Chip Type: pl2303_HX(Chip D)");
282b0fe7b8fSlg 	} else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_1) {
283b0fe7b8fSlg 		/* IO DATA USB-RSAQ3(usb67b,aaa2) uses pl2303_X chip */
284b0fe7b8fSlg 		mutex_enter(&plp->pl_mutex);
285b0fe7b8fSlg 		plp->pl_chiptype = pl2303_X;
286b0fe7b8fSlg 		mutex_exit(&plp->pl_mutex);
287b0fe7b8fSlg 		USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
288b0fe7b8fSlg 		    "Chip Type: pl2303_X with revison number=1");
2894de26129Sxs 	} else {
2904de26129Sxs 		mutex_enter(&plp->pl_mutex);
2914de26129Sxs 		plp->pl_chiptype = pl2303_UNKNOWN;
2924de26129Sxs 		mutex_exit(&plp->pl_mutex);
293cbab2b26Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, plp->pl_lh,
294b0fe7b8fSlg 		    "Chip Type: Unknown");
2954de26129Sxs 	}
2964de26129Sxs 
2974de26129Sxs 	plp->pl_def_ph = plp->pl_dev_data->dev_default_ph;
2984de26129Sxs 
2994de26129Sxs 	mutex_enter(&plp->pl_mutex);
3004de26129Sxs 	plp->pl_dev_state = USB_DEV_ONLINE;
3014de26129Sxs 	plp->pl_port_state = PL2303_PORT_CLOSED;
3024de26129Sxs 	mutex_exit(&plp->pl_mutex);
3034de26129Sxs 
3044de26129Sxs 	if (pl2303_create_pm_components(plp) != USB_SUCCESS) {
3056918308bSyz 		pl2303_cleanup(plp, 3);
3064de26129Sxs 
3074de26129Sxs 		return (USB_FAILURE);
3084de26129Sxs 	}
3094de26129Sxs 
3104de26129Sxs 	if (usb_register_event_cbs(plp->pl_dip, plp->pl_usb_events, 0)
3114de26129Sxs 	    != USB_SUCCESS) {
3126918308bSyz 		pl2303_cleanup(plp, 4);
3134de26129Sxs 
3144de26129Sxs 		return (USB_FAILURE);
3154de26129Sxs 	}
3164de26129Sxs 
3174de26129Sxs 	if (usb_pipe_get_max_bulk_transfer_size(plp->pl_dip,
3184de26129Sxs 	    &plp->pl_xfer_sz) != USB_SUCCESS) {
3196918308bSyz 		pl2303_cleanup(plp, 5);
3204de26129Sxs 
3214de26129Sxs 		return (USB_FAILURE);
3224de26129Sxs 	}
3234de26129Sxs 
3244de26129Sxs 	if (plp->pl_xfer_sz > PL2303_XFER_SZ_MAX) {
3254de26129Sxs 		plp->pl_xfer_sz = PL2303_XFER_SZ_MAX;
3264de26129Sxs 	}
3274de26129Sxs 
3284de26129Sxs 	if (pl2303_dev_attach(plp) != USB_SUCCESS) {
3296918308bSyz 		pl2303_cleanup(plp, 5);
3304de26129Sxs 
3314de26129Sxs 		return (USB_FAILURE);
3324de26129Sxs 	}
3334de26129Sxs 
3344de26129Sxs 	return (USB_SUCCESS);
3354de26129Sxs }
3364de26129Sxs 
3374de26129Sxs 
3384de26129Sxs /*
3394de26129Sxs  * ds_detach
3404de26129Sxs  */
3414de26129Sxs static void
pl2303_detach(ds_hdl_t hdl)3424de26129Sxs pl2303_detach(ds_hdl_t hdl)
3434de26129Sxs {
3444de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
3454de26129Sxs 
3464de26129Sxs 	pl2303_cleanup(plp, PL2303_CLEANUP_LEVEL_MAX);
3474de26129Sxs }
3484de26129Sxs 
3494de26129Sxs 
3504de26129Sxs /*
3514de26129Sxs  * ds_register_cb
3524de26129Sxs  */
3534de26129Sxs /*ARGSUSED*/
3544de26129Sxs static int
pl2303_register_cb(ds_hdl_t hdl,uint_t port_num,ds_cb_t * cb)3554de26129Sxs pl2303_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
3564de26129Sxs {
3574de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
3584de26129Sxs 
3594de26129Sxs 	plp->pl_cb = *cb;
3604de26129Sxs 
3614de26129Sxs 	return (USB_SUCCESS);
3624de26129Sxs }
3634de26129Sxs 
3644de26129Sxs 
3654de26129Sxs /*
3664de26129Sxs  * ds_unregister_cb
3674de26129Sxs  */
3684de26129Sxs /*ARGSUSED*/
3694de26129Sxs static void
pl2303_unregister_cb(ds_hdl_t hdl,uint_t port_num)3704de26129Sxs pl2303_unregister_cb(ds_hdl_t hdl, uint_t port_num)
3714de26129Sxs {
3724de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
3734de26129Sxs 
3744de26129Sxs 	bzero(&plp->pl_cb, sizeof (plp->pl_cb));
3754de26129Sxs }
3764de26129Sxs 
3774de26129Sxs 
3784de26129Sxs /*
3794de26129Sxs  * ds_open_port
3804de26129Sxs  */
3814de26129Sxs /*ARGSUSED*/
3824de26129Sxs static int
pl2303_open_port(ds_hdl_t hdl,uint_t port_num)3834de26129Sxs pl2303_open_port(ds_hdl_t hdl, uint_t port_num)
3844de26129Sxs {
3854de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
3864de26129Sxs 	int		rval = USB_FAILURE;
3874de26129Sxs 
3884de26129Sxs 	USB_DPRINTF_L4(DPRINT_OPEN, plp->pl_lh, "pl2303_open_port");
3894de26129Sxs 
3904de26129Sxs 	mutex_enter(&plp->pl_mutex);
3914de26129Sxs 	if ((plp->pl_dev_state == USB_DEV_DISCONNECTED) ||
3924de26129Sxs 	    (plp->pl_port_state != PL2303_PORT_CLOSED)) {
3934de26129Sxs 		mutex_exit(&plp->pl_mutex);
3944de26129Sxs 
3954de26129Sxs 		return (rval);
3964de26129Sxs 	}
3974de26129Sxs 
3984de26129Sxs 	mutex_exit(&plp->pl_mutex);
3994de26129Sxs 
4004de26129Sxs 	if ((rval = pl2303_pm_set_busy(plp)) != USB_SUCCESS) {
4014de26129Sxs 
4024de26129Sxs 		return (rval);
4034de26129Sxs 	}
4044de26129Sxs 
4054de26129Sxs 	/* initialize hardware serial port */
4064de26129Sxs 	rval = pl2303_open_hw_port(plp);
4074de26129Sxs 
4084de26129Sxs 	if (rval == USB_SUCCESS) {
4094de26129Sxs 		mutex_enter(&plp->pl_mutex);
4104de26129Sxs 
4114de26129Sxs 		/* start to receive data */
4126918308bSyz 		if (pl2303_rx_start(plp) != USB_SUCCESS) {
4136918308bSyz 			mutex_exit(&plp->pl_mutex);
4146918308bSyz 
4156918308bSyz 			return (USB_FAILURE);
4166918308bSyz 		}
4176918308bSyz 		plp->pl_port_state = PL2303_PORT_OPEN;
4184de26129Sxs 		mutex_exit(&plp->pl_mutex);
4194de26129Sxs 	} else {
4204de26129Sxs 		pl2303_pm_set_idle(plp);
4214de26129Sxs 	}
4224de26129Sxs 
4234de26129Sxs 	return (rval);
4244de26129Sxs }
4254de26129Sxs 
4264de26129Sxs 
4274de26129Sxs /*
4284de26129Sxs  * ds_close_port
4294de26129Sxs  */
4304de26129Sxs /*ARGSUSED*/
4314de26129Sxs static int
pl2303_close_port(ds_hdl_t hdl,uint_t port_num)4324de26129Sxs pl2303_close_port(ds_hdl_t hdl, uint_t port_num)
4334de26129Sxs {
4344de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
4354de26129Sxs 
4364de26129Sxs 	USB_DPRINTF_L4(DPRINT_CLOSE, plp->pl_lh, "pl2303_close_port");
4374de26129Sxs 
4384de26129Sxs 	mutex_enter(&plp->pl_mutex);
4394de26129Sxs 
4404de26129Sxs 	/* free resources and finalize state */
4414de26129Sxs 	if (plp->pl_rx_mp) {
4424de26129Sxs 		freemsg(plp->pl_rx_mp);
4434de26129Sxs 		plp->pl_rx_mp = NULL;
4444de26129Sxs 	}
4454de26129Sxs 	if (plp->pl_tx_mp) {
4464de26129Sxs 		freemsg(plp->pl_tx_mp);
4474de26129Sxs 		plp->pl_tx_mp = NULL;
4484de26129Sxs 	}
4494de26129Sxs 
4504de26129Sxs 	plp->pl_port_state = PL2303_PORT_CLOSED;
4514de26129Sxs 	mutex_exit(&plp->pl_mutex);
4524de26129Sxs 
4534de26129Sxs 	pl2303_pm_set_idle(plp);
4544de26129Sxs 
4554de26129Sxs 	return (USB_SUCCESS);
4564de26129Sxs }
4574de26129Sxs 
4584de26129Sxs 
4594de26129Sxs /*
4604de26129Sxs  * power management
4614de26129Sxs  * ----------------
4624de26129Sxs  *
4634de26129Sxs  * ds_usb_power
4644de26129Sxs  */
4654de26129Sxs /*ARGSUSED*/
4664de26129Sxs static int
pl2303_usb_power(ds_hdl_t hdl,int comp,int level,int * new_state)4674de26129Sxs pl2303_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
4684de26129Sxs {
4694de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
4704de26129Sxs 	pl2303_pm_t	*pm = plp->pl_pm;
4714de26129Sxs 	int		rval;
4724de26129Sxs 
4734de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_usb_power");
4744de26129Sxs 
4754de26129Sxs 	if (!pm) {
4764de26129Sxs 
4774de26129Sxs 		return (USB_FAILURE);
4784de26129Sxs 	}
4794de26129Sxs 
4804de26129Sxs 	mutex_enter(&plp->pl_mutex);
4814de26129Sxs 	/*
4824de26129Sxs 	 * check if we are transitioning to a legal power level
4834de26129Sxs 	 */
4844de26129Sxs 	if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
4854de26129Sxs 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "pl2303_usb_power: "
4864de26129Sxs 		    "illegal power level %d, pwr_states=%x",
4874de26129Sxs 		    level, pm->pm_pwr_states);
4884de26129Sxs 		mutex_exit(&plp->pl_mutex);
4894de26129Sxs 
4904de26129Sxs 		return (USB_FAILURE);
4914de26129Sxs 	}
4924de26129Sxs 
4934de26129Sxs 	/*
4944de26129Sxs 	 * if we are about to raise power and asked to lower power, fail
4954de26129Sxs 	 */
4964de26129Sxs 	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
4974de26129Sxs 		mutex_exit(&plp->pl_mutex);
4984de26129Sxs 
4994de26129Sxs 		return (USB_FAILURE);
5004de26129Sxs 	}
5014de26129Sxs 
5024de26129Sxs 	switch (level) {
5034de26129Sxs 	case USB_DEV_OS_PWR_OFF:
5044de26129Sxs 		rval = pl2303_pwrlvl0(plp);
5054de26129Sxs 
5064de26129Sxs 		break;
5074de26129Sxs 	case USB_DEV_OS_PWR_1:
5084de26129Sxs 		rval = pl2303_pwrlvl1(plp);
5094de26129Sxs 
5104de26129Sxs 		break;
5114de26129Sxs 	case USB_DEV_OS_PWR_2:
5124de26129Sxs 		rval = pl2303_pwrlvl2(plp);
5134de26129Sxs 
5144de26129Sxs 		break;
5154de26129Sxs 	case USB_DEV_OS_FULL_PWR:
5164de26129Sxs 		rval = pl2303_pwrlvl3(plp);
5174ee52f77Slg 		/*
5184ee52f77Slg 		 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
5194ee52f77Slg 		 * that the usb serial device is disconnected/suspended while it
5204ee52f77Slg 		 * is under power down state, now the device is powered up
5214ee52f77Slg 		 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
5224ee52f77Slg 		 * state to ONLINE, we need to set the dev state back to
5234ee52f77Slg 		 * DISCONNECTED/SUSPENDED.
5244ee52f77Slg 		 */
5254ee52f77Slg 		if ((rval == USB_SUCCESS) &&
5264ee52f77Slg 		    ((*new_state == USB_DEV_DISCONNECTED) ||
5274ee52f77Slg 		    (*new_state == USB_DEV_SUSPENDED))) {
5284ee52f77Slg 			plp->pl_dev_state = *new_state;
5294ee52f77Slg 		}
5304de26129Sxs 
5314de26129Sxs 		break;
5324de26129Sxs 	default:
5334de26129Sxs 		ASSERT(0);	/* cannot happen */
5344de26129Sxs 	}
5354de26129Sxs 
5364de26129Sxs 	*new_state = plp->pl_dev_state;
5374de26129Sxs 	mutex_exit(&plp->pl_mutex);
5384de26129Sxs 
5394de26129Sxs 	return (rval);
5404de26129Sxs }
5414de26129Sxs 
5424de26129Sxs 
5434de26129Sxs /*
5444de26129Sxs  * ds_suspend
5454de26129Sxs  */
5464de26129Sxs static int
pl2303_suspend(ds_hdl_t hdl)5474de26129Sxs pl2303_suspend(ds_hdl_t hdl)
5484de26129Sxs {
5494de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
5504ee52f77Slg 	int		state = USB_DEV_SUSPENDED;
5514de26129Sxs 
5524de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_suspend");
5534de26129Sxs 
5544ee52f77Slg 	/*
5554ee52f77Slg 	 * If the device is suspended while it is under PWRED_DOWN state, we
5564ee52f77Slg 	 * need to keep the PWRED_DOWN state so that it could be powered up
5574ee52f77Slg 	 * later. In the mean while, usbser dev state will be changed to
5584ee52f77Slg 	 * SUSPENDED state.
5594ee52f77Slg 	 */
5604de26129Sxs 	mutex_enter(&plp->pl_mutex);
5614ee52f77Slg 	if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
5624ee52f77Slg 		plp->pl_dev_state = USB_DEV_SUSPENDED;
5634ee52f77Slg 	}
5644de26129Sxs 	mutex_exit(&plp->pl_mutex);
5654de26129Sxs 
5664de26129Sxs 	pl2303_disconnect_pipes(plp);
5674de26129Sxs 
5684de26129Sxs 	return (state);
5694de26129Sxs }
5704de26129Sxs 
5714de26129Sxs 
5724de26129Sxs /*
5734de26129Sxs  * ds_resume
5744de26129Sxs  */
5754de26129Sxs static int
pl2303_resume(ds_hdl_t hdl)5764de26129Sxs pl2303_resume(ds_hdl_t hdl)
5774de26129Sxs {
5784de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
5794de26129Sxs 	int		current_state;
5804de26129Sxs 	int		rval;
5814de26129Sxs 
5824de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_resume");
5834de26129Sxs 
5844de26129Sxs 	mutex_enter(&plp->pl_mutex);
5854de26129Sxs 	current_state = plp->pl_dev_state;
5864de26129Sxs 	mutex_exit(&plp->pl_mutex);
5874de26129Sxs 
5884de26129Sxs 	if (current_state != USB_DEV_ONLINE) {
5894de26129Sxs 		rval = pl2303_restore_device_state(plp);
5904de26129Sxs 	} else {
5914de26129Sxs 		rval = USB_SUCCESS;
5924de26129Sxs 	}
5934de26129Sxs 
5944de26129Sxs 	return (rval);
5954de26129Sxs }
5964de26129Sxs 
5974de26129Sxs 
5984de26129Sxs /*
5994de26129Sxs  * ds_disconnect
6004de26129Sxs  */
6014de26129Sxs static int
pl2303_disconnect(ds_hdl_t hdl)6024de26129Sxs pl2303_disconnect(ds_hdl_t hdl)
6034de26129Sxs {
6044de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
6054ee52f77Slg 	int		state = USB_DEV_DISCONNECTED;
6064de26129Sxs 
6074de26129Sxs 	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_disconnect");
6084de26129Sxs 
6094ee52f77Slg 	/*
6104ee52f77Slg 	 * If the device is disconnected while it is under PWRED_DOWN state, we
6114ee52f77Slg 	 * need to keep the PWRED_DOWN state so that it could be powered up
6124ee52f77Slg 	 * later. In the mean while, usbser dev state will be changed to
6134ee52f77Slg 	 * DISCONNECTED state.
6144ee52f77Slg 	 */
6154de26129Sxs 	mutex_enter(&plp->pl_mutex);
6164ee52f77Slg 	if (plp->pl_dev_state != USB_DEV_PWRED_DOWN) {
6174ee52f77Slg 		plp->pl_dev_state = USB_DEV_DISCONNECTED;
6184ee52f77Slg 	}
6194de26129Sxs 	mutex_exit(&plp->pl_mutex);
6204de26129Sxs 
6214de26129Sxs 	pl2303_disconnect_pipes(plp);
6224de26129Sxs 
6234de26129Sxs 	return (state);
6244de26129Sxs }
6254de26129Sxs 
6264de26129Sxs 
6274de26129Sxs /*
6284de26129Sxs  * ds_reconnect
6294de26129Sxs  */
6304de26129Sxs static int
pl2303_reconnect(ds_hdl_t hdl)6314de26129Sxs pl2303_reconnect(ds_hdl_t hdl)
6324de26129Sxs {
6334de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
6344de26129Sxs 
6354de26129Sxs 	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_reconnect");
6364de26129Sxs 
6374de26129Sxs 	return (pl2303_restore_device_state(plp));
6384de26129Sxs }
6394de26129Sxs 
6404de26129Sxs 
6414de26129Sxs /*
6424de26129Sxs  * standard UART operations
6434de26129Sxs  * ------------------------
6444de26129Sxs  *
6454de26129Sxs  *
6464de26129Sxs  * ds_set_port_params
6474de26129Sxs  */
6484de26129Sxs /*ARGSUSED*/
6494de26129Sxs static int
pl2303_set_port_params(ds_hdl_t hdl,uint_t port_num,ds_port_params_t * tp)6504de26129Sxs pl2303_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
6514de26129Sxs {
6524de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
6534de26129Sxs 	int		rval = USB_FAILURE;
6544de26129Sxs 	mblk_t		*bp;
6554de26129Sxs 	int		i;
6564de26129Sxs 	uint_t		ui;
6574de26129Sxs 	int		baud;
6584de26129Sxs 	int		cnt;
6594de26129Sxs 	ds_port_param_entry_t *pe;
6604de26129Sxs 	uint16_t xonxoff_symbol;
6614de26129Sxs 	uint8_t xon_char;
6624de26129Sxs 	uint8_t xoff_char;
6634de26129Sxs 
6644de26129Sxs 	if (tp == NULL) {
6654de26129Sxs 
6664de26129Sxs 		return (rval);
6674de26129Sxs 	}
6684de26129Sxs 
6694de26129Sxs 	cnt = tp->tp_cnt;
6704de26129Sxs 	pe = tp->tp_entries;
6714de26129Sxs 
6724de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_port_params");
6734de26129Sxs 
6744de26129Sxs 	/*
6754de26129Sxs 	 * get Line Coding Structure Request
6764de26129Sxs 	 * including: baud rate, stop bit, parity type and data bit
6774de26129Sxs 	 */
6784de26129Sxs 	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
6794de26129Sxs 
6804de26129Sxs 		return (rval);
6814de26129Sxs 	}
6824de26129Sxs 
6834de26129Sxs 	/* translate parameters into device-specific bits */
6844de26129Sxs 	for (i = 0; i < cnt; i++, pe++) {
6854de26129Sxs 		switch (pe->param) {
6864de26129Sxs 		case DS_PARAM_BAUD:
6874de26129Sxs 			ui = pe->val.ui;
6884de26129Sxs 
6894de26129Sxs 			/* if we don't support this speed, return USB_FAILURE */
6904de26129Sxs 			if ((ui >= NELEM(pl2303_speedtab)) ||
6914de26129Sxs 			    ((ui > 0) && (pl2303_speedtab[ui] == 0))) {
6924de26129Sxs 				USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh,
6934de26129Sxs 				    "pl2303_set_port_params: bad baud %d", ui);
6944de26129Sxs 
6953c91d182Slg 				freeb(bp);
6963c91d182Slg 
6974de26129Sxs 				return (USB_FAILURE);
6984de26129Sxs 			}
6994de26129Sxs 
7004de26129Sxs 			baud = pl2303_speedtab[ui];
7014de26129Sxs 			bp->b_rptr[0] = baud & 0xff;
7024de26129Sxs 			bp->b_rptr[1] = (baud >> 8) & 0xff;
7034de26129Sxs 			bp->b_rptr[2] = (baud >> 16) & 0xff;
7044de26129Sxs 			bp->b_rptr[3] = (baud >> 24) & 0xff;
7054de26129Sxs 
7064de26129Sxs 			break;
7074de26129Sxs 		case DS_PARAM_PARITY:
7084de26129Sxs 			if (pe->val.ui & PARENB) {
7094de26129Sxs 				if (pe->val.ui & PARODD) {
7104de26129Sxs 					bp->b_rptr[5] = 1;
7114de26129Sxs 				} else {
7124de26129Sxs 					bp->b_rptr[5] = 2;
7134de26129Sxs 				}
7144de26129Sxs 			} else {
7154de26129Sxs 				bp->b_rptr[5] = 0;
7164de26129Sxs 			}
7174de26129Sxs 
7184de26129Sxs 			break;
7194de26129Sxs 		case DS_PARAM_STOPB:
7204de26129Sxs 			if (pe->val.ui & CSTOPB) {
7214de26129Sxs 				bp->b_rptr[4] = 2;
7224de26129Sxs 			} else {
7234de26129Sxs 				bp->b_rptr[4] = 0;
7244de26129Sxs 			}
7254de26129Sxs 
7264de26129Sxs 			break;
7274de26129Sxs 		case DS_PARAM_CHARSZ:
7284de26129Sxs 			switch (pe->val.ui) {
7294de26129Sxs 			case CS5:
7304de26129Sxs 				bp->b_rptr[6] = 5;
7314de26129Sxs 
7324de26129Sxs 				break;
7334de26129Sxs 			case CS6:
7344de26129Sxs 				bp->b_rptr[6] = 6;
7354de26129Sxs 
7364de26129Sxs 				break;
7374de26129Sxs 			case CS7:
7384de26129Sxs 				bp->b_rptr[6] = 7;
7394de26129Sxs 
7404de26129Sxs 				break;
7414de26129Sxs 			case CS8:
7424de26129Sxs 			default:
7434de26129Sxs 				bp->b_rptr[6] = 8;
7444de26129Sxs 
7454de26129Sxs 				break;
7464de26129Sxs 			}
7474de26129Sxs 
7484de26129Sxs 			break;
7494de26129Sxs 		case DS_PARAM_XON_XOFF:
7504de26129Sxs 			/*
7514de26129Sxs 			 * Software flow control: XON/XOFF
7524de26129Sxs 			 * not supported by PL-2303H, HX chips
7534de26129Sxs 			 */
7544de26129Sxs 			if (pe->val.ui & IXON || pe->val.ui & IXOFF) {
7554de26129Sxs 				/* not supported by PL-2303H chip */
7564de26129Sxs 				switch (plp->pl_chiptype) {
7574de26129Sxs 				case pl2303_H:
7584de26129Sxs 
7594de26129Sxs 					break;
7604de26129Sxs 				case pl2303_X:
761cbab2b26Slg 				case pl2303_HX_CHIP_D:
7624de26129Sxs 					xon_char = pe->val.uc[0];
7634de26129Sxs 					xoff_char = pe->val.uc[1];
7644de26129Sxs 					xonxoff_symbol = (xoff_char << 8)
7654ee52f77Slg 					    | xon_char;
7664de26129Sxs 
7676918308bSyz 					rval =	pl2303_cmd_vendor_write0(
7684ee52f77Slg 					    plp, SET_XONXOFF,
7694ee52f77Slg 					    xonxoff_symbol);
7704de26129Sxs 
7714de26129Sxs 					if (rval != USB_SUCCESS) {
7724de26129Sxs 						USB_DPRINTF_L3(DPRINT_CTLOP,
7734ee52f77Slg 						    plp->pl_lh,
7744ee52f77Slg 						    "pl2303_set_port_params: "
7754ee52f77Slg 						    "set XonXoff failed");
7764de26129Sxs 					}
7774de26129Sxs 
7784de26129Sxs 					break;
7794de26129Sxs 				case pl2303_UNKNOWN:
7804de26129Sxs 				default:
7814de26129Sxs 
7824de26129Sxs 					break;
7834de26129Sxs 				}
7844de26129Sxs 			}
7854de26129Sxs 
7864de26129Sxs 			break;
7874de26129Sxs 		case DS_PARAM_FLOW_CTL:
7884de26129Sxs 			/* Hardware flow control */
7894de26129Sxs 			if (pe->val.ui & CTSXON) {
7904de26129Sxs 				if ((rval = pl2303_cmd_set_rtscts(plp))
7914ee52f77Slg 				    != USB_SUCCESS) {
7924de26129Sxs 
7934de26129Sxs 					USB_DPRINTF_L3(DPRINT_CTLOP,
7944ee52f77Slg 					    plp->pl_lh,
7954ee52f77Slg 					    "pl2303_set_port_params: "
7964ee52f77Slg 					    "pl2303_cmd_set_rtscts failed");
7974de26129Sxs 				}
7984de26129Sxs 			}
7994de26129Sxs 
8004de26129Sxs 			break;
8014de26129Sxs 		default:
8024de26129Sxs 			USB_DPRINTF_L2(DPRINT_CTLOP, plp->pl_lh,
8034de26129Sxs 			    "pl2303_set_port_params: bad param %d", pe->param);
8044de26129Sxs 
8054de26129Sxs 			break;
8064de26129Sxs 		}
8074de26129Sxs 	}
8084de26129Sxs 
8094de26129Sxs 	/* set new values for Line Coding Structure */
8103c91d182Slg 	rval = pl2303_cmd_set_line(plp, bp);
8113c91d182Slg 
8123c91d182Slg 	freeb(bp);
8133c91d182Slg 
8143c91d182Slg 	if (rval != USB_SUCCESS) {
8154de26129Sxs 
8164de26129Sxs 		return (rval);
8174de26129Sxs 	}
8184de26129Sxs 
8194de26129Sxs 	/* hardware need to get Line Coding Structure again */
8204de26129Sxs 	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
8214de26129Sxs 
8224de26129Sxs 		return (rval);
8234de26129Sxs 	}
8244de26129Sxs 
8253c91d182Slg 	freeb(bp);
8264de26129Sxs 
8274de26129Sxs 	return (USB_SUCCESS);
8284de26129Sxs }
8294de26129Sxs 
8304de26129Sxs 
8314de26129Sxs /*
8324de26129Sxs  * ds_set_modem_ctl
8334de26129Sxs  */
8344de26129Sxs /*ARGSUSED*/
8354de26129Sxs static int
pl2303_set_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int val)8364de26129Sxs pl2303_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
8374de26129Sxs {
8384de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
8394de26129Sxs 	int		rval = USB_FAILURE;
8404de26129Sxs 	uint8_t		new_mctl;
8414de26129Sxs 
8424de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_modem_ctl");
8434de26129Sxs 
8444de26129Sxs 	mutex_enter(&plp->pl_mutex);
8454de26129Sxs 	new_mctl = plp->pl_mctl;
8464de26129Sxs 	mutex_exit(&plp->pl_mutex);
8474de26129Sxs 
8484de26129Sxs 	/* set RTS and DTR */
8494de26129Sxs 	pl2303_mctl2reg(mask, val, &new_mctl);
8504de26129Sxs 
8514de26129Sxs 	if ((rval = pl2303_cmd_set_ctl(plp, new_mctl)) == USB_SUCCESS) {
8524de26129Sxs 		mutex_enter(&plp->pl_mutex);
8534de26129Sxs 		plp->pl_mctl = new_mctl;
8544de26129Sxs 		mutex_exit(&plp->pl_mutex);
8554de26129Sxs 	}
8564de26129Sxs 
8574de26129Sxs 	return (rval);
8584de26129Sxs }
8594de26129Sxs 
8604de26129Sxs 
8614de26129Sxs /*
8624de26129Sxs  * ds_get_modem_ctl
8634de26129Sxs  */
8644de26129Sxs /*ARGSUSED*/
8654de26129Sxs static int
pl2303_get_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int * valp)8664de26129Sxs pl2303_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
8674de26129Sxs {
8684de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
8694de26129Sxs 
8704de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_get_modem_ctl");
8714de26129Sxs 
8724de26129Sxs 	mutex_enter(&plp->pl_mutex);
8734de26129Sxs 
8744de26129Sxs 	/* get RTS and DTR */
8754de26129Sxs 	*valp = pl2303_reg2mctl(plp->pl_mctl) & mask;
8764de26129Sxs 	*valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
8774de26129Sxs 	mutex_exit(&plp->pl_mutex);
8784de26129Sxs 
8794de26129Sxs 	return (USB_SUCCESS);
8804de26129Sxs }
8814de26129Sxs 
8824de26129Sxs 
8834de26129Sxs /*
8844de26129Sxs  * ds_break_ctl
8854de26129Sxs  */
8864de26129Sxs /*ARGSUSED*/
8874de26129Sxs static int
pl2303_break_ctl(ds_hdl_t hdl,uint_t port_num,int ctl)8884de26129Sxs pl2303_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
8894de26129Sxs {
8904de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
8914de26129Sxs 
8924de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_break_ctl");
8934de26129Sxs 
8944de26129Sxs 	return (pl2303_cmd_break(plp, ctl));
8954de26129Sxs }
8964de26129Sxs 
8974de26129Sxs 
8984de26129Sxs /*
8994de26129Sxs  * ds_tx
9004de26129Sxs  */
9014de26129Sxs /*ARGSUSED*/
9024de26129Sxs static int
pl2303_tx(ds_hdl_t hdl,uint_t port_num,mblk_t * mp)9034de26129Sxs pl2303_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
9044de26129Sxs {
9054de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
9064de26129Sxs 	int		xferd;
9074de26129Sxs 
9084de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx");
9094de26129Sxs 
9104de26129Sxs 	/*
9114de26129Sxs 	 * sanity checks
9124de26129Sxs 	 */
9134de26129Sxs 	if (mp == NULL) {
9144de26129Sxs 		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: mp=NULL");
9154de26129Sxs 
9164de26129Sxs 		return (USB_SUCCESS);
9174de26129Sxs 	}
91822eb7cb5Sgd 	if (MBLKL(mp) < 1) {
9194de26129Sxs 		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: len<=0");
9204de26129Sxs 		freemsg(mp);
9214de26129Sxs 
9224de26129Sxs 		return (USB_SUCCESS);
9234de26129Sxs 	}
9244de26129Sxs 
9254de26129Sxs 	mutex_enter(&plp->pl_mutex);
9264de26129Sxs 
9274de26129Sxs 	pl2303_put_tail(&plp->pl_tx_mp, mp);	/* add to the chain */
9284de26129Sxs 
9294de26129Sxs 	pl2303_tx_start(plp, &xferd);
9304de26129Sxs 
9314de26129Sxs 	mutex_exit(&plp->pl_mutex);
9324de26129Sxs 
9334de26129Sxs 	return (USB_SUCCESS);
9344de26129Sxs }
9354de26129Sxs 
9364de26129Sxs 
9374de26129Sxs /*
9384de26129Sxs  * ds_rx
9394de26129Sxs  * the real data receiving is in pl2303_open_port
9404de26129Sxs  */
9414de26129Sxs /*ARGSUSED*/
9424de26129Sxs static mblk_t *
pl2303_rx(ds_hdl_t hdl,uint_t port_num)9434de26129Sxs pl2303_rx(ds_hdl_t hdl, uint_t port_num)
9444de26129Sxs {
9454de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
9464de26129Sxs 	mblk_t		*mp;
9474de26129Sxs 
9484de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_rx");
9494de26129Sxs 
9504de26129Sxs 	mutex_enter(&plp->pl_mutex);
9514de26129Sxs 	mp = plp->pl_rx_mp;
9524de26129Sxs 	plp->pl_rx_mp = NULL;
9534de26129Sxs 	mutex_exit(&plp->pl_mutex);
9544de26129Sxs 
9554de26129Sxs 	return (mp);
9564de26129Sxs }
9574de26129Sxs 
9584de26129Sxs 
9594de26129Sxs /*
9604de26129Sxs  * ds_stop
9614de26129Sxs  */
9624de26129Sxs /*ARGSUSED*/
9634de26129Sxs static void
pl2303_stop(ds_hdl_t hdl,uint_t port_num,int dir)9644de26129Sxs pl2303_stop(ds_hdl_t hdl, uint_t port_num, int dir)
9654de26129Sxs {
9664de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
9674de26129Sxs 
9684de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_stop");
9694de26129Sxs 
9704de26129Sxs 	if (dir & DS_TX) {
9714de26129Sxs 		mutex_enter(&plp->pl_mutex);
9724de26129Sxs 		plp->pl_port_flags |= PL2303_PORT_TX_STOPPED;
9734de26129Sxs 		mutex_exit(&plp->pl_mutex);
9744de26129Sxs 	}
9754de26129Sxs }
9764de26129Sxs 
9774de26129Sxs 
9784de26129Sxs /*
9794de26129Sxs  * ds_start
9804de26129Sxs  */
9814de26129Sxs /*ARGSUSED*/
9824de26129Sxs static void
pl2303_start(ds_hdl_t hdl,uint_t port_num,int dir)9834de26129Sxs pl2303_start(ds_hdl_t hdl, uint_t port_num, int dir)
9844de26129Sxs {
9854de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
9864de26129Sxs 
9874de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_start");
9884de26129Sxs 
9894de26129Sxs 	if (dir & DS_TX) {
9904de26129Sxs 		mutex_enter(&plp->pl_mutex);
9914de26129Sxs 		if (plp->pl_port_flags & PL2303_PORT_TX_STOPPED) {
9924de26129Sxs 			plp->pl_port_flags &= ~PL2303_PORT_TX_STOPPED;
9934de26129Sxs 			pl2303_tx_start(plp, NULL);
9944de26129Sxs 		}
9954de26129Sxs 		mutex_exit(&plp->pl_mutex);
9964de26129Sxs 	}
9974de26129Sxs }
9984de26129Sxs 
9994de26129Sxs 
10004de26129Sxs /*
10014de26129Sxs  * ds_fifo_flush
10024de26129Sxs  */
10034de26129Sxs /*ARGSUSED*/
10044de26129Sxs static int
pl2303_fifo_flush(ds_hdl_t hdl,uint_t port_num,int dir)10054de26129Sxs pl2303_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
10064de26129Sxs {
10074de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
10084de26129Sxs 
10094de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_flush: dir=%x",
10104de26129Sxs 	    dir);
10114de26129Sxs 
10124de26129Sxs 	mutex_enter(&plp->pl_mutex);
10134de26129Sxs 	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
10144de26129Sxs 
10154de26129Sxs 	if ((dir & DS_TX) && plp->pl_tx_mp) {
10164de26129Sxs 		freemsg(plp->pl_tx_mp);
10174de26129Sxs 		plp->pl_tx_mp = NULL;
10184de26129Sxs 	}
10194de26129Sxs 	if ((dir & DS_RX) && plp->pl_rx_mp) {
10204de26129Sxs 		freemsg(plp->pl_rx_mp);
10214de26129Sxs 		plp->pl_rx_mp = NULL;
10224de26129Sxs 	}
10234de26129Sxs 	mutex_exit(&plp->pl_mutex);
10244de26129Sxs 
10254de26129Sxs 	return (USB_SUCCESS);
10264de26129Sxs }
10274de26129Sxs 
10284de26129Sxs 
10294de26129Sxs /*
10304de26129Sxs  * ds_fifo_drain
10314de26129Sxs  */
10324de26129Sxs /*ARGSUSED*/
10334de26129Sxs static int
pl2303_fifo_drain(ds_hdl_t hdl,uint_t port_num,int timeout)10344de26129Sxs pl2303_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
10354de26129Sxs {
10364de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
10374de26129Sxs 	int		rval = USB_SUCCESS;
10384de26129Sxs 
10394de26129Sxs 	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_drain");
10404de26129Sxs 
10414de26129Sxs 	mutex_enter(&plp->pl_mutex);
10424de26129Sxs 	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
10434de26129Sxs 
10444de26129Sxs 	/*
10454de26129Sxs 	 * for the reason of hardware, set timeout 0
10464de26129Sxs 	 */
10474de26129Sxs 	if (pl2303_wait_tx_drain(plp, 0) != USB_SUCCESS) {
10484de26129Sxs 
10494de26129Sxs 		mutex_exit(&plp->pl_mutex);
10504de26129Sxs 
10514de26129Sxs 		return (USB_FAILURE);
10524de26129Sxs 	}
10534de26129Sxs 
10544de26129Sxs 	mutex_exit(&plp->pl_mutex);
10554de26129Sxs 
10564de26129Sxs 	/* wait 500 ms until hw fifo drains */
10574de26129Sxs 	delay(drv_usectohz(500*1000));
10584de26129Sxs 
10594de26129Sxs 	return (rval);
10604de26129Sxs }
10614de26129Sxs 
10624de26129Sxs 
10634de26129Sxs /*
10644de26129Sxs  * configuration routines
10654de26129Sxs  * ----------------------
10664de26129Sxs  *
10674de26129Sxs  * clean up routine
10684de26129Sxs  */
10694de26129Sxs static void
pl2303_cleanup(pl2303_state_t * plp,int level)10704de26129Sxs pl2303_cleanup(pl2303_state_t *plp, int level)
10714de26129Sxs {
10724de26129Sxs 	ASSERT((level > 0) && (level <= PL2303_CLEANUP_LEVEL_MAX));
10734de26129Sxs 
10744de26129Sxs 	switch (level) {
10754de26129Sxs 	default:
10764de26129Sxs 		pl2303_close_pipes(plp);
10774de26129Sxs 		/* FALLTHRU */
10786918308bSyz 	case 5:
10794de26129Sxs 		usb_unregister_event_cbs(plp->pl_dip, plp->pl_usb_events);
10804de26129Sxs 		/* FALLTHRU */
10816918308bSyz 	case 4:
10824de26129Sxs 		pl2303_destroy_pm_components(plp);
10836918308bSyz 		/* FALLTHRU */
10846918308bSyz 	case 3:
10854de26129Sxs 		mutex_destroy(&plp->pl_mutex);
10864de26129Sxs 		cv_destroy(&plp->pl_tx_cv);
10874de26129Sxs 
10884de26129Sxs 		usb_free_log_hdl(plp->pl_lh);
10894de26129Sxs 		plp->pl_lh = NULL;
10904de26129Sxs 
10914de26129Sxs 		usb_free_descr_tree(plp->pl_dip, plp->pl_dev_data);
10924de26129Sxs 		plp->pl_def_ph = NULL;
10934de26129Sxs 		/* FALLTHRU */
10944de26129Sxs 	case 2:
10954de26129Sxs 		usb_client_detach(plp->pl_dip, plp->pl_dev_data);
10964de26129Sxs 		/* FALLTHRU */
10974de26129Sxs 	case 1:
10984de26129Sxs 		kmem_free(plp, sizeof (pl2303_state_t));
10994de26129Sxs 	}
11004de26129Sxs }
11014de26129Sxs 
11024de26129Sxs 
11034de26129Sxs /*
11044de26129Sxs  * device specific attach
11054de26129Sxs  */
11064de26129Sxs static int
pl2303_dev_attach(pl2303_state_t * plp)11074de26129Sxs pl2303_dev_attach(pl2303_state_t *plp)
11084de26129Sxs {
11094de26129Sxs 	if (pl2303_open_pipes(plp) != USB_SUCCESS) {
11104de26129Sxs 		return (USB_FAILURE);
11114de26129Sxs 	}
11124de26129Sxs 
11134de26129Sxs 	return (USB_SUCCESS);
11144de26129Sxs }
11154de26129Sxs 
11164de26129Sxs 
11174de26129Sxs /*
11184de26129Sxs  * hotplug
11194de26129Sxs  * -------
11204de26129Sxs  *
11214de26129Sxs  *
11224de26129Sxs  * restore device state after CPR resume or reconnect
11234de26129Sxs  */
11244de26129Sxs static int
pl2303_restore_device_state(pl2303_state_t * plp)11254de26129Sxs pl2303_restore_device_state(pl2303_state_t *plp)
11264de26129Sxs {
11274de26129Sxs 	int	state;
11284de26129Sxs 
11294de26129Sxs 	mutex_enter(&plp->pl_mutex);
11304de26129Sxs 	state = plp->pl_dev_state;
11314de26129Sxs 	mutex_exit(&plp->pl_mutex);
11324de26129Sxs 
11334de26129Sxs 	if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
11344de26129Sxs 
11354de26129Sxs 		return (state);
11364de26129Sxs 	}
11374de26129Sxs 
1138d291d9f2Sfrits 	if (usb_check_same_device(plp->pl_dip, plp->pl_lh, USB_LOG_L0,
11394de26129Sxs 	    DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
11404de26129Sxs 		mutex_enter(&plp->pl_mutex);
11414de26129Sxs 		state = plp->pl_dev_state = USB_DEV_DISCONNECTED;
11424de26129Sxs 		mutex_exit(&plp->pl_mutex);
11434de26129Sxs 
11444de26129Sxs 		return (state);
11454de26129Sxs 	}
11464de26129Sxs 
11474de26129Sxs 	if (state == USB_DEV_DISCONNECTED) {
11484de26129Sxs 		USB_DPRINTF_L0(DPRINT_HOTPLUG, plp->pl_lh,
11494de26129Sxs 		    "Device has been reconnected but data may have been lost");
11504de26129Sxs 	}
11514de26129Sxs 
11524de26129Sxs 	if (pl2303_reconnect_pipes(plp) != USB_SUCCESS) {
11534de26129Sxs 
11544de26129Sxs 		return (state);
11554de26129Sxs 	}
11564de26129Sxs 
11574de26129Sxs 	/*
11584de26129Sxs 	 * init device state
11594de26129Sxs 	 */
11604de26129Sxs 	mutex_enter(&plp->pl_mutex);
11614de26129Sxs 	state = plp->pl_dev_state = USB_DEV_ONLINE;
11624de26129Sxs 	mutex_exit(&plp->pl_mutex);
11634de26129Sxs 
11644de26129Sxs 	if ((pl2303_restore_port_state(plp) != USB_SUCCESS)) {
11654de26129Sxs 		USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
11664de26129Sxs 		    "pl2303_restore_device_state: failed");
11674de26129Sxs 	}
11684de26129Sxs 
11694de26129Sxs 	return (state);
11704de26129Sxs }
11714de26129Sxs 
11724de26129Sxs 
11734de26129Sxs /*
11744de26129Sxs  * restore ports state after CPR resume or reconnect
11754de26129Sxs  */
11764de26129Sxs static int
pl2303_restore_port_state(pl2303_state_t * plp)11774de26129Sxs pl2303_restore_port_state(pl2303_state_t *plp)
11784de26129Sxs {
11794de26129Sxs 	int		rval;
11804de26129Sxs 
11814de26129Sxs 	mutex_enter(&plp->pl_mutex);
11824de26129Sxs 	if (plp->pl_port_state != PL2303_PORT_OPEN) {
11834de26129Sxs 		mutex_exit(&plp->pl_mutex);
11844de26129Sxs 
11854de26129Sxs 		return (USB_SUCCESS);
11864de26129Sxs 	}
11874de26129Sxs 	mutex_exit(&plp->pl_mutex);
11884de26129Sxs 
11894de26129Sxs 	/* open hardware serial port */
11904de26129Sxs 	if ((rval = pl2303_open_hw_port(plp)) != USB_SUCCESS) {
11914de26129Sxs 		USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
11924de26129Sxs 		    "pl2303_restore_ports_state: failed");
11934de26129Sxs 	}
11944de26129Sxs 
11954de26129Sxs 	return (rval);
11964de26129Sxs }
11974de26129Sxs 
11984de26129Sxs 
11994de26129Sxs /*
12004de26129Sxs  * power management
12014de26129Sxs  * ----------------
12024de26129Sxs  *
12034de26129Sxs  *
12044de26129Sxs  * create PM components
12054de26129Sxs  */
12064de26129Sxs static int
pl2303_create_pm_components(pl2303_state_t * plp)12074de26129Sxs pl2303_create_pm_components(pl2303_state_t *plp)
12084de26129Sxs {
12094de26129Sxs 	dev_info_t	*dip = plp->pl_dip;
12104de26129Sxs 	pl2303_pm_t	*pm;
12114de26129Sxs 	uint_t		pwr_states;
12124de26129Sxs 
12134de26129Sxs 	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
12144de26129Sxs 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
12154de26129Sxs 		    "pl2303_create_pm_components: failed");
12164de26129Sxs 
12174de26129Sxs 		return (USB_SUCCESS);
12184de26129Sxs 	}
12194de26129Sxs 
12204de26129Sxs 	pm = plp->pl_pm = kmem_zalloc(sizeof (pl2303_pm_t), KM_SLEEP);
12214de26129Sxs 
12224de26129Sxs 	pm->pm_pwr_states = (uint8_t)pwr_states;
12234de26129Sxs 	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
12244de26129Sxs 	pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
12254ee52f77Slg 	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
12264de26129Sxs 
12274de26129Sxs 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
12284de26129Sxs 
12294de26129Sxs 	return (USB_SUCCESS);
12304de26129Sxs }
12314de26129Sxs 
12324de26129Sxs 
12334de26129Sxs /*
12344de26129Sxs  * destroy PM components
12354de26129Sxs  */
12364de26129Sxs static void
pl2303_destroy_pm_components(pl2303_state_t * plp)12374de26129Sxs pl2303_destroy_pm_components(pl2303_state_t *plp)
12384de26129Sxs {
12394de26129Sxs 	pl2303_pm_t	*pm = plp->pl_pm;
12404de26129Sxs 	dev_info_t	*dip = plp->pl_dip;
12414de26129Sxs 	int		rval;
12424de26129Sxs 
12434de26129Sxs 	if (!pm)
12444de26129Sxs 
12454de26129Sxs 		return;
12464de26129Sxs 
12474de26129Sxs 	if (plp->pl_dev_state != USB_DEV_DISCONNECTED) {
12484de26129Sxs 		if (pm->pm_wakeup_enabled) {
12494de26129Sxs 			rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
12504de26129Sxs 			if (rval != DDI_SUCCESS) {
1251d291d9f2Sfrits 				USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
12524de26129Sxs 				    "pl2303_destroy_pm_components:"
12534de26129Sxs 				    "raising power failed, rval=%d", rval);
12544de26129Sxs 			}
12554de26129Sxs 
12564de26129Sxs 			rval = usb_handle_remote_wakeup(dip,
12574ee52f77Slg 			    USB_REMOTE_WAKEUP_DISABLE);
12584de26129Sxs 			if (rval != USB_SUCCESS) {
12594de26129Sxs 				USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
12604de26129Sxs 				    "pl2303_destroy_pm_components: disable "
12614de26129Sxs 				    "remote wakeup failed, rval=%d", rval);
12624de26129Sxs 			}
12634de26129Sxs 		}
12644de26129Sxs 
12654de26129Sxs 		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
12664de26129Sxs 	}
12674de26129Sxs 	kmem_free(pm, sizeof (pl2303_pm_t));
12684de26129Sxs 	plp->pl_pm = NULL;
12694de26129Sxs }
12704de26129Sxs 
12714de26129Sxs 
12724de26129Sxs /*
12734de26129Sxs  * mark device busy and raise power
12744de26129Sxs  */
12754de26129Sxs static int
pl2303_pm_set_busy(pl2303_state_t * plp)12764de26129Sxs pl2303_pm_set_busy(pl2303_state_t *plp)
12774de26129Sxs {
12784de26129Sxs 	pl2303_pm_t	*pm = plp->pl_pm;
12794de26129Sxs 	dev_info_t	*dip = plp->pl_dip;
12804de26129Sxs 	int		rval;
12814de26129Sxs 
12824de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_busy");
12834de26129Sxs 
12844de26129Sxs 	if (!pm) {
12854de26129Sxs 
12864de26129Sxs 		return (USB_SUCCESS);
12874de26129Sxs 	}
12884de26129Sxs 
12894de26129Sxs 	mutex_enter(&plp->pl_mutex);
12904de26129Sxs 	/* if already marked busy, just increment the counter */
12914de26129Sxs 	if (pm->pm_busy_cnt++ > 0) {
12924de26129Sxs 		mutex_exit(&plp->pl_mutex);
12934de26129Sxs 
12944de26129Sxs 		return (USB_SUCCESS);
12954de26129Sxs 	}
12964de26129Sxs 
12974de26129Sxs 	rval = pm_busy_component(dip, 0);
12984de26129Sxs 	ASSERT(rval == DDI_SUCCESS);
12994de26129Sxs 
13004de26129Sxs 	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
13014de26129Sxs 		mutex_exit(&plp->pl_mutex);
13024de26129Sxs 
13034de26129Sxs 		return (USB_SUCCESS);
13044de26129Sxs 	}
13054de26129Sxs 
13066918308bSyz 	/* need to raise power	*/
13074de26129Sxs 	pm->pm_raise_power = B_TRUE;
13084de26129Sxs 	mutex_exit(&plp->pl_mutex);
13094de26129Sxs 
13104de26129Sxs 	rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
13114de26129Sxs 	if (rval != DDI_SUCCESS) {
1312d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "raising power failed");
13134de26129Sxs 	}
13144de26129Sxs 
13154de26129Sxs 	mutex_enter(&plp->pl_mutex);
13164de26129Sxs 	pm->pm_raise_power = B_FALSE;
13174de26129Sxs 	mutex_exit(&plp->pl_mutex);
13184de26129Sxs 
13194de26129Sxs 	return (USB_SUCCESS);
13204de26129Sxs }
13214de26129Sxs 
13224de26129Sxs 
13234de26129Sxs /*
13244de26129Sxs  * mark device idle
13254de26129Sxs  */
13264de26129Sxs static void
pl2303_pm_set_idle(pl2303_state_t * plp)13274de26129Sxs pl2303_pm_set_idle(pl2303_state_t *plp)
13284de26129Sxs {
13294de26129Sxs 	pl2303_pm_t	*pm = plp->pl_pm;
13304de26129Sxs 	dev_info_t	*dip = plp->pl_dip;
13314de26129Sxs 
13324de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_idle");
13334de26129Sxs 
13344de26129Sxs 	if (!pm) {
13354de26129Sxs 
13364de26129Sxs 		return;
13374de26129Sxs 	}
13384de26129Sxs 
13394de26129Sxs 	/*
13404de26129Sxs 	 * if more ports use the device, do not mark as yet
13414de26129Sxs 	 */
13424de26129Sxs 	mutex_enter(&plp->pl_mutex);
13434de26129Sxs 	if (--pm->pm_busy_cnt > 0) {
13444de26129Sxs 		mutex_exit(&plp->pl_mutex);
13454de26129Sxs 
13464de26129Sxs 		return;
13474de26129Sxs 	}
13484de26129Sxs 
13494de26129Sxs 	if (pm) {
13504de26129Sxs 		(void) pm_idle_component(dip, 0);
13514de26129Sxs 	}
13524de26129Sxs 	mutex_exit(&plp->pl_mutex);
13534de26129Sxs }
13544de26129Sxs 
13554de26129Sxs 
13564de26129Sxs /*
13574de26129Sxs  * Functions to handle power transition for OS levels 0 -> 3
13584de26129Sxs  * The same level as OS state, different from USB state
13594de26129Sxs  */
13604de26129Sxs static int
pl2303_pwrlvl0(pl2303_state_t * plp)13614de26129Sxs pl2303_pwrlvl0(pl2303_state_t *plp)
13624de26129Sxs {
13634de26129Sxs 	int	rval;
13644de26129Sxs 
13654de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl0");
13664de26129Sxs 
13674de26129Sxs 	switch (plp->pl_dev_state) {
13684de26129Sxs 	case USB_DEV_ONLINE:
13694de26129Sxs 		/* issue USB D3 command to the device */
13704de26129Sxs 		rval = usb_set_device_pwrlvl3(plp->pl_dip);
13714de26129Sxs 		ASSERT(rval == USB_SUCCESS);
13724de26129Sxs 
13734de26129Sxs 		plp->pl_dev_state = USB_DEV_PWRED_DOWN;
13744de26129Sxs 		plp->pl_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
13754de26129Sxs 
13764de26129Sxs 		/* FALLTHRU */
13774de26129Sxs 	case USB_DEV_DISCONNECTED:
13784de26129Sxs 	case USB_DEV_SUSPENDED:
13794de26129Sxs 		/* allow a disconnect/cpr'ed device to go to lower power */
13804de26129Sxs 
13814de26129Sxs 		return (USB_SUCCESS);
13824de26129Sxs 	case USB_DEV_PWRED_DOWN:
13834de26129Sxs 	default:
13844de26129Sxs 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
13854de26129Sxs 		    "pl2303_pwrlvl0: illegal device state");
13864de26129Sxs 
13874de26129Sxs 		return (USB_FAILURE);
13884de26129Sxs 	}
13894de26129Sxs }
13904de26129Sxs 
13914de26129Sxs 
13924de26129Sxs static int
pl2303_pwrlvl1(pl2303_state_t * plp)13934de26129Sxs pl2303_pwrlvl1(pl2303_state_t *plp)
13944de26129Sxs {
13954de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl1");
13964de26129Sxs 
13974de26129Sxs 	/* issue USB D2 command to the device */
13984de26129Sxs 	(void) usb_set_device_pwrlvl2(plp->pl_dip);
13994de26129Sxs 
14004de26129Sxs 	return (USB_FAILURE);
14014de26129Sxs }
14024de26129Sxs 
14034de26129Sxs 
14044de26129Sxs static int
pl2303_pwrlvl2(pl2303_state_t * plp)14054de26129Sxs pl2303_pwrlvl2(pl2303_state_t *plp)
14064de26129Sxs {
14074de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl2");
14084de26129Sxs 
14094de26129Sxs 	/* issue USB D1 command to the device */
14104de26129Sxs 	(void) usb_set_device_pwrlvl1(plp->pl_dip);
14114de26129Sxs 
14124de26129Sxs 	return (USB_FAILURE);
14134de26129Sxs }
14144de26129Sxs 
14154de26129Sxs 
14164de26129Sxs static int
pl2303_pwrlvl3(pl2303_state_t * plp)14174de26129Sxs pl2303_pwrlvl3(pl2303_state_t *plp)
14184de26129Sxs {
14194de26129Sxs 	int	rval;
14204de26129Sxs 
14214de26129Sxs 	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl3");
14224de26129Sxs 
14234de26129Sxs 	switch (plp->pl_dev_state) {
14244de26129Sxs 	case USB_DEV_PWRED_DOWN:
14254de26129Sxs 		/* Issue USB D0 command to the device here */
14264de26129Sxs 		rval = usb_set_device_pwrlvl0(plp->pl_dip);
14274de26129Sxs 		ASSERT(rval == USB_SUCCESS);
14284de26129Sxs 
14294de26129Sxs 		plp->pl_dev_state = USB_DEV_ONLINE;
14304de26129Sxs 		plp->pl_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
14314de26129Sxs 
14324de26129Sxs 		/* FALLTHRU */
14334de26129Sxs 	case USB_DEV_ONLINE:
14344de26129Sxs 		/* we are already in full power */
14354de26129Sxs 
14364de26129Sxs 		/* FALLTHRU */
14374de26129Sxs 	case USB_DEV_DISCONNECTED:
14384de26129Sxs 	case USB_DEV_SUSPENDED:
14394de26129Sxs 
14404de26129Sxs 		return (USB_SUCCESS);
14414de26129Sxs 	default:
14424de26129Sxs 		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
14434de26129Sxs 		    "pl2303_pwrlvl3: illegal device state");
14444de26129Sxs 
14454de26129Sxs 		return (USB_FAILURE);
14464de26129Sxs 	}
14474de26129Sxs }
14484de26129Sxs 
14494de26129Sxs 
14504de26129Sxs /*
14514de26129Sxs  * pipe operations
14524de26129Sxs  * ---------------
14534de26129Sxs  *
14544de26129Sxs  *
14554de26129Sxs  */
14564de26129Sxs static int
pl2303_open_pipes(pl2303_state_t * plp)14574de26129Sxs pl2303_open_pipes(pl2303_state_t *plp)
14584de26129Sxs {
14594de26129Sxs 	int		ifc, alt;
14604de26129Sxs 	usb_pipe_policy_t policy;
14614de26129Sxs 	usb_ep_data_t	*in_data, *out_data;
14624de26129Sxs 
14634de26129Sxs 	/* get ep data */
14644de26129Sxs 	ifc = plp->pl_dev_data->dev_curr_if;
14654de26129Sxs 	alt = 0;
14664de26129Sxs 
14674de26129Sxs 	in_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
14684de26129Sxs 	    0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
14694de26129Sxs 
14704de26129Sxs 	out_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
14714de26129Sxs 	    0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
14724de26129Sxs 
14734de26129Sxs 	if ((in_data == NULL) || (out_data == NULL)) {
14744de26129Sxs 		USB_DPRINTF_L2(DPRINT_ATTACH, plp->pl_lh,
14754de26129Sxs 		    "pl2303_open_pipes: can't get ep data");
14764de26129Sxs 
14774de26129Sxs 		return (USB_FAILURE);
14784de26129Sxs 	}
14794de26129Sxs 
14804de26129Sxs 	/* open pipes */
14814de26129Sxs 	policy.pp_max_async_reqs = 2;
14824de26129Sxs 
14834de26129Sxs 	if (usb_pipe_open(plp->pl_dip, &in_data->ep_descr, &policy,
14844de26129Sxs 	    USB_FLAGS_SLEEP, &plp->pl_bulkin_ph) != USB_SUCCESS) {
14854de26129Sxs 
14864de26129Sxs 		return (USB_FAILURE);
14874de26129Sxs 	}
14884de26129Sxs 
14894de26129Sxs 	if (usb_pipe_open(plp->pl_dip, &out_data->ep_descr, &policy,
14904de26129Sxs 	    USB_FLAGS_SLEEP, &plp->pl_bulkout_ph) != USB_SUCCESS) {
14914de26129Sxs 		usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP,
14924de26129Sxs 		    NULL, NULL);
14934de26129Sxs 
14944de26129Sxs 		return (USB_FAILURE);
14954de26129Sxs 	}
14964de26129Sxs 
14974de26129Sxs 	mutex_enter(&plp->pl_mutex);
14984de26129Sxs 	plp->pl_bulkin_state = PL2303_PIPE_IDLE;
14994de26129Sxs 	plp->pl_bulkout_state = PL2303_PIPE_IDLE;
15004de26129Sxs 	mutex_exit(&plp->pl_mutex);
15014de26129Sxs 
15024de26129Sxs 	return (USB_SUCCESS);
15034de26129Sxs }
15044de26129Sxs 
15054de26129Sxs 
15064de26129Sxs static void
pl2303_close_pipes(pl2303_state_t * plp)15074de26129Sxs pl2303_close_pipes(pl2303_state_t *plp)
15084de26129Sxs {
15096918308bSyz 	if (plp->pl_bulkin_ph) {
15106918308bSyz 		usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph,
15116918308bSyz 		    USB_FLAGS_SLEEP, 0, 0);
15126918308bSyz 	}
15136918308bSyz 	if (plp->pl_bulkout_ph) {
15146918308bSyz 		usb_pipe_close(plp->pl_dip, plp->pl_bulkout_ph,
15156918308bSyz 		    USB_FLAGS_SLEEP, 0, 0);
15164de26129Sxs 	}
15174de26129Sxs 
15184de26129Sxs 	mutex_enter(&plp->pl_mutex);
15194de26129Sxs 	plp->pl_bulkin_state = PL2303_PIPE_CLOSED;
15204de26129Sxs 	plp->pl_bulkout_state = PL2303_PIPE_CLOSED;
15214de26129Sxs 	mutex_exit(&plp->pl_mutex);
15224de26129Sxs }
15234de26129Sxs 
15244de26129Sxs 
15254de26129Sxs static void
pl2303_disconnect_pipes(pl2303_state_t * plp)15264de26129Sxs pl2303_disconnect_pipes(pl2303_state_t *plp)
15274de26129Sxs {
15284de26129Sxs 	pl2303_close_pipes(plp);
15294de26129Sxs }
15304de26129Sxs 
15314de26129Sxs 
15324de26129Sxs static int
pl2303_reconnect_pipes(pl2303_state_t * plp)15334de26129Sxs pl2303_reconnect_pipes(pl2303_state_t *plp)
15344de26129Sxs {
15354de26129Sxs 	if ((pl2303_open_pipes(plp) != USB_SUCCESS)) {
15364de26129Sxs 
15374de26129Sxs 		return (USB_FAILURE);
15384de26129Sxs 	}
15394de26129Sxs 
15404de26129Sxs 	return (USB_SUCCESS);
15414de26129Sxs }
15424de26129Sxs 
15434de26129Sxs 
15444de26129Sxs /*
15454de26129Sxs  * pipe callbacks
15464de26129Sxs  * --------------
15474de26129Sxs  *
15484de26129Sxs  *
15494de26129Sxs  * bulk in common and exeception callback
15504de26129Sxs  *
15514de26129Sxs  */
15524de26129Sxs /*ARGSUSED*/
15534de26129Sxs void
pl2303_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)15544de26129Sxs pl2303_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
15554de26129Sxs {
15564de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
15574de26129Sxs 	mblk_t		*data;
15584de26129Sxs 	int		data_len;
15594de26129Sxs 
15604de26129Sxs 	data = req->bulk_data;
15614de26129Sxs 	data_len = (data) ? MBLKL(data) : 0;
15624de26129Sxs 
15634de26129Sxs 	USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh, "pl2303_bulkin_cb: "
15644de26129Sxs 	    "cr=%d len=%d",
15654de26129Sxs 	    req->bulk_completion_reason,
15664de26129Sxs 	    data_len);
15674de26129Sxs 
15684de26129Sxs 	/* save data and notify GSD */
15694de26129Sxs 	if ((plp->pl_port_state == PL2303_PORT_OPEN) && (data_len) &&
15704ee52f77Slg 	    (req->bulk_completion_reason == USB_CR_OK)) {
15714de26129Sxs 		req->bulk_data = NULL;
15724de26129Sxs 		pl2303_put_tail(&plp->pl_rx_mp, data);
15734de26129Sxs 		if (plp->pl_cb.cb_rx) {
15744de26129Sxs 			plp->pl_cb.cb_rx(plp->pl_cb.cb_arg);
15754de26129Sxs 		}
15764de26129Sxs 	}
15774de26129Sxs 
15784de26129Sxs 	usb_free_bulk_req(req);
15794de26129Sxs 
15804de26129Sxs 	/* receive more */
15814de26129Sxs 	mutex_enter(&plp->pl_mutex);
15824de26129Sxs 	plp->pl_bulkin_state = PL2303_PIPE_IDLE;
15836918308bSyz 	if ((plp->pl_port_state == PL2303_PORT_OPEN) &&
15846918308bSyz 	    (plp->pl_dev_state == USB_DEV_ONLINE)) {
15856918308bSyz 		if (pl2303_rx_start(plp) != USB_SUCCESS) {
15866918308bSyz 			USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
15876918308bSyz 			    "pl2303_bulkin_cb: restart rx fail");
15886918308bSyz 		}
15894de26129Sxs 	}
15904de26129Sxs 	mutex_exit(&plp->pl_mutex);
15914de26129Sxs }
15924de26129Sxs 
15934de26129Sxs 
15944de26129Sxs /*
15954de26129Sxs  * bulk out common and exeception callback
15964de26129Sxs  */
15974de26129Sxs /*ARGSUSED*/
15984de26129Sxs void
pl2303_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)15994de26129Sxs pl2303_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
16004de26129Sxs {
16014de26129Sxs 	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
16024de26129Sxs 	int		data_len;
16034de26129Sxs 	mblk_t		*data = req->bulk_data;
16044de26129Sxs 
16054de26129Sxs 	data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
16064de26129Sxs 
16074de26129Sxs 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
16084de26129Sxs 	    "pl2303_bulkout_cb: cr=%d len=%d",
16094de26129Sxs 	    req->bulk_completion_reason,
16104de26129Sxs 	    data_len);
16114de26129Sxs 
1612*e81e6188SLin Guo - Sun Microsystems 	/* Re-send data only when port is open */
1613*e81e6188SLin Guo - Sun Microsystems 	if ((plp->pl_port_state == PL2303_PORT_OPEN) &&
1614*e81e6188SLin Guo - Sun Microsystems 	    req->bulk_completion_reason && (data_len > 0)) {
16154de26129Sxs 		pl2303_put_head(&plp->pl_tx_mp, data);
16164de26129Sxs 		req->bulk_data = NULL;
16174de26129Sxs 	}
16184de26129Sxs 
16194de26129Sxs 	usb_free_bulk_req(req);
16204de26129Sxs 
16214de26129Sxs 	/* notify GSD */
16224de26129Sxs 	if (plp->pl_cb.cb_tx) {
16234de26129Sxs 		plp->pl_cb.cb_tx(plp->pl_cb.cb_arg);
16244de26129Sxs 	}
16254de26129Sxs 
16264de26129Sxs 	/* send more */
16274de26129Sxs 	mutex_enter(&plp->pl_mutex);
16284de26129Sxs 	plp->pl_bulkout_state = PL2303_PIPE_IDLE;
16294de26129Sxs 	if (plp->pl_tx_mp == NULL) {
16304de26129Sxs 		cv_broadcast(&plp->pl_tx_cv);
16314de26129Sxs 	} else {
16324de26129Sxs 		pl2303_tx_start(plp, NULL);
16334de26129Sxs 	}
16344de26129Sxs 	mutex_exit(&plp->pl_mutex);
16354de26129Sxs }
16364de26129Sxs 
16374de26129Sxs 
16384de26129Sxs /*
16394de26129Sxs  * data transfer routines
16404de26129Sxs  * ----------------------
16414de26129Sxs  *
16424de26129Sxs  *
16434de26129Sxs  * start data receipt
16444de26129Sxs  */
16454de26129Sxs static int
pl2303_rx_start(pl2303_state_t * plp)16464de26129Sxs pl2303_rx_start(pl2303_state_t *plp)
16474de26129Sxs {
16484de26129Sxs 	usb_bulk_req_t	*br;
16494de26129Sxs 	int		rval = USB_FAILURE;
16504de26129Sxs 
16514de26129Sxs 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_rx_start");
16524de26129Sxs 
16534de26129Sxs 	ASSERT(mutex_owned(&plp->pl_mutex));
16544de26129Sxs 
16554de26129Sxs 	plp->pl_bulkin_state = PL2303_PIPE_BUSY;
16564de26129Sxs 	mutex_exit(&plp->pl_mutex);
16574de26129Sxs 
16584de26129Sxs 	br = usb_alloc_bulk_req(plp->pl_dip, plp->pl_xfer_sz, USB_FLAGS_SLEEP);
16594de26129Sxs 	br->bulk_len = plp->pl_xfer_sz;
16604de26129Sxs 	br->bulk_timeout = PL2303_BULKIN_TIMEOUT;
16614de26129Sxs 	br->bulk_cb = pl2303_bulkin_cb;
16624de26129Sxs 	br->bulk_exc_cb = pl2303_bulkin_cb;
16634de26129Sxs 	br->bulk_client_private = (usb_opaque_t)plp;
16644de26129Sxs 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
16654de26129Sxs 
16664de26129Sxs 	rval = usb_pipe_bulk_xfer(plp->pl_bulkin_ph, br, 0);
16674de26129Sxs 
16684de26129Sxs 	if (rval != USB_SUCCESS) {
16694de26129Sxs 		USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
16704de26129Sxs 		    "pl2303_rx_start: xfer failed %d", rval);
16714de26129Sxs 		usb_free_bulk_req(br);
16724de26129Sxs 	}
16734de26129Sxs 
16744de26129Sxs 	mutex_enter(&plp->pl_mutex);
16754de26129Sxs 	if (rval != USB_SUCCESS) {
16764de26129Sxs 		plp->pl_bulkin_state = PL2303_PIPE_IDLE;
16774de26129Sxs 	}
16784de26129Sxs 
16794de26129Sxs 	return (rval);
16804de26129Sxs }
16814de26129Sxs 
16824de26129Sxs 
16834de26129Sxs /*
16844de26129Sxs  * start data transmit
16854de26129Sxs  */
16864de26129Sxs static void
pl2303_tx_start(pl2303_state_t * plp,int * xferd)16874de26129Sxs pl2303_tx_start(pl2303_state_t *plp, int *xferd)
16884de26129Sxs {
16894de26129Sxs 	int		len;		/* bytes we can transmit */
16904de26129Sxs 	mblk_t		*data;		/* data to be transmitted */
16914de26129Sxs 	int		data_len;	/* bytes in 'data' */
16924de26129Sxs 	mblk_t		*mp;		/* current msgblk */
16934de26129Sxs 	int		copylen;	/* bytes copy from 'mp' to 'data' */
16944de26129Sxs 	int		rval;
16954de26129Sxs 
16964de26129Sxs 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_tx_start");
16974de26129Sxs 	ASSERT(mutex_owned(&plp->pl_mutex));
16984de26129Sxs 	ASSERT(plp->pl_port_state != PL2303_PORT_CLOSED);
16994de26129Sxs 
17004de26129Sxs 	if (xferd) {
17014de26129Sxs 		*xferd = 0;
17024de26129Sxs 	}
17034de26129Sxs 	if ((plp->pl_port_flags & PL2303_PORT_TX_STOPPED) ||
17044de26129Sxs 	    (plp->pl_tx_mp == NULL)) {
17054de26129Sxs 
17064de26129Sxs 		return;
17074de26129Sxs 	}
17084de26129Sxs 	if (plp->pl_bulkout_state != PL2303_PIPE_IDLE) {
17094de26129Sxs 		USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
17104de26129Sxs 		    "pl2303_tx_start: pipe busy");
17114de26129Sxs 
17124de26129Sxs 		return;
17134de26129Sxs 	}
17144de26129Sxs 	ASSERT(MBLKL(plp->pl_tx_mp) > 0);
17154de26129Sxs 
17164de26129Sxs 	/* send as much data as port can receive */
17174de26129Sxs 	len = min(msgdsize(plp->pl_tx_mp), plp->pl_xfer_sz);
17184de26129Sxs 
17194de26129Sxs 	if (len == 0) {
17204de26129Sxs 
17214de26129Sxs 		return;
17224de26129Sxs 	}
17234de26129Sxs 
17244de26129Sxs 	if ((data = allocb(len, BPRI_LO)) == NULL) {
17254de26129Sxs 
17264de26129Sxs 		return;
17274de26129Sxs 	}
17284de26129Sxs 
17294de26129Sxs 	/*
17304de26129Sxs 	 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
17314de26129Sxs 	 */
17324de26129Sxs 	data_len = 0;
17334de26129Sxs 
17344de26129Sxs 	while ((data_len < len) && plp->pl_tx_mp) {
17354de26129Sxs 		mp = plp->pl_tx_mp;
17364de26129Sxs 		copylen = min(MBLKL(mp), len - data_len);
17374de26129Sxs 		bcopy(mp->b_rptr, data->b_wptr, copylen);
17384de26129Sxs 		mp->b_rptr += copylen;
17394de26129Sxs 		data->b_wptr += copylen;
17404de26129Sxs 		data_len += copylen;
17414de26129Sxs 
174222eb7cb5Sgd 		if (MBLKL(mp) < 1) {
17434de26129Sxs 			plp->pl_tx_mp = unlinkb(mp);
17444de26129Sxs 			freeb(mp);
17454de26129Sxs 		} else {
17464de26129Sxs 			ASSERT(data_len == len);
17474de26129Sxs 		}
17484de26129Sxs 	}
17494de26129Sxs 
17504de26129Sxs 	if (data_len <= 0) {
17514de26129Sxs 		USB_DPRINTF_L3(DPRINT_OUT_PIPE, plp->pl_lh,
17524de26129Sxs 		    "pl2303_tx_start: copied zero bytes");
17534de26129Sxs 		freeb(data);
17544de26129Sxs 
17554de26129Sxs 		return;
17564de26129Sxs 	}
17574de26129Sxs 
17584de26129Sxs 	plp->pl_bulkout_state = PL2303_PIPE_BUSY;
17594de26129Sxs 	mutex_exit(&plp->pl_mutex);
17604de26129Sxs 
17614de26129Sxs 	rval = pl2303_send_data(plp, data);
17624de26129Sxs 	mutex_enter(&plp->pl_mutex);
17634de26129Sxs 
17644de26129Sxs 	if (rval != USB_SUCCESS) {
17654de26129Sxs 		plp->pl_bulkout_state = PL2303_PIPE_IDLE;
17663c91d182Slg 		pl2303_put_head(&plp->pl_tx_mp, data);
17674de26129Sxs 	} else {
17684de26129Sxs 		if (xferd) {
17694de26129Sxs 			*xferd = data_len;
17704de26129Sxs 		}
17714de26129Sxs 	}
17724de26129Sxs }
17734de26129Sxs 
17744de26129Sxs 
17754de26129Sxs static int
pl2303_send_data(pl2303_state_t * plp,mblk_t * data)17764de26129Sxs pl2303_send_data(pl2303_state_t *plp, mblk_t *data)
17774de26129Sxs {
17784de26129Sxs 	usb_bulk_req_t	*br;
17794de26129Sxs 	int		len = MBLKL(data);
17804de26129Sxs 	int		rval;
17814de26129Sxs 
17824de26129Sxs 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_send_data: %d "
17834de26129Sxs 	    "%x %x %x", len, data->b_rptr[0],
17844de26129Sxs 	    (len > 1) ? data->b_rptr[1] : 0,
17854de26129Sxs 	    (len > 2) ? data->b_rptr[2] : 0);
17864de26129Sxs 	ASSERT(!mutex_owned(&plp->pl_mutex));
17874de26129Sxs 
17884de26129Sxs 	br = usb_alloc_bulk_req(plp->pl_dip, 0, USB_FLAGS_SLEEP);
17894de26129Sxs 	br->bulk_data = data;
17904de26129Sxs 	br->bulk_len = len;
17914de26129Sxs 	br->bulk_timeout = PL2303_BULKOUT_TIMEOUT;
17924de26129Sxs 	br->bulk_cb = pl2303_bulkout_cb;
17934de26129Sxs 	br->bulk_exc_cb = pl2303_bulkout_cb;
17944de26129Sxs 	br->bulk_client_private = (usb_opaque_t)plp;
17954de26129Sxs 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
17964de26129Sxs 
17974de26129Sxs 	rval = usb_pipe_bulk_xfer(plp->pl_bulkout_ph, br, 0);
17984de26129Sxs 
17994de26129Sxs 	if (rval != USB_SUCCESS) {
18004de26129Sxs 		USB_DPRINTF_L2(DPRINT_OUT_PIPE, plp->pl_lh,
18014de26129Sxs 		    "pl2303_send_data: xfer failed %d", rval);
18023c91d182Slg 
18033c91d182Slg 		br->bulk_data = NULL;
18044de26129Sxs 		usb_free_bulk_req(br);
18054de26129Sxs 	}
18064de26129Sxs 
18074de26129Sxs 	return (rval);
18084de26129Sxs }
18094de26129Sxs 
18104de26129Sxs 
18114de26129Sxs /*
18124de26129Sxs  * wait until local tx buffer drains.
18134de26129Sxs  * 'timeout' is in seconds, zero means wait forever
18144de26129Sxs  */
18154de26129Sxs static int
pl2303_wait_tx_drain(pl2303_state_t * plp,int timeout)18164de26129Sxs pl2303_wait_tx_drain(pl2303_state_t *plp, int timeout)
18174de26129Sxs {
18184de26129Sxs 	clock_t	until;
18194de26129Sxs 	int	over = 0;
18204de26129Sxs 
18214de26129Sxs 	until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
18224de26129Sxs 
18234de26129Sxs 	while (plp->pl_tx_mp && !over) {
18244de26129Sxs 		if (timeout > 0) {
18254de26129Sxs 			/* whether timedout or signal pending */
18264de26129Sxs 			over = (cv_timedwait_sig(&plp->pl_tx_cv,
18274ee52f77Slg 			    &plp->pl_mutex, until) <= 0);
18284de26129Sxs 		} else {
18294de26129Sxs 			/* whether a signal is pending */
18304de26129Sxs 			over = (cv_wait_sig(&plp->pl_tx_cv,
18314ee52f77Slg 			    &plp->pl_mutex) == 0);
18324de26129Sxs 		}
18334de26129Sxs 	}
18344de26129Sxs 
18354de26129Sxs 	return ((plp->pl_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
18364de26129Sxs }
18374de26129Sxs 
18384de26129Sxs 
18394de26129Sxs /*
18404de26129Sxs  * device operations
18414de26129Sxs  * -----------------
18424de26129Sxs  *
18434de26129Sxs  *
18444de26129Sxs  * initialize hardware serial port
18454de26129Sxs  */
18464de26129Sxs static int
pl2303_open_hw_port(pl2303_state_t * plp)18474de26129Sxs pl2303_open_hw_port(pl2303_state_t *plp)
18484de26129Sxs {
18494de26129Sxs 	int		rval = USB_SUCCESS;
18504de26129Sxs 
18514de26129Sxs 	/*
18524de26129Sxs 	 * initialize three Device Configuration Registers (DCR):
18534de26129Sxs 	 * DCR0, DCR1, and DCR2
18544de26129Sxs 	 */
18554de26129Sxs 
18564de26129Sxs 	switch (plp->pl_chiptype) {
18574de26129Sxs 	case (pl2303_H):
18584de26129Sxs 		/* Set DCR0 */
18594de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
18604ee52f77Slg 		    DCR0_INIT_H)) != USB_SUCCESS) {
18614de26129Sxs 
18624de26129Sxs 			return (rval);
18634de26129Sxs 		}
18644de26129Sxs 
18654de26129Sxs 		/* Set DCR1 */
18664de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
18674ee52f77Slg 		    DCR1_INIT_H)) != USB_SUCCESS) {
18684de26129Sxs 
18694de26129Sxs 			return (rval);
18704de26129Sxs 		}
18714de26129Sxs 
18724de26129Sxs 		/* Set DCR2 */
18734de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
18744ee52f77Slg 		    DCR2_INIT_H)) != USB_SUCCESS) {
18754de26129Sxs 
18764de26129Sxs 			return (rval);
18774de26129Sxs 		}
18784de26129Sxs 
18794de26129Sxs 		break;
18804de26129Sxs 	case (pl2303_X):
1881cbab2b26Slg 	case (pl2303_HX_CHIP_D):
18824de26129Sxs 
18834de26129Sxs 		/* Set DCR0 */
18844de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
18854ee52f77Slg 		    DCR0_INIT)) != USB_SUCCESS) {
18864de26129Sxs 
18874de26129Sxs 			return (rval);
18884de26129Sxs 		}
18894de26129Sxs 
18904de26129Sxs 		/* Set DCR1 */
18914de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
18924ee52f77Slg 		    DCR1_INIT_X)) != USB_SUCCESS) {
18934de26129Sxs 
18944de26129Sxs 			return (rval);
18954de26129Sxs 		}
18964de26129Sxs 
18974de26129Sxs 		/* Set DCR2 */
18984de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
18994ee52f77Slg 		    DCR2_INIT_X)) != USB_SUCCESS) {
19004de26129Sxs 
19014de26129Sxs 			return (rval);
19024de26129Sxs 		}
19034de26129Sxs 
19044de26129Sxs 		/* reset Downstream data pipes */
19054de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp,
19064ee52f77Slg 		    RESET_DOWNSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
19074de26129Sxs 
19084de26129Sxs 			return (rval);
19094de26129Sxs 		}
19104de26129Sxs 
19114de26129Sxs 		/* reset Upstream data pipes */
19124de26129Sxs 		if ((rval = pl2303_cmd_vendor_write0(plp,
19134ee52f77Slg 		    RESET_UPSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
19144de26129Sxs 
19154de26129Sxs 			return (rval);
19164de26129Sxs 		}
19174de26129Sxs 
19184de26129Sxs 		break;
19194de26129Sxs 	case (pl2303_UNKNOWN):
19204de26129Sxs 	default:
19214de26129Sxs 		USB_DPRINTF_L2(DPRINT_OPEN, plp->pl_lh,
19224ee52f77Slg 		    "pl2303_open_hw_port: unknown chiptype");
19234de26129Sxs 
19244de26129Sxs 		rval = USB_FAILURE;
19254de26129Sxs 	}
19264de26129Sxs 
19274de26129Sxs 	return (rval);
19284de26129Sxs }
19294de26129Sxs 
19304de26129Sxs 
19314de26129Sxs /*
19324de26129Sxs  * vendor-specific commands
19334de26129Sxs  * ------------------------
19344de26129Sxs  *
19354de26129Sxs  *
19364de26129Sxs  * Get_Line_Coding Request
19374de26129Sxs  */
19384de26129Sxs static int
pl2303_cmd_get_line(pl2303_state_t * plp,mblk_t ** data)19394de26129Sxs pl2303_cmd_get_line(pl2303_state_t *plp, mblk_t **data)
19404de26129Sxs {
19414de26129Sxs 	usb_ctrl_setup_t setup = { PL2303_GET_LINE_CODING_REQUEST_TYPE,
19424ee52f77Slg 	    PL2303_GET_LINE_CODING_REQUEST, 0, 0,
19434ee52f77Slg 	    PL2303_GET_LINE_CODING_LENGTH, 0 };
19444de26129Sxs 	usb_cb_flags_t	cb_flags;
19454de26129Sxs 	usb_cr_t	cr;
19464de26129Sxs 	int		rval;
19474de26129Sxs 
19484de26129Sxs 	*data = NULL;
19494de26129Sxs 
19504de26129Sxs 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, data,
19514ee52f77Slg 	    &cr, &cb_flags, 0);
19524de26129Sxs 
19534de26129Sxs 	if ((rval == USB_SUCCESS) && (*data != NULL)) {
19544de26129Sxs 		USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
19554de26129Sxs 		    "pl2303_cmd_get_line: %x %x %x %x %x %x %x",
19564de26129Sxs 		    (*data)->b_rptr[0], (*data)->b_rptr[1], (*data)->b_rptr[2],
19574de26129Sxs 		    (*data)->b_rptr[3], (*data)->b_rptr[4], (*data)->b_rptr[5],
19584de26129Sxs 		    (*data)->b_rptr[6]);
19594de26129Sxs 	} else {
19604de26129Sxs 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
19614de26129Sxs 		    "pl2303_cmd_get_line: failed %d %d %x",
19624de26129Sxs 		    rval, cr, cb_flags);
19633c91d182Slg 
19643c91d182Slg 		if (*data != NULL) {
19653c91d182Slg 			freeb(*data);
19663c91d182Slg 		}
19674de26129Sxs 	}
19684de26129Sxs 
19694de26129Sxs 	return (rval);
19704de26129Sxs }
19714de26129Sxs 
19724de26129Sxs 
19734de26129Sxs /*
19744de26129Sxs  * Set_Line_Coding Request
19754de26129Sxs  */
19764de26129Sxs static int
pl2303_cmd_set_line(pl2303_state_t * plp,mblk_t * data)19774de26129Sxs pl2303_cmd_set_line(pl2303_state_t *plp, mblk_t *data)
19784de26129Sxs {
19794de26129Sxs 	usb_ctrl_setup_t setup = { PL2303_SET_LINE_CODING_REQUEST_TYPE,
19804ee52f77Slg 	    PL2303_SET_LINE_CODING_REQUEST, 0, 0,
19814ee52f77Slg 	    PL2303_SET_LINE_CODING_LENGTH, 0 };
19824de26129Sxs 	usb_cb_flags_t	cb_flags;
19834de26129Sxs 	usb_cr_t	cr;
19844de26129Sxs 	int		rval;
19854de26129Sxs 
19864de26129Sxs 	USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
19874de26129Sxs 	    "pl2303_cmd_set_line: %x %x %x %x %x %x %x",
19884de26129Sxs 	    data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
19894de26129Sxs 	    data->b_rptr[3], data->b_rptr[4], data->b_rptr[5], data->b_rptr[6]);
19904de26129Sxs 
19914de26129Sxs 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, &data,
19924ee52f77Slg 	    &cr, &cb_flags, 0);
19934de26129Sxs 
19944de26129Sxs 	if (rval != USB_SUCCESS) {
19954de26129Sxs 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
19964de26129Sxs 		    "pl2303_cmd_set_line: failed %d %d %x",
19974de26129Sxs 		    rval, cr, cb_flags);
19984de26129Sxs 	}
19994de26129Sxs 
20004de26129Sxs 	return (rval);
20014de26129Sxs }
20024de26129Sxs 
20034de26129Sxs 
20044de26129Sxs /*
20054de26129Sxs  * Set_Control_Line_State Request to RTS and DTR
20064de26129Sxs  */
20074de26129Sxs static int
pl2303_cmd_set_ctl(pl2303_state_t * plp,uint8_t val)20084de26129Sxs pl2303_cmd_set_ctl(pl2303_state_t *plp, uint8_t val)
20094de26129Sxs {
20104de26129Sxs 	usb_ctrl_setup_t setup = { PL2303_SET_CONTROL_REQUEST_TYPE,
20114ee52f77Slg 	    PL2303_SET_CONTROL_REQUEST, 0, 0,
20124ee52f77Slg 	    PL2303_SET_CONTROL_LENGTH, 0 };
20134de26129Sxs 	usb_cb_flags_t	cb_flags;
20144de26129Sxs 	usb_cr_t	cr;
20154de26129Sxs 	int		rval;
20164de26129Sxs 
20174de26129Sxs 	setup.wValue = val;
20184de26129Sxs 
20194de26129Sxs 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
20204ee52f77Slg 	    &cr, &cb_flags, 0);
20214de26129Sxs 
20224de26129Sxs 	if (rval != USB_SUCCESS) {
20234de26129Sxs 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
20244de26129Sxs 		    "pl2303_cmd_set_ctl: failed %d %d %x",
20254de26129Sxs 		    rval, cr, cb_flags);
20264de26129Sxs 	}
20274de26129Sxs 
20284de26129Sxs 	return (rval);
20294de26129Sxs }
20304de26129Sxs 
20314de26129Sxs 
20324de26129Sxs /*
20334de26129Sxs  * Vendor_Specific_Write Request
20344de26129Sxs  * wLength: 0
20354de26129Sxs  */
20364de26129Sxs static int
pl2303_cmd_vendor_write0(pl2303_state_t * plp,uint16_t value,int16_t index)20374de26129Sxs pl2303_cmd_vendor_write0(pl2303_state_t *plp, uint16_t value, int16_t index)
20384de26129Sxs {
20394de26129Sxs 	usb_ctrl_setup_t setup = { PL2303_VENDOR_WRITE_REQUEST_TYPE,
20404ee52f77Slg 	    PL2303_VENDOR_WRITE_REQUEST, 0, 0,
20414ee52f77Slg 	    PL2303_VENDOR_WRITE_LENGTH, 0 };
20424de26129Sxs 	usb_cb_flags_t	cb_flags;
20434de26129Sxs 	usb_cr_t	cr;
20444de26129Sxs 	int		rval;
20454de26129Sxs 
20464de26129Sxs 	setup.wValue = value;
20474de26129Sxs 	setup.wIndex = index;
20484de26129Sxs 
20494de26129Sxs 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
20504ee52f77Slg 	    &cr, &cb_flags, 0);
20514de26129Sxs 
20524de26129Sxs 	if (rval != USB_SUCCESS) {
20534de26129Sxs 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
20544de26129Sxs 		    "pl2303_cmd_vendor_write0: %x %x failed %d %d %x",
20554de26129Sxs 		    value, index, rval, cr, cb_flags);
20564de26129Sxs 	}
20574de26129Sxs 
20584de26129Sxs 	return (rval);
20594de26129Sxs }
20604de26129Sxs 
20614de26129Sxs 
20624de26129Sxs /*
20634de26129Sxs  * For Hardware flow control
20644de26129Sxs  */
20654de26129Sxs static int
pl2303_cmd_set_rtscts(pl2303_state_t * plp)20664de26129Sxs pl2303_cmd_set_rtscts(pl2303_state_t *plp)
20674de26129Sxs {
20684de26129Sxs 	/* Set DCR0 */
20694de26129Sxs 	switch (plp->pl_chiptype) {
20704de26129Sxs 	case pl2303_H:
20714de26129Sxs 
20724de26129Sxs 		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_H));
20734de26129Sxs 	case pl2303_X:
2074cbab2b26Slg 	case pl2303_HX_CHIP_D:
20754de26129Sxs 
20764de26129Sxs 		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_X));
20774de26129Sxs 	case pl2303_UNKNOWN:
20784de26129Sxs 	default:
20794de26129Sxs 
20804de26129Sxs 		return (USB_FAILURE);
20814de26129Sxs 	}
20824de26129Sxs }
20834de26129Sxs 
20844de26129Sxs 
20854de26129Sxs /*
20864de26129Sxs  * Set TxD BREAK_ON or BREAK_OFF
20874de26129Sxs  */
20884de26129Sxs static int
pl2303_cmd_break(pl2303_state_t * plp,int ctl)20894de26129Sxs pl2303_cmd_break(pl2303_state_t *plp, int ctl)
20904de26129Sxs {
20914de26129Sxs 	usb_ctrl_setup_t setup = { PL2303_BREAK_REQUEST_TYPE,
20924ee52f77Slg 	    PL2303_BREAK_REQUEST, 0, 0,
20934ee52f77Slg 	    PL2303_BREAK_LENGTH, 0 };
20944de26129Sxs 	usb_cb_flags_t	cb_flags;
20954de26129Sxs 	usb_cr_t	cr;
20964de26129Sxs 	int		rval;
20974de26129Sxs 
20984de26129Sxs 	setup.wValue = (ctl == DS_ON) ? PL2303_BREAK_ON : PL2303_BREAK_OFF;
20994de26129Sxs 
21004de26129Sxs 	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
21014ee52f77Slg 	    &cr, &cb_flags, 0);
21024de26129Sxs 
21034de26129Sxs 	if (rval != USB_SUCCESS) {
21044de26129Sxs 		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
21054ee52f77Slg 		    "pl2303_cmd_break: failed rval=%d,cr=%d,cb_flags=0x%x",
21064ee52f77Slg 		    rval, cr, cb_flags);
21074de26129Sxs 	}
21084de26129Sxs 
21094de26129Sxs 	return (rval);
21104de26129Sxs }
21114de26129Sxs 
21124de26129Sxs 
21134de26129Sxs /*
21144de26129Sxs  * for set_mod_ctl
21154de26129Sxs  */
21164de26129Sxs static void
pl2303_mctl2reg(int mask,int val,uint8_t * line_ctl)21174de26129Sxs pl2303_mctl2reg(int mask, int val, uint8_t *line_ctl)
21184de26129Sxs {
21194de26129Sxs 	if (mask & TIOCM_RTS) {
21204de26129Sxs 		if (val & TIOCM_RTS) {
21214de26129Sxs 			*line_ctl |= PL2303_CONTROL_RTS;
21224de26129Sxs 		} else {
21234de26129Sxs 			*line_ctl &= ~PL2303_CONTROL_RTS;
21244de26129Sxs 		}
21254de26129Sxs 	}
21264de26129Sxs 	if (mask & TIOCM_DTR) {
21274de26129Sxs 		if (val & TIOCM_DTR) {
21284de26129Sxs 			*line_ctl |= PL2303_CONTROL_DTR;
21294de26129Sxs 		} else {
21304de26129Sxs 			*line_ctl &= ~PL2303_CONTROL_DTR;
21314de26129Sxs 		}
21324de26129Sxs 	}
21334de26129Sxs }
21344de26129Sxs 
21354de26129Sxs 
21364de26129Sxs /*
21374de26129Sxs  * for get_mod_ctl
21384de26129Sxs  */
21394de26129Sxs static int
pl2303_reg2mctl(uint8_t line_ctl)21404de26129Sxs pl2303_reg2mctl(uint8_t line_ctl)
21414de26129Sxs {
21424de26129Sxs 	int	val = 0;
21434de26129Sxs 
21444de26129Sxs 	if (line_ctl & PL2303_CONTROL_RTS) {
21454de26129Sxs 		val |= TIOCM_RTS;
21464de26129Sxs 	}
21474de26129Sxs 	if (line_ctl & PL2303_CONTROL_DTR) {
21484de26129Sxs 		val |= TIOCM_DTR;
21494de26129Sxs 	}
21504de26129Sxs 
21514de26129Sxs 	return (val);
21524de26129Sxs }
21534de26129Sxs 
21544de26129Sxs 
21554de26129Sxs /*
21564de26129Sxs  * misc routines
21574de26129Sxs  * -------------
21584de26129Sxs  *
21594de26129Sxs  */
21604de26129Sxs 
21614de26129Sxs /*
21624de26129Sxs  * link a message block to tail of message
21634de26129Sxs  * account for the case when message is null
21644de26129Sxs  */
21654de26129Sxs static void
pl2303_put_tail(mblk_t ** mpp,mblk_t * bp)21664de26129Sxs pl2303_put_tail(mblk_t **mpp, mblk_t *bp)
21674de26129Sxs {
21684de26129Sxs 	if (*mpp) {
21694de26129Sxs 		linkb(*mpp, bp);
21704de26129Sxs 	} else {
21714de26129Sxs 		*mpp = bp;
21724de26129Sxs 	}
21734de26129Sxs }
21744de26129Sxs 
21754de26129Sxs 
21764de26129Sxs /*
21774de26129Sxs  * put a message block at the head of the message
21784de26129Sxs  * account for the case when message is null
21794de26129Sxs  */
21804de26129Sxs static void
pl2303_put_head(mblk_t ** mpp,mblk_t * bp)21814de26129Sxs pl2303_put_head(mblk_t **mpp, mblk_t *bp)
21824de26129Sxs {
21834de26129Sxs 	if (*mpp) {
21844de26129Sxs 		linkb(bp, *mpp);
21854de26129Sxs 	}
21864de26129Sxs 	*mpp = bp;
21874de26129Sxs }
218828cdc3d7Sszhou 
218928cdc3d7Sszhou /*ARGSUSED*/
219028cdc3d7Sszhou static usb_pipe_handle_t
pl2303_out_pipe(ds_hdl_t hdl,uint_t port_num)219128cdc3d7Sszhou pl2303_out_pipe(ds_hdl_t hdl, uint_t port_num)
219228cdc3d7Sszhou {
219328cdc3d7Sszhou 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
219428cdc3d7Sszhou 
219528cdc3d7Sszhou 	return (plp->pl_bulkout_ph);
219628cdc3d7Sszhou }
219728cdc3d7Sszhou 
219828cdc3d7Sszhou /*ARGSUSED*/
219928cdc3d7Sszhou static usb_pipe_handle_t
pl2303_in_pipe(ds_hdl_t hdl,uint_t port_num)220028cdc3d7Sszhou pl2303_in_pipe(ds_hdl_t hdl, uint_t port_num)
220128cdc3d7Sszhou {
220228cdc3d7Sszhou 	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
220328cdc3d7Sszhou 
220428cdc3d7Sszhou 	return (plp->pl_bulkin_ph);
220528cdc3d7Sszhou }
2206