90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * CDDL HEADER START
90f050286227cf4c4f8aa425555d04723d331d48yq *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f050286227cf4c4f8aa425555d04723d331d48yq * or http://www.opensolaris.org/os/licensing.
90f050286227cf4c4f8aa425555d04723d331d48yq * See the License for the specific language governing permissions
90f050286227cf4c4f8aa425555d04723d331d48yq * and limitations under the License.
90f050286227cf4c4f8aa425555d04723d331d48yq *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq * CDDL HEADER END
90f050286227cf4c4f8aa425555d04723d331d48yq */
de81e71e031139a0a7f13b7bf64152c3faa76698Tim Marsland
90f050286227cf4c4f8aa425555d04723d331d48yq/*
9e37f2b5d225bd6428d62c06655138fc78fd1ac0Raymond Chen * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
90f050286227cf4c4f8aa425555d04723d331d48yq * Use is subject to license terms.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * USB Serial CDC ACM driver
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq * 1. General Concepts
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------------
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq * 2. Implementation
90f050286227cf4c4f8aa425555d04723d331d48yq * -----------------
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 *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq * port_state:
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq * attach_ports
90f050286227cf4c4f8aa425555d04723d331d48yq * |
90f050286227cf4c4f8aa425555d04723d331d48yq * |
90f050286227cf4c4f8aa425555d04723d331d48yq * |
90f050286227cf4c4f8aa425555d04723d331d48yq * v
90f050286227cf4c4f8aa425555d04723d331d48yq * USBSACM_PORT_CLOSED
90f050286227cf4c4f8aa425555d04723d331d48yq * | ^
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * V |
90f050286227cf4c4f8aa425555d04723d331d48yq * open_port close_port
90f050286227cf4c4f8aa425555d04723d331d48yq * | ^
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * V |
90f050286227cf4c4f8aa425555d04723d331d48yq * USBSACM_PORT_OPEN
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq * pipe_state:
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_alloc_ports usbsacm_free_ports
90f050286227cf4c4f8aa425555d04723d331d48yq * | ^
90f050286227cf4c4f8aa425555d04723d331d48yq * v |
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * |---->------ USBSACM_PORT_CLOSED ------>------+
90f050286227cf4c4f8aa425555d04723d331d48yq * ^ |
90f050286227cf4c4f8aa425555d04723d331d48yq * | reconnect/resume/open_port
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * disconnect/suspend/close_port |
90f050286227cf4c4f8aa425555d04723d331d48yq * | v
90f050286227cf4c4f8aa425555d04723d331d48yq * +------<------ USBSACM_PIPE_IDLE ------<------|
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * V ^
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * +-----------------+ +-----------+
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * V ^
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * rx_start/tx_start----->------failed------->---------|
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * | bulkin_cb/bulkout_cb
90f050286227cf4c4f8aa425555d04723d331d48yq * V |
90f050286227cf4c4f8aa425555d04723d331d48yq * | ^
90f050286227cf4c4f8aa425555d04723d331d48yq * | |
90f050286227cf4c4f8aa425555d04723d331d48yq * +----->----- USBSACM_PIPE_BUSY ---->------+
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq *
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 *
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/types.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/param.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/conf.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/stream.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/strsun.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/termio.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/termiox.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/ddi.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/sunddi.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/byteorder.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#define USBDRV_MAJOR_VER 2
90f050286227cf4c4f8aa425555d04723d331d48yq#define USBDRV_MINOR_VER 0
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/usba.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/usba/usba_types.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/clients/usbser/usbser.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/clients/usbser/usbser_dsdi.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/clients/usbcdc/usb_cdc.h>
90f050286227cf4c4f8aa425555d04723d331d48yq#include <sys/usb/clients/usbser/usbsacm/usbsacm.h>
90f050286227cf4c4f8aa425555d04723d331d48yq
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 *,
90f050286227cf4c4f8aa425555d04723d331d48yq void **);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_open(queue_t *, dev_t *, int, int, cred_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* DSD operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_attach(ds_attach_info_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_ds_detach(ds_hdl_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_ds_unregister_cb(ds_hdl_t, uint_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_open_port(ds_hdl_t, uint_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_close_port(ds_hdl_t, uint_t);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* standard UART operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_set_port_params(ds_hdl_t, uint_t,
90f050286227cf4c4f8aa425555d04723d331d48yq ds_port_params_t *);
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 *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_break_ctl(ds_hdl_t, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* data xfer */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_tx(ds_hdl_t, uint_t, mblk_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic mblk_t *usbsacm_ds_rx(ds_hdl_t, uint_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_ds_stop(ds_hdl_t, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_ds_start(ds_hdl_t, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* fifo operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_fifo_flush(ds_hdl_t, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_fifo_drain(ds_hdl_t, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_wait_tx_drain(usbsacm_port_t *, int);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_fifo_flush_locked(usbsacm_state_t *, uint_t, int);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* power management and CPR */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_suspend(ds_hdl_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_resume(ds_hdl_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_disconnect(ds_hdl_t);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_ds_reconnect(ds_hdl_t);
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 *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_pm_set_busy(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_pm_set_idle(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_pwrlvl0(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_pwrlvl1(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_pwrlvl2(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_pwrlvl3(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
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
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
90f050286227cf4c4f8aa425555d04723d331d48yq/* Utility functions */
90f050286227cf4c4f8aa425555d04723d331d48yq/* data transfer routines */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_rx_start(usbsacm_port_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_tx_start(usbsacm_port_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_send_data(usbsacm_port_t *, mblk_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* Initialize or release resources */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_init_alloc_ports(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_free_ports(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_cleanup(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* analysis functional descriptors */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_get_descriptors(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* hotplug */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_restore_device_state(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_restore_port_state(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* pipe operations */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_open_port_pipes(usbsacm_port_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_close_port_pipes(usbsacm_port_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_close_pipes(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_disconnect_pipes(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_reconnect_pipes(usbsacm_state_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* vendor-specific commands */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_req_write(usbsacm_port_t *, uchar_t, uint16_t,
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t **);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_set_line_coding(usbsacm_port_t *,
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cdc_line_coding_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_mctl2reg(int mask, int val, uint8_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_reg2mctl(uint8_t);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* misc */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_put_tail(mblk_t **, mblk_t *);
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void usbsacm_put_head(mblk_t **, mblk_t *);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * Standard STREAMS driver definitions
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstruct module_info usbsacm_modinfo = {
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* module id */
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm", /* module name */
90f050286227cf4c4f8aa425555d04723d331d48yq USBSER_MIN_PKTSZ, /* min pkt size */
90f050286227cf4c4f8aa425555d04723d331d48yq USBSER_MAX_PKTSZ, /* max pkt size */
90f050286227cf4c4f8aa425555d04723d331d48yq USBSER_HIWAT, /* hi watermark */
90f050286227cf4c4f8aa425555d04723d331d48yq USBSER_LOWAT /* low watermark */
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic struct qinit usbsacm_rinit = {
90f050286227cf4c4f8aa425555d04723d331d48yq NULL,
90f050286227cf4c4f8aa425555d04723d331d48yq usbser_rsrv,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_open,
90f050286227cf4c4f8aa425555d04723d331d48yq usbser_close,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL,
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_modinfo,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic struct qinit usbsacm_winit = {
90f050286227cf4c4f8aa425555d04723d331d48yq usbser_wput,
90f050286227cf4c4f8aa425555d04723d331d48yq usbser_wsrv,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL,
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_modinfo,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstruct streamtab usbsacm_str_info = {
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_rinit, &usbsacm_winit, NULL, NULL
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* cb_ops structure */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic struct cb_ops usbsacm_cb_ops = {
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_open */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_close */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_strategy */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_print */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_dump */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_read */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_write */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_ioctl */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_devmap */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_mmap */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* cb_segmap */
90f050286227cf4c4f8aa425555d04723d331d48yq nochpoll, /* cb_chpoll */
90f050286227cf4c4f8aa425555d04723d331d48yq ddi_prop_op, /* cb_prop_op */
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_str_info, /* cb_stream */
90f050286227cf4c4f8aa425555d04723d331d48yq (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG) /* cb_flag */
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* dev_ops structure */
90f050286227cf4c4f8aa425555d04723d331d48yqstruct dev_ops usbsacm_ops = {
90f050286227cf4c4f8aa425555d04723d331d48yq DEVO_REV, /* devo_rev */
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* devo_refcnt */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_getinfo, /* devo_getinfo */
90f050286227cf4c4f8aa425555d04723d331d48yq nulldev, /* devo_identify */
90f050286227cf4c4f8aa425555d04723d331d48yq nulldev, /* devo_probe */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_attach, /* devo_attach */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_detach, /* devo_detach */
90f050286227cf4c4f8aa425555d04723d331d48yq nodev, /* devo_reset */
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_cb_ops, /* devo_cb_ops */
90f050286227cf4c4f8aa425555d04723d331d48yq (struct bus_ops *)NULL, /* devo_bus_ops */
193974072f41a843678abf5f61979c748687e66bSherry Moore usbser_power, /* devo_power */
be529ebc20c1845423cc7561286bd60dcc97f677Raymond Chen ddi_quiesce_not_needed, /* devo_quiesce */
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqextern struct mod_ops mod_driverops;
90f050286227cf4c4f8aa425555d04723d331d48yq/* modldrv structure */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic struct modldrv modldrv = {
90f050286227cf4c4f8aa425555d04723d331d48yq &mod_driverops, /* type of module - driver */
77e515715b61e28fcf0c3f30936492888cecfd8bgongtian zhao - Sun Microsystems - Beijing China "USB Serial CDC ACM driver",
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_ops,
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/* modlinkage structure */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic struct modlinkage modlinkage = {
90f050286227cf4c4f8aa425555d04723d331d48yq MODREV_1,
90f050286227cf4c4f8aa425555d04723d331d48yq &modldrv,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void *usbsacm_statep; /* soft state */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * DSD definitions
90f050286227cf4c4f8aa425555d04723d331d48yq */
e8ed0869d5c65afe0c37c4755bf81f7381d1f43cJohn Beckstatic ds_ops_t usbsacm_ds_ops = {
90f050286227cf4c4f8aa425555d04723d331d48yq DS_OPS_VERSION,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_attach,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_detach,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_register_cb,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_unregister_cb,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_open_port,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_close_port,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_usb_power,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_suspend,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_resume,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_disconnect,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_reconnect,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_set_port_params,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_set_modem_ctl,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_get_modem_ctl,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_break_ctl,
90f050286227cf4c4f8aa425555d04723d331d48yq NULL, /* NULL if h/w doesn't support loopback */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_tx,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_rx,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_stop,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_start,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_fifo_flush,
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_ds_fifo_drain
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * baud code -> baud rate (0 means unsupported rate)
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int usbsacm_speedtab[] = {
90f050286227cf4c4f8aa425555d04723d331d48yq 0, /* B0 */
90f050286227cf4c4f8aa425555d04723d331d48yq 50, /* B50 */
90f050286227cf4c4f8aa425555d04723d331d48yq 75, /* B75 */
90f050286227cf4c4f8aa425555d04723d331d48yq 110, /* B110 */
90f050286227cf4c4f8aa425555d04723d331d48yq 134, /* B134 */
90f050286227cf4c4f8aa425555d04723d331d48yq 150, /* B150 */
90f050286227cf4c4f8aa425555d04723d331d48yq 200, /* B200 */
90f050286227cf4c4f8aa425555d04723d331d48yq 300, /* B300 */
90f050286227cf4c4f8aa425555d04723d331d48yq 600, /* B600 */
90f050286227cf4c4f8aa425555d04723d331d48yq 1200, /* B1200 */
90f050286227cf4c4f8aa425555d04723d331d48yq 1800, /* B1800 */
90f050286227cf4c4f8aa425555d04723d331d48yq 2400, /* B2400 */
90f050286227cf4c4f8aa425555d04723d331d48yq 4800, /* B4800 */
90f050286227cf4c4f8aa425555d04723d331d48yq 9600, /* B9600 */
90f050286227cf4c4f8aa425555d04723d331d48yq 19200, /* B19200 */
90f050286227cf4c4f8aa425555d04723d331d48yq 38400, /* B38400 */
90f050286227cf4c4f8aa425555d04723d331d48yq 57600, /* B57600 */
90f050286227cf4c4f8aa425555d04723d331d48yq 76800, /* B76800 */
90f050286227cf4c4f8aa425555d04723d331d48yq 115200, /* B115200 */
90f050286227cf4c4f8aa425555d04723d331d48yq 153600, /* B153600 */
90f050286227cf4c4f8aa425555d04723d331d48yq 230400, /* B230400 */
90f050286227cf4c4f8aa425555d04723d331d48yq 307200, /* B307200 */
de81e71e031139a0a7f13b7bf64152c3faa76698Tim Marsland 460800, /* B460800 */
de81e71e031139a0a7f13b7bf64152c3faa76698Tim Marsland 921600 /* B921600 */
90f050286227cf4c4f8aa425555d04723d331d48yq};
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic uint_t usbsacm_errlevel = USB_LOG_L4;
90f050286227cf4c4f8aa425555d04723d331d48yqstatic uint_t usbsacm_errmask = 0xffffffff;
90f050286227cf4c4f8aa425555d04723d331d48yqstatic uint_t usbsacm_instance_debug = (uint_t)-1;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm driver's entry points
90f050286227cf4c4f8aa425555d04723d331d48yq * -----------------------------
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * Module-wide initialization routine.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqint
90f050286227cf4c4f8aa425555d04723d331d48yq_init(void)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int error;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((error = mod_install(&modlinkage)) == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq error = ddi_soft_state_init(&usbsacm_statep,
90f050286227cf4c4f8aa425555d04723d331d48yq usbser_soft_state_size(), 1);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (error);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * Module-wide tear-down routine.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqint
90f050286227cf4c4f8aa425555d04723d331d48yq_fini(void)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int error;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((error = mod_remove(&modlinkage)) == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq ddi_soft_state_fini(&usbsacm_statep);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (error);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqint
90f050286227cf4c4f8aa425555d04723d331d48yq_info(struct modinfo *modinfop)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq return (mod_info(&modlinkage, modinfop));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * Device configuration entry points
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
90f050286227cf4c4f8aa425555d04723d331d48yq{
e8ed0869d5c65afe0c37c4755bf81f7381d1f43cJohn Beck return (usbser_attach(dip, cmd, usbsacm_statep, &usbsacm_ds_ops));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbser_detach(dip, cmd, usbsacm_statep));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqint
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
90f050286227cf4c4f8aa425555d04723d331d48yq void **result)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbser_getinfo(dip, infocmd, arg, result, usbsacm_statep));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbser_open(rq, dev, flag, sflag, cr, usbsacm_statep));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_attach(ds_attach_info_t *aip)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp = (usbsacm_state_t *)kmem_zalloc(sizeof (usbsacm_state_t),
90f050286227cf4c4f8aa425555d04723d331d48yq KM_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dip = aip->ai_dip;
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_usb_events = aip->ai_usb_events;
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_ports = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq *aip->ai_hdl = (ds_hdl_t)acmp;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* registers usbsacm with the USBA framework */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_client_attach(acmp->acm_dip, USBDRV_VERSION,
90f050286227cf4c4f8aa425555d04723d331d48yq 0) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get the configuration information of device */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_get_dev_data(acmp->acm_dip, &acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_PARSE_LVL_CFG, 0) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_def_ph = acmp->acm_dev_data->dev_default_ph;
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_state = USB_DEV_ONLINE;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_init(&acmp->acm_mutex, NULL, MUTEX_DRIVER,
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_data->dev_iblock_cookie);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_lh = usb_alloc_log_hdl(acmp->acm_dip, "usbsacm",
90f050286227cf4c4f8aa425555d04723d331d48yq &usbsacm_errlevel, &usbsacm_errmask, &usbsacm_instance_debug, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Create power management components */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_create_pm_components(acmp) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: create pm components failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Register to get callbacks for USB events */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_register_event_cbs(acmp->acm_dip, acmp->acm_usb_events, 0)
90f050286227cf4c4f8aa425555d04723d331d48yq != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: register event callback failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If devices conform to acm spec, driver will attach using class id;
90f050286227cf4c4f8aa425555d04723d331d48yq * if not, using device id.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbif,class2.2") == 0) ||
90f050286227cf4c4f8aa425555d04723d331d48yq ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name,
90f050286227cf4c4f8aa425555d04723d331d48yq "usb,class2.2.0") == 0))) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_compatibility = B_TRUE;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: A nonstandard device is attaching to "
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm driver. This device doesn't conform to "
90f050286227cf4c4f8aa425555d04723d331d48yq "usb cdc spec.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_compatibility = B_FALSE;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize state variables */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_init_alloc_ports(acmp) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: initialize port structure failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq *aip->ai_port_cnt = acmp->acm_port_cnt;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get max data size of bulk transfer */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_pipe_get_max_bulk_transfer_size(acmp->acm_dip,
90f050286227cf4c4f8aa425555d04723d331d48yq &acmp->acm_xfer_sz) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_attach: get max size of transfer failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq goto fail;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yqfail:
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_cleanup(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_detach:
90f050286227cf4c4f8aa425555d04723d331d48yq * detach device instance, called from GSD detach
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_detach(ds_hdl_t hdl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_detach:");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_close_pipes(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_cleanup(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_register_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_register_cb to register interrupt callbacks
90f050286227cf4c4f8aa425555d04723d331d48yq * for the given port
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_register_cb: acmp = 0x%p port_num = %d",
112116d842e816e29d26a8fe28ed25d201063169fb (void *)acmp, port_num);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check if port number is greater than actual port number. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (port_num >= acmp->acm_port_cnt) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_register_cb: port number is wrong.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_cb = *cb;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_unregister_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_unregister_cb to unregister
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt callbacks for the given port
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_unregister_cb(ds_hdl_t hdl, uint_t port_num)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_unregister_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (port_num < acmp->acm_port_cnt) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* Release callback function */
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq bzero(&acm_port->acm_cb, sizeof (acm_port->acm_cb));
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_open_port:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_open_port
90f050286227cf4c4f8aa425555d04723d331d48yq * to open the given port
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_open_port(ds_hdl_t hdl, uint_t port_num)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_open_port: port_num = %d", port_num);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check the status of the given port and device */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acmp->acm_dev_state == USB_DEV_DISCONNECTED) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (acm_port->acm_port_state != USBSACM_PORT_CLOSED)) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_set_busy(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* open pipes of port */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_open_port_pipes(acm_port) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_open_port: open pipes failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* data receipt */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_rx_start(acm_port) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_open_port: start receive data failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_port_state = USBSACM_PORT_OPEN;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_close_port:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_close_port
90f050286227cf4c4f8aa425555d04723d331d48yq * to close the given port
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_close_port(ds_hdl_t hdl, uint_t port_num)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq int rval = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_close_port: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_port_state = USBSACM_PORT_CLOSED;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_close_port_pipes(acm_port);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_fifo_flush_locked(acmp, port_num, DS_TX | DS_RX);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_set_idle(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_usb_power:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_usb_power
90f050286227cf4c4f8aa425555d04723d331d48yq * to set power level of the component
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_t *pm = acmp->acm_pm;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* check if pm is NULL */
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: pm is NULL.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * check if we are transitioning to a legal power level
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: "
90f050286227cf4c4f8aa425555d04723d331d48yq "illegal power level %d, pwr_states=%x",
90f050286227cf4c4f8aa425555d04723d331d48yq level, pm->pm_pwr_states);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * if we are about to raise power and asked to lower power, fail
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_usb_power: wrong condition.");
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Set the power status of device by request level.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq switch (level) {
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_OS_PWR_OFF:
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_pwrlvl0(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_OS_PWR_1:
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_pwrlvl1(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_OS_PWR_2:
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_pwrlvl2(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_OS_FULL_PWR:
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_pwrlvl3(acmp);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /*
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
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * DISCONNECTED/SUSPENDED.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg */
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if ((rval == USB_SUCCESS) &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg ((*new_state == USB_DEV_DISCONNECTED) ||
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg (*new_state == USB_DEV_SUSPENDED))) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_dev_state = *new_state;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq *new_state = acmp->acm_dev_state;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_suspend:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_suspend
90f050286227cf4c4f8aa425555d04723d331d48yq * during CPR suspend
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_suspend(ds_hdl_t hdl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg int state = USB_DEV_SUSPENDED;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_suspend: ");
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /* set device status to suspend */
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_dev_state = USB_DEV_SUSPENDED;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_disconnect_pipes(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_resume:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_resume
90f050286227cf4c4f8aa425555d04723d331d48yq * during CPR resume
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_resume(ds_hdl_t hdl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq int current_state;
90f050286227cf4c4f8aa425555d04723d331d48yq int ret;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_resume: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq current_state = acmp->acm_dev_state;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* restore the status of device */
90f050286227cf4c4f8aa425555d04723d331d48yq if (current_state != USB_DEV_ONLINE) {
90f050286227cf4c4f8aa425555d04723d331d48yq ret = usbsacm_restore_device_state(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq ret = USB_DEV_ONLINE;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_disconnect:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_disconnect
90f050286227cf4c4f8aa425555d04723d331d48yq * to disconnect USB device
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_disconnect(ds_hdl_t hdl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg int state = USB_DEV_DISCONNECTED;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_disconnect: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /* set device status to disconnected */
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_dev_state = USB_DEV_DISCONNECTED;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_disconnect_pipes(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_reconnect:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq * to reconnect USB device
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_reconnect(ds_hdl_t hdl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_reconnect: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbsacm_restore_device_state(acmp));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_set_port_params:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_set_port_params
90f050286227cf4c4f8aa425555d04723d331d48yq * to set one or more port parameters
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq uint_t ui;
90f050286227cf4c4f8aa425555d04723d331d48yq ds_port_param_entry_t *pe;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cdc_line_coding_t lc;
90f050286227cf4c4f8aa425555d04723d331d48yq int ret;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_set_port_params: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to set port param.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_compatibility == B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq "don't support Set_Line_Coding.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq lc = acm_port->acm_line_coding;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq pe = tp->tp_entries;
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get parameter information from ds_port_params_t */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < tp->tp_cnt; i++, pe++) {
90f050286227cf4c4f8aa425555d04723d331d48yq switch (pe->param) {
90f050286227cf4c4f8aa425555d04723d331d48yq case DS_PARAM_BAUD:
90f050286227cf4c4f8aa425555d04723d331d48yq /* Data terminal rate, in bits per second. */
90f050286227cf4c4f8aa425555d04723d331d48yq ui = pe->val.ui;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* if we don't support this speed, return USB_FAILURE */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((ui >= NELEM(usbsacm_speedtab)) ||
90f050286227cf4c4f8aa425555d04723d331d48yq ((ui > 0) && (usbsacm_speedtab[ui] == 0))) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq " error baud rate");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq lc.dwDTERate = LE_32(usbsacm_speedtab[ui]);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case DS_PARAM_PARITY:
90f050286227cf4c4f8aa425555d04723d331d48yq /* Parity Type */
90f050286227cf4c4f8aa425555d04723d331d48yq if (pe->val.ui & PARENB) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (pe->val.ui & PARODD) {
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bParityType = USB_CDC_PARITY_ODD;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bParityType = USB_CDC_PARITY_EVEN;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bParityType = USB_CDC_PARITY_NO;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case DS_PARAM_STOPB:
90f050286227cf4c4f8aa425555d04723d331d48yq /* Stop bit */
90f050286227cf4c4f8aa425555d04723d331d48yq if (pe->val.ui & CSTOPB) {
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bCharFormat = USB_CDC_STOP_BITS_2;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bCharFormat = USB_CDC_STOP_BITS_1;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case DS_PARAM_CHARSZ:
90f050286227cf4c4f8aa425555d04723d331d48yq /* Data Bits */
90f050286227cf4c4f8aa425555d04723d331d48yq switch (pe->val.ui) {
90f050286227cf4c4f8aa425555d04723d331d48yq case CS5:
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bDataBits = 5;
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case CS6:
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bDataBits = 6;
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case CS7:
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bDataBits = 7;
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case CS8:
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq lc.bDataBits = 8;
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_port_params: "
90f050286227cf4c4f8aa425555d04723d331d48yq "parameter 0x%x isn't supported",
90f050286227cf4c4f8aa425555d04723d331d48yq pe->param);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((ret = usbsacm_set_line_coding(acm_port, &lc)) == USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_line_coding = lc;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to acm spec, return success directly.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility != B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq ret = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_set_modem_ctl:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_set_modem_ctl
90f050286227cf4c4f8aa425555d04723d331d48yq * to set modem control of the given port
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq uint8_t new_mctl;
90f050286227cf4c4f8aa425555d04723d331d48yq int ret;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_modem_ctl: mask = 0x%x val = 0x%x",
90f050286227cf4c4f8aa425555d04723d331d48yq mask, val);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to set modem
90f050286227cf4c4f8aa425555d04723d331d48yq * controls.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_compatibility == B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_set_modem_ctl: "
90f050286227cf4c4f8aa425555d04723d331d48yq "don't support Set_Control_Line_State.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq new_mctl = acm_port->acm_mctlout;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_mctl2reg(mask, val, &new_mctl);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acmp->acm_compatibility == B_FALSE) || ((ret =
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_req_write(acm_port, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
90f050286227cf4c4f8aa425555d04723d331d48yq new_mctl, NULL)) == USB_SUCCESS)) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_mctlout = new_mctl;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to acm spec, return success directly.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility != B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq ret = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq *valp = usbsacm_reg2mctl(acm_port->acm_mctlout) & mask;
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, polling function can modify the value
90f050286227cf4c4f8aa425555d04723d331d48yq * of acm_mctlin; else set to default value.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility) {
90f050286227cf4c4f8aa425555d04723d331d48yq *valp |= usbsacm_reg2mctl(acm_port->acm_mctlin) & mask;
90f050286227cf4c4f8aa425555d04723d331d48yq *valp |= (mask & (TIOCM_CD | TIOCM_CTS));
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_get_modem_ctl: val = 0x%x", *valp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_tx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_break_ctl
90f050286227cf4c4f8aa425555d04723d331d48yq * to set/clear break
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_break_ctl: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, check if it support to send break.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SEND_BREAK) == 0 &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_compatibility == B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_break_ctl: don't support send break.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (usbsacm_req_write(acm_port, USB_CDC_REQ_SEND_BREAK,
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg ((ctl == DS_ON) ? 0xffff : 0), NULL));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_tx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_tx
90f050286227cf4c4f8aa425555d04723d331d48yq * to data transmit
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_tx: mp = 0x%p acmp = 0x%p", (void *)mp, (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* sanity checks */
90f050286227cf4c4f8aa425555d04723d331d48yq if (mp == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq }
22eb7cb54d8a6bcf6fe2674cb4b1f0cf2d85cfb6gd if (MBLKL(mp) < 1) {
90f050286227cf4c4f8aa425555d04723d331d48yq freemsg(mp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* put mblk to tail of mblk chain */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_put_tail(&acm_port->acm_tx_mp, mp);
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_tx_start(acm_port);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_rx:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_rx;
90f050286227cf4c4f8aa425555d04723d331d48yq * to data receipt
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic mblk_t *
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_rx(ds_hdl_t hdl, uint_t port_num)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *mp;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_ds_rx: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mp = acm_port->acm_rx_mp;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_rx_mp = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (mp);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_stop:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_stop;
90f050286227cf4c4f8aa425555d04723d331d48yq * but acm spec don't define this function
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_stop(ds_hdl_t hdl, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_stop: don't support!");
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_start;
90f050286227cf4c4f8aa425555d04723d331d48yq * but acm spec don't define this function
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_start(ds_hdl_t hdl, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_start: don't support!");
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_fifo_flush:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_fifo_flush
90f050286227cf4c4f8aa425555d04723d331d48yq * to flush FIFOs
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq int ret = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_flush: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq ret = usbsacm_fifo_flush_locked(acmp, port_num, dir);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_ds_fifo_drain:
90f050286227cf4c4f8aa425555d04723d331d48yq * GSD routine call ds_fifo_drain
90f050286227cf4c4f8aa425555d04723d331d48yq * to wait until empty output FIFO
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_ds_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = (usbsacm_state_t *)hdl;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq int rval = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_drain: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq ASSERT(acm_port->acm_port_state == USBSACM_PORT_OPEN);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_wait_tx_drain(acm_port, timeout) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_ds_fifo_drain: fifo drain failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_fifo_flush_locked:
90f050286227cf4c4f8aa425555d04723d331d48yq * flush FIFOs of the given ports
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_fifo_flush_locked(usbsacm_state_t *acmp, uint_t port_num, int dir)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = &acmp->acm_ports[port_num];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_fifo_flush_locked: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* flush transmit FIFO if DS_TX is set */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((dir & DS_TX) && acm_port->acm_tx_mp) {
90f050286227cf4c4f8aa425555d04723d331d48yq freemsg(acm_port->acm_tx_mp);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_tx_mp = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq /* flush received FIFO if DS_RX is set */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((dir & DS_RX) && acm_port->acm_rx_mp) {
90f050286227cf4c4f8aa425555d04723d331d48yq freemsg(acm_port->acm_rx_mp);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_rx_mp = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_get_bulk_pipe_number:
90f050286227cf4c4f8aa425555d04723d331d48yq * Calculate the number of bulk in or out pipes in current device.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_get_bulk_pipe_number(usbsacm_state_t *acmp, uint_t dir)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int count = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq int i, skip;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_if_data_t *cur_if;
90f050286227cf4c4f8aa425555d04723d331d48yq int ep_num;
90f050286227cf4c4f8aa425555d04723d331d48yq int if_num;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_bulk_pipe_number: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if;
90f050286227cf4c4f8aa425555d04723d331d48yq if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* search each interface which have bulk endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < if_num; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq ep_num = cur_if->if_alt->altif_n_ep;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * search endpoints in current interface,
90f050286227cf4c4f8aa425555d04723d331d48yq * which type is input parameter 'dir'
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq for (skip = 0; skip < ep_num; skip++) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if (usb_lookup_ep_data(acmp->acm_dip,
9e37f2b5d225bd6428d62c06655138fc78fd1ac0Raymond Chen acmp->acm_dev_data, i, 0, skip,
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USB_EP_ATTR_BULK, dir) == NULL) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg /*
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * If not found, skip the internal loop
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg * and search the next interface.
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg */
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg break;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg count++;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cur_if++;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (count);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * port management
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq * initialize, release port.
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_ports_status:
90f050286227cf4c4f8aa425555d04723d331d48yq * Initialize the port status for the current device.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_init_ports_status(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *cur_port;
90f050286227cf4c4f8aa425555d04723d331d48yq int i, skip;
90f050286227cf4c4f8aa425555d04723d331d48yq int if_num;
90f050286227cf4c4f8aa425555d04723d331d48yq int intr_if_no = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq int ep_num;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_if_data_t *cur_if;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_init_ports_status: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Initialize the port status to default value */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < acmp->acm_port_cnt; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port = &acmp->acm_ports[i];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cv_init(&cur_port->acm_tx_cv, NULL, CV_DRIVER, NULL);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_port_state = USBSACM_PORT_CLOSED;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.dwDTERate = LE_32((uint32_t)9600);
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.bCharFormat = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.bParityType = USB_CDC_PARITY_NO;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_line_coding.bDataBits = 8;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_device = acmp;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_init(&cur_port->acm_port_mutex, NULL, MUTEX_DRIVER,
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_data->dev_iblock_cookie);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to cdc acm spec, parse function descriptors.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility == B_TRUE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_get_descriptors(acmp) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device don't conform to spec, search pairs of bulk in/out
90f050286227cf4c4f8aa425555d04723d331d48yq * endpoints and fill port structure.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if;
90f050286227cf4c4f8aa425555d04723d331d48yq if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port = acmp->acm_ports;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* search each interface which have bulk in and out */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < if_num; i++) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg ep_num = cur_if->if_alt->altif_n_ep;
90f050286227cf4c4f8aa425555d04723d331d48yq
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg for (skip = 0; skip < ep_num; skip++) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* search interrupt pipe. */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq i, 0, skip, USB_EP_ATTR_INTR, USB_EP_DIR_IN) != NULL)) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq intr_if_no = i;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
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_IN) == NULL) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (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
90f050286227cf4c4f8aa425555d04723d331d48yq continue;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_data_if_no = i;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_ctrl_if_no = intr_if_no;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port->acm_data_port_no = skip;
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port++;
90f050286227cf4c4f8aa425555d04723d331d48yq intr_if_no = 0;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_if++;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_init_alloc_ports:
90f050286227cf4c4f8aa425555d04723d331d48yq * Allocate memory and initialize the port state for the current device.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_init_alloc_ports(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg int rval = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq int count_in = 0, count_out = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility) {
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_port_cnt = 1;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
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
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: count_in = %d, count_out = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq count_in, count_out);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_port_cnt = min(count_in, count_out);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* return if not found any pair of bulk in/out endpoint. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_port_cnt == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: port count is zero.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate memory for ports */
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_ports = (usbsacm_port_t *)kmem_zalloc(acmp->acm_port_cnt *
90f050286227cf4c4f8aa425555d04723d331d48yq sizeof (usbsacm_port_t), KM_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_ports == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_init_alloc_ports: allocate memory failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* fill the status of port structure. */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_init_ports_status(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_free_ports(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_free_ports:
90f050286227cf4c4f8aa425555d04723d331d48yq * Release ports and deallocate memory.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_free_ports(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_free_ports: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Release memory and data structure for each port */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < acmp->acm_port_cnt; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq cv_destroy(&acmp->acm_ports[i].acm_tx_cv);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_destroy(&acmp->acm_ports[i].acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq kmem_free((caddr_t)acmp->acm_ports, sizeof (usbsacm_port_t) *
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_port_cnt);
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_ports = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_get_descriptors:
90f050286227cf4c4f8aa425555d04723d331d48yq * analysis functional descriptors of acm device
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_get_descriptors(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cfg_data_t *cfg;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_alt_if_data_t *altif;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cvs_data_t *cvs;
90f050286227cf4c4f8aa425555d04723d331d48yq int mgmt_cap = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq int master_if = -1, slave_if = -1;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = acmp->acm_ports;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cfg = acmp->acm_dev_data->dev_curr_cfg;
90f050286227cf4c4f8aa425555d04723d331d48yq /* set default control and data interface */
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_ctrl_if_no = acm_port->acm_data_if_no = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
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 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: elements in if_alt is %d",
90f050286227cf4c4f8aa425555d04723d331d48yq cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq altif = &cfg->cfg_if[acm_port->acm_ctrl_if_no].if_alt[0];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < altif->altif_n_cvs; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq cvs = &altif->altif_cvs[i];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((cvs->cvs_buf == NULL) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) {
90f050286227cf4c4f8aa425555d04723d331d48yq continue;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq switch (cvs->cvs_buf[2]) {
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_DESCR_TYPE_CALL_MANAGEMENT:
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse call management functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (cvs->cvs_buf_len >= 5) {
90f050286227cf4c4f8aa425555d04723d331d48yq mgmt_cap = cvs->cvs_buf[3];
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no = cvs->cvs_buf[4];
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_DESCR_TYPE_ACM:
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse ACM functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (cvs->cvs_buf_len >= 4) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_cap = cvs->cvs_buf[3];
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_DESCR_TYPE_UNION:
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse Union functional descriptor. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (cvs->cvs_buf_len >= 5) {
90f050286227cf4c4f8aa425555d04723d331d48yq master_if = cvs->cvs_buf[3];
90f050286227cf4c4f8aa425555d04723d331d48yq slave_if = cvs->cvs_buf[4];
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* For usb acm devices, it must satisfy the following options. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (cfg->cfg_n_if < 2) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: # of interfaces %d < 2",
90f050286227cf4c4f8aa425555d04723d331d48yq cfg->cfg_n_if);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_data_if_no == 0 &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg slave_if != acm_port->acm_data_if_no) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: Device hasn't call management "
90f050286227cf4c4f8aa425555d04723d331d48yq "descriptor and use Union Descriptor.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no = slave_if;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((master_if != acm_port->acm_ctrl_if_no) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (slave_if != acm_port->acm_data_if_no)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: control interface or "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface don't match.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq if (((mgmt_cap & USB_CDC_CALL_MGMT_CAP_CALL_MGMT) == 0) ||
90f050286227cf4c4f8aa425555d04723d331d48yq ((mgmt_cap & USB_CDC_CALL_MGMT_CAP_DATA_INTERFACE) == 0)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "insufficient mgmt capabilities %x",
90f050286227cf4c4f8aa425555d04723d331d48yq mgmt_cap);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_ctrl_if_no >= cfg->cfg_n_if) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (acm_port->acm_data_if_no >= cfg->cfg_n_if)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: control interface %d or "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d out of range.",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_ctrl_if_no, acm_port->acm_data_if_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* control interface must have interrupt endpoint */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_DIR_IN) == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "ctrl interface %d has no interrupt endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* data interface must have bulk in and out */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_DIR_IN) == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d has no bulk in endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_DIR_OUT) == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_get_descriptors: "
90f050286227cf4c4f8aa425555d04723d331d48yq "data interface %d has no bulk out endpoint",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_cleanup:
90f050286227cf4c4f8aa425555d04723d331d48yq * Release resources of current device during detach.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_cleanup(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_cleanup: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* free ports */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_ports != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_free_ports(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* unregister callback function */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_usb_events != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usb_unregister_event_cbs(acmp->acm_dip,
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg acmp->acm_usb_events);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* destroy power management components */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_pm != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_destroy_pm_components(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* free description of device tree. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_def_ph != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_destroy(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_descr_tree(acmp->acm_dip, acmp->acm_dev_data);
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_def_ph = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_lh != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_log_hdl(acmp->acm_lh);
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_lh = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* detach client device */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_dev_data != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usb_client_detach(acmp->acm_dip, acmp->acm_dev_data);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq kmem_free((caddr_t)acmp, sizeof (usbsacm_state_t));
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_restore_device_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * restore device state after CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_restore_device_state(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int state;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq state = acmp->acm_dev_state;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Check device status */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
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 -1, USB_CHK_ALL, NULL) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq state = acmp->acm_dev_state = USB_DEV_DISCONNECTED;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (state == USB_DEV_DISCONNECTED) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L1(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: Device has been reconnected "
90f050286227cf4c4f8aa425555d04723d331d48yq "but data may have been lost");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* reconnect pipes */
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_reconnect_pipes(acmp) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * init device state
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq state = acmp->acm_dev_state = USB_DEV_ONLINE;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((usbsacm_restore_port_state(acmp) != USB_SUCCESS)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_device_state: failed");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (state);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_restore_port_state:
90f050286227cf4c4f8aa425555d04723d331d48yq * restore ports state after CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_restore_port_state(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int i, ret = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *cur_port;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_port_state: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* restore status of all ports */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < acmp->acm_port_cnt; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port = &acmp->acm_ports[i];
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (cur_port->acm_port_state != USBSACM_PORT_OPEN) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq continue;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if ((ret = usbsacm_set_line_coding(cur_port,
90f050286227cf4c4f8aa425555d04723d331d48yq &cur_port->acm_line_coding)) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_restore_port_state: failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * pipe management
90f050286227cf4c4f8aa425555d04723d331d48yq * ---------------
90f050286227cf4c4f8aa425555d04723d331d48yq *
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 */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_open_port_pipes(usbsacm_port_t *acm_port)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int rval = USB_SUCCESS;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_ep_data_t *in_data, *out_data, *intr_pipe;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_policy_t policy;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_open_port_pipes: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get bulk and interrupt endpoint data */
90f050286227cf4c4f8aa425555d04723d331d48yq intr_pipe = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_ctrl_if_no, 0, 0,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_ATTR_INTR, USB_EP_DIR_IN);
90f050286227cf4c4f8aa425555d04723d331d48yq in_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_ATTR_BULK, USB_EP_DIR_IN);
90f050286227cf4c4f8aa425555d04723d331d48yq out_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data,
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Bulk in and out must exist meanwhile. */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((in_data == NULL) || (out_data == NULL)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: look up bulk pipe failed in "
90f050286227cf4c4f8aa425555d04723d331d48yq "interface %d port %d",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_data_if_no, acm_port->acm_data_port_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If device conform to acm spec, it must have an interrupt pipe
90f050286227cf4c4f8aa425555d04723d331d48yq * for this port.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_compatibility == B_TRUE && intr_pipe == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: look up interrupt pipe failed in "
90f050286227cf4c4f8aa425555d04723d331d48yq "interface %d", acm_port->acm_ctrl_if_no);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq policy.pp_max_async_reqs = 2;
90f050286227cf4c4f8aa425555d04723d331d48yq
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 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: open bulkin pipe failed!");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
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 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: open bulkout pipe failed!");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, NULL, NULL);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Open interrupt endpoint if found. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (intr_pipe != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
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 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_open_port_pipes: "
90f050286227cf4c4f8aa425555d04723d331d48yq "open control pipe failed");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, NULL, NULL);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, NULL, NULL);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the port structure. */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_size = in_data->ep_descr.wMaxPacketSize;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_intr_ph != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_ep_descr = intr_pipe->ep_descr;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_intr_ph != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pipe_start_polling(acm_port);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_close_port_pipes(usbsacm_port_t *acm_port)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: acm_bulkin_state = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the status of the given port. If port is closing or closed,
90f050286227cf4c4f8aa425555d04723d331d48yq * return directly.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSED) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSING)) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: port is closing or has closed");
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSING;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Close pipes */
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_reset(acmp->acm_dip, acm_port->acm_bulkin_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, 0, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, 0, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, 0, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_intr_ph != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_stop_intr_polling(acm_port->acm_intr_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_pipe_close(acmp->acm_dip, acm_port->acm_intr_ph,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_FLAGS_SLEEP, 0, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* Reset the status of pipes to closed */
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSED;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_ph = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_state = USBSACM_PIPE_CLOSED;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_ph = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_intr_ph != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_state = USBSACM_PIPE_CLOSED;
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_ph = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_port_pipes: port has been closed.");
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_close_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * close all opened pipes of current devices.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_close_pipes(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_close_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* Close all ports */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < acmp->acm_port_cnt; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_close_port_pipes(&acmp->acm_ports[i]);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_disconnect_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * this function just call usbsacm_close_pipes.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_disconnect_pipes(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_disconnect_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_close_pipes(acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_reconnect_pipes:
90f050286227cf4c4f8aa425555d04723d331d48yq * reconnect pipes in CPR resume or reconnect
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_reconnect_pipes(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *cur_port = acmp->acm_ports;
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_reconnect_pipes: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* reopen all ports of current device. */
90f050286227cf4c4f8aa425555d04723d331d48yq for (i = 0; i < acmp->acm_port_cnt; i++) {
90f050286227cf4c4f8aa425555d04723d331d48yq cur_port = &acmp->acm_ports[i];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If port status is open, reopen it;
90f050286227cf4c4f8aa425555d04723d331d48yq * else retain the current status.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (cur_port->acm_port_state == USBSACM_PORT_OPEN) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_open_port_pipes(cur_port) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_reconnect_pipes: "
90f050286227cf4c4f8aa425555d04723d331d48yq "open port %d failed.", i);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&cur_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *data;
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq data = req->bulk_data;
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = (data) ? MBLKL(data) : 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
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
90f050286227cf4c4f8aa425555d04723d331d48yq if ((acm_port->acm_port_state == USBSACM_PORT_OPEN) && (data_len) &&
90f050286227cf4c4f8aa425555d04723d331d48yq (req->bulk_completion_reason == USB_CR_OK)) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* prevent USBA from freeing data along with the request */
90f050286227cf4c4f8aa425555d04723d331d48yq req->bulk_data = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* save data on the receive list */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_put_tail(&acm_port->acm_rx_mp, data);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* invoke GSD receive callback */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_cb.cb_rx) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_cb.cb_rx(acm_port->acm_cb.cb_arg);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_bulk_req(req);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* receive more */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (((acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) ||
90f050286227cf4c4f8aa425555d04723d331d48yq (acm_port->acm_bulkin_state == USBSACM_PIPE_IDLE)) &&
90f050286227cf4c4f8aa425555d04723d331d48yq (acm_port->acm_port_state == USBSACM_PORT_OPEN) &&
90f050286227cf4c4f8aa425555d04723d331d48yq (acmp->acm_dev_state == USB_DEV_ONLINE)) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (usbsacm_rx_start(acm_port) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_bulkin_cb: restart rx fail "
90f050286227cf4c4f8aa425555d04723d331d48yq "acm_port_state = %d", acm_port->acm_port_state);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq } else if (acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *data = req->bulk_data;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_bulkout_cb: acmp = 0x%p", (void *)acmp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* put untransferred residue back on the transfer list */
90f050286227cf4c4f8aa425555d04723d331d48yq if (req->bulk_completion_reason && (data_len > 0)) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_put_head(&acm_port->acm_tx_mp, data);
90f050286227cf4c4f8aa425555d04723d331d48yq req->bulk_data = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_bulk_req(req);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* invoke GSD transmit callback */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_cb.cb_tx) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_cb.cb_tx(acm_port->acm_cb.cb_arg);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* send more */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_tx_mp == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq cv_broadcast(&acm_port->acm_tx_cv);
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_tx_start(acm_port);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_rx_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * start data receipt
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_rx_start(usbsacm_port_t *acm_port)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_bulk_req_t *br;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval = USB_FAILURE;
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_rx_start: acm_xfer_sz = 0x%lx acm_bulkin_size = 0x%lx",
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_xfer_sz, acm_port->acm_bulkin_size);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_BUSY;
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Qualcomm CDMA card won't response the first request,
90f050286227cf4c4f8aa425555d04723d331d48yq * if the following code don't multiply by 2.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = min(acmp->acm_xfer_sz, acm_port->acm_bulkin_size * 2);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq br = usb_alloc_bulk_req(acmp->acm_dip, data_len, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq if (br == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_rx_start: allocate bulk request failed");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize bulk in request. */
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_len = data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_timeout = USBSACM_BULKIN_TIMEOUT;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_cb = usbsacm_bulkin_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_exc_cb = usbsacm_bulkin_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_client_private = (usb_opaque_t)acm_port;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_attributes = USB_ATTRS_AUTOCLEARING
90f050286227cf4c4f8aa425555d04723d331d48yq | USB_ATTRS_SHORT_XFER_OK;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_bulk_xfer(acm_port->acm_bulkin_ph, br, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_rx_start: bulk transfer failed %d", rval);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_bulk_req(br);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_tx_start:
90f050286227cf4c4f8aa425555d04723d331d48yq * start data transmit
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_tx_start(usbsacm_port_t *acm_port)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int len; /* bytes we can transmit */
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *data; /* data to be transmitted */
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len; /* bytes in 'data' */
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *mp; /* current msgblk */
90f050286227cf4c4f8aa425555d04723d331d48yq int copylen; /* bytes copy from 'mp' to 'data' */
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* check the transmitted data. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_tx_mp == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: acm_tx_mp is NULL");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* check pipe status */
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_bulkout_state != USBSACM_PIPE_IDLE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: error state in bulkout endpoint");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq ASSERT(MBLKL(acm_port->acm_tx_mp) > 0);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* send as much data as port can receive */
90f050286227cf4c4f8aa425555d04723d331d48yq len = min(msgdsize(acm_port->acm_tx_mp), acmp->acm_xfer_sz);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (len == 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: data len is 0");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate memory for sending data. */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((data = allocb(len, BPRI_LO)) == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_tx_start: failure in allocate memory");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq while ((data_len < len) && acm_port->acm_tx_mp) {
90f050286227cf4c4f8aa425555d04723d331d48yq /* Get the first mblk from chain. */
90f050286227cf4c4f8aa425555d04723d331d48yq mp = acm_port->acm_tx_mp;
90f050286227cf4c4f8aa425555d04723d331d48yq copylen = min(MBLKL(mp), len - data_len);
90f050286227cf4c4f8aa425555d04723d331d48yq bcopy(mp->b_rptr, data->b_wptr, copylen);
90f050286227cf4c4f8aa425555d04723d331d48yq mp->b_rptr += copylen;
90f050286227cf4c4f8aa425555d04723d331d48yq data->b_wptr += copylen;
90f050286227cf4c4f8aa425555d04723d331d48yq data_len += copylen;
90f050286227cf4c4f8aa425555d04723d331d48yq
22eb7cb54d8a6bcf6fe2674cb4b1f0cf2d85cfb6gd if (MBLKL(mp) < 1) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_tx_mp = unlinkb(mp);
90f050286227cf4c4f8aa425555d04723d331d48yq freeb(mp);
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq ASSERT(data_len == len);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (data_len <= 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq freeb(data);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_state = USBSACM_PIPE_BUSY;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* send request. */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usbsacm_send_data(acm_port, data);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If send failed, retransmit data when acm_tx_mp is null.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_tx_mp == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_put_head(&acm_port->acm_tx_mp, data);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_send_data:
90f050286227cf4c4f8aa425555d04723d331d48yq * data transfer
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_send_data(usbsacm_port_t *acm_port, mblk_t *data)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_bulk_req_t *br;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len = MBLKL(data);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: data address is 0x%p, length = %d",
112116d842e816e29d26a8fe28ed25d201063169fb (void *)data, data_len);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq br = usb_alloc_bulk_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq if (br == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: alloc req failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the bulk out request */
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_data = data;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_len = data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_timeout = USBSACM_BULKOUT_TIMEOUT;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_cb = usbsacm_bulkout_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_exc_cb = usbsacm_bulkout_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_client_private = (usb_opaque_t)acm_port;
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_bulk_xfer(acm_port->acm_bulkout_ph, br, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_send_data: Send Data failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Don't free it in usb_free_bulk_req because it will
90f050286227cf4c4f8aa425555d04723d331d48yq * be linked in usbsacm_put_head
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq br->bulk_data = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_bulk_req(br);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (rval);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_wait_tx_drain:
90f050286227cf4c4f8aa425555d04723d331d48yq * wait until local tx buffer drains.
90f050286227cf4c4f8aa425555d04723d331d48yq * 'timeout' is in seconds, zero means wait forever
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_wait_tx_drain(usbsacm_port_t *acm_port, int timeout)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq clock_t until;
90f050286227cf4c4f8aa425555d04723d331d48yq int over = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq while (acm_port->acm_tx_mp && !over) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (timeout > 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq over = (cv_timedwait_sig(&acm_port->acm_tx_cv,
90f050286227cf4c4f8aa425555d04723d331d48yq &acm_port->acm_port_mutex, until) <= 0);
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq over = (cv_wait_sig(&acm_port->acm_tx_cv,
90f050286227cf4c4f8aa425555d04723d331d48yq &acm_port->acm_port_mutex) == 0);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return ((acm_port->acm_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_req_write:
90f050286227cf4c4f8aa425555d04723d331d48yq * send command over control pipe
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_req_write(usbsacm_port_t *acm_port, uchar_t request, uint16_t value,
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t **data)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_ctrl_setup_t setup;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cb_flags_t cb_flags;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cr_t cr;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_req_write: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the control request. */
90f050286227cf4c4f8aa425555d04723d331d48yq setup.bmRequestType = USBSACM_REQ_WRITE_IF;
90f050286227cf4c4f8aa425555d04723d331d48yq setup.bRequest = request;
90f050286227cf4c4f8aa425555d04723d331d48yq setup.wValue = value;
90f050286227cf4c4f8aa425555d04723d331d48yq setup.wIndex = acm_port->acm_ctrl_if_no;
90f050286227cf4c4f8aa425555d04723d331d48yq setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
90f050286227cf4c4f8aa425555d04723d331d48yq setup.attrs = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (usb_pipe_ctrl_xfer_wait(acmp->acm_def_ph, &setup, data,
90f050286227cf4c4f8aa425555d04723d331d48yq &cr, &cb_flags, 0));
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_set_line_coding:
90f050286227cf4c4f8aa425555d04723d331d48yq * Send USB_CDC_REQ_SET_LINE_CODING request
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_set_line_coding(usbsacm_port_t *acm_port, usb_cdc_line_coding_t *lc)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *bp;
90f050286227cf4c4f8aa425555d04723d331d48yq int ret;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* allocate mblk and copy supplied structure into it */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((bp = allocb(USB_CDC_LINE_CODING_LEN, BPRI_HI)) == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_NO_RESOURCES);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq#ifndef __lock_lint /* warlock gets confused here */
d29f5a711240f866521445b1656d114da090335ezhigang lu - Sun Microsystems - Beijing China /* LINTED E_BAD_PTR_CAST_ALIGN */
90f050286227cf4c4f8aa425555d04723d331d48yq *((usb_cdc_line_coding_t *)bp->b_wptr) = *lc;
90f050286227cf4c4f8aa425555d04723d331d48yq bp->b_wptr += USB_CDC_LINE_CODING_LEN;
90f050286227cf4c4f8aa425555d04723d331d48yq#endif
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq ret = usbsacm_req_write(acm_port, USB_CDC_REQ_SET_LINE_CODING, 0, &bp);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (bp != NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq freeb(bp);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (ret);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_mctl2reg:
90f050286227cf4c4f8aa425555d04723d331d48yq * Set Modem control status
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_mctl2reg(int mask, int val, uint8_t *line_ctl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq if (mask & TIOCM_RTS) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (val & TIOCM_RTS) {
90f050286227cf4c4f8aa425555d04723d331d48yq *line_ctl |= USB_CDC_ACM_CONTROL_RTS;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq *line_ctl &= ~USB_CDC_ACM_CONTROL_RTS;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (mask & TIOCM_DTR) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (val & TIOCM_DTR) {
90f050286227cf4c4f8aa425555d04723d331d48yq *line_ctl |= USB_CDC_ACM_CONTROL_DTR;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq *line_ctl &= ~USB_CDC_ACM_CONTROL_DTR;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_reg2mctl:
90f050286227cf4c4f8aa425555d04723d331d48yq * Get Modem control status
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_reg2mctl(uint8_t line_ctl)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int val = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (line_ctl & USB_CDC_ACM_CONTROL_RTS) {
90f050286227cf4c4f8aa425555d04723d331d48yq val |= TIOCM_RTS;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (line_ctl & USB_CDC_ACM_CONTROL_DTR) {
90f050286227cf4c4f8aa425555d04723d331d48yq val |= TIOCM_DTR;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (line_ctl & USB_CDC_ACM_CONTROL_DSR) {
90f050286227cf4c4f8aa425555d04723d331d48yq val |= TIOCM_DSR;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (line_ctl & USB_CDC_ACM_CONTROL_RNG) {
90f050286227cf4c4f8aa425555d04723d331d48yq val |= TIOCM_RI;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (val);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * misc routines
90f050286227cf4c4f8aa425555d04723d331d48yq * -------------
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_put_tail:
90f050286227cf4c4f8aa425555d04723d331d48yq * link a message block to tail of message
90f050286227cf4c4f8aa425555d04723d331d48yq * account for the case when message is null
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_put_tail(mblk_t **mpp, mblk_t *bp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq if (*mpp) {
90f050286227cf4c4f8aa425555d04723d331d48yq linkb(*mpp, bp);
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq *mpp = bp;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_put_head:
90f050286227cf4c4f8aa425555d04723d331d48yq * put a message block at the head of the message
90f050286227cf4c4f8aa425555d04723d331d48yq * account for the case when message is null
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_put_head(mblk_t **mpp, mblk_t *bp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq if (*mpp) {
90f050286227cf4c4f8aa425555d04723d331d48yq linkb(bp, *mpp);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq *mpp = bp;
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * power management
90f050286227cf4c4f8aa425555d04723d331d48yq * ----------------
90f050286227cf4c4f8aa425555d04723d331d48yq *
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_create_pm_components:
90f050286227cf4c4f8aa425555d04723d331d48yq * create PM components
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_create_pm_components(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq dev_info_t *dip = acmp->acm_dip;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_t *pm;
90f050286227cf4c4f8aa425555d04723d331d48yq uint_t pwr_states;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_dev_descr_t *dev_descr;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_create_pm_components: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_create_pm_components: failed");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq pm = acmp->acm_pm =
90f050286227cf4c4f8aa425555d04723d331d48yq (usbsacm_pm_t *)kmem_zalloc(sizeof (usbsacm_pm_t), KM_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_pwr_states = (uint8_t)pwr_states;
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
90f050286227cf4c4f8aa425555d04723d331d48yq /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq dev_descr = acmp->acm_dev_data->dev_descr;
90f050286227cf4c4f8aa425555d04723d331d48yq if (dev_descr->idVendor == 0x5c6 && dev_descr->idProduct == 0x3100) {
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_wakeup_enabled = 0;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_destroy_pm_components:
90f050286227cf4c4f8aa425555d04723d331d48yq * destroy PM components
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_destroy_pm_components(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_t *pm = acmp->acm_pm;
90f050286227cf4c4f8aa425555d04723d331d48yq dev_info_t *dip = acmp->acm_dip;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_dev_state != USB_DEV_DISCONNECTED) {
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm->pm_wakeup_enabled) {
90f050286227cf4c4f8aa425555d04723d331d48yq rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != DDI_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: "
90f050286227cf4c4f8aa425555d04723d331d48yq "raising power failed (%d)", rval);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_handle_remote_wakeup(dip,
90f050286227cf4c4f8aa425555d04723d331d48yq USB_REMOTE_WAKEUP_DISABLE);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_destroy_pm_components: "
90f050286227cf4c4f8aa425555d04723d331d48yq "disable remote wakeup failed (%d)", rval);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq kmem_free((caddr_t)pm, sizeof (usbsacm_pm_t));
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_pm = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pm_set_busy:
90f050286227cf4c4f8aa425555d04723d331d48yq * mark device busy and raise power
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pm_set_busy(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_t *pm = acmp->acm_pm;
90f050286227cf4c4f8aa425555d04723d331d48yq dev_info_t *dip = acmp->acm_dip;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
112116d842e816e29d26a8fe28ed25d201063169fb "usbsacm_pm_set_busy: pm = 0x%p", (void *)pm);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* if already marked busy, just increment the counter */
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm->pm_busy_cnt++ > 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq (void) pm_busy_component(dip, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* need to raise power */
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_raise_power = B_TRUE;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval != DDI_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pm_set_busy: raising power failed");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq pm->pm_raise_power = B_FALSE;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pm_set_idle:
90f050286227cf4c4f8aa425555d04723d331d48yq * mark device idle
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pm_set_idle(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pm_t *pm = acmp->acm_pm;
90f050286227cf4c4f8aa425555d04723d331d48yq dev_info_t *dip = acmp->acm_dip;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pm_set_idle: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * if more ports use the device, do not mark as yet
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (--pm->pm_busy_cnt > 0) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (pm) {
90f050286227cf4c4f8aa425555d04723d331d48yq (void) pm_idle_component(dip, 0);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pwrlvl0(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *cur_port = acmp->acm_ports;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl0: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq switch (acmp->acm_dev_state) {
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_ONLINE:
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D3 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_set_device_pwrlvl3(acmp->acm_dip);
90f050286227cf4c4f8aa425555d04723d331d48yq ASSERT(rval == USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (cur_port != NULL) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg for (i = 0; i < acmp->acm_port_cnt; i++) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port = &acmp->acm_ports[i];
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if (cur_port->acm_intr_ph != NULL &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port->acm_port_state !=
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USBSACM_PORT_CLOSED) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_exit(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg usb_pipe_stop_intr_polling(
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port->acm_intr_ph,
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USB_FLAGS_SLEEP);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_enter(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_enter(&cur_port->acm_port_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port->acm_intr_state =
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USBSACM_PIPE_IDLE;
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_exit(&cur_port->acm_port_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_state = USB_DEV_PWRED_DOWN;
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_DISCONNECTED:
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_SUSPENDED:
90f050286227cf4c4f8aa425555d04723d331d48yq /* allow a disconnect/cpr'ed device to go to lower power */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_PWRED_DOWN:
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl0: illegal device state");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl1:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 1 -> 2
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pwrlvl1(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D2 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq (void) usb_set_device_pwrlvl2(acmp->acm_dip);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pwrlvl2:
90f050286227cf4c4f8aa425555d04723d331d48yq * Functions to handle power transition for OS levels 2 -> 1
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pwrlvl2(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq /* issue USB D1 command to the device */
90f050286227cf4c4f8aa425555d04723d331d48yq (void) usb_set_device_pwrlvl1(acmp->acm_dip);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic int
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pwrlvl3(usbsacm_state_t *acmp)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq int i;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *cur_port = acmp->acm_ports;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl3: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq switch (acmp->acm_dev_state) {
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_PWRED_DOWN:
90f050286227cf4c4f8aa425555d04723d331d48yq /* Issue USB D0 command to the device here */
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_set_device_pwrlvl0(acmp->acm_dip);
90f050286227cf4c4f8aa425555d04723d331d48yq ASSERT(rval == USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (cur_port != NULL) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg for (i = 0; i < acmp->acm_port_cnt; i++) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port = &acmp->acm_ports[i];
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg if (cur_port->acm_intr_ph != NULL &&
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg cur_port->acm_port_state !=
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USBSACM_PORT_CLOSED) {
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_exit(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg usbsacm_pipe_start_polling(cur_port);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg mutex_enter(&acmp->acm_mutex);
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_state = USB_DEV_ONLINE;
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_ONLINE:
90f050286227cf4c4f8aa425555d04723d331d48yq /* we are already in full power */
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* FALLTHRU */
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_DISCONNECTED:
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_DEV_SUSPENDED:
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_SUCCESS);
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pwrlvl3: illegal device state");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return (USB_FAILURE);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_pipe_start_polling:
90f050286227cf4c4f8aa425555d04723d331d48yq * start polling on the interrupt pipe
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_pipe_start_polling(usbsacm_port_t *acm_port)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usb_intr_req_t *intr;
90f050286227cf4c4f8aa425555d04723d331d48yq int rval;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pipe_start_polling: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acm_port->acm_intr_ph == NULL) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq intr = usb_alloc_intr_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If it is in interrupt context, usb_alloc_intr_req will return NULL if
90f050286227cf4c4f8aa425555d04723d331d48yq * called with SLEEP flag.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (!intr) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pipe_start_polling: alloc req failed.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* initialize the interrupt request. */
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
4ee52f775fcbf4add00fa9cd15090a02e7e12e3blg USB_ATTRS_AUTOCLEARING;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_len = acm_port->acm_intr_ep_descr.wMaxPacketSize;
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_client_private = (usb_opaque_t)acm_port;
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_cb = usbsacm_intr_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq intr->intr_exc_cb = usbsacm_intr_ex_cb;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq rval = usb_pipe_intr_xfer(acm_port->acm_intr_ph, intr, USB_FLAGS_SLEEP);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq if (rval == USB_SUCCESS) {
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_state = USBSACM_PIPE_BUSY;
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_intr_req(intr);
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_intr_state = USBSACM_PIPE_IDLE;
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_pipe_start_polling: failed (%d)", rval);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_intr_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt pipe normal callback
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq mblk_t *data = req->intr_data;
90f050286227cf4c4f8aa425555d04723d331d48yq int data_len;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq data_len = (data) ? MBLKL(data) : 0;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /* check data length */
90f050286227cf4c4f8aa425555d04723d331d48yq if (data_len < 8) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_cb: %d packet too short", data_len);
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_intr_req(req);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq req->intr_data = NULL;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_intr_req(req);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq /* parse interrupt data. */
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_parse_intr_data(acm_port, data);
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acm_port->acm_port_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_intr_ex_cb:
90f050286227cf4c4f8aa425555d04723d331d48yq * interrupt pipe exception callback
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq/*ARGSUSED*/
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private;
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq usb_cr_t cr = req->intr_completion_reason;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_ex_cb: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usb_free_intr_req(req);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * If completion reason isn't USB_CR_PIPE_CLOSING and
90f050286227cf4c4f8aa425555d04723d331d48yq * USB_CR_STOPPED_POLLING, restart polling.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_enter(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (acmp->acm_dev_state != USB_DEV_ONLINE) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_intr_ex_cb: state = %d",
90f050286227cf4c4f8aa425555d04723d331d48yq acmp->acm_dev_state);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq mutex_exit(&acmp->acm_mutex);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_pipe_start_polling(acm_port);
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq}
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq/*
90f050286227cf4c4f8aa425555d04723d331d48yq * usbsacm_parse_intr_data:
90f050286227cf4c4f8aa425555d04723d331d48yq * Parse data received from interrupt callback
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yqstatic void
90f050286227cf4c4f8aa425555d04723d331d48yqusbsacm_parse_intr_data(usbsacm_port_t *acm_port, mblk_t *data)
90f050286227cf4c4f8aa425555d04723d331d48yq{
90f050286227cf4c4f8aa425555d04723d331d48yq usbsacm_state_t *acmp = acm_port->acm_device;
90f050286227cf4c4f8aa425555d04723d331d48yq uint8_t bmRequestType;
90f050286227cf4c4f8aa425555d04723d331d48yq uint8_t bNotification;
90f050286227cf4c4f8aa425555d04723d331d48yq uint16_t wValue;
90f050286227cf4c4f8aa425555d04723d331d48yq uint16_t wLength;
90f050286227cf4c4f8aa425555d04723d331d48yq uint16_t wData;
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: ");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq bmRequestType = data->b_rptr[0];
90f050286227cf4c4f8aa425555d04723d331d48yq bNotification = data->b_rptr[1];
90f050286227cf4c4f8aa425555d04723d331d48yq /*
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 */
90f050286227cf4c4f8aa425555d04723d331d48yq wValue = data->b_rptr[2];
90f050286227cf4c4f8aa425555d04723d331d48yq wLength = data->b_rptr[6];
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: unknown request type - 0x%x",
90f050286227cf4c4f8aa425555d04723d331d48yq bmRequestType);
90f050286227cf4c4f8aa425555d04723d331d48yq
9e37f2b5d225bd6428d62c06655138fc78fd1ac0Raymond Chen freemsg(data);
9e37f2b5d225bd6428d62c06655138fc78fd1ac0Raymond Chen
90f050286227cf4c4f8aa425555d04723d331d48yq return;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the return value of device
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq switch (bNotification) {
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_NOTIFICATION_NETWORK_CONNECTION:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: %s network!",
90f050286227cf4c4f8aa425555d04723d331d48yq wValue ? "connected to" :"disconnected from");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: A response is a available.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq case USB_CDC_NOTIFICATION_SERIAL_STATE:
90f050286227cf4c4f8aa425555d04723d331d48yq /* check the parameter's length. */
90f050286227cf4c4f8aa425555d04723d331d48yq if (wLength != 2) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: error data length.");
90f050286227cf4c4f8aa425555d04723d331d48yq } else {
90f050286227cf4c4f8aa425555d04723d331d48yq /*
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 * error.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq wData = data->b_rptr[8];
90f050286227cf4c4f8aa425555d04723d331d48yq /*
90f050286227cf4c4f8aa425555d04723d331d48yq * Check the serial state of the current port.
90f050286227cf4c4f8aa425555d04723d331d48yq */
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_DCD) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "receiver carrier is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_DSR) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "transmission carrier is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_DSR;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_BREAK) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "break detection mechanism is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_RNG) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "ring signal detection is set.");
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_RNG;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_FRAMING) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "A framing error has occurred.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_PARITY) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "A parity error has occurred.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq if (wData & USB_CDC_ACM_CONTROL_OVERRUN) {
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: "
90f050286227cf4c4f8aa425555d04723d331d48yq "Received data has been discarded "
90f050286227cf4c4f8aa425555d04723d331d48yq "due to overrun.");
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq default:
90f050286227cf4c4f8aa425555d04723d331d48yq USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh,
90f050286227cf4c4f8aa425555d04723d331d48yq "usbsacm_parse_intr_data: unknown notification - 0x%x!",
90f050286227cf4c4f8aa425555d04723d331d48yq bNotification);
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq break;
90f050286227cf4c4f8aa425555d04723d331d48yq }
90f050286227cf4c4f8aa425555d04723d331d48yq
90f050286227cf4c4f8aa425555d04723d331d48yq freemsg(data);
90f050286227cf4c4f8aa425555d04723d331d48yq}