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