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