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