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
pl2303_attach(ds_attach_info_t * aip)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
pl2303_detach(ds_hdl_t hdl)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
pl2303_register_cb(ds_hdl_t hdl,uint_t port_num,ds_cb_t * cb)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
pl2303_unregister_cb(ds_hdl_t hdl,uint_t port_num)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
pl2303_open_port(ds_hdl_t hdl,uint_t port_num)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
pl2303_close_port(ds_hdl_t hdl,uint_t port_num)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
pl2303_usb_power(ds_hdl_t hdl,int comp,int level,int * new_state)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
pl2303_suspend(ds_hdl_t hdl)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
pl2303_resume(ds_hdl_t hdl)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
pl2303_disconnect(ds_hdl_t hdl)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
pl2303_reconnect(ds_hdl_t hdl)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
pl2303_set_port_params(ds_hdl_t hdl,uint_t port_num,ds_port_params_t * tp)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
pl2303_set_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int val)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
pl2303_get_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int * valp)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
pl2303_break_ctl(ds_hdl_t hdl,uint_t port_num,int ctl)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
pl2303_tx(ds_hdl_t hdl,uint_t port_num,mblk_t * mp)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 *
pl2303_rx(ds_hdl_t hdl,uint_t port_num)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
pl2303_stop(ds_hdl_t hdl,uint_t port_num,int dir)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
pl2303_start(ds_hdl_t hdl,uint_t port_num,int dir)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
pl2303_fifo_flush(ds_hdl_t hdl,uint_t port_num,int dir)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
pl2303_fifo_drain(ds_hdl_t hdl,uint_t port_num,int timeout)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
pl2303_cleanup(pl2303_state_t * plp,int level)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
pl2303_dev_attach(pl2303_state_t * plp)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
pl2303_restore_device_state(pl2303_state_t * plp)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
pl2303_restore_port_state(pl2303_state_t * plp)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
pl2303_create_pm_components(pl2303_state_t * plp)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
pl2303_destroy_pm_components(pl2303_state_t * plp)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
pl2303_pm_set_busy(pl2303_state_t * plp)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
pl2303_pm_set_idle(pl2303_state_t * plp)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
pl2303_pwrlvl0(pl2303_state_t * plp)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
pl2303_pwrlvl1(pl2303_state_t * plp)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
pl2303_pwrlvl2(pl2303_state_t * plp)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
pl2303_pwrlvl3(pl2303_state_t * plp)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
pl2303_open_pipes(pl2303_state_t * plp)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
pl2303_close_pipes(pl2303_state_t * plp)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
pl2303_disconnect_pipes(pl2303_state_t * plp)1526 pl2303_disconnect_pipes(pl2303_state_t *plp)
1527 {
1528 pl2303_close_pipes(plp);
1529 }
1530
1531
1532 static int
pl2303_reconnect_pipes(pl2303_state_t * plp)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
pl2303_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)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
pl2303_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)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
pl2303_rx_start(pl2303_state_t * plp)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
pl2303_tx_start(pl2303_state_t * plp,int * xferd)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
pl2303_send_data(pl2303_state_t * plp,mblk_t * data)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
pl2303_wait_tx_drain(pl2303_state_t * plp,int timeout)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
pl2303_open_hw_port(pl2303_state_t * plp)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
pl2303_cmd_get_line(pl2303_state_t * plp,mblk_t ** data)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
pl2303_cmd_set_line(pl2303_state_t * plp,mblk_t * data)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
pl2303_cmd_set_ctl(pl2303_state_t * plp,uint8_t val)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
pl2303_cmd_vendor_write0(pl2303_state_t * plp,uint16_t value,int16_t index)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
pl2303_cmd_set_rtscts(pl2303_state_t * plp)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
pl2303_cmd_break(pl2303_state_t * plp,int ctl)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
pl2303_mctl2reg(int mask,int val,uint8_t * line_ctl)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
pl2303_reg2mctl(uint8_t line_ctl)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
pl2303_put_tail(mblk_t ** mpp,mblk_t * bp)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
pl2303_put_head(mblk_t ** mpp,mblk_t * bp)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
pl2303_out_pipe(ds_hdl_t hdl,uint_t port_num)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
pl2303_in_pipe(ds_hdl_t hdl,uint_t port_num)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