90f050286227cf4c4f8aa425555d04723d331d48yq * CDDL HEADER START
90f050286227cf4c4f8aa425555d04723d331d48yq * The contents of this file are subject to the terms of the
90f050286227cf4c4f8aa425555d04723d331d48yq * Common Development and Distribution License (the "License").
90f050286227cf4c4f8aa425555d04723d331d48yq * You may not use this file except in compliance with the License.
90f050286227cf4c4f8aa425555d04723d331d48yq * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f050286227cf4c4f8aa425555d04723d331d48yq * See the License for the specific language governing permissions
90f050286227cf4c4f8aa425555d04723d331d48yq * and limitations under the License.
90f050286227cf4c4f8aa425555d04723d331d48yq * When distributing Covered Code, include this CDDL HEADER in each
90f050286227cf4c4f8aa425555d04723d331d48yq * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
90f050286227cf4c4f8aa425555d04723d331d48yq * If applicable, add the following below this CDDL HEADER, with the
90f050286227cf4c4f8aa425555d04723d331d48yq * fields enclosed by brackets "[]" replaced with your own identifying
90f050286227cf4c4f8aa425555d04723d331d48yq * information: Portions Copyright [yyyy] [name of copyright owner]
90f050286227cf4c4f8aa425555d04723d331d48yq * CDDL HEADER END
9e37f2b5d225bd6428d62c06655138fc78fd1ac0Raymond Chen * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
90f050286227cf4c4f8aa425555d04723d331d48yq * Use is subject to license terms.
90f050286227cf4c4f8aa425555d04723d331d48yq * USB Serial CDC ACM driver
90f050286227cf4c4f8aa425555d04723d331d48yq * 1. General Concepts
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.1 Overview
90f050286227cf4c4f8aa425555d04723d331d48yq * ------------
90f050286227cf4c4f8aa425555d04723d331d48yq * This driver supports devices that comply with the USB Communication
90f050286227cf4c4f8aa425555d04723d331d48yq * Device Class Abstract Control Model (USB CDC ACM) specification,
90f050286227cf4c4f8aa425555d04723d331d48yq * which is available at http://www.usb.org. Given the broad nature
90f050286227cf4c4f8aa425555d04723d331d48yq * of communication equipment, this driver supports the following
90f050286227cf4c4f8aa425555d04723d331d48yq * types of devices:
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * + Telecommunications devices: analog modems, mobile phones;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * + Networking devices: cable modems;
90f050286227cf4c4f8aa425555d04723d331d48yq * Except the above mentioned acm devices, this driver also supports
90f050286227cf4c4f8aa425555d04723d331d48yq * some devices which provide modem-like function and have pairs of
90f050286227cf4c4f8aa425555d04723d331d48yq * bulk in/out pipes.
90f050286227cf4c4f8aa425555d04723d331d48yq * There are three classes that make up the definition for communication
90f050286227cf4c4f8aa425555d04723d331d48yq * devices: the Communication Device Class, the Communication Interface
90f050286227cf4c4f8aa425555d04723d331d48yq * Class and the Data Interface Class. The Communication Device Class
90f050286227cf4c4f8aa425555d04723d331d48yq * is a device level definition and is used by the host to properly
90f050286227cf4c4f8aa425555d04723d331d48yq * identify a communication device that may present several different
90f050286227cf4c4f8aa425555d04723d331d48yq * types of interfaces. The Communication Interface Class defines a
90f050286227cf4c4f8aa425555d04723d331d48yq * general-purpose mechanism that can be used to enable all types of
90f050286227cf4c4f8aa425555d04723d331d48yq * communication services on the Universal Serial Bus (USB). The Data
90f050286227cf4c4f8aa425555d04723d331d48yq * Interface Class defines a general-purpose mechanism to enable bulk
90f050286227cf4c4f8aa425555d04723d331d48yq * transfer on the USB when the data does not meet the requirements
90f050286227cf4c4f8aa425555d04723d331d48yq * for any other class.
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.2 Interface Definitions
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * Communication Class Interface is used for device management and,
90f050286227cf4c4f8aa425555d04723d331d48yq * optionally, call management. Device management includes the requests
90f050286227cf4c4f8aa425555d04723d331d48yq * that manage the operational state of a device, the device responses,
90f050286227cf4c4f8aa425555d04723d331d48yq * and event notifications. In Abstract Control Model, the device can
90f050286227cf4c4f8aa425555d04723d331d48yq * provide an internal implementation of call management over the Data
90f050286227cf4c4f8aa425555d04723d331d48yq * Class interface or the Communication Class interface.
90f050286227cf4c4f8aa425555d04723d331d48yq * The Data Class defines a data interface as an interface with a class
90f050286227cf4c4f8aa425555d04723d331d48yq * type of Data Class. Data transmission on a communication device is
90f050286227cf4c4f8aa425555d04723d331d48yq * not restricted to interfaces using the Data Class. Rather, a data
90f050286227cf4c4f8aa425555d04723d331d48yq * interface is used to transmit and/or receive data that is not
90f050286227cf4c4f8aa425555d04723d331d48yq * defined by any other class. The data could be:
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * + Some form of raw data from a communication line.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * + Legacy modem data.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * + Data using a proprietary format.
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.3 Endpoint Requirements
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * The Communication Class interface requires one endpoint, the management
90f050286227cf4c4f8aa425555d04723d331d48yq * element. Optionally, it can have an additional endpoint, the notification
90f050286227cf4c4f8aa425555d04723d331d48yq * element. The management element uses the default endpoint for all
90f050286227cf4c4f8aa425555d04723d331d48yq * standard and Communication Class-specific requests. The notification
90f050286227cf4c4f8aa425555d04723d331d48yq * element normally uses an interrupt endpoint.
90f050286227cf4c4f8aa425555d04723d331d48yq * The type of endpoints belonging to a Data Class interface are restricted
90f050286227cf4c4f8aa425555d04723d331d48yq * to bulk, and are expected to exist in pairs of the same type (one In and
90f050286227cf4c4f8aa425555d04723d331d48yq * one Out).
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.4 ACM Function Characteristics
90f050286227cf4c4f8aa425555d04723d331d48yq * --------------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * With Abstract Control Model, the USB device understands standard
90f050286227cf4c4f8aa425555d04723d331d48yq * V.25ter (AT) commands. The device contains a Datapump and micro-
90f050286227cf4c4f8aa425555d04723d331d48yq * controller that handles the AT commands and relay controls. The
90f050286227cf4c4f8aa425555d04723d331d48yq * device uses both a Data Class interface and a Communication Class.
90f050286227cf4c4f8aa425555d04723d331d48yq * interface.
90f050286227cf4c4f8aa425555d04723d331d48yq * A Communication Class interface of type Abstract Control Model will
90f050286227cf4c4f8aa425555d04723d331d48yq * consist of a minimum of two pipes; one is used to implement the
90f050286227cf4c4f8aa425555d04723d331d48yq * management element and the other to implement a notification element.
90f050286227cf4c4f8aa425555d04723d331d48yq * In addition, the device can use two pipes to implement channels over
90f050286227cf4c4f8aa425555d04723d331d48yq * which to carry unspecified data, typically over a Data Class interface.
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.5 ACM Serial Emulation
90f050286227cf4c4f8aa425555d04723d331d48yq * ------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * The Abstract Control Model can bridge the gap between legacy modem
90f050286227cf4c4f8aa425555d04723d331d48yq * devices and USB devices. To support certain types of legacy applications,
90f050286227cf4c4f8aa425555d04723d331d48yq * two problems need to be addressed. The first is supporting specific
90f050286227cf4c4f8aa425555d04723d331d48yq * legacy control signals and state variables which are addressed
90f050286227cf4c4f8aa425555d04723d331d48yq * directly by the various carrier modulation standards. To support these
90f050286227cf4c4f8aa425555d04723d331d48yq * requirement, additional requests and notifications have been created.
90f050286227cf4c4f8aa425555d04723d331d48yq * Please refer to macro, beginning with USB_CDC_REQ_* and
90f050286227cf4c4f8aa425555d04723d331d48yq * USB_CDC_NOTIFICATION_*.
90f050286227cf4c4f8aa425555d04723d331d48yq * The second significant item which is needed to bridge the gap between
90f050286227cf4c4f8aa425555d04723d331d48yq * legacy modem designs and the Abstract Control Model is a means to
90f050286227cf4c4f8aa425555d04723d331d48yq * multiplex call control (AT commands) on the Data Class interface.
90f050286227cf4c4f8aa425555d04723d331d48yq * Legacy modem designs are limited by only supporting one channel for
90f050286227cf4c4f8aa425555d04723d331d48yq * both "AT" commands and the actual data. To allow this type of
90f050286227cf4c4f8aa425555d04723d331d48yq * functionality, the device must have a means to specify this limitation
90f050286227cf4c4f8aa425555d04723d331d48yq * to the host.
90f050286227cf4c4f8aa425555d04723d331d48yq * When describing this type of device, the Communication Class interface
90f050286227cf4c4f8aa425555d04723d331d48yq * would still specify a Abstract Control Model, but call control would
90f050286227cf4c4f8aa425555d04723d331d48yq * actually occur over the Data Class interface. To describe this
90f050286227cf4c4f8aa425555d04723d331d48yq * particular characteristic, the Call Management Functional Descriptor
90f050286227cf4c4f8aa425555d04723d331d48yq * would have bit D1 of bmCapabilities set.
90f050286227cf4c4f8aa425555d04723d331d48yq * 1.6 Other Bulk In/Out Devices
90f050286227cf4c4f8aa425555d04723d331d48yq * -----------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * Some devices don't conform to USB CDC specification, but they provide
90f050286227cf4c4f8aa425555d04723d331d48yq * modem-like function and have pairs of bulk in/out pipes. This driver
90f050286227cf4c4f8aa425555d04723d331d48yq * supports this kind of device and exports term nodes by their pipes.
90f050286227cf4c4f8aa425555d04723d331d48yq * 2. Implementation
90f050286227cf4c4f8aa425555d04723d331d48yq * -----------------
90f050286227cf4c4f8aa425555d04723d331d48yq * 2.1 Overview
90f050286227cf4c4f8aa425555d04723d331d48yq * ------------
90f050286227cf4c4f8aa425555d04723d331d48yq * It is a device-specific driver (DSD) working with USB generic serial
90f050286227cf4c4f8aa425555d04723d331d48yq * driver (GSD). It implements the USB-to-serial device-specific driver
90f050286227cf4c4f8aa425555d04723d331d48yq * interface (DSDI) which is offered by GSD. The interface is defined
90f050286227cf4c4f8aa425555d04723d331d48yq * by ds_ops_t structure.
90f050286227cf4c4f8aa425555d04723d331d48yq * 2.2 Port States
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq * For USB CDC ACM devices, this driver is attached to its interface,
90f050286227cf4c4f8aa425555d04723d331d48yq * and exports one port for each interface. For other modem-like devices,
90f050286227cf4c4f8aa425555d04723d331d48yq * this driver can dynamically find the ports in the current device,
90f050286227cf4c4f8aa425555d04723d331d48yq * and export one port for each pair bulk in/out pipes. Each port can
90f050286227cf4c4f8aa425555d04723d331d48yq * be operated independently.
90f050286227cf4c4f8aa425555d04723d331d48yq * port_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * attach_ports
90f050286227cf4c4f8aa425555d04723d331d48yq * USBSACM_PORT_CLOSED
90f050286227cf4c4f8aa425555d04723d331d48yq * open_port close_port
90f050286227cf4c4f8aa425555d04723d331d48yq * USBSACM_PORT_OPEN
90f050286227cf4c4f8aa425555d04723d331d48yq * 2.3 Pipe States
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq * Each port has its own bulk in/out pipes and some ports could also have
90f050286227cf4c4f8aa425555d04723d331d48yq * its own interrupt pipes (traced by usbsacm_port structure), which are
90f050286227cf4c4f8aa425555d04723d331d48yq * opened during attach. The pipe status is as following:
90f050286227cf4c4f8aa425555d04723d331d48yq * pipe_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_alloc_ports usbsacm_free_ports
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * |---->------ USBSACM_PORT_CLOSED ------>------+
90f050286227cf4c4f8aa425555d04723d331d48yq * +------<------ USBSACM_PIPE_IDLE ------<------|
90f050286227cf4c4f8aa425555d04723d331d48yq * +-----------------+ +-----------+
90f050286227cf4c4f8aa425555d04723d331d48yq * rx_start/tx_start----->------failed------->---------|
90f050286227cf4c4f8aa425555d04723d331d48yq * +----->----- USBSACM_PIPE_BUSY ---->------+
90f050286227cf4c4f8aa425555d04723d331d48yq * To get its status in a timely way, acm driver can get the status
90f050286227cf4c4f8aa425555d04723d331d48yq * of the device by polling the interrupt pipe.
90f050286227cf4c4f8aa425555d04723d331d48yq/* devops entry points */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_attach(dev_info_t *, ddi_attach_cmd_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_detach(dev_info_t *, ddi_detach_cmd_t);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blgstatic int usbsacm_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_open(queue_t *, dev_t *, int, int, cred_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* DSD operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* standard UART operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_set_modem_ctl(ds_hdl_t, uint_t, int, int);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* data xfer */
90f050286227cf4c4f8aa425555d04723d331d48yq/* fifo operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_fifo_flush_locked(usbsacm_state_t *, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yq/* power management and CPR */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_usb_power(ds_hdl_t, int, int, int *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_create_pm_components(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_destroy_pm_components(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* event handling */
90f050286227cf4c4f8aa425555d04723d331d48yq/* pipe callbacks */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* interrupt pipe */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_pipe_start_polling(usbsacm_port_t *acmp);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_parse_intr_data(usbsacm_port_t *acmp, mblk_t *data);
90f050286227cf4c4f8aa425555d04723d331d48yq/* Utility functions */
90f050286227cf4c4f8aa425555d04723d331d48yq/* data transfer routines */
90f050286227cf4c4f8aa425555d04723d331d48yq/* Initialize or release resources */
90f050286227cf4c4f8aa425555d04723d331d48yq/* analysis functional descriptors */
90f050286227cf4c4f8aa425555d04723d331d48yq/* hotplug */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_restore_device_state(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq/* pipe operations */
90f050286227cf4c4f8aa425555d04723d331d48yq/* vendor-specific commands */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_req_write(usbsacm_port_t *, uchar_t, uint16_t,
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_mctl2reg(int mask, int val, uint8_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq * Standard STREAMS driver definitions
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* module id */
90f050286227cf4c4f8aa425555d04723d331d48yq/* cb_ops structure */
90f050286227cf4c4f8aa425555d04723d331d48yq/* dev_ops structure */
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* devo_refcnt */
90f050286227cf4c4f8aa425555d04723d331d48yq/* modldrv structure */
77e515715b61e28fcf0c3f30936492888cecfd8bgongtian zhao - Sun Microsystems - Beijing China "USB Serial CDC ACM driver",
90f050286227cf4c4f8aa425555d04723d331d48yq/* modlinkage structure */
90f050286227cf4c4f8aa425555d04723d331d48yq * DSD definitions
90f050286227cf4c4f8aa425555d04723d331d48yq * baud code -> baud rate (0 means unsupported rate)
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* B0 */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm driver's entry points
90f050286227cf4c4f8aa425555d04723d331d48yq * -----------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq * Module-wide initialization routine.
90f050286227cf4c4f8aa425555d04723d331d48yq * Module-wide tear-down routine.
90f050286227cf4c4f8aa425555d04723d331d48yq * Device configuration entry points
e8ed0869d5c65afe0c37c4755bf81f7381d1f43cJohn Beck return (usbser_attach(dip, cmd, usbsacm_statep, &usbsacm_ds_ops));
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbser_getinfo(dip, infocmd, arg, result, usbsacm_statep));
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbser_open(rq, dev, flag, sflag, cr, usbsacm_statep));
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_detach:
90f050286227cf4c4f8aa425555d04723d331d48yq * attach device instance, called from GSD attach
90f050286227cf4c4f8aa425555d04723d331d48yq * initialize state and device, including:
90f050286227cf4c4f8aa425555d04723d331d48yq * state variables, locks, device node
90f050286227cf4c4f8aa425555d04723d331d48yq * device registration with system
90f050286227cf4c4f8aa425555d04723d331d48yq * power management
90f050286227cf4c4f8aa425555d04723d331d48yq acmp = (usbsacm_state_t *)kmem_zalloc(sizeof (usbsacm_state_t),
90f050286227cf4c4f8aa425555d04723d331d48yq /* registers usbsacm with the USBA framework */
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get the configuration information of device */
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_lh = usb_alloc_log_hdl(acmp->acm_dip, "usbsacm",
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_errlevel, &usbsacm_errmask, &usbsacm_instance_debug, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq /* Create power management components */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: create pm components failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Register to get callbacks for USB events */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_register_event_cbs(acmp->acm_dip, acmp->acm_usb_events, 0)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: register event callback failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * If devices conform to acm spec, driver will attach using class id;
90f050286227cf4c4f8aa425555d04723d331d48yq * if not, using device id.
90f050286227cf4c4f8aa425555d04723d331d48yq "usbif,class2.2") == 0) ||
90f050286227cf4c4f8aa425555d04723d331d48yq "usb,class2.2.0") == 0))) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: A nonstandard device is attaching to "
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm driver. This device doesn't conform to "
90f050286227cf4c4f8aa425555d04723d331d48yq "usb cdc spec.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize state variables */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: initialize port structure failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get max data size of bulk transfer */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: get max size of transfer failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_detach:
90f050286227cf4c4f8aa425555d04723d331d48yq * detach device instance, called from GSD detach
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_detach:");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_register_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_register_cb to register interrupt callbacks
90f050286227cf4c4f8aa425555d04723d331d48yq * for the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_register_cb: acmp = 0x%p port_num = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check if port number is greater than actual port number. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_register_cb: port number is wrong.");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_unregister_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_unregister_cb to unregister
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt callbacks for the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_unregister_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Release callback function */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_open_port:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_open_port
90f050286227cf4c4f8aa425555d04723d331d48yq * to open the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check the status of the given port and device */
90f050286227cf4c4f8aa425555d04723d331d48yq /* open pipes of port */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_open_port: open pipes failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* data receipt */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_open_port: start receive data failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_close_port:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_close_port
90f050286227cf4c4f8aa425555d04723d331d48yq * to close the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_fifo_flush_locked(acmp, port_num, DS_TX | DS_RX);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_usb_power:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_usb_power
90f050286227cf4c4f8aa425555d04723d331d48yq * to set power level of the component
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* check if pm is NULL */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: pm is NULL.");
90f050286227cf4c4f8aa425555d04723d331d48yq * check if we are transitioning to a legal power level
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: "
90f050286227cf4c4f8aa425555d04723d331d48yq "illegal power level %d, pwr_states=%x",
90f050286227cf4c4f8aa425555d04723d331d48yq * if we are about to raise power and asked to lower power, fail
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: wrong condition.");
90f050286227cf4c4f8aa425555d04723d331d48yq * Set the power status of device by request level.
90f050286227cf4c4f8aa425555d04723d331d48yq switch (level) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * that the usb serial device is disconnected/suspended while it
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * is under power down state, now the device is powered up
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * state to ONLINE, we need to set the dev state back to
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_suspend:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_suspend
90f050286227cf4c4f8aa425555d04723d331d48yq * during CPR suspend
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_suspend: ");
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * If the device is suspended while it is under PWRED_DOWN state, we
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * need to keep the PWRED_DOWN state so that it could be powered up
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * later. In the mean while, usbser dev state will be changed to
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * SUSPENDED state.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /* set device status to suspend */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_resume:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_resume
90f050286227cf4c4f8aa425555d04723d331d48yq * during CPR resume
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_resume: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* restore the status of device */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_disconnect:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_disconnect
90f050286227cf4c4f8aa425555d04723d331d48yq * to disconnect USB device
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_disconnect: ");
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * If the device is disconnected while it is under PWRED_DOWN state, we
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * need to keep the PWRED_DOWN state so that it could be powered up
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * later. In the mean while, usbser dev state will be changed to
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * DISCONNECTED state.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /* set device status to disconnected */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_reconnect:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq * to reconnect USB device
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_reconnect: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_set_port_params:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_set_port_params
90f050286227cf4c4f8aa425555d04723d331d48yq * to set one or more port parameters
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_set_port_params: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to set port param.
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq "don't support Set_Line_Coding.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get parameter information from ds_port_params_t */
90f050286227cf4c4f8aa425555d04723d331d48yq /* Data terminal rate, in bits per second. */
90f050286227cf4c4f8aa425555d04723d331d48yq /* if we don't support this speed, return USB_FAILURE */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq " error baud rate");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Parity Type */
90f050286227cf4c4f8aa425555d04723d331d48yq /* Stop bit */
90f050286227cf4c4f8aa425555d04723d331d48yq /* Data Bits */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq "parameter 0x%x isn't supported",
90f050286227cf4c4f8aa425555d04723d331d48yq if ((ret = usbsacm_set_line_coding(acm_port, &lc)) == USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to acm spec, return success directly.
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_set_modem_ctl:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_set_modem_ctl
90f050286227cf4c4f8aa425555d04723d331d48yq * to set modem control of the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_modem_ctl: mask = 0x%x val = 0x%x",
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to set modem
90f050286227cf4c4f8aa425555d04723d331d48yq * controls.
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_modem_ctl: "
90f050286227cf4c4f8aa425555d04723d331d48yq "don't support Set_Control_Line_State.");
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_req_write(acm_port, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to acm spec, return success directly.
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_get_modem_ctl:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_get_modem_ctl
90f050286227cf4c4f8aa425555d04723d331d48yq * to get modem control/status of the given port
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, polling function can modify the value
90f050286227cf4c4f8aa425555d04723d331d48yq * of acm_mctlin; else set to default value.
90f050286227cf4c4f8aa425555d04723d331d48yq *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_tx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_break_ctl
90f050286227cf4c4f8aa425555d04723d331d48yq * to set/clear break
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_break_ctl: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to send break.
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SEND_BREAK) == 0 &&
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_break_ctl: don't support send break.");
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbsacm_req_write(acm_port, USB_CDC_REQ_SEND_BREAK,
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_tx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_tx
90f050286227cf4c4f8aa425555d04723d331d48yq * to data transmit
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_tx: mp = 0x%p acmp = 0x%p", (void *)mp, (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq /* sanity checks */
90f050286227cf4c4f8aa425555d04723d331d48yq /* put mblk to tail of mblk chain */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_rx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_rx;
90f050286227cf4c4f8aa425555d04723d331d48yq * to data receipt
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yq return (mp);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_stop:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_stop;
90f050286227cf4c4f8aa425555d04723d331d48yq * but acm spec don't define this function
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_stop: don't support!");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_start;
90f050286227cf4c4f8aa425555d04723d331d48yq * but acm spec don't define this function
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_start: don't support!");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_fifo_flush:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_fifo_flush
90f050286227cf4c4f8aa425555d04723d331d48yq * to flush FIFOs
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_flush: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_fifo_drain:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_fifo_drain
90f050286227cf4c4f8aa425555d04723d331d48yq * to wait until empty output FIFO
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_drain: ");
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_wait_tx_drain(acm_port, timeout) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_drain: fifo drain failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_fifo_flush_locked:
90f050286227cf4c4f8aa425555d04723d331d48yq * flush FIFOs of the given ports
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_fifo_flush_locked(usbsacm_state_t *acmp, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_fifo_flush_locked: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* flush transmit FIFO if DS_TX is set */
90f050286227cf4c4f8aa425555d04723d331d48yq /* flush received FIFO if DS_RX is set */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_get_bulk_pipe_number:
90f050286227cf4c4f8aa425555d04723d331d48yq * Calculate the number of bulk in or out pipes in current device.
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_get_bulk_pipe_number(usbsacm_state_t *acmp, uint_t dir)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_bulk_pipe_number: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* search each interface which have bulk endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < if_num; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq * search endpoints in current interface,
90f050286227cf4c4f8aa425555d04723d331d48yq * which type is input parameter 'dir'
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * If not found, skip the internal loop
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * and search the next interface.
90f050286227cf4c4f8aa425555d04723d331d48yq * port management
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq * initialize, release port.
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_ports_status:
90f050286227cf4c4f8aa425555d04723d331d48yq * Initialize the port status for the current device.
90f050286227cf4c4f8aa425555d04723d331d48yq /* Initialize the port status to default value */
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.dwDTERate = LE_32((uint32_t)9600);
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.bParityType = USB_CDC_PARITY_NO;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_init(&cur_port->acm_port_mutex, NULL, MUTEX_DRIVER,
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to cdc acm spec, parse function descriptors.
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to spec, search pairs of bulk in/out
90f050286227cf4c4f8aa425555d04723d331d48yq * endpoints and fill port structure.
90f050286227cf4c4f8aa425555d04723d331d48yq /* search each interface which have bulk in and out */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < if_num; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* search interrupt pipe. */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq /* search pair of bulk in/out endpoints. */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT) == NULL)) {
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_alloc_ports:
90f050286227cf4c4f8aa425555d04723d331d48yq * Allocate memory and initialize the port state for the current device.
90f050286227cf4c4f8aa425555d04723d331d48yq /* Calculate the number of the bulk in/out endpoints */
90f050286227cf4c4f8aa425555d04723d331d48yq count_in = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_IN);
90f050286227cf4c4f8aa425555d04723d331d48yq count_out = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_OUT);
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: count_in = %d, count_out = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq /* return if not found any pair of bulk in/out endpoint. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: port count is zero.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate memory for ports */
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_ports = (usbsacm_port_t *)kmem_zalloc(acmp->acm_port_cnt *
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: allocate memory failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* fill the status of port structure. */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_free_ports:
90f050286227cf4c4f8aa425555d04723d331d48yq * Release ports and deallocate memory.
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_free_ports: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Release memory and data structure for each port */
90f050286227cf4c4f8aa425555d04723d331d48yq kmem_free((caddr_t)acmp->acm_ports, sizeof (usbsacm_port_t) *
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_get_descriptors:
90f050286227cf4c4f8aa425555d04723d331d48yq * analysis functional descriptors of acm device
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* set default control and data interface */
90f050286227cf4c4f8aa425555d04723d331d48yq /* get current interfaces */
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_ctrl_if_no = acmp->acm_dev_data->dev_curr_if;
90f050286227cf4c4f8aa425555d04723d331d48yq if (cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: elements in if_alt is %d",
90f050286227cf4c4f8aa425555d04723d331d48yq altif = &cfg->cfg_if[acm_port->acm_ctrl_if_no].if_alt[0];
90f050286227cf4c4f8aa425555d04723d331d48yq * Based on CDC specification, ACM devices usually include the
90f050286227cf4c4f8aa425555d04723d331d48yq * following function descriptors: Header, ACM, Union and Call
90f050286227cf4c4f8aa425555d04723d331d48yq * Management function descriptors. This loop search tree data
90f050286227cf4c4f8aa425555d04723d331d48yq * structure for each acm class descriptor.
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse call management functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse ACM functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse Union functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq /* For usb acm devices, it must satisfy the following options. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: # of interfaces %d < 2",
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: Device hasn't call management "
90f050286227cf4c4f8aa425555d04723d331d48yq "descriptor and use Union Descriptor.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: control interface or "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface don't match.");
90f050286227cf4c4f8aa425555d04723d331d48yq * We usually need both call and data capabilities, but
90f050286227cf4c4f8aa425555d04723d331d48yq * some devices, such as Nokia mobile phones, don't provide
90f050286227cf4c4f8aa425555d04723d331d48yq * call management descriptor, so we just give a warning
90f050286227cf4c4f8aa425555d04723d331d48yq * message.
90f050286227cf4c4f8aa425555d04723d331d48yq if (((mgmt_cap & USB_CDC_CALL_MGMT_CAP_CALL_MGMT) == 0) ||
90f050286227cf4c4f8aa425555d04723d331d48yq ((mgmt_cap & USB_CDC_CALL_MGMT_CAP_DATA_INTERFACE) == 0)) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "insufficient mgmt capabilities %x",
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: control interface %d or "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d out of range.",
90f050286227cf4c4f8aa425555d04723d331d48yq /* control interface must have interrupt endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "ctrl interface %d has no interrupt endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq /* data interface must have bulk in and out */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d has no bulk in endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d has no bulk out endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_cleanup:
90f050286227cf4c4f8aa425555d04723d331d48yq * Release resources of current device during detach.
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_cleanup: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* free ports */
90f050286227cf4c4f8aa425555d04723d331d48yq /* unregister callback function */
90f050286227cf4c4f8aa425555d04723d331d48yq /* destroy power management components */
90f050286227cf4c4f8aa425555d04723d331d48yq /* free description of device tree. */
90f050286227cf4c4f8aa425555d04723d331d48yq /* detach client device */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_restore_device_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * restore device state after CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check device status */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check if we are talking to the same device */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_check_same_device(acmp->acm_dip, acmp->acm_lh, USB_LOG_L0,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: Device has been reconnected "
90f050286227cf4c4f8aa425555d04723d331d48yq "but data may have been lost");
90f050286227cf4c4f8aa425555d04723d331d48yq /* reconnect pipes */
90f050286227cf4c4f8aa425555d04723d331d48yq * init device state
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: failed");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_restore_port_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * restore ports state after CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_port_state: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* restore status of all ports */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_port_state: failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * pipe management
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_open_port_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * Open pipes of one port and set port structure;
90f050286227cf4c4f8aa425555d04723d331d48yq * Each port includes three pipes: bulk in, bulk out and interrupt.
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get bulk and interrupt endpoint data */
90f050286227cf4c4f8aa425555d04723d331d48yq intr_pipe = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq in_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq out_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq /* Bulk in and out must exist meanwhile. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: look up bulk pipe failed in "
90f050286227cf4c4f8aa425555d04723d331d48yq "interface %d port %d",
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, it must have an interrupt pipe
90f050286227cf4c4f8aa425555d04723d331d48yq * for this port.
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility == B_TRUE && intr_pipe == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: look up interrupt pipe failed in "
90f050286227cf4c4f8aa425555d04723d331d48yq /* Open bulk in endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_pipe_open(acmp->acm_dip, &in_data->ep_descr, &policy,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, &acm_port->acm_bulkin_ph) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: open bulkin pipe failed!");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Open bulk out endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_pipe_open(acmp->acm_dip, &out_data->ep_descr, &policy,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, &acm_port->acm_bulkout_ph) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: open bulkout pipe failed!");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Open interrupt endpoint if found. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_pipe_open(acmp->acm_dip, &intr_pipe->ep_descr, &policy,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, &acm_port->acm_intr_ph) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: "
90f050286227cf4c4f8aa425555d04723d331d48yq "open control pipe failed");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the port structure. */
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_size = in_data->ep_descr.wMaxPacketSize;
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_close_port_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * Close pipes of one port and reset port structure to closed;
90f050286227cf4c4f8aa425555d04723d331d48yq * Each port includes three pipes: bulk in, bulk out and interrupt.
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: acm_bulkin_state = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the status of the given port. If port is closing or closed,
90f050286227cf4c4f8aa425555d04723d331d48yq * return directly.
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSED) ||
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: port is closing or has closed");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Close pipes */
90f050286227cf4c4f8aa425555d04723d331d48yq /* Reset the status of pipes to closed */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: port has been closed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_close_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * close all opened pipes of current devices.
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Close all ports */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_disconnect_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * this function just call usbsacm_close_pipes.
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_disconnect_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_reconnect_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * reconnect pipes in CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_reconnect_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* reopen all ports of current device. */
90f050286227cf4c4f8aa425555d04723d331d48yq * If port status is open, reopen it;
90f050286227cf4c4f8aa425555d04723d331d48yq * else retain the current status.
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_reconnect_pipes: "
90f050286227cf4c4f8aa425555d04723d331d48yq "open port %d failed.", i);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_bulkin_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * Bulk In regular and exeception callback;
90f050286227cf4c4f8aa425555d04723d331d48yq * USBA framework will call this callback
90f050286227cf4c4f8aa425555d04723d331d48yq * after deal with bulkin request.
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_bulkin_cb: "
90f050286227cf4c4f8aa425555d04723d331d48yq "acm_bulkin_state = %d acm_port_state = %d data_len = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state, acm_port->acm_port_state, data_len);
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_port_state == USBSACM_PORT_OPEN) && (data_len) &&
90f050286227cf4c4f8aa425555d04723d331d48yq /* prevent USBA from freeing data along with the request */
90f050286227cf4c4f8aa425555d04723d331d48yq /* save data on the receive list */
90f050286227cf4c4f8aa425555d04723d331d48yq /* invoke GSD receive callback */
90f050286227cf4c4f8aa425555d04723d331d48yq /* receive more */
90f050286227cf4c4f8aa425555d04723d331d48yq if (((acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) ||
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_bulkin_cb: restart rx fail "
90f050286227cf4c4f8aa425555d04723d331d48yq } else if (acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) {
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_bulkout_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * Bulk Out regular and exeception callback;
90f050286227cf4c4f8aa425555d04723d331d48yq * USBA framework will call this callback function
90f050286227cf4c4f8aa425555d04723d331d48yq * after deal with bulkout request.
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq /* put untransferred residue back on the transfer list */
90f050286227cf4c4f8aa425555d04723d331d48yq /* invoke GSD transmit callback */
90f050286227cf4c4f8aa425555d04723d331d48yq /* send more */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_rx_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * start data receipt
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_rx_start: acm_xfer_sz = 0x%lx acm_bulkin_size = 0x%lx",
90f050286227cf4c4f8aa425555d04723d331d48yq * Qualcomm CDMA card won't response the first request,
90f050286227cf4c4f8aa425555d04723d331d48yq * if the following code don't multiply by 2.
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = min(acmp->acm_xfer_sz, acm_port->acm_bulkin_size * 2);
90f050286227cf4c4f8aa425555d04723d331d48yq br = usb_alloc_bulk_req(acmp->acm_dip, data_len, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_rx_start: allocate bulk request failed");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize bulk in request. */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_bulk_xfer(acm_port->acm_bulkin_ph, br, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_tx_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * start data transmit
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* check the transmitted data. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: acm_tx_mp is NULL");
90f050286227cf4c4f8aa425555d04723d331d48yq /* check pipe status */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: error state in bulkout endpoint");
90f050286227cf4c4f8aa425555d04723d331d48yq /* send as much data as port can receive */
90f050286227cf4c4f8aa425555d04723d331d48yq len = min(msgdsize(acm_port->acm_tx_mp), acmp->acm_xfer_sz);
90f050286227cf4c4f8aa425555d04723d331d48yq if (len == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: data len is 0");
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate memory for sending data. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: failure in allocate memory");
90f050286227cf4c4f8aa425555d04723d331d48yq * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get the first mblk from chain. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (data_len <= 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* send request. */
90f050286227cf4c4f8aa425555d04723d331d48yq * If send failed, retransmit data when acm_tx_mp is null.
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_send_data:
90f050286227cf4c4f8aa425555d04723d331d48yq * data transfer
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: data address is 0x%p, length = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq br = usb_alloc_bulk_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: alloc req failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the bulk out request */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_bulk_xfer(acm_port->acm_bulkout_ph, br, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: Send Data failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq * Don't free it in usb_free_bulk_req because it will
90f050286227cf4c4f8aa425555d04723d331d48yq * be linked in usbsacm_put_head
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_wait_tx_drain:
90f050286227cf4c4f8aa425555d04723d331d48yq * wait until local tx buffer drains.
90f050286227cf4c4f8aa425555d04723d331d48yq * 'timeout' is in seconds, zero means wait forever
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_wait_tx_drain(usbsacm_port_t *acm_port, int timeout)
90f050286227cf4c4f8aa425555d04723d331d48yq until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
90f050286227cf4c4f8aa425555d04723d331d48yq return ((acm_port->acm_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_req_write:
90f050286227cf4c4f8aa425555d04723d331d48yq * send command over control pipe
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_req_write(usbsacm_port_t *acm_port, uchar_t request, uint16_t value,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_req_write: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the control request. */
90f050286227cf4c4f8aa425555d04723d331d48yq setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
90f050286227cf4c4f8aa425555d04723d331d48yq return (usb_pipe_ctrl_xfer_wait(acmp->acm_def_ph, &setup, data,
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_set_line_coding:
90f050286227cf4c4f8aa425555d04723d331d48yq * Send USB_CDC_REQ_SET_LINE_CODING request
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_set_line_coding(usbsacm_port_t *acm_port, usb_cdc_line_coding_t *lc)
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate mblk and copy supplied structure into it */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((bp = allocb(USB_CDC_LINE_CODING_LEN, BPRI_HI)) == NULL) {
d29f5a711240f866521445b1656d114da090335ezhigang lu - Sun Microsystems - Beijing China /* LINTED E_BAD_PTR_CAST_ALIGN */
90f050286227cf4c4f8aa425555d04723d331d48yq ret = usbsacm_req_write(acm_port, USB_CDC_REQ_SET_LINE_CODING, 0, &bp);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_mctl2reg:
90f050286227cf4c4f8aa425555d04723d331d48yq * Set Modem control status
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_reg2mctl:
90f050286227cf4c4f8aa425555d04723d331d48yq * Get Modem control status
90f050286227cf4c4f8aa425555d04723d331d48yq * misc routines
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_put_tail:
90f050286227cf4c4f8aa425555d04723d331d48yq * link a message block to tail of message
90f050286227cf4c4f8aa425555d04723d331d48yq * account for the case when message is null
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_put_head:
90f050286227cf4c4f8aa425555d04723d331d48yq * put a message block at the head of the message
90f050286227cf4c4f8aa425555d04723d331d48yq * account for the case when message is null
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq * power management
90f050286227cf4c4f8aa425555d04723d331d48yq * ----------------
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_create_pm_components:
90f050286227cf4c4f8aa425555d04723d331d48yq * create PM components
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_create_pm_components: ");
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_create_pm_components: failed");
90f050286227cf4c4f8aa425555d04723d331d48yq (usbsacm_pm_t *)kmem_zalloc(sizeof (usbsacm_pm_t), KM_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq * Qualcomm CDMA card won't response the following control commands
90f050286227cf4c4f8aa425555d04723d331d48yq * after receive USB_REMOTE_WAKEUP_ENABLE. So we just set
90f050286227cf4c4f8aa425555d04723d331d48yq * pm_wakeup_enable to 0 for this specific device.
90f050286227cf4c4f8aa425555d04723d331d48yq if (dev_descr->idVendor == 0x5c6 && dev_descr->idProduct == 0x3100) {
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_destroy_pm_components:
90f050286227cf4c4f8aa425555d04723d331d48yq * destroy PM components
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: ");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: "
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: "
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pm_set_busy:
90f050286227cf4c4f8aa425555d04723d331d48yq * mark device busy and raise power
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq /* if already marked busy, just increment the counter */
90f050286227cf4c4f8aa425555d04723d331d48yq /* need to raise power */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pm_set_busy: raising power failed");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pm_set_idle:
90f050286227cf4c4f8aa425555d04723d331d48yq * mark device idle
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pm_set_idle: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * if more ports use the device, do not mark as yet
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl0:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 0 -> 3
90f050286227cf4c4f8aa425555d04723d331d48yq * The same level as OS state, different from USB state
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl0: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D3 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq /* allow a disconnect/cpr'ed device to go to lower power */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl0: illegal device state");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl1:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 1 -> 2
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D2 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl2:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 2 -> 1
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D1 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl3:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 3 -> 0
90f050286227cf4c4f8aa425555d04723d331d48yq * The same level as OS state, different from USB state
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl3: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* Issue USB D0 command to the device here */
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq /* we are already in full power */
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl3: illegal device state");
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pipe_start_polling:
90f050286227cf4c4f8aa425555d04723d331d48yq * start polling on the interrupt pipe
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pipe_start_polling: ");
90f050286227cf4c4f8aa425555d04723d331d48yq intr = usb_alloc_intr_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq * If it is in interrupt context, usb_alloc_intr_req will return NULL if
90f050286227cf4c4f8aa425555d04723d331d48yq * called with SLEEP flag.
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pipe_start_polling: alloc req failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the interrupt request. */
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_len = acm_port->acm_intr_ep_descr.wMaxPacketSize;
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_intr_xfer(acm_port->acm_intr_ph, intr, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_intr_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt pipe normal callback
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq /* check data length */
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse interrupt data. */
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_intr_ex_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt pipe exception callback
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_ex_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * If completion reason isn't USB_CR_PIPE_CLOSING and
90f050286227cf4c4f8aa425555d04723d331d48yq * USB_CR_STOPPED_POLLING, restart polling.
90f050286227cf4c4f8aa425555d04723d331d48yq if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_ex_cb: state = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_parse_intr_data:
90f050286227cf4c4f8aa425555d04723d331d48yq * Parse data received from interrupt callback
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_parse_intr_data(usbsacm_port_t *acm_port, mblk_t *data)
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: ");
90f050286227cf4c4f8aa425555d04723d331d48yq * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1,
90f050286227cf4c4f8aa425555d04723d331d48yq * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0,
90f050286227cf4c4f8aa425555d04723d331d48yq * mLength is 2. So we directly get the value from the byte.
90f050286227cf4c4f8aa425555d04723d331d48yq if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: unknown request type - 0x%x",
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the return value of device
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: %s network!",
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: A response is a available.");
90f050286227cf4c4f8aa425555d04723d331d48yq /* check the parameter's length. */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: error data length.");
90f050286227cf4c4f8aa425555d04723d331d48yq * The Data field is a bitmapped value that contains
90f050286227cf4c4f8aa425555d04723d331d48yq * the current state of carrier detect, transmission
90f050286227cf4c4f8aa425555d04723d331d48yq * carrier, break, ring signal and device overrun
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the serial state of the current port.
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "receiver carrier is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "transmission carrier is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "break detection mechanism is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "ring signal detection is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "A framing error has occurred.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "A parity error has occurred.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "Received data has been discarded "
90f050286227cf4c4f8aa425555d04723d331d48yq "due to overrun.");
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: unknown notification - 0x%x!",