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 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * USB Serial CDC ACM driver
29 *
30 * 1. General Concepts
31 * -------------------
32 *
33 * 1.1 Overview
34 * ------------
35 * This driver supports devices that comply with the USB Communication
36 * Device Class Abstract Control Model (USB CDC ACM) specification,
37 * which is available at http://www.usb.org. Given the broad nature
38 * of communication equipment, this driver supports the following
39 * types of devices:
40 * + Telecommunications devices: analog modems, mobile phones;
41 * + Networking devices: cable modems;
42 * Except the above mentioned acm devices, this driver also supports
43 * some devices which provide modem-like function and have pairs of
44 * bulk in/out pipes.
45 *
46 * There are three classes that make up the definition for communication
47 * devices: the Communication Device Class, the Communication Interface
48 * Class and the Data Interface Class. The Communication Device Class
49 * is a device level definition and is used by the host to properly
50 * identify a communication device that may present several different
51 * types of interfaces. The Communication Interface Class defines a
52 * general-purpose mechanism that can be used to enable all types of
53 * communication services on the Universal Serial Bus (USB). The Data
54 * Interface Class defines a general-purpose mechanism to enable bulk
55 * transfer on the USB when the data does not meet the requirements
56 * for any other class.
57 *
58 * 1.2 Interface Definitions
59 * -------------------------
60 * Communication Class Interface is used for device management and,
61 * optionally, call management. Device management includes the requests
62 * that manage the operational state of a device, the device responses,
63 * and event notifications. In Abstract Control Model, the device can
64 * provide an internal implementation of call management over the Data
65 * Class interface or the Communication Class interface.
66 *
67 * The Data Class defines a data interface as an interface with a class
68 * type of Data Class. Data transmission on a communication device is
69 * not restricted to interfaces using the Data Class. Rather, a data
70 * interface is used to transmit and/or receive data that is not
71 * defined by any other class. The data could be:
72 * + Some form of raw data from a communication line.
73 * + Legacy modem data.
74 * + Data using a proprietary format.
75 *
76 * 1.3 Endpoint Requirements
77 * -------------------------
78 * The Communication Class interface requires one endpoint, the management
79 * element. Optionally, it can have an additional endpoint, the notification
80 * element. The management element uses the default endpoint for all
81 * standard and Communication Class-specific requests. The notification
82 * element normally uses an interrupt endpoint.
83 *
84 * The type of endpoints belonging to a Data Class interface are restricted
85 * to bulk, and are expected to exist in pairs of the same type (one In and
86 * one Out).
87 *
88 * 1.4 ACM Function Characteristics
89 * --------------------------------
90 * With Abstract Control Model, the USB device understands standard
91 * V.25ter (AT) commands. The device contains a Datapump and micro-
92 * controller that handles the AT commands and relay controls. The
93 * device uses both a Data Class interface and a Communication Class.
94 * interface.
95 *
96 * A Communication Class interface of type Abstract Control Model will
97 * consist of a minimum of two pipes; one is used to implement the
98 * management element and the other to implement a notification element.
99 * In addition, the device can use two pipes to implement channels over
100 * which to carry unspecified data, typically over a Data Class interface.
101 *
102 * 1.5 ACM Serial Emulation
103 * ------------------------
104 * The Abstract Control Model can bridge the gap between legacy modem
105 * devices and USB devices. To support certain types of legacy applications,
106 * two problems need to be addressed. The first is supporting specific
107 * legacy control signals and state variables which are addressed
108 * directly by the various carrier modulation standards. To support these
109 * requirement, additional requests and notifications have been created.
110 * Please refer to macro, beginning with USB_CDC_REQ_* and
111 * USB_CDC_NOTIFICATION_*.
112 *
113 * The second significant item which is needed to bridge the gap between
114 * legacy modem designs and the Abstract Control Model is a means to
115 * multiplex call control (AT commands) on the Data Class interface.
116 * Legacy modem designs are limited by only supporting one channel for
117 * both "AT" commands and the actual data. To allow this type of
118 * functionality, the device must have a means to specify this limitation
119 * to the host.
120 *
121 * When describing this type of device, the Communication Class interface
122 * would still specify a Abstract Control Model, but call control would
123 * actually occur over the Data Class interface. To describe this
124 * particular characteristic, the Call Management Functional Descriptor
125 * would have bit D1 of bmCapabilities set.
126 *
127 * 1.6 Other Bulk In/Out Devices
128 * -----------------------------
129 * Some devices don't conform to USB CDC specification, but they provide
130 * modem-like function and have pairs of bulk in/out pipes. This driver
131 * supports this kind of device and exports term nodes by their pipes.
132 *
133 * 2. Implementation
134 * -----------------
135 *
136 * 2.1 Overview
137 * ------------
138 * It is a device-specific driver (DSD) working with USB generic serial
139 * driver (GSD). It implements the USB-to-serial device-specific driver
140 * interface (DSDI) which is offered by GSD. The interface is defined
141 * by ds_ops_t structure.
142 *
143 * 2.2 Port States
144 * ---------------
145 * For USB CDC ACM devices, this driver is attached to its interface,
146 * and exports one port for each interface. For other modem-like devices,
147 * this driver can dynamically find the ports in the current device,
148 * and export one port for each pair bulk in/out pipes. Each port can
149 * be operated independently.
150 *
151 * port_state:
152 *
153 * attach_ports
154 * |
155 * |
156 * |
157 * v
158 * USBSACM_PORT_CLOSED
159 * | ^
160 * | |
161 * V |
162 * open_port close_port
163 * | ^
164 * | |
165 * V |
166 * USBSACM_PORT_OPEN
167 *
168 *
169 * 2.3 Pipe States
170 * ---------------
171 * Each port has its own bulk in/out pipes and some ports could also have
172 * its own interrupt pipes (traced by usbsacm_port structure), which are
173 * opened during attach. The pipe status is as following:
174 *
175 * pipe_state:
176 *
177 * usbsacm_init_alloc_ports usbsacm_free_ports
178 * | ^
179 * v |
180 * |---->------ USBSACM_PORT_CLOSED ------>------+
181 * ^ |
182 * | reconnect/resume/open_port
183 * | |
184 * disconnect/suspend/close_port |
185 * | v
186 * +------<------ USBSACM_PIPE_IDLE ------<------|
187 * | |
188 * V ^
189 * | |
190 * +-----------------+ +-----------+
191 * | |
192 * V ^
193 * | |
194 * rx_start/tx_start----->------failed------->---------|
195 * | |
196 * | bulkin_cb/bulkout_cb
197 * V |
198 * | ^
199 * | |
200 * +----->----- USBSACM_PIPE_BUSY ---->------+
201 *
202 *
203 * To get its status in a timely way, acm driver can get the status
204 * of the device by polling the interrupt pipe.
205 *
206 */
207
208 #include <sys/types.h>
209 #include <sys/param.h>
210 #include <sys/conf.h>
211 #include <sys/stream.h>
212 #include <sys/strsun.h>
213 #include <sys/termio.h>
214 #include <sys/termiox.h>
215 #include <sys/ddi.h>
216 #include <sys/sunddi.h>
217 #include <sys/byteorder.h>
218 #define USBDRV_MAJOR_VER 2
219 #define USBDRV_MINOR_VER 0
220 #include <sys/usb/usba.h>
221 #include <sys/usb/usba/usba_types.h>
222 #include <sys/usb/clients/usbser/usbser.h>
223 #include <sys/usb/clients/usbser/usbser_dsdi.h>
224 #include <sys/usb/clients/usbcdc/usb_cdc.h>
225 #include <sys/usb/clients/usbser/usbsacm/usbsacm.h>
226
227 /* devops entry points */
228 static int usbsacm_attach(dev_info_t *, ddi_attach_cmd_t);
229 static int usbsacm_detach(dev_info_t *, ddi_detach_cmd_t);
230 static int usbsacm_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
231 void **);
232 static int usbsacm_open(queue_t *, dev_t *, int, int, cred_t *);
233
234 /* DSD operations */
235 static int usbsacm_ds_attach(ds_attach_info_t *);
236 static void usbsacm_ds_detach(ds_hdl_t);
237 static int usbsacm_ds_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
238 static void usbsacm_ds_unregister_cb(ds_hdl_t, uint_t);
239 static int usbsacm_ds_open_port(ds_hdl_t, uint_t);
240 static int usbsacm_ds_close_port(ds_hdl_t, uint_t);
241
242 /* standard UART operations */
243 static int usbsacm_ds_set_port_params(ds_hdl_t, uint_t,
244 ds_port_params_t *);
245 static int usbsacm_ds_set_modem_ctl(ds_hdl_t, uint_t, int, int);
246 static int usbsacm_ds_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
247 static int usbsacm_ds_break_ctl(ds_hdl_t, uint_t, int);
248
249 /* data xfer */
250 static int usbsacm_ds_tx(ds_hdl_t, uint_t, mblk_t *);
251 static mblk_t *usbsacm_ds_rx(ds_hdl_t, uint_t);
252 static void usbsacm_ds_stop(ds_hdl_t, uint_t, int);
253 static void usbsacm_ds_start(ds_hdl_t, uint_t, int);
254
255 /* fifo operations */
256 static int usbsacm_ds_fifo_flush(ds_hdl_t, uint_t, int);
257 static int usbsacm_ds_fifo_drain(ds_hdl_t, uint_t, int);
258 static int usbsacm_wait_tx_drain(usbsacm_port_t *, int);
259 static int usbsacm_fifo_flush_locked(usbsacm_state_t *, uint_t, int);
260
261 /* power management and CPR */
262 static int usbsacm_ds_suspend(ds_hdl_t);
263 static int usbsacm_ds_resume(ds_hdl_t);
264 static int usbsacm_ds_disconnect(ds_hdl_t);
265 static int usbsacm_ds_reconnect(ds_hdl_t);
266 static int usbsacm_ds_usb_power(ds_hdl_t, int, int, int *);
267 static int usbsacm_create_pm_components(usbsacm_state_t *);
268 static void usbsacm_destroy_pm_components(usbsacm_state_t *);
269 static void usbsacm_pm_set_busy(usbsacm_state_t *);
270 static void usbsacm_pm_set_idle(usbsacm_state_t *);
271 static int usbsacm_pwrlvl0(usbsacm_state_t *);
272 static int usbsacm_pwrlvl1(usbsacm_state_t *);
273 static int usbsacm_pwrlvl2(usbsacm_state_t *);
274 static int usbsacm_pwrlvl3(usbsacm_state_t *);
275
276 /* event handling */
277 /* pipe callbacks */
278 static void usbsacm_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
279 static void usbsacm_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
280
281 /* interrupt pipe */
282 static void usbsacm_pipe_start_polling(usbsacm_port_t *acmp);
283 static void usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
284 static void usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
285 static void usbsacm_parse_intr_data(usbsacm_port_t *acmp, mblk_t *data);
286
287 /* Utility functions */
288 /* data transfer routines */
289 static int usbsacm_rx_start(usbsacm_port_t *);
290 static void usbsacm_tx_start(usbsacm_port_t *);
291 static int usbsacm_send_data(usbsacm_port_t *, mblk_t *);
292
293 /* Initialize or release resources */
294 static int usbsacm_init_alloc_ports(usbsacm_state_t *);
295 static void usbsacm_free_ports(usbsacm_state_t *);
296 static void usbsacm_cleanup(usbsacm_state_t *);
297
298 /* analysis functional descriptors */
299 static int usbsacm_get_descriptors(usbsacm_state_t *);
300
301 /* hotplug */
302 static int usbsacm_restore_device_state(usbsacm_state_t *);
303 static int usbsacm_restore_port_state(usbsacm_state_t *);
304
305 /* pipe operations */
306 static int usbsacm_open_port_pipes(usbsacm_port_t *);
307 static void usbsacm_close_port_pipes(usbsacm_port_t *);
308 static void usbsacm_close_pipes(usbsacm_state_t *);
309 static void usbsacm_disconnect_pipes(usbsacm_state_t *);
310 static int usbsacm_reconnect_pipes(usbsacm_state_t *);
311
312 /* vendor-specific commands */
313 static int usbsacm_req_write(usbsacm_port_t *, uchar_t, uint16_t,
314 mblk_t **);
315 static int usbsacm_set_line_coding(usbsacm_port_t *,
316 usb_cdc_line_coding_t *);
317 static void usbsacm_mctl2reg(int mask, int val, uint8_t *);
318 static int usbsacm_reg2mctl(uint8_t);
319
320 /* misc */
321 static void usbsacm_put_tail(mblk_t **, mblk_t *);
322 static void usbsacm_put_head(mblk_t **, mblk_t *);
323
324
325 /*
326 * Standard STREAMS driver definitions
327 */
328 struct module_info usbsacm_modinfo = {
329 0, /* module id */
330 "usbsacm", /* module name */
331 USBSER_MIN_PKTSZ, /* min pkt size */
332 USBSER_MAX_PKTSZ, /* max pkt size */
333 USBSER_HIWAT, /* hi watermark */
334 USBSER_LOWAT /* low watermark */
335 };
336
337 static struct qinit usbsacm_rinit = {
338 NULL,
339 usbser_rsrv,
340 usbsacm_open,
341 usbser_close,
342 NULL,
343 &usbsacm_modinfo,
344 NULL
345 };
346
347 static struct qinit usbsacm_winit = {
348 usbser_wput,
349 usbser_wsrv,
350 NULL,
351 NULL,
352 NULL,
353 &usbsacm_modinfo,
354 NULL
355 };
356
357
358 struct streamtab usbsacm_str_info = {
359 &usbsacm_rinit, &usbsacm_winit, NULL, NULL
360 };
361
362 /* cb_ops structure */
363 static struct cb_ops usbsacm_cb_ops = {
364 nodev, /* cb_open */
365 nodev, /* cb_close */
366 nodev, /* cb_strategy */
367 nodev, /* cb_print */
368 nodev, /* cb_dump */
369 nodev, /* cb_read */
370 nodev, /* cb_write */
371 nodev, /* cb_ioctl */
372 nodev, /* cb_devmap */
373 nodev, /* cb_mmap */
374 nodev, /* cb_segmap */
375 nochpoll, /* cb_chpoll */
376 ddi_prop_op, /* cb_prop_op */
377 &usbsacm_str_info, /* cb_stream */
378 (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG) /* cb_flag */
379 };
380
381 /* dev_ops structure */
382 struct dev_ops usbsacm_ops = {
383 DEVO_REV, /* devo_rev */
384 0, /* devo_refcnt */
385 usbsacm_getinfo, /* devo_getinfo */
386 nulldev, /* devo_identify */
387 nulldev, /* devo_probe */
388 usbsacm_attach, /* devo_attach */
389 usbsacm_detach, /* devo_detach */
390 nodev, /* devo_reset */
391 &usbsacm_cb_ops, /* devo_cb_ops */
392 (struct bus_ops *)NULL, /* devo_bus_ops */
393 usbser_power, /* devo_power */
394 ddi_quiesce_not_needed, /* devo_quiesce */
395 };
396
397 extern struct mod_ops mod_driverops;
398 /* modldrv structure */
399 static struct modldrv modldrv = {
400 &mod_driverops, /* type of module - driver */
401 "USB Serial CDC ACM driver",
402 &usbsacm_ops,
403 };
404
405 /* modlinkage structure */
406 static struct modlinkage modlinkage = {
407 MODREV_1,
408 &modldrv,
409 NULL
410 };
411
412 static void *usbsacm_statep; /* soft state */
413
414 /*
415 * DSD definitions
416 */
417 static ds_ops_t usbsacm_ds_ops = {
418 DS_OPS_VERSION,
419 usbsacm_ds_attach,
420 usbsacm_ds_detach,
421 usbsacm_ds_register_cb,
422 usbsacm_ds_unregister_cb,
423 usbsacm_ds_open_port,
424 usbsacm_ds_close_port,
425 usbsacm_ds_usb_power,
426 usbsacm_ds_suspend,
427 usbsacm_ds_resume,
428 usbsacm_ds_disconnect,
429 usbsacm_ds_reconnect,
430 usbsacm_ds_set_port_params,
431 usbsacm_ds_set_modem_ctl,
432 usbsacm_ds_get_modem_ctl,
433 usbsacm_ds_break_ctl,
434 NULL, /* NULL if h/w doesn't support loopback */
435 usbsacm_ds_tx,
436 usbsacm_ds_rx,
437 usbsacm_ds_stop,
438 usbsacm_ds_start,
439 usbsacm_ds_fifo_flush,
440 usbsacm_ds_fifo_drain
441 };
442
443 /*
444 * baud code -> baud rate (0 means unsupported rate)
445 */
446 static int usbsacm_speedtab[] = {
447 0, /* B0 */
448 50, /* B50 */
449 75, /* B75 */
450 110, /* B110 */
451 134, /* B134 */
452 150, /* B150 */
453 200, /* B200 */
454 300, /* B300 */
455 600, /* B600 */
456 1200, /* B1200 */
457 1800, /* B1800 */
458 2400, /* B2400 */
459 4800, /* B4800 */
460 9600, /* B9600 */
461 19200, /* B19200 */
462 38400, /* B38400 */
463 57600, /* B57600 */
464 76800, /* B76800 */
465 115200, /* B115200 */
466 153600, /* B153600 */
467 230400, /* B230400 */
468 307200, /* B307200 */
469 460800, /* B460800 */
470 921600 /* B921600 */
471 };
472
473
474 static uint_t usbsacm_errlevel = USB_LOG_L4;
475 static uint_t usbsacm_errmask = 0xffffffff;
476 static uint_t usbsacm_instance_debug = (uint_t)-1;
477
478
479 /*
480 * usbsacm driver's entry points
481 * -----------------------------
482 */
483 /*
484 * Module-wide initialization routine.
485 */
486 int
_init(void)487 _init(void)
488 {
489 int error;
490
491 if ((error = mod_install(&modlinkage)) == 0) {
492
493 error = ddi_soft_state_init(&usbsacm_statep,
494 usbser_soft_state_size(), 1);
495 }
496
497 return (error);
498 }
499
500
501 /*
502 * Module-wide tear-down routine.
503 */
504 int
_fini(void)505 _fini(void)
506 {
507 int error;
508
509 if ((error = mod_remove(&modlinkage)) == 0) {
510 ddi_soft_state_fini(&usbsacm_statep);
511 }
512
513 return (error);
514 }
515
516
517 int
_info(struct modinfo * modinfop)518 _info(struct modinfo *modinfop)
519 {
520 return (mod_info(&modlinkage, modinfop));
521 }
522
523
524 /*
525 * Device configuration entry points
526 */
527 static int
usbsacm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)528 usbsacm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
529 {
530 return (usbser_attach(dip, cmd, usbsacm_statep, &usbsacm_ds_ops));
531 }
532
533
534 static int
usbsacm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)535 usbsacm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
536 {
537 return (usbser_detach(dip, cmd, usbsacm_statep));
538 }
539
540
541 int
usbsacm_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)542 usbsacm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
543 void **result)
544 {
545 return (usbser_getinfo(dip, infocmd, arg, result, usbsacm_statep));
546 }
547
548
549 static int
usbsacm_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)550 usbsacm_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
551 {
552 return (usbser_open(rq, dev, flag, sflag, cr, usbsacm_statep));
553 }
554
555 /*
556 * usbsacm_ds_detach:
557 * attach device instance, called from GSD attach
558 * initialize state and device, including:
559 * state variables, locks, device node
560 * device registration with system
561 * power management
562 */
563 static int
usbsacm_ds_attach(ds_attach_info_t * aip)564 usbsacm_ds_attach(ds_attach_info_t *aip)
565 {
566 usbsacm_state_t *acmp;
567
568 acmp = (usbsacm_state_t *)kmem_zalloc(sizeof (usbsacm_state_t),
569 KM_SLEEP);
570 acmp->acm_dip = aip->ai_dip;
571 acmp->acm_usb_events = aip->ai_usb_events;
572 acmp->acm_ports = NULL;
573 *aip->ai_hdl = (ds_hdl_t)acmp;
574
575 /* registers usbsacm with the USBA framework */
576 if (usb_client_attach(acmp->acm_dip, USBDRV_VERSION,
577 0) != USB_SUCCESS) {
578
579 goto fail;
580 }
581
582 /* Get the configuration information of device */
583 if (usb_get_dev_data(acmp->acm_dip, &acmp->acm_dev_data,
584 USB_PARSE_LVL_CFG, 0) != USB_SUCCESS) {
585
586 goto fail;
587 }
588 acmp->acm_def_ph = acmp->acm_dev_data->dev_default_ph;
589 acmp->acm_dev_state = USB_DEV_ONLINE;
590 mutex_init(&acmp->acm_mutex, NULL, MUTEX_DRIVER,
591 acmp->acm_dev_data->dev_iblock_cookie);
592
593 acmp->acm_lh = usb_alloc_log_hdl(acmp->acm_dip, "usbsacm",
594 &usbsacm_errlevel, &usbsacm_errmask, &usbsacm_instance_debug, 0);
595
596 /* Create power management components */
597 if (usbsacm_create_pm_components(acmp) != USB_SUCCESS) {
598 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
599 "usbsacm_ds_attach: create pm components failed.");
600
601 goto fail;
602 }
603
604 /* Register to get callbacks for USB events */
605 if (usb_register_event_cbs(acmp->acm_dip, acmp->acm_usb_events, 0)
606 != USB_SUCCESS) {
607 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
608 "usbsacm_ds_attach: register event callback failed.");
609
610 goto fail;
611 }
612
613 /*
614 * If devices conform to acm spec, driver will attach using class id;
615 * if not, using device id.
616 */
617 if ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name,
618 "usbif,class2.2") == 0) ||
619 ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name,
620 "usb,class2.2.0") == 0))) {
621
622 acmp->acm_compatibility = B_TRUE;
623 } else {
624 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
625 "usbsacm_ds_attach: A nonstandard device is attaching to "
626 "usbsacm driver. This device doesn't conform to "
627 "usb cdc spec.");
628
629 acmp->acm_compatibility = B_FALSE;
630 }
631
632 /* initialize state variables */
633 if (usbsacm_init_alloc_ports(acmp) != USB_SUCCESS) {
634 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
635 "usbsacm_ds_attach: initialize port structure failed.");
636
637 goto fail;
638 }
639 *aip->ai_port_cnt = acmp->acm_port_cnt;
640
641 /* Get max data size of bulk transfer */
642 if (usb_pipe_get_max_bulk_transfer_size(acmp->acm_dip,
643 &acmp->acm_xfer_sz) != USB_SUCCESS) {
644 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
645 "usbsacm_ds_attach: get max size of transfer failed.");
646
647 goto fail;
648 }
649
650 return (USB_SUCCESS);
651 fail:
652 usbsacm_cleanup(acmp);
653
654 return (USB_FAILURE);
655 }
656
657
658 /*
659 * usbsacm_ds_detach:
660 * detach device instance, called from GSD detach
661 */
662 static void
usbsacm_ds_detach(ds_hdl_t hdl)663 usbsacm_ds_detach(ds_hdl_t hdl)
664 {
665 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
666
667 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
668 "usbsacm_ds_detach:");
669
670 usbsacm_close_pipes(acmp);
671 usbsacm_cleanup(acmp);
672 }
673
674
675 /*
676 * usbsacm_ds_register_cb:
677 * GSD routine call ds_register_cb to register interrupt callbacks
678 * for the given port
679 */
680 /*ARGSUSED*/
681 static int
usbsacm_ds_register_cb(ds_hdl_t hdl,uint_t port_num,ds_cb_t * cb)682 usbsacm_ds_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
683 {
684 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
685 usbsacm_port_t *acm_port;
686
687 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
688 "usbsacm_ds_register_cb: acmp = 0x%p port_num = %d",
689 (void *)acmp, port_num);
690
691 /* Check if port number is greater than actual port number. */
692 if (port_num >= acmp->acm_port_cnt) {
693 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
694 "usbsacm_ds_register_cb: port number is wrong.");
695
696 return (USB_FAILURE);
697 }
698 acm_port = &acmp->acm_ports[port_num];
699 acm_port->acm_cb = *cb;
700
701 return (USB_SUCCESS);
702 }
703
704
705 /*
706 * usbsacm_ds_unregister_cb:
707 * GSD routine call ds_unregister_cb to unregister
708 * interrupt callbacks for the given port
709 */
710 /*ARGSUSED*/
711 static void
usbsacm_ds_unregister_cb(ds_hdl_t hdl,uint_t port_num)712 usbsacm_ds_unregister_cb(ds_hdl_t hdl, uint_t port_num)
713 {
714 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
715 usbsacm_port_t *acm_port;
716
717 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
718 "usbsacm_ds_unregister_cb: ");
719
720 if (port_num < acmp->acm_port_cnt) {
721 /* Release callback function */
722 acm_port = &acmp->acm_ports[port_num];
723 bzero(&acm_port->acm_cb, sizeof (acm_port->acm_cb));
724 }
725 }
726
727
728 /*
729 * usbsacm_ds_open_port:
730 * GSD routine call ds_open_port
731 * to open the given port
732 */
733 /*ARGSUSED*/
734 static int
usbsacm_ds_open_port(ds_hdl_t hdl,uint_t port_num)735 usbsacm_ds_open_port(ds_hdl_t hdl, uint_t port_num)
736 {
737 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
738 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
739
740 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
741 "usbsacm_ds_open_port: port_num = %d", port_num);
742
743 mutex_enter(&acm_port->acm_port_mutex);
744 /* Check the status of the given port and device */
745 if ((acmp->acm_dev_state == USB_DEV_DISCONNECTED) ||
746 (acm_port->acm_port_state != USBSACM_PORT_CLOSED)) {
747 mutex_exit(&acm_port->acm_port_mutex);
748
749 return (USB_FAILURE);
750 }
751 mutex_exit(&acm_port->acm_port_mutex);
752
753 usbsacm_pm_set_busy(acmp);
754
755 /* open pipes of port */
756 if (usbsacm_open_port_pipes(acm_port) != USB_SUCCESS) {
757 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
758 "usbsacm_ds_open_port: open pipes failed.");
759
760 return (USB_FAILURE);
761 }
762
763 mutex_enter(&acm_port->acm_port_mutex);
764 /* data receipt */
765 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) {
766 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
767 "usbsacm_ds_open_port: start receive data failed.");
768 mutex_exit(&acm_port->acm_port_mutex);
769
770 return (USB_FAILURE);
771 }
772 acm_port->acm_port_state = USBSACM_PORT_OPEN;
773
774 mutex_exit(&acm_port->acm_port_mutex);
775
776 return (USB_SUCCESS);
777 }
778
779
780 /*
781 * usbsacm_ds_close_port:
782 * GSD routine call ds_close_port
783 * to close the given port
784 */
785 /*ARGSUSED*/
786 static int
usbsacm_ds_close_port(ds_hdl_t hdl,uint_t port_num)787 usbsacm_ds_close_port(ds_hdl_t hdl, uint_t port_num)
788 {
789 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
790 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
791 int rval = USB_SUCCESS;
792
793 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
794 "usbsacm_ds_close_port: acmp = 0x%p", (void *)acmp);
795
796 mutex_enter(&acm_port->acm_port_mutex);
797 acm_port->acm_port_state = USBSACM_PORT_CLOSED;
798 mutex_exit(&acm_port->acm_port_mutex);
799
800 usbsacm_close_port_pipes(acm_port);
801
802 mutex_enter(&acm_port->acm_port_mutex);
803 rval = usbsacm_fifo_flush_locked(acmp, port_num, DS_TX | DS_RX);
804 mutex_exit(&acm_port->acm_port_mutex);
805
806 usbsacm_pm_set_idle(acmp);
807
808 return (rval);
809 }
810
811
812 /*
813 * usbsacm_ds_usb_power:
814 * GSD routine call ds_usb_power
815 * to set power level of the component
816 */
817 /*ARGSUSED*/
818 static int
usbsacm_ds_usb_power(ds_hdl_t hdl,int comp,int level,int * new_state)819 usbsacm_ds_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
820 {
821 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
822 usbsacm_pm_t *pm = acmp->acm_pm;
823 int rval = USB_SUCCESS;
824
825 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
826 "usbsacm_ds_usb_power: ");
827
828 /* check if pm is NULL */
829 if (pm == NULL) {
830 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
831 "usbsacm_ds_usb_power: pm is NULL.");
832
833 return (USB_FAILURE);
834 }
835
836 mutex_enter(&acmp->acm_mutex);
837 /*
838 * check if we are transitioning to a legal power level
839 */
840 if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
841 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
842 "usbsacm_ds_usb_power: "
843 "illegal power level %d, pwr_states=%x",
844 level, pm->pm_pwr_states);
845 mutex_exit(&acmp->acm_mutex);
846
847 return (USB_FAILURE);
848 }
849
850 /*
851 * if we are about to raise power and asked to lower power, fail
852 */
853 if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
854 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
855 "usbsacm_ds_usb_power: wrong condition.");
856 mutex_exit(&acmp->acm_mutex);
857
858 return (USB_FAILURE);
859 }
860
861 /*
862 * Set the power status of device by request level.
863 */
864 switch (level) {
865 case USB_DEV_OS_PWR_OFF:
866 rval = usbsacm_pwrlvl0(acmp);
867
868 break;
869 case USB_DEV_OS_PWR_1:
870 rval = usbsacm_pwrlvl1(acmp);
871
872 break;
873 case USB_DEV_OS_PWR_2:
874 rval = usbsacm_pwrlvl2(acmp);
875
876 break;
877 case USB_DEV_OS_FULL_PWR:
878 rval = usbsacm_pwrlvl3(acmp);
879 /*
880 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
881 * that the usb serial device is disconnected/suspended while it
882 * is under power down state, now the device is powered up
883 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
884 * state to ONLINE, we need to set the dev state back to
885 * DISCONNECTED/SUSPENDED.
886 */
887 if ((rval == USB_SUCCESS) &&
888 ((*new_state == USB_DEV_DISCONNECTED) ||
889 (*new_state == USB_DEV_SUSPENDED))) {
890 acmp->acm_dev_state = *new_state;
891 }
892
893 break;
894 }
895
896 *new_state = acmp->acm_dev_state;
897 mutex_exit(&acmp->acm_mutex);
898
899 return (rval);
900 }
901
902
903 /*
904 * usbsacm_ds_suspend:
905 * GSD routine call ds_suspend
906 * during CPR suspend
907 */
908 static int
usbsacm_ds_suspend(ds_hdl_t hdl)909 usbsacm_ds_suspend(ds_hdl_t hdl)
910 {
911 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
912 int state = USB_DEV_SUSPENDED;
913
914 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
915 "usbsacm_ds_suspend: ");
916 /*
917 * If the device is suspended while it is under PWRED_DOWN state, we
918 * need to keep the PWRED_DOWN state so that it could be powered up
919 * later. In the mean while, usbser dev state will be changed to
920 * SUSPENDED state.
921 */
922 mutex_enter(&acmp->acm_mutex);
923 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) {
924 /* set device status to suspend */
925 acmp->acm_dev_state = USB_DEV_SUSPENDED;
926 }
927 mutex_exit(&acmp->acm_mutex);
928
929 usbsacm_disconnect_pipes(acmp);
930
931 return (state);
932 }
933
934 /*
935 * usbsacm_ds_resume:
936 * GSD routine call ds_resume
937 * during CPR resume
938 */
939 /*ARGSUSED*/
940 static int
usbsacm_ds_resume(ds_hdl_t hdl)941 usbsacm_ds_resume(ds_hdl_t hdl)
942 {
943 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
944 int current_state;
945 int ret;
946
947 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
948 "usbsacm_ds_resume: ");
949
950 mutex_enter(&acmp->acm_mutex);
951 current_state = acmp->acm_dev_state;
952 mutex_exit(&acmp->acm_mutex);
953
954 /* restore the status of device */
955 if (current_state != USB_DEV_ONLINE) {
956 ret = usbsacm_restore_device_state(acmp);
957 } else {
958 ret = USB_DEV_ONLINE;
959 }
960
961 return (ret);
962 }
963
964 /*
965 * usbsacm_ds_disconnect:
966 * GSD routine call ds_disconnect
967 * to disconnect USB device
968 */
969 static int
usbsacm_ds_disconnect(ds_hdl_t hdl)970 usbsacm_ds_disconnect(ds_hdl_t hdl)
971 {
972 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
973 int state = USB_DEV_DISCONNECTED;
974
975 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
976 "usbsacm_ds_disconnect: ");
977
978 /*
979 * If the device is disconnected while it is under PWRED_DOWN state, we
980 * need to keep the PWRED_DOWN state so that it could be powered up
981 * later. In the mean while, usbser dev state will be changed to
982 * DISCONNECTED state.
983 */
984 mutex_enter(&acmp->acm_mutex);
985 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) {
986 /* set device status to disconnected */
987 acmp->acm_dev_state = USB_DEV_DISCONNECTED;
988 }
989 mutex_exit(&acmp->acm_mutex);
990
991 usbsacm_disconnect_pipes(acmp);
992
993 return (state);
994 }
995
996
997 /*
998 * usbsacm_ds_reconnect:
999 * GSD routine call ds_reconnect
1000 * to reconnect USB device
1001 */
1002 /*ARGSUSED*/
1003 static int
usbsacm_ds_reconnect(ds_hdl_t hdl)1004 usbsacm_ds_reconnect(ds_hdl_t hdl)
1005 {
1006 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1007
1008 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
1009 "usbsacm_ds_reconnect: ");
1010
1011 return (usbsacm_restore_device_state(acmp));
1012 }
1013
1014
1015 /*
1016 * usbsacm_ds_set_port_params:
1017 * GSD routine call ds_set_port_params
1018 * to set one or more port parameters
1019 */
1020 /*ARGSUSED*/
1021 static int
usbsacm_ds_set_port_params(ds_hdl_t hdl,uint_t port_num,ds_port_params_t * tp)1022 usbsacm_ds_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
1023 {
1024 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1025 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1026 int i;
1027 uint_t ui;
1028 ds_port_param_entry_t *pe;
1029 usb_cdc_line_coding_t lc;
1030 int ret;
1031
1032 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1033 "usbsacm_ds_set_port_params: acmp = 0x%p", (void *)acmp);
1034
1035 mutex_enter(&acm_port->acm_port_mutex);
1036 /*
1037 * If device conform to acm spec, check if it support to set port param.
1038 */
1039 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
1040 acmp->acm_compatibility == B_TRUE) {
1041
1042 mutex_exit(&acm_port->acm_port_mutex);
1043 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
1044 "usbsacm_ds_set_port_params: "
1045 "don't support Set_Line_Coding.");
1046
1047 return (USB_FAILURE);
1048 }
1049
1050 lc = acm_port->acm_line_coding;
1051 mutex_exit(&acm_port->acm_port_mutex);
1052 pe = tp->tp_entries;
1053 /* Get parameter information from ds_port_params_t */
1054 for (i = 0; i < tp->tp_cnt; i++, pe++) {
1055 switch (pe->param) {
1056 case DS_PARAM_BAUD:
1057 /* Data terminal rate, in bits per second. */
1058 ui = pe->val.ui;
1059
1060 /* if we don't support this speed, return USB_FAILURE */
1061 if ((ui >= NELEM(usbsacm_speedtab)) ||
1062 ((ui > 0) && (usbsacm_speedtab[ui] == 0))) {
1063 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
1064 "usbsacm_ds_set_port_params: "
1065 " error baud rate");
1066
1067 return (USB_FAILURE);
1068 }
1069 lc.dwDTERate = LE_32(usbsacm_speedtab[ui]);
1070
1071 break;
1072 case DS_PARAM_PARITY:
1073 /* Parity Type */
1074 if (pe->val.ui & PARENB) {
1075 if (pe->val.ui & PARODD) {
1076 lc.bParityType = USB_CDC_PARITY_ODD;
1077 } else {
1078 lc.bParityType = USB_CDC_PARITY_EVEN;
1079 }
1080 } else {
1081 lc.bParityType = USB_CDC_PARITY_NO;
1082 }
1083
1084 break;
1085 case DS_PARAM_STOPB:
1086 /* Stop bit */
1087 if (pe->val.ui & CSTOPB) {
1088 lc.bCharFormat = USB_CDC_STOP_BITS_2;
1089 } else {
1090 lc.bCharFormat = USB_CDC_STOP_BITS_1;
1091 }
1092
1093 break;
1094 case DS_PARAM_CHARSZ:
1095 /* Data Bits */
1096 switch (pe->val.ui) {
1097 case CS5:
1098 lc.bDataBits = 5;
1099 break;
1100 case CS6:
1101 lc.bDataBits = 6;
1102 break;
1103 case CS7:
1104 lc.bDataBits = 7;
1105 break;
1106 case CS8:
1107 default:
1108 lc.bDataBits = 8;
1109 break;
1110 }
1111
1112 break;
1113 default:
1114 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
1115 "usbsacm_ds_set_port_params: "
1116 "parameter 0x%x isn't supported",
1117 pe->param);
1118
1119 break;
1120 }
1121 }
1122
1123 if ((ret = usbsacm_set_line_coding(acm_port, &lc)) == USB_SUCCESS) {
1124 mutex_enter(&acm_port->acm_port_mutex);
1125 acm_port->acm_line_coding = lc;
1126 mutex_exit(&acm_port->acm_port_mutex);
1127 }
1128
1129 /*
1130 * If device don't conform to acm spec, return success directly.
1131 */
1132 if (acmp->acm_compatibility != B_TRUE) {
1133 ret = USB_SUCCESS;
1134 }
1135
1136 return (ret);
1137 }
1138
1139
1140 /*
1141 * usbsacm_ds_set_modem_ctl:
1142 * GSD routine call ds_set_modem_ctl
1143 * to set modem control of the given port
1144 */
1145 /*ARGSUSED*/
1146 static int
usbsacm_ds_set_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int val)1147 usbsacm_ds_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
1148 {
1149 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1150 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1151 uint8_t new_mctl;
1152 int ret;
1153
1154 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1155 "usbsacm_ds_set_modem_ctl: mask = 0x%x val = 0x%x",
1156 mask, val);
1157
1158 mutex_enter(&acm_port->acm_port_mutex);
1159 /*
1160 * If device conform to acm spec, check if it support to set modem
1161 * controls.
1162 */
1163 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
1164 acmp->acm_compatibility == B_TRUE) {
1165
1166 mutex_exit(&acm_port->acm_port_mutex);
1167 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
1168 "usbsacm_ds_set_modem_ctl: "
1169 "don't support Set_Control_Line_State.");
1170
1171 return (USB_FAILURE);
1172 }
1173
1174 new_mctl = acm_port->acm_mctlout;
1175 mutex_exit(&acm_port->acm_port_mutex);
1176
1177 usbsacm_mctl2reg(mask, val, &new_mctl);
1178
1179 if ((acmp->acm_compatibility == B_FALSE) || ((ret =
1180 usbsacm_req_write(acm_port, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
1181 new_mctl, NULL)) == USB_SUCCESS)) {
1182 mutex_enter(&acm_port->acm_port_mutex);
1183 acm_port->acm_mctlout = new_mctl;
1184 mutex_exit(&acm_port->acm_port_mutex);
1185 }
1186
1187 /*
1188 * If device don't conform to acm spec, return success directly.
1189 */
1190 if (acmp->acm_compatibility != B_TRUE) {
1191 ret = USB_SUCCESS;
1192 }
1193
1194 return (ret);
1195 }
1196
1197
1198 /*
1199 * usbsacm_ds_get_modem_ctl:
1200 * GSD routine call ds_get_modem_ctl
1201 * to get modem control/status of the given port
1202 */
1203 /*ARGSUSED*/
1204 static int
usbsacm_ds_get_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int * valp)1205 usbsacm_ds_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
1206 {
1207 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1208 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1209
1210 mutex_enter(&acm_port->acm_port_mutex);
1211 *valp = usbsacm_reg2mctl(acm_port->acm_mctlout) & mask;
1212 /*
1213 * If device conform to acm spec, polling function can modify the value
1214 * of acm_mctlin; else set to default value.
1215 */
1216 if (acmp->acm_compatibility) {
1217 *valp |= usbsacm_reg2mctl(acm_port->acm_mctlin) & mask;
1218 *valp |= (mask & (TIOCM_CD | TIOCM_CTS));
1219 } else {
1220 *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
1221 }
1222 mutex_exit(&acm_port->acm_port_mutex);
1223
1224 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1225 "usbsacm_ds_get_modem_ctl: val = 0x%x", *valp);
1226
1227 return (USB_SUCCESS);
1228 }
1229
1230
1231 /*
1232 * usbsacm_ds_tx:
1233 * GSD routine call ds_break_ctl
1234 * to set/clear break
1235 */
1236 /*ARGSUSED*/
1237 static int
usbsacm_ds_break_ctl(ds_hdl_t hdl,uint_t port_num,int ctl)1238 usbsacm_ds_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
1239 {
1240 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1241 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1242
1243 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1244 "usbsacm_ds_break_ctl: ");
1245
1246 mutex_enter(&acm_port->acm_port_mutex);
1247 /*
1248 * If device conform to acm spec, check if it support to send break.
1249 */
1250 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SEND_BREAK) == 0 &&
1251 acmp->acm_compatibility == B_TRUE) {
1252
1253 mutex_exit(&acm_port->acm_port_mutex);
1254 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
1255 "usbsacm_ds_break_ctl: don't support send break.");
1256
1257 return (USB_FAILURE);
1258 }
1259 mutex_exit(&acm_port->acm_port_mutex);
1260
1261 return (usbsacm_req_write(acm_port, USB_CDC_REQ_SEND_BREAK,
1262 ((ctl == DS_ON) ? 0xffff : 0), NULL));
1263 }
1264
1265
1266 /*
1267 * usbsacm_ds_tx:
1268 * GSD routine call ds_tx
1269 * to data transmit
1270 */
1271 /*ARGSUSED*/
1272 static int
usbsacm_ds_tx(ds_hdl_t hdl,uint_t port_num,mblk_t * mp)1273 usbsacm_ds_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
1274 {
1275 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1276 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1277
1278 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1279 "usbsacm_ds_tx: mp = 0x%p acmp = 0x%p", (void *)mp, (void *)acmp);
1280
1281 /* sanity checks */
1282 if (mp == NULL) {
1283
1284 return (USB_SUCCESS);
1285 }
1286 if (MBLKL(mp) < 1) {
1287 freemsg(mp);
1288
1289 return (USB_SUCCESS);
1290 }
1291
1292 mutex_enter(&acm_port->acm_port_mutex);
1293 /* put mblk to tail of mblk chain */
1294 usbsacm_put_tail(&acm_port->acm_tx_mp, mp);
1295 usbsacm_tx_start(acm_port);
1296 mutex_exit(&acm_port->acm_port_mutex);
1297
1298 return (USB_SUCCESS);
1299 }
1300
1301
1302 /*
1303 * usbsacm_ds_rx:
1304 * GSD routine call ds_rx;
1305 * to data receipt
1306 */
1307 /*ARGSUSED*/
1308 static mblk_t *
usbsacm_ds_rx(ds_hdl_t hdl,uint_t port_num)1309 usbsacm_ds_rx(ds_hdl_t hdl, uint_t port_num)
1310 {
1311 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1312 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1313 mblk_t *mp;
1314
1315 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1316 "usbsacm_ds_rx: acmp = 0x%p", (void *)acmp);
1317
1318 mutex_enter(&acm_port->acm_port_mutex);
1319
1320 mp = acm_port->acm_rx_mp;
1321 acm_port->acm_rx_mp = NULL;
1322 mutex_exit(&acm_port->acm_port_mutex);
1323
1324 return (mp);
1325 }
1326
1327
1328 /*
1329 * usbsacm_ds_stop:
1330 * GSD routine call ds_stop;
1331 * but acm spec don't define this function
1332 */
1333 /*ARGSUSED*/
1334 static void
usbsacm_ds_stop(ds_hdl_t hdl,uint_t port_num,int dir)1335 usbsacm_ds_stop(ds_hdl_t hdl, uint_t port_num, int dir)
1336 {
1337 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1338
1339 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
1340 "usbsacm_ds_stop: don't support!");
1341 }
1342
1343
1344 /*
1345 * usbsacm_ds_start:
1346 * GSD routine call ds_start;
1347 * but acm spec don't define this function
1348 */
1349 /*ARGSUSED*/
1350 static void
usbsacm_ds_start(ds_hdl_t hdl,uint_t port_num,int dir)1351 usbsacm_ds_start(ds_hdl_t hdl, uint_t port_num, int dir)
1352 {
1353 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1354
1355 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
1356 "usbsacm_ds_start: don't support!");
1357 }
1358
1359
1360 /*
1361 * usbsacm_ds_fifo_flush:
1362 * GSD routine call ds_fifo_flush
1363 * to flush FIFOs
1364 */
1365 /*ARGSUSED*/
1366 static int
usbsacm_ds_fifo_flush(ds_hdl_t hdl,uint_t port_num,int dir)1367 usbsacm_ds_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
1368 {
1369 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1370 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1371 int ret = USB_SUCCESS;
1372
1373 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1374 "usbsacm_ds_fifo_flush: ");
1375
1376 mutex_enter(&acm_port->acm_port_mutex);
1377 ret = usbsacm_fifo_flush_locked(acmp, port_num, dir);
1378 mutex_exit(&acm_port->acm_port_mutex);
1379
1380 return (ret);
1381 }
1382
1383
1384 /*
1385 * usbsacm_ds_fifo_drain:
1386 * GSD routine call ds_fifo_drain
1387 * to wait until empty output FIFO
1388 */
1389 /*ARGSUSED*/
1390 static int
usbsacm_ds_fifo_drain(ds_hdl_t hdl,uint_t port_num,int timeout)1391 usbsacm_ds_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
1392 {
1393 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
1394 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1395 int rval = USB_SUCCESS;
1396
1397 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
1398 "usbsacm_ds_fifo_drain: ");
1399
1400 mutex_enter(&acm_port->acm_port_mutex);
1401 ASSERT(acm_port->acm_port_state == USBSACM_PORT_OPEN);
1402
1403 if (usbsacm_wait_tx_drain(acm_port, timeout) != USB_SUCCESS) {
1404 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
1405 "usbsacm_ds_fifo_drain: fifo drain failed.");
1406 mutex_exit(&acm_port->acm_port_mutex);
1407
1408 return (USB_FAILURE);
1409 }
1410
1411 mutex_exit(&acm_port->acm_port_mutex);
1412
1413 return (rval);
1414 }
1415
1416
1417 /*
1418 * usbsacm_fifo_flush_locked:
1419 * flush FIFOs of the given ports
1420 */
1421 /*ARGSUSED*/
1422 static int
usbsacm_fifo_flush_locked(usbsacm_state_t * acmp,uint_t port_num,int dir)1423 usbsacm_fifo_flush_locked(usbsacm_state_t *acmp, uint_t port_num, int dir)
1424 {
1425 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
1426
1427 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
1428 "usbsacm_fifo_flush_locked: ");
1429
1430 /* flush transmit FIFO if DS_TX is set */
1431 if ((dir & DS_TX) && acm_port->acm_tx_mp) {
1432 freemsg(acm_port->acm_tx_mp);
1433 acm_port->acm_tx_mp = NULL;
1434 }
1435 /* flush received FIFO if DS_RX is set */
1436 if ((dir & DS_RX) && acm_port->acm_rx_mp) {
1437 freemsg(acm_port->acm_rx_mp);
1438 acm_port->acm_rx_mp = NULL;
1439 }
1440
1441 return (USB_SUCCESS);
1442 }
1443
1444
1445 /*
1446 * usbsacm_get_bulk_pipe_number:
1447 * Calculate the number of bulk in or out pipes in current device.
1448 */
1449 static int
usbsacm_get_bulk_pipe_number(usbsacm_state_t * acmp,uint_t dir)1450 usbsacm_get_bulk_pipe_number(usbsacm_state_t *acmp, uint_t dir)
1451 {
1452 int count = 0;
1453 int i, skip;
1454 usb_if_data_t *cur_if;
1455 int ep_num;
1456 int if_num;
1457
1458 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
1459 "usbsacm_get_bulk_pipe_number: ");
1460
1461 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if;
1462 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if;
1463
1464 /* search each interface which have bulk endpoint */
1465 for (i = 0; i < if_num; i++) {
1466 ep_num = cur_if->if_alt->altif_n_ep;
1467
1468 /*
1469 * search endpoints in current interface,
1470 * which type is input parameter 'dir'
1471 */
1472 for (skip = 0; skip < ep_num; skip++) {
1473 if (usb_lookup_ep_data(acmp->acm_dip,
1474 acmp->acm_dev_data, i, 0, skip,
1475 USB_EP_ATTR_BULK, dir) == NULL) {
1476
1477 /*
1478 * If not found, skip the internal loop
1479 * and search the next interface.
1480 */
1481 break;
1482 }
1483 count++;
1484 }
1485
1486 cur_if++;
1487 }
1488
1489 return (count);
1490 }
1491
1492
1493 /*
1494 * port management
1495 * ---------------
1496 * initialize, release port.
1497 *
1498 *
1499 * usbsacm_init_ports_status:
1500 * Initialize the port status for the current device.
1501 */
1502 static int
usbsacm_init_ports_status(usbsacm_state_t * acmp)1503 usbsacm_init_ports_status(usbsacm_state_t *acmp)
1504 {
1505 usbsacm_port_t *cur_port;
1506 int i, skip;
1507 int if_num;
1508 int intr_if_no = 0;
1509 int ep_num;
1510 usb_if_data_t *cur_if;
1511
1512 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
1513 "usbsacm_init_ports_status: acmp = 0x%p", (void *)acmp);
1514
1515 /* Initialize the port status to default value */
1516 for (i = 0; i < acmp->acm_port_cnt; i++) {
1517 cur_port = &acmp->acm_ports[i];
1518
1519 cv_init(&cur_port->acm_tx_cv, NULL, CV_DRIVER, NULL);
1520
1521 cur_port->acm_port_state = USBSACM_PORT_CLOSED;
1522
1523 cur_port->acm_line_coding.dwDTERate = LE_32((uint32_t)9600);
1524 cur_port->acm_line_coding.bCharFormat = 0;
1525 cur_port->acm_line_coding.bParityType = USB_CDC_PARITY_NO;
1526 cur_port->acm_line_coding.bDataBits = 8;
1527 cur_port->acm_device = acmp;
1528 mutex_init(&cur_port->acm_port_mutex, NULL, MUTEX_DRIVER,
1529 acmp->acm_dev_data->dev_iblock_cookie);
1530 }
1531
1532 /*
1533 * If device conform to cdc acm spec, parse function descriptors.
1534 */
1535 if (acmp->acm_compatibility == B_TRUE) {
1536
1537 if (usbsacm_get_descriptors(acmp) != USB_SUCCESS) {
1538
1539 return (USB_FAILURE);
1540 }
1541
1542 return (USB_SUCCESS);
1543 }
1544
1545 /*
1546 * If device don't conform to spec, search pairs of bulk in/out
1547 * endpoints and fill port structure.
1548 */
1549 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if;
1550 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if;
1551 cur_port = acmp->acm_ports;
1552
1553 /* search each interface which have bulk in and out */
1554 for (i = 0; i < if_num; i++) {
1555 ep_num = cur_if->if_alt->altif_n_ep;
1556
1557 for (skip = 0; skip < ep_num; skip++) {
1558
1559 /* search interrupt pipe. */
1560 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1561 i, 0, skip, USB_EP_ATTR_INTR, USB_EP_DIR_IN) != NULL)) {
1562
1563 intr_if_no = i;
1564 }
1565
1566 /* search pair of bulk in/out endpoints. */
1567 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1568 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_IN) == NULL) ||
1569 (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1570 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT) == NULL)) {
1571
1572 continue;
1573 }
1574
1575 cur_port->acm_data_if_no = i;
1576 cur_port->acm_ctrl_if_no = intr_if_no;
1577 cur_port->acm_data_port_no = skip;
1578 cur_port++;
1579 intr_if_no = 0;
1580 }
1581
1582 cur_if++;
1583 }
1584
1585 return (USB_SUCCESS);
1586 }
1587
1588
1589 /*
1590 * usbsacm_init_alloc_ports:
1591 * Allocate memory and initialize the port state for the current device.
1592 */
1593 static int
usbsacm_init_alloc_ports(usbsacm_state_t * acmp)1594 usbsacm_init_alloc_ports(usbsacm_state_t *acmp)
1595 {
1596 int rval = USB_SUCCESS;
1597 int count_in = 0, count_out = 0;
1598
1599 if (acmp->acm_compatibility) {
1600 acmp->acm_port_cnt = 1;
1601 } else {
1602 /* Calculate the number of the bulk in/out endpoints */
1603 count_in = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_IN);
1604 count_out = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_OUT);
1605
1606 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh,
1607 "usbsacm_init_alloc_ports: count_in = %d, count_out = %d",
1608 count_in, count_out);
1609
1610 acmp->acm_port_cnt = min(count_in, count_out);
1611 }
1612
1613 /* return if not found any pair of bulk in/out endpoint. */
1614 if (acmp->acm_port_cnt == 0) {
1615 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
1616 "usbsacm_init_alloc_ports: port count is zero.");
1617
1618 return (USB_FAILURE);
1619 }
1620
1621 /* allocate memory for ports */
1622 acmp->acm_ports = (usbsacm_port_t *)kmem_zalloc(acmp->acm_port_cnt *
1623 sizeof (usbsacm_port_t), KM_SLEEP);
1624 if (acmp->acm_ports == NULL) {
1625 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
1626 "usbsacm_init_alloc_ports: allocate memory failed.");
1627
1628 return (USB_FAILURE);
1629 }
1630
1631 /* fill the status of port structure. */
1632 rval = usbsacm_init_ports_status(acmp);
1633 if (rval != USB_SUCCESS) {
1634 usbsacm_free_ports(acmp);
1635 }
1636
1637 return (rval);
1638 }
1639
1640
1641 /*
1642 * usbsacm_free_ports:
1643 * Release ports and deallocate memory.
1644 */
1645 static void
usbsacm_free_ports(usbsacm_state_t * acmp)1646 usbsacm_free_ports(usbsacm_state_t *acmp)
1647 {
1648 int i;
1649
1650 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
1651 "usbsacm_free_ports: ");
1652
1653 /* Release memory and data structure for each port */
1654 for (i = 0; i < acmp->acm_port_cnt; i++) {
1655 cv_destroy(&acmp->acm_ports[i].acm_tx_cv);
1656 mutex_destroy(&acmp->acm_ports[i].acm_port_mutex);
1657 }
1658 kmem_free((caddr_t)acmp->acm_ports, sizeof (usbsacm_port_t) *
1659 acmp->acm_port_cnt);
1660 acmp->acm_ports = NULL;
1661 }
1662
1663
1664 /*
1665 * usbsacm_get_descriptors:
1666 * analysis functional descriptors of acm device
1667 */
1668 static int
usbsacm_get_descriptors(usbsacm_state_t * acmp)1669 usbsacm_get_descriptors(usbsacm_state_t *acmp)
1670 {
1671 int i;
1672 usb_cfg_data_t *cfg;
1673 usb_alt_if_data_t *altif;
1674 usb_cvs_data_t *cvs;
1675 int mgmt_cap = 0;
1676 int master_if = -1, slave_if = -1;
1677 usbsacm_port_t *acm_port = acmp->acm_ports;
1678
1679 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
1680 "usbsacm_get_descriptors: ");
1681
1682 cfg = acmp->acm_dev_data->dev_curr_cfg;
1683 /* set default control and data interface */
1684 acm_port->acm_ctrl_if_no = acm_port->acm_data_if_no = 0;
1685
1686 /* get current interfaces */
1687 acm_port->acm_ctrl_if_no = acmp->acm_dev_data->dev_curr_if;
1688 if (cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt == 0) {
1689 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1690 "usbsacm_get_descriptors: elements in if_alt is %d",
1691 cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt);
1692
1693 return (USB_FAILURE);
1694 }
1695
1696 altif = &cfg->cfg_if[acm_port->acm_ctrl_if_no].if_alt[0];
1697
1698 /*
1699 * Based on CDC specification, ACM devices usually include the
1700 * following function descriptors: Header, ACM, Union and Call
1701 * Management function descriptors. This loop search tree data
1702 * structure for each acm class descriptor.
1703 */
1704 for (i = 0; i < altif->altif_n_cvs; i++) {
1705
1706 cvs = &altif->altif_cvs[i];
1707
1708 if ((cvs->cvs_buf == NULL) ||
1709 (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) {
1710 continue;
1711 }
1712
1713 switch (cvs->cvs_buf[2]) {
1714 case USB_CDC_DESCR_TYPE_CALL_MANAGEMENT:
1715 /* parse call management functional descriptor. */
1716 if (cvs->cvs_buf_len >= 5) {
1717 mgmt_cap = cvs->cvs_buf[3];
1718 acm_port->acm_data_if_no = cvs->cvs_buf[4];
1719 }
1720 break;
1721 case USB_CDC_DESCR_TYPE_ACM:
1722 /* parse ACM functional descriptor. */
1723 if (cvs->cvs_buf_len >= 4) {
1724 acm_port->acm_cap = cvs->cvs_buf[3];
1725 }
1726 break;
1727 case USB_CDC_DESCR_TYPE_UNION:
1728 /* parse Union functional descriptor. */
1729 if (cvs->cvs_buf_len >= 5) {
1730 master_if = cvs->cvs_buf[3];
1731 slave_if = cvs->cvs_buf[4];
1732 }
1733 break;
1734 default:
1735 break;
1736 }
1737 }
1738
1739 /* For usb acm devices, it must satisfy the following options. */
1740 if (cfg->cfg_n_if < 2) {
1741 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1742 "usbsacm_get_descriptors: # of interfaces %d < 2",
1743 cfg->cfg_n_if);
1744
1745 return (USB_FAILURE);
1746 }
1747
1748 if (acm_port->acm_data_if_no == 0 &&
1749 slave_if != acm_port->acm_data_if_no) {
1750 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1751 "usbsacm_get_descriptors: Device hasn't call management "
1752 "descriptor and use Union Descriptor.");
1753
1754 acm_port->acm_data_if_no = slave_if;
1755 }
1756
1757 if ((master_if != acm_port->acm_ctrl_if_no) ||
1758 (slave_if != acm_port->acm_data_if_no)) {
1759 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1760 "usbsacm_get_descriptors: control interface or "
1761 "data interface don't match.");
1762
1763 return (USB_FAILURE);
1764 }
1765
1766 /*
1767 * We usually need both call and data capabilities, but
1768 * some devices, such as Nokia mobile phones, don't provide
1769 * call management descriptor, so we just give a warning
1770 * message.
1771 */
1772 if (((mgmt_cap & USB_CDC_CALL_MGMT_CAP_CALL_MGMT) == 0) ||
1773 ((mgmt_cap & USB_CDC_CALL_MGMT_CAP_DATA_INTERFACE) == 0)) {
1774 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1775 "usbsacm_get_descriptors: "
1776 "insufficient mgmt capabilities %x",
1777 mgmt_cap);
1778 }
1779
1780 if ((acm_port->acm_ctrl_if_no >= cfg->cfg_n_if) ||
1781 (acm_port->acm_data_if_no >= cfg->cfg_n_if)) {
1782 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1783 "usbsacm_get_descriptors: control interface %d or "
1784 "data interface %d out of range.",
1785 acm_port->acm_ctrl_if_no, acm_port->acm_data_if_no);
1786
1787 return (USB_FAILURE);
1788 }
1789
1790 /* control interface must have interrupt endpoint */
1791 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1792 acm_port->acm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR,
1793 USB_EP_DIR_IN) == NULL) {
1794 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1795 "usbsacm_get_descriptors: "
1796 "ctrl interface %d has no interrupt endpoint",
1797 acm_port->acm_data_if_no);
1798
1799 return (USB_FAILURE);
1800 }
1801
1802 /* data interface must have bulk in and out */
1803 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1804 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK,
1805 USB_EP_DIR_IN) == NULL) {
1806 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1807 "usbsacm_get_descriptors: "
1808 "data interface %d has no bulk in endpoint",
1809 acm_port->acm_data_if_no);
1810
1811 return (USB_FAILURE);
1812 }
1813 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1814 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK,
1815 USB_EP_DIR_OUT) == NULL) {
1816 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1817 "usbsacm_get_descriptors: "
1818 "data interface %d has no bulk out endpoint",
1819 acm_port->acm_data_if_no);
1820
1821 return (USB_FAILURE);
1822 }
1823
1824 return (USB_SUCCESS);
1825 }
1826
1827
1828 /*
1829 * usbsacm_cleanup:
1830 * Release resources of current device during detach.
1831 */
1832 static void
usbsacm_cleanup(usbsacm_state_t * acmp)1833 usbsacm_cleanup(usbsacm_state_t *acmp)
1834 {
1835 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
1836 "usbsacm_cleanup: ");
1837
1838 if (acmp != NULL) {
1839 /* free ports */
1840 if (acmp->acm_ports != NULL) {
1841 usbsacm_free_ports(acmp);
1842 }
1843
1844 /* unregister callback function */
1845 if (acmp->acm_usb_events != NULL) {
1846 usb_unregister_event_cbs(acmp->acm_dip,
1847 acmp->acm_usb_events);
1848 }
1849
1850 /* destroy power management components */
1851 if (acmp->acm_pm != NULL) {
1852 usbsacm_destroy_pm_components(acmp);
1853 }
1854
1855 /* free description of device tree. */
1856 if (acmp->acm_def_ph != NULL) {
1857 mutex_destroy(&acmp->acm_mutex);
1858
1859 usb_free_descr_tree(acmp->acm_dip, acmp->acm_dev_data);
1860 acmp->acm_def_ph = NULL;
1861 }
1862
1863 if (acmp->acm_lh != NULL) {
1864 usb_free_log_hdl(acmp->acm_lh);
1865 acmp->acm_lh = NULL;
1866 }
1867
1868 /* detach client device */
1869 if (acmp->acm_dev_data != NULL) {
1870 usb_client_detach(acmp->acm_dip, acmp->acm_dev_data);
1871 }
1872
1873 kmem_free((caddr_t)acmp, sizeof (usbsacm_state_t));
1874 }
1875 }
1876
1877
1878 /*
1879 * usbsacm_restore_device_state:
1880 * restore device state after CPR resume or reconnect
1881 */
1882 static int
usbsacm_restore_device_state(usbsacm_state_t * acmp)1883 usbsacm_restore_device_state(usbsacm_state_t *acmp)
1884 {
1885 int state;
1886
1887 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1888 "usbsacm_restore_device_state: ");
1889
1890 mutex_enter(&acmp->acm_mutex);
1891 state = acmp->acm_dev_state;
1892 mutex_exit(&acmp->acm_mutex);
1893
1894 /* Check device status */
1895 if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1896
1897 return (state);
1898 }
1899
1900 /* Check if we are talking to the same device */
1901 if (usb_check_same_device(acmp->acm_dip, acmp->acm_lh, USB_LOG_L0,
1902 -1, USB_CHK_ALL, NULL) != USB_SUCCESS) {
1903 mutex_enter(&acmp->acm_mutex);
1904 state = acmp->acm_dev_state = USB_DEV_DISCONNECTED;
1905 mutex_exit(&acmp->acm_mutex);
1906
1907 return (state);
1908 }
1909
1910 if (state == USB_DEV_DISCONNECTED) {
1911 USB_DPRINTF_L1(PRINT_MASK_ALL, acmp->acm_lh,
1912 "usbsacm_restore_device_state: Device has been reconnected "
1913 "but data may have been lost");
1914 }
1915
1916 /* reconnect pipes */
1917 if (usbsacm_reconnect_pipes(acmp) != USB_SUCCESS) {
1918
1919 return (state);
1920 }
1921
1922 /*
1923 * init device state
1924 */
1925 mutex_enter(&acmp->acm_mutex);
1926 state = acmp->acm_dev_state = USB_DEV_ONLINE;
1927 mutex_exit(&acmp->acm_mutex);
1928
1929 if ((usbsacm_restore_port_state(acmp) != USB_SUCCESS)) {
1930 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1931 "usbsacm_restore_device_state: failed");
1932 }
1933
1934 return (state);
1935 }
1936
1937
1938 /*
1939 * usbsacm_restore_port_state:
1940 * restore ports state after CPR resume or reconnect
1941 */
1942 static int
usbsacm_restore_port_state(usbsacm_state_t * acmp)1943 usbsacm_restore_port_state(usbsacm_state_t *acmp)
1944 {
1945 int i, ret = USB_SUCCESS;
1946 usbsacm_port_t *cur_port;
1947
1948 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
1949 "usbsacm_restore_port_state: ");
1950
1951 /* restore status of all ports */
1952 for (i = 0; i < acmp->acm_port_cnt; i++) {
1953 cur_port = &acmp->acm_ports[i];
1954 mutex_enter(&cur_port->acm_port_mutex);
1955 if (cur_port->acm_port_state != USBSACM_PORT_OPEN) {
1956 mutex_exit(&cur_port->acm_port_mutex);
1957
1958 continue;
1959 }
1960 mutex_exit(&cur_port->acm_port_mutex);
1961
1962 if ((ret = usbsacm_set_line_coding(cur_port,
1963 &cur_port->acm_line_coding)) != USB_SUCCESS) {
1964 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
1965 "usbsacm_restore_port_state: failed.");
1966 }
1967 }
1968
1969 return (ret);
1970 }
1971
1972
1973 /*
1974 * pipe management
1975 * ---------------
1976 *
1977 *
1978 * usbsacm_open_port_pipes:
1979 * Open pipes of one port and set port structure;
1980 * Each port includes three pipes: bulk in, bulk out and interrupt.
1981 */
1982 static int
usbsacm_open_port_pipes(usbsacm_port_t * acm_port)1983 usbsacm_open_port_pipes(usbsacm_port_t *acm_port)
1984 {
1985 int rval = USB_SUCCESS;
1986 usbsacm_state_t *acmp = acm_port->acm_device;
1987 usb_ep_data_t *in_data, *out_data, *intr_pipe;
1988 usb_pipe_policy_t policy;
1989
1990 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
1991 "usbsacm_open_port_pipes: acmp = 0x%p", (void *)acmp);
1992
1993 /* Get bulk and interrupt endpoint data */
1994 intr_pipe = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1995 acm_port->acm_ctrl_if_no, 0, 0,
1996 USB_EP_ATTR_INTR, USB_EP_DIR_IN);
1997 in_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
1998 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no,
1999 USB_EP_ATTR_BULK, USB_EP_DIR_IN);
2000 out_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
2001 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no,
2002 USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
2003
2004 /* Bulk in and out must exist meanwhile. */
2005 if ((in_data == NULL) || (out_data == NULL)) {
2006 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2007 "usbsacm_open_port_pipes: look up bulk pipe failed in "
2008 "interface %d port %d",
2009 acm_port->acm_data_if_no, acm_port->acm_data_port_no);
2010
2011 return (USB_FAILURE);
2012 }
2013
2014 /*
2015 * If device conform to acm spec, it must have an interrupt pipe
2016 * for this port.
2017 */
2018 if (acmp->acm_compatibility == B_TRUE && intr_pipe == NULL) {
2019 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2020 "usbsacm_open_port_pipes: look up interrupt pipe failed in "
2021 "interface %d", acm_port->acm_ctrl_if_no);
2022
2023 return (USB_FAILURE);
2024 }
2025
2026 policy.pp_max_async_reqs = 2;
2027
2028 /* Open bulk in endpoint */
2029 if (usb_pipe_open(acmp->acm_dip, &in_data->ep_descr, &policy,
2030 USB_FLAGS_SLEEP, &acm_port->acm_bulkin_ph) != USB_SUCCESS) {
2031 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2032 "usbsacm_open_port_pipes: open bulkin pipe failed!");
2033
2034 return (USB_FAILURE);
2035 }
2036
2037 /* Open bulk out endpoint */
2038 if (usb_pipe_open(acmp->acm_dip, &out_data->ep_descr, &policy,
2039 USB_FLAGS_SLEEP, &acm_port->acm_bulkout_ph) != USB_SUCCESS) {
2040 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2041 "usbsacm_open_port_pipes: open bulkout pipe failed!");
2042
2043 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
2044 USB_FLAGS_SLEEP, NULL, NULL);
2045
2046 return (USB_FAILURE);
2047 }
2048
2049 /* Open interrupt endpoint if found. */
2050 if (intr_pipe != NULL) {
2051
2052 if (usb_pipe_open(acmp->acm_dip, &intr_pipe->ep_descr, &policy,
2053 USB_FLAGS_SLEEP, &acm_port->acm_intr_ph) != USB_SUCCESS) {
2054 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2055 "usbsacm_open_port_pipes: "
2056 "open control pipe failed");
2057
2058 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
2059 USB_FLAGS_SLEEP, NULL, NULL);
2060 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph,
2061 USB_FLAGS_SLEEP, NULL, NULL);
2062
2063 return (USB_FAILURE);
2064 }
2065 }
2066
2067 /* initialize the port structure. */
2068 mutex_enter(&acm_port->acm_port_mutex);
2069 acm_port->acm_bulkin_size = in_data->ep_descr.wMaxPacketSize;
2070 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
2071 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
2072 if (acm_port->acm_intr_ph != NULL) {
2073 acm_port->acm_intr_state = USBSACM_PIPE_IDLE;
2074 acm_port->acm_intr_ep_descr = intr_pipe->ep_descr;
2075 }
2076 mutex_exit(&acm_port->acm_port_mutex);
2077
2078 if (acm_port->acm_intr_ph != NULL) {
2079
2080 usbsacm_pipe_start_polling(acm_port);
2081 }
2082
2083 return (rval);
2084 }
2085
2086
2087 /*
2088 * usbsacm_close_port_pipes:
2089 * Close pipes of one port and reset port structure to closed;
2090 * Each port includes three pipes: bulk in, bulk out and interrupt.
2091 */
2092 static void
usbsacm_close_port_pipes(usbsacm_port_t * acm_port)2093 usbsacm_close_port_pipes(usbsacm_port_t *acm_port)
2094 {
2095 usbsacm_state_t *acmp = acm_port->acm_device;
2096
2097 mutex_enter(&acm_port->acm_port_mutex);
2098 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
2099 "usbsacm_close_port_pipes: acm_bulkin_state = %d",
2100 acm_port->acm_bulkin_state);
2101
2102 /*
2103 * Check the status of the given port. If port is closing or closed,
2104 * return directly.
2105 */
2106 if ((acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSED) ||
2107 (acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSING)) {
2108 USB_DPRINTF_L2(PRINT_MASK_CLOSE, acmp->acm_lh,
2109 "usbsacm_close_port_pipes: port is closing or has closed");
2110 mutex_exit(&acm_port->acm_port_mutex);
2111
2112 return;
2113 }
2114
2115 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSING;
2116 mutex_exit(&acm_port->acm_port_mutex);
2117
2118 /* Close pipes */
2119 usb_pipe_reset(acmp->acm_dip, acm_port->acm_bulkin_ph,
2120 USB_FLAGS_SLEEP, 0, 0);
2121 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
2122 USB_FLAGS_SLEEP, 0, 0);
2123 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph,
2124 USB_FLAGS_SLEEP, 0, 0);
2125 if (acm_port->acm_intr_ph != NULL) {
2126 usb_pipe_stop_intr_polling(acm_port->acm_intr_ph,
2127 USB_FLAGS_SLEEP);
2128 usb_pipe_close(acmp->acm_dip, acm_port->acm_intr_ph,
2129 USB_FLAGS_SLEEP, 0, 0);
2130 }
2131
2132 mutex_enter(&acm_port->acm_port_mutex);
2133 /* Reset the status of pipes to closed */
2134 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSED;
2135 acm_port->acm_bulkin_ph = NULL;
2136 acm_port->acm_bulkout_state = USBSACM_PIPE_CLOSED;
2137 acm_port->acm_bulkout_ph = NULL;
2138 if (acm_port->acm_intr_ph != NULL) {
2139 acm_port->acm_intr_state = USBSACM_PIPE_CLOSED;
2140 acm_port->acm_intr_ph = NULL;
2141 }
2142
2143 mutex_exit(&acm_port->acm_port_mutex);
2144
2145 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
2146 "usbsacm_close_port_pipes: port has been closed.");
2147 }
2148
2149
2150 /*
2151 * usbsacm_close_pipes:
2152 * close all opened pipes of current devices.
2153 */
2154 static void
usbsacm_close_pipes(usbsacm_state_t * acmp)2155 usbsacm_close_pipes(usbsacm_state_t *acmp)
2156 {
2157 int i;
2158
2159 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
2160 "usbsacm_close_pipes: ");
2161
2162 /* Close all ports */
2163 for (i = 0; i < acmp->acm_port_cnt; i++) {
2164 usbsacm_close_port_pipes(&acmp->acm_ports[i]);
2165 }
2166 }
2167
2168
2169 /*
2170 * usbsacm_disconnect_pipes:
2171 * this function just call usbsacm_close_pipes.
2172 */
2173 static void
usbsacm_disconnect_pipes(usbsacm_state_t * acmp)2174 usbsacm_disconnect_pipes(usbsacm_state_t *acmp)
2175 {
2176 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
2177 "usbsacm_disconnect_pipes: ");
2178
2179 usbsacm_close_pipes(acmp);
2180 }
2181
2182
2183 /*
2184 * usbsacm_reconnect_pipes:
2185 * reconnect pipes in CPR resume or reconnect
2186 */
2187 static int
usbsacm_reconnect_pipes(usbsacm_state_t * acmp)2188 usbsacm_reconnect_pipes(usbsacm_state_t *acmp)
2189 {
2190 usbsacm_port_t *cur_port = acmp->acm_ports;
2191 int i;
2192
2193 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
2194 "usbsacm_reconnect_pipes: ");
2195
2196 /* reopen all ports of current device. */
2197 for (i = 0; i < acmp->acm_port_cnt; i++) {
2198 cur_port = &acmp->acm_ports[i];
2199
2200 mutex_enter(&cur_port->acm_port_mutex);
2201 /*
2202 * If port status is open, reopen it;
2203 * else retain the current status.
2204 */
2205 if (cur_port->acm_port_state == USBSACM_PORT_OPEN) {
2206
2207 mutex_exit(&cur_port->acm_port_mutex);
2208 if (usbsacm_open_port_pipes(cur_port) != USB_SUCCESS) {
2209 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
2210 "usbsacm_reconnect_pipes: "
2211 "open port %d failed.", i);
2212
2213 return (USB_FAILURE);
2214 }
2215 mutex_enter(&cur_port->acm_port_mutex);
2216 }
2217 mutex_exit(&cur_port->acm_port_mutex);
2218 }
2219
2220 return (USB_SUCCESS);
2221 }
2222
2223 /*
2224 * usbsacm_bulkin_cb:
2225 * Bulk In regular and exeception callback;
2226 * USBA framework will call this callback
2227 * after deal with bulkin request.
2228 */
2229 /*ARGSUSED*/
2230 static void
usbsacm_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)2231 usbsacm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2232 {
2233 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
2234 usbsacm_state_t *acmp = acm_port->acm_device;
2235 mblk_t *data;
2236 int data_len;
2237
2238 data = req->bulk_data;
2239 data_len = (data) ? MBLKL(data) : 0;
2240
2241 mutex_enter(&acm_port->acm_port_mutex);
2242 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
2243 "usbsacm_bulkin_cb: "
2244 "acm_bulkin_state = %d acm_port_state = %d data_len = %d",
2245 acm_port->acm_bulkin_state, acm_port->acm_port_state, data_len);
2246
2247 if ((acm_port->acm_port_state == USBSACM_PORT_OPEN) && (data_len) &&
2248 (req->bulk_completion_reason == USB_CR_OK)) {
2249 mutex_exit(&acm_port->acm_port_mutex);
2250 /* prevent USBA from freeing data along with the request */
2251 req->bulk_data = NULL;
2252
2253 /* save data on the receive list */
2254 usbsacm_put_tail(&acm_port->acm_rx_mp, data);
2255
2256 /* invoke GSD receive callback */
2257 if (acm_port->acm_cb.cb_rx) {
2258 acm_port->acm_cb.cb_rx(acm_port->acm_cb.cb_arg);
2259 }
2260 mutex_enter(&acm_port->acm_port_mutex);
2261 }
2262 mutex_exit(&acm_port->acm_port_mutex);
2263
2264 usb_free_bulk_req(req);
2265
2266 /* receive more */
2267 mutex_enter(&acm_port->acm_port_mutex);
2268 if (((acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) ||
2269 (acm_port->acm_bulkin_state == USBSACM_PIPE_IDLE)) &&
2270 (acm_port->acm_port_state == USBSACM_PORT_OPEN) &&
2271 (acmp->acm_dev_state == USB_DEV_ONLINE)) {
2272 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) {
2273 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2274 "usbsacm_bulkin_cb: restart rx fail "
2275 "acm_port_state = %d", acm_port->acm_port_state);
2276 }
2277 } else if (acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) {
2278 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
2279 }
2280 mutex_exit(&acm_port->acm_port_mutex);
2281 }
2282
2283
2284 /*
2285 * usbsacm_bulkout_cb:
2286 * Bulk Out regular and exeception callback;
2287 * USBA framework will call this callback function
2288 * after deal with bulkout request.
2289 */
2290 /*ARGSUSED*/
2291 static void
usbsacm_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)2292 usbsacm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2293 {
2294 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
2295 usbsacm_state_t *acmp = acm_port->acm_device;
2296 int data_len;
2297 mblk_t *data = req->bulk_data;
2298
2299 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
2300 "usbsacm_bulkout_cb: acmp = 0x%p", (void *)acmp);
2301
2302 data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
2303
2304 /* put untransferred residue back on the transfer list */
2305 if (req->bulk_completion_reason && (data_len > 0)) {
2306 usbsacm_put_head(&acm_port->acm_tx_mp, data);
2307 req->bulk_data = NULL;
2308 }
2309
2310 usb_free_bulk_req(req);
2311
2312 /* invoke GSD transmit callback */
2313 if (acm_port->acm_cb.cb_tx) {
2314 acm_port->acm_cb.cb_tx(acm_port->acm_cb.cb_arg);
2315 }
2316
2317 /* send more */
2318 mutex_enter(&acm_port->acm_port_mutex);
2319 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
2320 if (acm_port->acm_tx_mp == NULL) {
2321 cv_broadcast(&acm_port->acm_tx_cv);
2322 } else {
2323 usbsacm_tx_start(acm_port);
2324 }
2325 mutex_exit(&acm_port->acm_port_mutex);
2326 }
2327
2328
2329 /*
2330 * usbsacm_rx_start:
2331 * start data receipt
2332 */
2333 static int
usbsacm_rx_start(usbsacm_port_t * acm_port)2334 usbsacm_rx_start(usbsacm_port_t *acm_port)
2335 {
2336 usbsacm_state_t *acmp = acm_port->acm_device;
2337 usb_bulk_req_t *br;
2338 int rval = USB_FAILURE;
2339 int data_len;
2340
2341 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
2342 "usbsacm_rx_start: acm_xfer_sz = 0x%lx acm_bulkin_size = 0x%lx",
2343 acmp->acm_xfer_sz, acm_port->acm_bulkin_size);
2344
2345 acm_port->acm_bulkin_state = USBSACM_PIPE_BUSY;
2346 /*
2347 * Qualcomm CDMA card won't response the first request,
2348 * if the following code don't multiply by 2.
2349 */
2350 data_len = min(acmp->acm_xfer_sz, acm_port->acm_bulkin_size * 2);
2351 mutex_exit(&acm_port->acm_port_mutex);
2352
2353 br = usb_alloc_bulk_req(acmp->acm_dip, data_len, USB_FLAGS_SLEEP);
2354 if (br == NULL) {
2355 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2356 "usbsacm_rx_start: allocate bulk request failed");
2357
2358 mutex_enter(&acm_port->acm_port_mutex);
2359
2360 return (USB_FAILURE);
2361 }
2362 /* initialize bulk in request. */
2363 br->bulk_len = data_len;
2364 br->bulk_timeout = USBSACM_BULKIN_TIMEOUT;
2365 br->bulk_cb = usbsacm_bulkin_cb;
2366 br->bulk_exc_cb = usbsacm_bulkin_cb;
2367 br->bulk_client_private = (usb_opaque_t)acm_port;
2368 br->bulk_attributes = USB_ATTRS_AUTOCLEARING
2369 | USB_ATTRS_SHORT_XFER_OK;
2370
2371 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkin_ph, br, 0);
2372
2373 mutex_enter(&acm_port->acm_port_mutex);
2374 if (rval != USB_SUCCESS) {
2375 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2376 "usbsacm_rx_start: bulk transfer failed %d", rval);
2377 usb_free_bulk_req(br);
2378 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
2379 }
2380
2381 return (rval);
2382 }
2383
2384
2385 /*
2386 * usbsacm_tx_start:
2387 * start data transmit
2388 */
2389 static void
usbsacm_tx_start(usbsacm_port_t * acm_port)2390 usbsacm_tx_start(usbsacm_port_t *acm_port)
2391 {
2392 int len; /* bytes we can transmit */
2393 mblk_t *data; /* data to be transmitted */
2394 int data_len; /* bytes in 'data' */
2395 mblk_t *mp; /* current msgblk */
2396 int copylen; /* bytes copy from 'mp' to 'data' */
2397 int rval;
2398 usbsacm_state_t *acmp = acm_port->acm_device;
2399
2400 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
2401 "usbsacm_tx_start: ");
2402
2403 /* check the transmitted data. */
2404 if (acm_port->acm_tx_mp == NULL) {
2405 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2406 "usbsacm_tx_start: acm_tx_mp is NULL");
2407
2408 return;
2409 }
2410
2411 /* check pipe status */
2412 if (acm_port->acm_bulkout_state != USBSACM_PIPE_IDLE) {
2413
2414 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2415 "usbsacm_tx_start: error state in bulkout endpoint");
2416
2417 return;
2418 }
2419 ASSERT(MBLKL(acm_port->acm_tx_mp) > 0);
2420
2421 /* send as much data as port can receive */
2422 len = min(msgdsize(acm_port->acm_tx_mp), acmp->acm_xfer_sz);
2423
2424 if (len == 0) {
2425 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2426 "usbsacm_tx_start: data len is 0");
2427
2428 return;
2429 }
2430
2431 /* allocate memory for sending data. */
2432 if ((data = allocb(len, BPRI_LO)) == NULL) {
2433 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2434 "usbsacm_tx_start: failure in allocate memory");
2435
2436 return;
2437 }
2438
2439 /*
2440 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
2441 */
2442 data_len = 0;
2443 while ((data_len < len) && acm_port->acm_tx_mp) {
2444 /* Get the first mblk from chain. */
2445 mp = acm_port->acm_tx_mp;
2446 copylen = min(MBLKL(mp), len - data_len);
2447 bcopy(mp->b_rptr, data->b_wptr, copylen);
2448 mp->b_rptr += copylen;
2449 data->b_wptr += copylen;
2450 data_len += copylen;
2451
2452 if (MBLKL(mp) < 1) {
2453 acm_port->acm_tx_mp = unlinkb(mp);
2454 freeb(mp);
2455 } else {
2456 ASSERT(data_len == len);
2457 }
2458 }
2459
2460 if (data_len <= 0) {
2461 freeb(data);
2462
2463 return;
2464 }
2465
2466 acm_port->acm_bulkout_state = USBSACM_PIPE_BUSY;
2467
2468 mutex_exit(&acm_port->acm_port_mutex);
2469 /* send request. */
2470 rval = usbsacm_send_data(acm_port, data);
2471 mutex_enter(&acm_port->acm_port_mutex);
2472
2473 /*
2474 * If send failed, retransmit data when acm_tx_mp is null.
2475 */
2476 if (rval != USB_SUCCESS) {
2477 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
2478 if (acm_port->acm_tx_mp == NULL) {
2479 usbsacm_put_head(&acm_port->acm_tx_mp, data);
2480 }
2481 }
2482 }
2483
2484
2485 /*
2486 * usbsacm_send_data:
2487 * data transfer
2488 */
2489 static int
usbsacm_send_data(usbsacm_port_t * acm_port,mblk_t * data)2490 usbsacm_send_data(usbsacm_port_t *acm_port, mblk_t *data)
2491 {
2492 usbsacm_state_t *acmp = acm_port->acm_device;
2493 usb_bulk_req_t *br;
2494 int rval;
2495 int data_len = MBLKL(data);
2496
2497 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
2498 "usbsacm_send_data: data address is 0x%p, length = %d",
2499 (void *)data, data_len);
2500
2501 br = usb_alloc_bulk_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
2502 if (br == NULL) {
2503 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
2504 "usbsacm_send_data: alloc req failed.");
2505
2506 return (USB_FAILURE);
2507 }
2508
2509 /* initialize the bulk out request */
2510 br->bulk_data = data;
2511 br->bulk_len = data_len;
2512 br->bulk_timeout = USBSACM_BULKOUT_TIMEOUT;
2513 br->bulk_cb = usbsacm_bulkout_cb;
2514 br->bulk_exc_cb = usbsacm_bulkout_cb;
2515 br->bulk_client_private = (usb_opaque_t)acm_port;
2516 br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
2517
2518 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkout_ph, br, 0);
2519
2520 if (rval != USB_SUCCESS) {
2521 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
2522 "usbsacm_send_data: Send Data failed.");
2523
2524 /*
2525 * Don't free it in usb_free_bulk_req because it will
2526 * be linked in usbsacm_put_head
2527 */
2528 br->bulk_data = NULL;
2529
2530 usb_free_bulk_req(br);
2531 }
2532
2533 return (rval);
2534 }
2535
2536 /*
2537 * usbsacm_wait_tx_drain:
2538 * wait until local tx buffer drains.
2539 * 'timeout' is in seconds, zero means wait forever
2540 */
2541 static int
usbsacm_wait_tx_drain(usbsacm_port_t * acm_port,int timeout)2542 usbsacm_wait_tx_drain(usbsacm_port_t *acm_port, int timeout)
2543 {
2544 clock_t until;
2545 int over = 0;
2546
2547 until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
2548
2549 while (acm_port->acm_tx_mp && !over) {
2550 if (timeout > 0) {
2551 over = (cv_timedwait_sig(&acm_port->acm_tx_cv,
2552 &acm_port->acm_port_mutex, until) <= 0);
2553 } else {
2554 over = (cv_wait_sig(&acm_port->acm_tx_cv,
2555 &acm_port->acm_port_mutex) == 0);
2556 }
2557 }
2558
2559 return ((acm_port->acm_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
2560 }
2561
2562
2563 /*
2564 * usbsacm_req_write:
2565 * send command over control pipe
2566 */
2567 static int
usbsacm_req_write(usbsacm_port_t * acm_port,uchar_t request,uint16_t value,mblk_t ** data)2568 usbsacm_req_write(usbsacm_port_t *acm_port, uchar_t request, uint16_t value,
2569 mblk_t **data)
2570 {
2571 usbsacm_state_t *acmp = acm_port->acm_device;
2572 usb_ctrl_setup_t setup;
2573 usb_cb_flags_t cb_flags;
2574 usb_cr_t cr;
2575
2576 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
2577 "usbsacm_req_write: ");
2578
2579 /* initialize the control request. */
2580 setup.bmRequestType = USBSACM_REQ_WRITE_IF;
2581 setup.bRequest = request;
2582 setup.wValue = value;
2583 setup.wIndex = acm_port->acm_ctrl_if_no;
2584 setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
2585 setup.attrs = 0;
2586
2587 return (usb_pipe_ctrl_xfer_wait(acmp->acm_def_ph, &setup, data,
2588 &cr, &cb_flags, 0));
2589 }
2590
2591
2592 /*
2593 * usbsacm_set_line_coding:
2594 * Send USB_CDC_REQ_SET_LINE_CODING request
2595 */
2596 static int
usbsacm_set_line_coding(usbsacm_port_t * acm_port,usb_cdc_line_coding_t * lc)2597 usbsacm_set_line_coding(usbsacm_port_t *acm_port, usb_cdc_line_coding_t *lc)
2598 {
2599 mblk_t *bp;
2600 int ret;
2601
2602 /* allocate mblk and copy supplied structure into it */
2603 if ((bp = allocb(USB_CDC_LINE_CODING_LEN, BPRI_HI)) == NULL) {
2604
2605 return (USB_NO_RESOURCES);
2606 }
2607
2608 #ifndef __lock_lint /* warlock gets confused here */
2609 /* LINTED E_BAD_PTR_CAST_ALIGN */
2610 *((usb_cdc_line_coding_t *)bp->b_wptr) = *lc;
2611 bp->b_wptr += USB_CDC_LINE_CODING_LEN;
2612 #endif
2613
2614 ret = usbsacm_req_write(acm_port, USB_CDC_REQ_SET_LINE_CODING, 0, &bp);
2615
2616 if (bp != NULL) {
2617 freeb(bp);
2618 }
2619
2620 return (ret);
2621 }
2622
2623
2624
2625 /*
2626 * usbsacm_mctl2reg:
2627 * Set Modem control status
2628 */
2629 static void
usbsacm_mctl2reg(int mask,int val,uint8_t * line_ctl)2630 usbsacm_mctl2reg(int mask, int val, uint8_t *line_ctl)
2631 {
2632 if (mask & TIOCM_RTS) {
2633 if (val & TIOCM_RTS) {
2634 *line_ctl |= USB_CDC_ACM_CONTROL_RTS;
2635 } else {
2636 *line_ctl &= ~USB_CDC_ACM_CONTROL_RTS;
2637 }
2638 }
2639 if (mask & TIOCM_DTR) {
2640 if (val & TIOCM_DTR) {
2641 *line_ctl |= USB_CDC_ACM_CONTROL_DTR;
2642 } else {
2643 *line_ctl &= ~USB_CDC_ACM_CONTROL_DTR;
2644 }
2645 }
2646 }
2647
2648
2649 /*
2650 * usbsacm_reg2mctl:
2651 * Get Modem control status
2652 */
2653 static int
usbsacm_reg2mctl(uint8_t line_ctl)2654 usbsacm_reg2mctl(uint8_t line_ctl)
2655 {
2656 int val = 0;
2657
2658 if (line_ctl & USB_CDC_ACM_CONTROL_RTS) {
2659 val |= TIOCM_RTS;
2660 }
2661 if (line_ctl & USB_CDC_ACM_CONTROL_DTR) {
2662 val |= TIOCM_DTR;
2663 }
2664 if (line_ctl & USB_CDC_ACM_CONTROL_DSR) {
2665 val |= TIOCM_DSR;
2666 }
2667 if (line_ctl & USB_CDC_ACM_CONTROL_RNG) {
2668 val |= TIOCM_RI;
2669 }
2670
2671 return (val);
2672 }
2673
2674
2675 /*
2676 * misc routines
2677 * -------------
2678 *
2679 */
2680
2681 /*
2682 * usbsacm_put_tail:
2683 * link a message block to tail of message
2684 * account for the case when message is null
2685 */
2686 static void
usbsacm_put_tail(mblk_t ** mpp,mblk_t * bp)2687 usbsacm_put_tail(mblk_t **mpp, mblk_t *bp)
2688 {
2689 if (*mpp) {
2690 linkb(*mpp, bp);
2691 } else {
2692 *mpp = bp;
2693 }
2694 }
2695
2696
2697 /*
2698 * usbsacm_put_head:
2699 * put a message block at the head of the message
2700 * account for the case when message is null
2701 */
2702 static void
usbsacm_put_head(mblk_t ** mpp,mblk_t * bp)2703 usbsacm_put_head(mblk_t **mpp, mblk_t *bp)
2704 {
2705 if (*mpp) {
2706 linkb(bp, *mpp);
2707 }
2708 *mpp = bp;
2709 }
2710
2711
2712 /*
2713 * power management
2714 * ----------------
2715 *
2716 * usbsacm_create_pm_components:
2717 * create PM components
2718 */
2719 static int
usbsacm_create_pm_components(usbsacm_state_t * acmp)2720 usbsacm_create_pm_components(usbsacm_state_t *acmp)
2721 {
2722 dev_info_t *dip = acmp->acm_dip;
2723 usbsacm_pm_t *pm;
2724 uint_t pwr_states;
2725 usb_dev_descr_t *dev_descr;
2726
2727 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
2728 "usbsacm_create_pm_components: ");
2729
2730 if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
2731 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
2732 "usbsacm_create_pm_components: failed");
2733
2734 return (USB_SUCCESS);
2735 }
2736
2737 pm = acmp->acm_pm =
2738 (usbsacm_pm_t *)kmem_zalloc(sizeof (usbsacm_pm_t), KM_SLEEP);
2739
2740 pm->pm_pwr_states = (uint8_t)pwr_states;
2741 pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
2742 /*
2743 * Qualcomm CDMA card won't response the following control commands
2744 * after receive USB_REMOTE_WAKEUP_ENABLE. So we just set
2745 * pm_wakeup_enable to 0 for this specific device.
2746 */
2747 dev_descr = acmp->acm_dev_data->dev_descr;
2748 if (dev_descr->idVendor == 0x5c6 && dev_descr->idProduct == 0x3100) {
2749 pm->pm_wakeup_enabled = 0;
2750 } else {
2751 pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
2752 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
2753 }
2754
2755 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2756
2757 return (USB_SUCCESS);
2758 }
2759
2760
2761 /*
2762 * usbsacm_destroy_pm_components:
2763 * destroy PM components
2764 */
2765 static void
usbsacm_destroy_pm_components(usbsacm_state_t * acmp)2766 usbsacm_destroy_pm_components(usbsacm_state_t *acmp)
2767 {
2768 usbsacm_pm_t *pm = acmp->acm_pm;
2769 dev_info_t *dip = acmp->acm_dip;
2770 int rval;
2771
2772 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
2773 "usbsacm_destroy_pm_components: ");
2774
2775 if (acmp->acm_dev_state != USB_DEV_DISCONNECTED) {
2776 if (pm->pm_wakeup_enabled) {
2777 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2778 if (rval != DDI_SUCCESS) {
2779 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
2780 "usbsacm_destroy_pm_components: "
2781 "raising power failed (%d)", rval);
2782 }
2783
2784 rval = usb_handle_remote_wakeup(dip,
2785 USB_REMOTE_WAKEUP_DISABLE);
2786 if (rval != USB_SUCCESS) {
2787 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
2788 "usbsacm_destroy_pm_components: "
2789 "disable remote wakeup failed (%d)", rval);
2790 }
2791 }
2792
2793 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
2794 }
2795 kmem_free((caddr_t)pm, sizeof (usbsacm_pm_t));
2796 acmp->acm_pm = NULL;
2797 }
2798
2799
2800 /*
2801 * usbsacm_pm_set_busy:
2802 * mark device busy and raise power
2803 */
2804 static void
usbsacm_pm_set_busy(usbsacm_state_t * acmp)2805 usbsacm_pm_set_busy(usbsacm_state_t *acmp)
2806 {
2807 usbsacm_pm_t *pm = acmp->acm_pm;
2808 dev_info_t *dip = acmp->acm_dip;
2809 int rval;
2810
2811 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
2812 "usbsacm_pm_set_busy: pm = 0x%p", (void *)pm);
2813
2814 if (pm == NULL) {
2815
2816 return;
2817 }
2818
2819 mutex_enter(&acmp->acm_mutex);
2820 /* if already marked busy, just increment the counter */
2821 if (pm->pm_busy_cnt++ > 0) {
2822 mutex_exit(&acmp->acm_mutex);
2823
2824 return;
2825 }
2826
2827 (void) pm_busy_component(dip, 0);
2828
2829 if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
2830 mutex_exit(&acmp->acm_mutex);
2831
2832 return;
2833 }
2834
2835 /* need to raise power */
2836 pm->pm_raise_power = B_TRUE;
2837 mutex_exit(&acmp->acm_mutex);
2838
2839 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2840 if (rval != DDI_SUCCESS) {
2841 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
2842 "usbsacm_pm_set_busy: raising power failed");
2843 }
2844
2845 mutex_enter(&acmp->acm_mutex);
2846 pm->pm_raise_power = B_FALSE;
2847 mutex_exit(&acmp->acm_mutex);
2848 }
2849
2850
2851 /*
2852 * usbsacm_pm_set_idle:
2853 * mark device idle
2854 */
2855 static void
usbsacm_pm_set_idle(usbsacm_state_t * acmp)2856 usbsacm_pm_set_idle(usbsacm_state_t *acmp)
2857 {
2858 usbsacm_pm_t *pm = acmp->acm_pm;
2859 dev_info_t *dip = acmp->acm_dip;
2860
2861 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
2862 "usbsacm_pm_set_idle: ");
2863
2864 if (pm == NULL) {
2865
2866 return;
2867 }
2868
2869 /*
2870 * if more ports use the device, do not mark as yet
2871 */
2872 mutex_enter(&acmp->acm_mutex);
2873 if (--pm->pm_busy_cnt > 0) {
2874 mutex_exit(&acmp->acm_mutex);
2875
2876 return;
2877 }
2878
2879 if (pm) {
2880 (void) pm_idle_component(dip, 0);
2881 }
2882 mutex_exit(&acmp->acm_mutex);
2883 }
2884
2885
2886 /*
2887 * usbsacm_pwrlvl0:
2888 * Functions to handle power transition for OS levels 0 -> 3
2889 * The same level as OS state, different from USB state
2890 */
2891 static int
usbsacm_pwrlvl0(usbsacm_state_t * acmp)2892 usbsacm_pwrlvl0(usbsacm_state_t *acmp)
2893 {
2894 int rval;
2895 int i;
2896 usbsacm_port_t *cur_port = acmp->acm_ports;
2897
2898 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
2899 "usbsacm_pwrlvl0: ");
2900
2901 switch (acmp->acm_dev_state) {
2902 case USB_DEV_ONLINE:
2903 /* issue USB D3 command to the device */
2904 rval = usb_set_device_pwrlvl3(acmp->acm_dip);
2905 ASSERT(rval == USB_SUCCESS);
2906
2907 if (cur_port != NULL) {
2908 for (i = 0; i < acmp->acm_port_cnt; i++) {
2909 cur_port = &acmp->acm_ports[i];
2910 if (cur_port->acm_intr_ph != NULL &&
2911 cur_port->acm_port_state !=
2912 USBSACM_PORT_CLOSED) {
2913
2914 mutex_exit(&acmp->acm_mutex);
2915 usb_pipe_stop_intr_polling(
2916 cur_port->acm_intr_ph,
2917 USB_FLAGS_SLEEP);
2918 mutex_enter(&acmp->acm_mutex);
2919
2920 mutex_enter(&cur_port->acm_port_mutex);
2921 cur_port->acm_intr_state =
2922 USBSACM_PIPE_IDLE;
2923 mutex_exit(&cur_port->acm_port_mutex);
2924 }
2925 }
2926 }
2927
2928 acmp->acm_dev_state = USB_DEV_PWRED_DOWN;
2929 acmp->acm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
2930
2931 /* FALLTHRU */
2932 case USB_DEV_DISCONNECTED:
2933 case USB_DEV_SUSPENDED:
2934 /* allow a disconnect/cpr'ed device to go to lower power */
2935
2936 return (USB_SUCCESS);
2937 case USB_DEV_PWRED_DOWN:
2938 default:
2939 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
2940 "usbsacm_pwrlvl0: illegal device state");
2941
2942 return (USB_FAILURE);
2943 }
2944 }
2945
2946
2947 /*
2948 * usbsacm_pwrlvl1:
2949 * Functions to handle power transition for OS levels 1 -> 2
2950 */
2951 static int
usbsacm_pwrlvl1(usbsacm_state_t * acmp)2952 usbsacm_pwrlvl1(usbsacm_state_t *acmp)
2953 {
2954 /* issue USB D2 command to the device */
2955 (void) usb_set_device_pwrlvl2(acmp->acm_dip);
2956
2957 return (USB_FAILURE);
2958 }
2959
2960
2961 /*
2962 * usbsacm_pwrlvl2:
2963 * Functions to handle power transition for OS levels 2 -> 1
2964 */
2965 static int
usbsacm_pwrlvl2(usbsacm_state_t * acmp)2966 usbsacm_pwrlvl2(usbsacm_state_t *acmp)
2967 {
2968 /* issue USB D1 command to the device */
2969 (void) usb_set_device_pwrlvl1(acmp->acm_dip);
2970
2971 return (USB_FAILURE);
2972 }
2973
2974
2975 /*
2976 * usbsacm_pwrlvl3:
2977 * Functions to handle power transition for OS levels 3 -> 0
2978 * The same level as OS state, different from USB state
2979 */
2980 static int
usbsacm_pwrlvl3(usbsacm_state_t * acmp)2981 usbsacm_pwrlvl3(usbsacm_state_t *acmp)
2982 {
2983 int rval;
2984 int i;
2985 usbsacm_port_t *cur_port = acmp->acm_ports;
2986
2987 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
2988 "usbsacm_pwrlvl3: ");
2989
2990 switch (acmp->acm_dev_state) {
2991 case USB_DEV_PWRED_DOWN:
2992 /* Issue USB D0 command to the device here */
2993 rval = usb_set_device_pwrlvl0(acmp->acm_dip);
2994 ASSERT(rval == USB_SUCCESS);
2995
2996 if (cur_port != NULL) {
2997 for (i = 0; i < acmp->acm_port_cnt; i++) {
2998 cur_port = &acmp->acm_ports[i];
2999 if (cur_port->acm_intr_ph != NULL &&
3000 cur_port->acm_port_state !=
3001 USBSACM_PORT_CLOSED) {
3002
3003 mutex_exit(&acmp->acm_mutex);
3004 usbsacm_pipe_start_polling(cur_port);
3005 mutex_enter(&acmp->acm_mutex);
3006 }
3007 }
3008 }
3009
3010 acmp->acm_dev_state = USB_DEV_ONLINE;
3011 acmp->acm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
3012
3013 /* FALLTHRU */
3014 case USB_DEV_ONLINE:
3015 /* we are already in full power */
3016
3017 /* FALLTHRU */
3018 case USB_DEV_DISCONNECTED:
3019 case USB_DEV_SUSPENDED:
3020
3021 return (USB_SUCCESS);
3022 default:
3023 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
3024 "usbsacm_pwrlvl3: illegal device state");
3025
3026 return (USB_FAILURE);
3027 }
3028 }
3029
3030
3031 /*
3032 * usbsacm_pipe_start_polling:
3033 * start polling on the interrupt pipe
3034 */
3035 static void
usbsacm_pipe_start_polling(usbsacm_port_t * acm_port)3036 usbsacm_pipe_start_polling(usbsacm_port_t *acm_port)
3037 {
3038 usb_intr_req_t *intr;
3039 int rval;
3040 usbsacm_state_t *acmp = acm_port->acm_device;
3041
3042 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
3043 "usbsacm_pipe_start_polling: ");
3044
3045 if (acm_port->acm_intr_ph == NULL) {
3046
3047 return;
3048 }
3049
3050 intr = usb_alloc_intr_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
3051
3052 /*
3053 * If it is in interrupt context, usb_alloc_intr_req will return NULL if
3054 * called with SLEEP flag.
3055 */
3056 if (!intr) {
3057 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
3058 "usbsacm_pipe_start_polling: alloc req failed.");
3059
3060 return;
3061 }
3062
3063 /* initialize the interrupt request. */
3064 intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
3065 USB_ATTRS_AUTOCLEARING;
3066 mutex_enter(&acm_port->acm_port_mutex);
3067 intr->intr_len = acm_port->acm_intr_ep_descr.wMaxPacketSize;
3068 mutex_exit(&acm_port->acm_port_mutex);
3069 intr->intr_client_private = (usb_opaque_t)acm_port;
3070 intr->intr_cb = usbsacm_intr_cb;
3071 intr->intr_exc_cb = usbsacm_intr_ex_cb;
3072
3073 rval = usb_pipe_intr_xfer(acm_port->acm_intr_ph, intr, USB_FLAGS_SLEEP);
3074
3075 mutex_enter(&acm_port->acm_port_mutex);
3076 if (rval == USB_SUCCESS) {
3077 acm_port->acm_intr_state = USBSACM_PIPE_BUSY;
3078 } else {
3079 usb_free_intr_req(intr);
3080 acm_port->acm_intr_state = USBSACM_PIPE_IDLE;
3081 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh,
3082 "usbsacm_pipe_start_polling: failed (%d)", rval);
3083 }
3084 mutex_exit(&acm_port->acm_port_mutex);
3085 }
3086
3087
3088 /*
3089 * usbsacm_intr_cb:
3090 * interrupt pipe normal callback
3091 */
3092 /*ARGSUSED*/
3093 static void
usbsacm_intr_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)3094 usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
3095 {
3096 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
3097 usbsacm_state_t *acmp = acm_port->acm_device;
3098 mblk_t *data = req->intr_data;
3099 int data_len;
3100
3101 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh,
3102 "usbsacm_intr_cb: ");
3103
3104 data_len = (data) ? MBLKL(data) : 0;
3105
3106 /* check data length */
3107 if (data_len < 8) {
3108 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh,
3109 "usbsacm_intr_cb: %d packet too short", data_len);
3110 usb_free_intr_req(req);
3111
3112 return;
3113 }
3114 req->intr_data = NULL;
3115 usb_free_intr_req(req);
3116
3117 mutex_enter(&acm_port->acm_port_mutex);
3118 /* parse interrupt data. */
3119 usbsacm_parse_intr_data(acm_port, data);
3120 mutex_exit(&acm_port->acm_port_mutex);
3121 }
3122
3123
3124 /*
3125 * usbsacm_intr_ex_cb:
3126 * interrupt pipe exception callback
3127 */
3128 /*ARGSUSED*/
3129 static void
usbsacm_intr_ex_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)3130 usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
3131 {
3132 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
3133 usbsacm_state_t *acmp = acm_port->acm_device;
3134 usb_cr_t cr = req->intr_completion_reason;
3135
3136 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh,
3137 "usbsacm_intr_ex_cb: ");
3138
3139 usb_free_intr_req(req);
3140
3141 /*
3142 * If completion reason isn't USB_CR_PIPE_CLOSING and
3143 * USB_CR_STOPPED_POLLING, restart polling.
3144 */
3145 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
3146 mutex_enter(&acmp->acm_mutex);
3147
3148 if (acmp->acm_dev_state != USB_DEV_ONLINE) {
3149
3150 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3151 "usbsacm_intr_ex_cb: state = %d",
3152 acmp->acm_dev_state);
3153
3154 mutex_exit(&acmp->acm_mutex);
3155
3156 return;
3157 }
3158 mutex_exit(&acmp->acm_mutex);
3159
3160 usbsacm_pipe_start_polling(acm_port);
3161 }
3162 }
3163
3164
3165 /*
3166 * usbsacm_parse_intr_data:
3167 * Parse data received from interrupt callback
3168 */
3169 static void
usbsacm_parse_intr_data(usbsacm_port_t * acm_port,mblk_t * data)3170 usbsacm_parse_intr_data(usbsacm_port_t *acm_port, mblk_t *data)
3171 {
3172 usbsacm_state_t *acmp = acm_port->acm_device;
3173 uint8_t bmRequestType;
3174 uint8_t bNotification;
3175 uint16_t wValue;
3176 uint16_t wLength;
3177 uint16_t wData;
3178
3179 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
3180 "usbsacm_parse_intr_data: ");
3181
3182 bmRequestType = data->b_rptr[0];
3183 bNotification = data->b_rptr[1];
3184 /*
3185 * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1,
3186 * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0,
3187 * mLength is 2. So we directly get the value from the byte.
3188 */
3189 wValue = data->b_rptr[2];
3190 wLength = data->b_rptr[6];
3191
3192 if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
3193 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh,
3194 "usbsacm_parse_intr_data: unknown request type - 0x%x",
3195 bmRequestType);
3196
3197 freemsg(data);
3198
3199 return;
3200 }
3201
3202 /*
3203 * Check the return value of device
3204 */
3205 switch (bNotification) {
3206 case USB_CDC_NOTIFICATION_NETWORK_CONNECTION:
3207 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3208 "usbsacm_parse_intr_data: %s network!",
3209 wValue ? "connected to" :"disconnected from");
3210
3211 break;
3212 case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE:
3213 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3214 "usbsacm_parse_intr_data: A response is a available.");
3215
3216 break;
3217 case USB_CDC_NOTIFICATION_SERIAL_STATE:
3218 /* check the parameter's length. */
3219 if (wLength != 2) {
3220
3221 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3222 "usbsacm_parse_intr_data: error data length.");
3223 } else {
3224 /*
3225 * The Data field is a bitmapped value that contains
3226 * the current state of carrier detect, transmission
3227 * carrier, break, ring signal and device overrun
3228 * error.
3229 */
3230 wData = data->b_rptr[8];
3231 /*
3232 * Check the serial state of the current port.
3233 */
3234 if (wData & USB_CDC_ACM_CONTROL_DCD) {
3235
3236 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3237 "usbsacm_parse_intr_data: "
3238 "receiver carrier is set.");
3239 }
3240 if (wData & USB_CDC_ACM_CONTROL_DSR) {
3241
3242 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3243 "usbsacm_parse_intr_data: "
3244 "transmission carrier is set.");
3245
3246 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_DSR;
3247 }
3248 if (wData & USB_CDC_ACM_CONTROL_BREAK) {
3249
3250 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3251 "usbsacm_parse_intr_data: "
3252 "break detection mechanism is set.");
3253 }
3254 if (wData & USB_CDC_ACM_CONTROL_RNG) {
3255
3256 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3257 "usbsacm_parse_intr_data: "
3258 "ring signal detection is set.");
3259
3260 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_RNG;
3261 }
3262 if (wData & USB_CDC_ACM_CONTROL_FRAMING) {
3263
3264 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3265 "usbsacm_parse_intr_data: "
3266 "A framing error has occurred.");
3267 }
3268 if (wData & USB_CDC_ACM_CONTROL_PARITY) {
3269
3270 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3271 "usbsacm_parse_intr_data: "
3272 "A parity error has occurred.");
3273 }
3274 if (wData & USB_CDC_ACM_CONTROL_OVERRUN) {
3275
3276 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3277 "usbsacm_parse_intr_data: "
3278 "Received data has been discarded "
3279 "due to overrun.");
3280 }
3281 }
3282
3283 break;
3284 default:
3285 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
3286 "usbsacm_parse_intr_data: unknown notification - 0x%x!",
3287 bNotification);
3288
3289 break;
3290 }
3291
3292 freemsg(data);
3293 }
3294