162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * f_acm.c -- USB CDC serial (ACM) function driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
662306a36Sopenharmony_ci * Copyright (C) 2008 by David Brownell
762306a36Sopenharmony_ci * Copyright (C) 2008 by Nokia Corporation
862306a36Sopenharmony_ci * Copyright (C) 2009 by Samsung Electronics
962306a36Sopenharmony_ci * Author: Michal Nazarewicz (mina86@mina86.com)
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* #define VERBOSE_DEBUG */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/device.h>
1862306a36Sopenharmony_ci#include <linux/err.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "u_serial.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * This CDC ACM function support just wraps control functions and
2562306a36Sopenharmony_ci * notifications around the generic serial-over-usb code.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * Because CDC ACM is standardized by the USB-IF, many host operating
2862306a36Sopenharmony_ci * systems have drivers for it.  Accordingly, ACM is the preferred
2962306a36Sopenharmony_ci * interop solution for serial-port type connections.  The control
3062306a36Sopenharmony_ci * models are often not necessary, and in any case don't do much in
3162306a36Sopenharmony_ci * this bare-bones implementation.
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Note that even MS-Windows has some support for ACM.  However, that
3462306a36Sopenharmony_ci * support is somewhat broken because when you use ACM in a composite
3562306a36Sopenharmony_ci * device, having multiple interfaces confuses the poor OS.  It doesn't
3662306a36Sopenharmony_ci * seem to understand CDC Union descriptors.  The new "association"
3762306a36Sopenharmony_ci * descriptors (roughly equivalent to CDC Unions) may sometimes help.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct f_acm {
4162306a36Sopenharmony_ci	struct gserial			port;
4262306a36Sopenharmony_ci	u8				ctrl_id, data_id;
4362306a36Sopenharmony_ci	u8				port_num;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	u8				pending;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* lock is mostly for pending and notify_req ... they get accessed
4862306a36Sopenharmony_ci	 * by callbacks both from tty (open/close/break) under its spinlock,
4962306a36Sopenharmony_ci	 * and notify_req.complete() which can't use that lock.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	spinlock_t			lock;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	struct usb_ep			*notify;
5462306a36Sopenharmony_ci	struct usb_request		*notify_req;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
5962306a36Sopenharmony_ci	u16				port_handshake_bits;
6062306a36Sopenharmony_ci	/* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
6162306a36Sopenharmony_ci	u16				serial_state;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline struct f_acm *func_to_acm(struct usb_function *f)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return container_of(f, struct f_acm, port.func);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline struct f_acm *port_to_acm(struct gserial *p)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	return container_of(p, struct f_acm, port);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* notification endpoint uses smallish and infrequent fixed-size messages */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define GS_NOTIFY_INTERVAL_MS		32
7962306a36Sopenharmony_ci#define GS_NOTIFY_MAXPACKET		10	/* notification + 2 bytes */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* interface and class descriptors: */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic struct usb_interface_assoc_descriptor
8462306a36Sopenharmony_ciacm_iad_descriptor = {
8562306a36Sopenharmony_ci	.bLength =		sizeof acm_iad_descriptor,
8662306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* .bFirstInterface =	DYNAMIC, */
8962306a36Sopenharmony_ci	.bInterfaceCount = 	2,	// control + data
9062306a36Sopenharmony_ci	.bFunctionClass =	USB_CLASS_COMM,
9162306a36Sopenharmony_ci	.bFunctionSubClass =	USB_CDC_SUBCLASS_ACM,
9262306a36Sopenharmony_ci	.bFunctionProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
9362306a36Sopenharmony_ci	/* .iFunction =		DYNAMIC */
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct usb_interface_descriptor acm_control_interface_desc = {
9862306a36Sopenharmony_ci	.bLength =		USB_DT_INTERFACE_SIZE,
9962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_INTERFACE,
10062306a36Sopenharmony_ci	/* .bInterfaceNumber = DYNAMIC */
10162306a36Sopenharmony_ci	.bNumEndpoints =	1,
10262306a36Sopenharmony_ci	.bInterfaceClass =	USB_CLASS_COMM,
10362306a36Sopenharmony_ci	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ACM,
10462306a36Sopenharmony_ci	.bInterfaceProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
10562306a36Sopenharmony_ci	/* .iInterface = DYNAMIC */
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic struct usb_interface_descriptor acm_data_interface_desc = {
10962306a36Sopenharmony_ci	.bLength =		USB_DT_INTERFACE_SIZE,
11062306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_INTERFACE,
11162306a36Sopenharmony_ci	/* .bInterfaceNumber = DYNAMIC */
11262306a36Sopenharmony_ci	.bNumEndpoints =	2,
11362306a36Sopenharmony_ci	.bInterfaceClass =	USB_CLASS_CDC_DATA,
11462306a36Sopenharmony_ci	.bInterfaceSubClass =	0,
11562306a36Sopenharmony_ci	.bInterfaceProtocol =	0,
11662306a36Sopenharmony_ci	/* .iInterface = DYNAMIC */
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic struct usb_cdc_header_desc acm_header_desc = {
12062306a36Sopenharmony_ci	.bLength =		sizeof(acm_header_desc),
12162306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_CS_INTERFACE,
12262306a36Sopenharmony_ci	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
12362306a36Sopenharmony_ci	.bcdCDC =		cpu_to_le16(0x0110),
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic struct usb_cdc_call_mgmt_descriptor
12762306a36Sopenharmony_ciacm_call_mgmt_descriptor = {
12862306a36Sopenharmony_ci	.bLength =		sizeof(acm_call_mgmt_descriptor),
12962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_CS_INTERFACE,
13062306a36Sopenharmony_ci	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
13162306a36Sopenharmony_ci	.bmCapabilities =	0,
13262306a36Sopenharmony_ci	/* .bDataInterface = DYNAMIC */
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct usb_cdc_acm_descriptor acm_descriptor = {
13662306a36Sopenharmony_ci	.bLength =		sizeof(acm_descriptor),
13762306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_CS_INTERFACE,
13862306a36Sopenharmony_ci	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
13962306a36Sopenharmony_ci	.bmCapabilities =	USB_CDC_CAP_LINE,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct usb_cdc_union_desc acm_union_desc = {
14362306a36Sopenharmony_ci	.bLength =		sizeof(acm_union_desc),
14462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_CS_INTERFACE,
14562306a36Sopenharmony_ci	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
14662306a36Sopenharmony_ci	/* .bMasterInterface0 =	DYNAMIC */
14762306a36Sopenharmony_ci	/* .bSlaveInterface0 =	DYNAMIC */
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* full speed support: */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_fs_notify_desc = {
15362306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
15462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
15562306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
15662306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_INT,
15762306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
15862306a36Sopenharmony_ci	.bInterval =		GS_NOTIFY_INTERVAL_MS,
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_fs_in_desc = {
16262306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
16362306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
16462306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
16562306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_fs_out_desc = {
16962306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
17062306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
17162306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
17262306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic struct usb_descriptor_header *acm_fs_function[] = {
17662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_iad_descriptor,
17762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_control_interface_desc,
17862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_header_desc,
17962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
18062306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_descriptor,
18162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_union_desc,
18262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_fs_notify_desc,
18362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_data_interface_desc,
18462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_fs_in_desc,
18562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_fs_out_desc,
18662306a36Sopenharmony_ci	NULL,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/* high speed support: */
19062306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_hs_notify_desc = {
19162306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
19262306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
19362306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
19462306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_INT,
19562306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
19662306a36Sopenharmony_ci	.bInterval =		USB_MS_TO_HS_INTERVAL(GS_NOTIFY_INTERVAL_MS),
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_hs_in_desc = {
20062306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
20162306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
20262306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
20362306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_hs_out_desc = {
20762306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
20862306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
20962306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
21062306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic struct usb_descriptor_header *acm_hs_function[] = {
21462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_iad_descriptor,
21562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_control_interface_desc,
21662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_header_desc,
21762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
21862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_descriptor,
21962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_union_desc,
22062306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_hs_notify_desc,
22162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_data_interface_desc,
22262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_hs_in_desc,
22362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_hs_out_desc,
22462306a36Sopenharmony_ci	NULL,
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_ss_in_desc = {
22862306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
22962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
23062306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
23162306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(1024),
23262306a36Sopenharmony_ci};
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic struct usb_endpoint_descriptor acm_ss_out_desc = {
23562306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
23662306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
23762306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
23862306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(1024),
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
24262306a36Sopenharmony_ci	.bLength =              sizeof acm_ss_bulk_comp_desc,
24362306a36Sopenharmony_ci	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic struct usb_descriptor_header *acm_ss_function[] = {
24762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_iad_descriptor,
24862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_control_interface_desc,
24962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_header_desc,
25062306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
25162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_descriptor,
25262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_union_desc,
25362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_hs_notify_desc,
25462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
25562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_data_interface_desc,
25662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_ss_in_desc,
25762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
25862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_ss_out_desc,
25962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
26062306a36Sopenharmony_ci	NULL,
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/* string descriptors: */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#define ACM_CTRL_IDX	0
26662306a36Sopenharmony_ci#define ACM_DATA_IDX	1
26762306a36Sopenharmony_ci#define ACM_IAD_IDX	2
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/* static strings, in UTF-8 */
27062306a36Sopenharmony_cistatic struct usb_string acm_string_defs[] = {
27162306a36Sopenharmony_ci	[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
27262306a36Sopenharmony_ci	[ACM_DATA_IDX].s = "CDC ACM Data",
27362306a36Sopenharmony_ci	[ACM_IAD_IDX ].s = "CDC Serial",
27462306a36Sopenharmony_ci	{  } /* end of list */
27562306a36Sopenharmony_ci};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic struct usb_gadget_strings acm_string_table = {
27862306a36Sopenharmony_ci	.language =		0x0409,	/* en-us */
27962306a36Sopenharmony_ci	.strings =		acm_string_defs,
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic struct usb_gadget_strings *acm_strings[] = {
28362306a36Sopenharmony_ci	&acm_string_table,
28462306a36Sopenharmony_ci	NULL,
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/* ACM control ... data handling is delegated to tty library code.
29062306a36Sopenharmony_ci * The main task of this function is to activate and deactivate
29162306a36Sopenharmony_ci * that code based on device state; track parameters like line
29262306a36Sopenharmony_ci * speed, handshake state, and so on; and issue notifications.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic void acm_complete_set_line_coding(struct usb_ep *ep,
29662306a36Sopenharmony_ci		struct usb_request *req)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct f_acm	*acm = ep->driver_data;
29962306a36Sopenharmony_ci	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (req->status != 0) {
30262306a36Sopenharmony_ci		dev_dbg(&cdev->gadget->dev, "acm ttyGS%d completion, err %d\n",
30362306a36Sopenharmony_ci			acm->port_num, req->status);
30462306a36Sopenharmony_ci		return;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* normal completion */
30862306a36Sopenharmony_ci	if (req->actual != sizeof(acm->port_line_coding)) {
30962306a36Sopenharmony_ci		dev_dbg(&cdev->gadget->dev, "acm ttyGS%d short resp, len %d\n",
31062306a36Sopenharmony_ci			acm->port_num, req->actual);
31162306a36Sopenharmony_ci		usb_ep_set_halt(ep);
31262306a36Sopenharmony_ci	} else {
31362306a36Sopenharmony_ci		struct usb_cdc_line_coding	*value = req->buf;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		/* REVISIT:  we currently just remember this data.
31662306a36Sopenharmony_ci		 * If we change that, (a) validate it first, then
31762306a36Sopenharmony_ci		 * (b) update whatever hardware needs updating,
31862306a36Sopenharmony_ci		 * (c) worry about locking.  This is information on
31962306a36Sopenharmony_ci		 * the order of 9600-8-N-1 ... most of which means
32062306a36Sopenharmony_ci		 * nothing unless we control a real RS232 line.
32162306a36Sopenharmony_ci		 */
32262306a36Sopenharmony_ci		acm->port_line_coding = *value;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int acm_send_break(struct gserial *port, int duration);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct f_acm		*acm = func_to_acm(f);
33162306a36Sopenharmony_ci	struct usb_composite_dev *cdev = f->config->cdev;
33262306a36Sopenharmony_ci	struct usb_request	*req = cdev->req;
33362306a36Sopenharmony_ci	int			value = -EOPNOTSUPP;
33462306a36Sopenharmony_ci	u16			w_index = le16_to_cpu(ctrl->wIndex);
33562306a36Sopenharmony_ci	u16			w_value = le16_to_cpu(ctrl->wValue);
33662306a36Sopenharmony_ci	u16			w_length = le16_to_cpu(ctrl->wLength);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* composite driver infrastructure handles everything except
33962306a36Sopenharmony_ci	 * CDC class messages; interface activation uses set_alt().
34062306a36Sopenharmony_ci	 *
34162306a36Sopenharmony_ci	 * Note CDC spec table 4 lists the ACM request profile.  It requires
34262306a36Sopenharmony_ci	 * encapsulated command support ... we don't handle any, and respond
34362306a36Sopenharmony_ci	 * to them by stalling.  Options include get/set/clear comm features
34462306a36Sopenharmony_ci	 * (not that useful) and SEND_BREAK.
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* SET_LINE_CODING ... just read and save what the host sends */
34962306a36Sopenharmony_ci	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
35062306a36Sopenharmony_ci			| USB_CDC_REQ_SET_LINE_CODING:
35162306a36Sopenharmony_ci		if (w_length != sizeof(struct usb_cdc_line_coding)
35262306a36Sopenharmony_ci				|| w_index != acm->ctrl_id)
35362306a36Sopenharmony_ci			goto invalid;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		value = w_length;
35662306a36Sopenharmony_ci		cdev->gadget->ep0->driver_data = acm;
35762306a36Sopenharmony_ci		req->complete = acm_complete_set_line_coding;
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* GET_LINE_CODING ... return what host sent, or initial value */
36162306a36Sopenharmony_ci	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
36262306a36Sopenharmony_ci			| USB_CDC_REQ_GET_LINE_CODING:
36362306a36Sopenharmony_ci		if (w_index != acm->ctrl_id)
36462306a36Sopenharmony_ci			goto invalid;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		value = min_t(unsigned, w_length,
36762306a36Sopenharmony_ci				sizeof(struct usb_cdc_line_coding));
36862306a36Sopenharmony_ci		memcpy(req->buf, &acm->port_line_coding, value);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* SET_CONTROL_LINE_STATE ... save what the host sent */
37262306a36Sopenharmony_ci	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
37362306a36Sopenharmony_ci			| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
37462306a36Sopenharmony_ci		if (w_index != acm->ctrl_id)
37562306a36Sopenharmony_ci			goto invalid;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		value = 0;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		/* FIXME we should not allow data to flow until the
38062306a36Sopenharmony_ci		 * host sets the USB_CDC_CTRL_DTR bit; and when it clears
38162306a36Sopenharmony_ci		 * that bit, we should return to that no-flow state.
38262306a36Sopenharmony_ci		 */
38362306a36Sopenharmony_ci		acm->port_handshake_bits = w_value;
38462306a36Sopenharmony_ci		break;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
38762306a36Sopenharmony_ci			| USB_CDC_REQ_SEND_BREAK:
38862306a36Sopenharmony_ci		if (w_index != acm->ctrl_id)
38962306a36Sopenharmony_ci			goto invalid;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		acm_send_break(&acm->port, w_value);
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	default:
39562306a36Sopenharmony_ciinvalid:
39662306a36Sopenharmony_ci		dev_vdbg(&cdev->gadget->dev,
39762306a36Sopenharmony_ci			 "invalid control req%02x.%02x v%04x i%04x l%d\n",
39862306a36Sopenharmony_ci			 ctrl->bRequestType, ctrl->bRequest,
39962306a36Sopenharmony_ci			 w_value, w_index, w_length);
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* respond with data transfer or status phase? */
40362306a36Sopenharmony_ci	if (value >= 0) {
40462306a36Sopenharmony_ci		dev_dbg(&cdev->gadget->dev,
40562306a36Sopenharmony_ci			"acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
40662306a36Sopenharmony_ci			acm->port_num, ctrl->bRequestType, ctrl->bRequest,
40762306a36Sopenharmony_ci			w_value, w_index, w_length);
40862306a36Sopenharmony_ci		req->zero = 0;
40962306a36Sopenharmony_ci		req->length = value;
41062306a36Sopenharmony_ci		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
41162306a36Sopenharmony_ci		if (value < 0)
41262306a36Sopenharmony_ci			ERROR(cdev, "acm response on ttyGS%d, err %d\n",
41362306a36Sopenharmony_ci					acm->port_num, value);
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* device either stalls (value < 0) or reports success */
41762306a36Sopenharmony_ci	return value;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct f_acm		*acm = func_to_acm(f);
42362306a36Sopenharmony_ci	struct usb_composite_dev *cdev = f->config->cdev;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* we know alt == 0, so this is an activation or a reset */
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (intf == acm->ctrl_id) {
42862306a36Sopenharmony_ci		if (acm->notify->enabled) {
42962306a36Sopenharmony_ci			dev_vdbg(&cdev->gadget->dev,
43062306a36Sopenharmony_ci					"reset acm control interface %d\n", intf);
43162306a36Sopenharmony_ci			usb_ep_disable(acm->notify);
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		if (!acm->notify->desc)
43562306a36Sopenharmony_ci			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
43662306a36Sopenharmony_ci				return -EINVAL;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		usb_ep_enable(acm->notify);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	} else if (intf == acm->data_id) {
44162306a36Sopenharmony_ci		if (acm->notify->enabled) {
44262306a36Sopenharmony_ci			dev_dbg(&cdev->gadget->dev,
44362306a36Sopenharmony_ci				"reset acm ttyGS%d\n", acm->port_num);
44462306a36Sopenharmony_ci			gserial_disconnect(&acm->port);
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci		if (!acm->port.in->desc || !acm->port.out->desc) {
44762306a36Sopenharmony_ci			dev_dbg(&cdev->gadget->dev,
44862306a36Sopenharmony_ci				"activate acm ttyGS%d\n", acm->port_num);
44962306a36Sopenharmony_ci			if (config_ep_by_speed(cdev->gadget, f,
45062306a36Sopenharmony_ci					       acm->port.in) ||
45162306a36Sopenharmony_ci			    config_ep_by_speed(cdev->gadget, f,
45262306a36Sopenharmony_ci					       acm->port.out)) {
45362306a36Sopenharmony_ci				acm->port.in->desc = NULL;
45462306a36Sopenharmony_ci				acm->port.out->desc = NULL;
45562306a36Sopenharmony_ci				return -EINVAL;
45662306a36Sopenharmony_ci			}
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci		gserial_connect(&acm->port, acm->port_num);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	} else
46162306a36Sopenharmony_ci		return -EINVAL;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic void acm_disable(struct usb_function *f)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct f_acm	*acm = func_to_acm(f);
46962306a36Sopenharmony_ci	struct usb_composite_dev *cdev = f->config->cdev;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	dev_dbg(&cdev->gadget->dev, "acm ttyGS%d deactivated\n", acm->port_num);
47262306a36Sopenharmony_ci	gserial_disconnect(&acm->port);
47362306a36Sopenharmony_ci	usb_ep_disable(acm->notify);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * acm_cdc_notify - issue CDC notification to host
48062306a36Sopenharmony_ci * @acm: wraps host to be notified
48162306a36Sopenharmony_ci * @type: notification type
48262306a36Sopenharmony_ci * @value: Refer to cdc specs, wValue field.
48362306a36Sopenharmony_ci * @data: data to be sent
48462306a36Sopenharmony_ci * @length: size of data
48562306a36Sopenharmony_ci * Context: irqs blocked, acm->lock held, acm_notify_req non-null
48662306a36Sopenharmony_ci *
48762306a36Sopenharmony_ci * Returns zero on success or a negative errno.
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * See section 6.3.5 of the CDC 1.1 specification for information
49062306a36Sopenharmony_ci * about the only notification we issue:  SerialState change.
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_cistatic int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
49362306a36Sopenharmony_ci		void *data, unsigned length)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct usb_ep			*ep = acm->notify;
49662306a36Sopenharmony_ci	struct usb_request		*req;
49762306a36Sopenharmony_ci	struct usb_cdc_notification	*notify;
49862306a36Sopenharmony_ci	const unsigned			len = sizeof(*notify) + length;
49962306a36Sopenharmony_ci	void				*buf;
50062306a36Sopenharmony_ci	int				status;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	req = acm->notify_req;
50362306a36Sopenharmony_ci	acm->notify_req = NULL;
50462306a36Sopenharmony_ci	acm->pending = false;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	req->length = len;
50762306a36Sopenharmony_ci	notify = req->buf;
50862306a36Sopenharmony_ci	buf = notify + 1;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
51162306a36Sopenharmony_ci			| USB_RECIP_INTERFACE;
51262306a36Sopenharmony_ci	notify->bNotificationType = type;
51362306a36Sopenharmony_ci	notify->wValue = cpu_to_le16(value);
51462306a36Sopenharmony_ci	notify->wIndex = cpu_to_le16(acm->ctrl_id);
51562306a36Sopenharmony_ci	notify->wLength = cpu_to_le16(length);
51662306a36Sopenharmony_ci	memcpy(buf, data, length);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* ep_queue() can complete immediately if it fills the fifo... */
51962306a36Sopenharmony_ci	spin_unlock(&acm->lock);
52062306a36Sopenharmony_ci	status = usb_ep_queue(ep, req, GFP_ATOMIC);
52162306a36Sopenharmony_ci	spin_lock(&acm->lock);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (status < 0) {
52462306a36Sopenharmony_ci		ERROR(acm->port.func.config->cdev,
52562306a36Sopenharmony_ci				"acm ttyGS%d can't notify serial state, %d\n",
52662306a36Sopenharmony_ci				acm->port_num, status);
52762306a36Sopenharmony_ci		acm->notify_req = req;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return status;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int acm_notify_serial_state(struct f_acm *acm)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
53662306a36Sopenharmony_ci	int			status;
53762306a36Sopenharmony_ci	__le16			serial_state;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	spin_lock(&acm->lock);
54062306a36Sopenharmony_ci	if (acm->notify_req) {
54162306a36Sopenharmony_ci		dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n",
54262306a36Sopenharmony_ci			acm->port_num, acm->serial_state);
54362306a36Sopenharmony_ci		serial_state = cpu_to_le16(acm->serial_state);
54462306a36Sopenharmony_ci		status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
54562306a36Sopenharmony_ci				0, &serial_state, sizeof(acm->serial_state));
54662306a36Sopenharmony_ci	} else {
54762306a36Sopenharmony_ci		acm->pending = true;
54862306a36Sopenharmony_ci		status = 0;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci	spin_unlock(&acm->lock);
55162306a36Sopenharmony_ci	return status;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	struct f_acm		*acm = req->context;
55762306a36Sopenharmony_ci	u8			doit = false;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* on this call path we do NOT hold the port spinlock,
56062306a36Sopenharmony_ci	 * which is why ACM needs its own spinlock
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	spin_lock(&acm->lock);
56362306a36Sopenharmony_ci	if (req->status != -ESHUTDOWN)
56462306a36Sopenharmony_ci		doit = acm->pending;
56562306a36Sopenharmony_ci	acm->notify_req = req;
56662306a36Sopenharmony_ci	spin_unlock(&acm->lock);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (doit)
56962306a36Sopenharmony_ci		acm_notify_serial_state(acm);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci/* connect == the TTY link is open */
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic void acm_connect(struct gserial *port)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct f_acm		*acm = port_to_acm(port);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	acm->serial_state |= USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD;
57962306a36Sopenharmony_ci	acm_notify_serial_state(acm);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void acm_disconnect(struct gserial *port)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct f_acm		*acm = port_to_acm(port);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	acm->serial_state &= ~(USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD);
58762306a36Sopenharmony_ci	acm_notify_serial_state(acm);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic int acm_send_break(struct gserial *port, int duration)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct f_acm		*acm = port_to_acm(port);
59362306a36Sopenharmony_ci	u16			state;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	state = acm->serial_state;
59662306a36Sopenharmony_ci	state &= ~USB_CDC_SERIAL_STATE_BREAK;
59762306a36Sopenharmony_ci	if (duration)
59862306a36Sopenharmony_ci		state |= USB_CDC_SERIAL_STATE_BREAK;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	acm->serial_state = state;
60162306a36Sopenharmony_ci	return acm_notify_serial_state(acm);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci/* ACM function driver setup/binding */
60762306a36Sopenharmony_cistatic int
60862306a36Sopenharmony_ciacm_bind(struct usb_configuration *c, struct usb_function *f)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct usb_composite_dev *cdev = c->cdev;
61162306a36Sopenharmony_ci	struct f_acm		*acm = func_to_acm(f);
61262306a36Sopenharmony_ci	struct usb_string	*us;
61362306a36Sopenharmony_ci	int			status;
61462306a36Sopenharmony_ci	struct usb_ep		*ep;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* REVISIT might want instance-specific strings to help
61762306a36Sopenharmony_ci	 * distinguish instances ...
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* maybe allocate device-global string IDs, and patch descriptors */
62162306a36Sopenharmony_ci	us = usb_gstrings_attach(cdev, acm_strings,
62262306a36Sopenharmony_ci			ARRAY_SIZE(acm_string_defs));
62362306a36Sopenharmony_ci	if (IS_ERR(us))
62462306a36Sopenharmony_ci		return PTR_ERR(us);
62562306a36Sopenharmony_ci	acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id;
62662306a36Sopenharmony_ci	acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
62762306a36Sopenharmony_ci	acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/* allocate instance-specific interface IDs, and patch descriptors */
63062306a36Sopenharmony_ci	status = usb_interface_id(c, f);
63162306a36Sopenharmony_ci	if (status < 0)
63262306a36Sopenharmony_ci		goto fail;
63362306a36Sopenharmony_ci	acm->ctrl_id = status;
63462306a36Sopenharmony_ci	acm_iad_descriptor.bFirstInterface = status;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	acm_control_interface_desc.bInterfaceNumber = status;
63762306a36Sopenharmony_ci	acm_union_desc .bMasterInterface0 = status;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	status = usb_interface_id(c, f);
64062306a36Sopenharmony_ci	if (status < 0)
64162306a36Sopenharmony_ci		goto fail;
64262306a36Sopenharmony_ci	acm->data_id = status;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	acm_data_interface_desc.bInterfaceNumber = status;
64562306a36Sopenharmony_ci	acm_union_desc.bSlaveInterface0 = status;
64662306a36Sopenharmony_ci	acm_call_mgmt_descriptor.bDataInterface = status;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	status = -ENODEV;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* allocate instance-specific endpoints */
65162306a36Sopenharmony_ci	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
65262306a36Sopenharmony_ci	if (!ep)
65362306a36Sopenharmony_ci		goto fail;
65462306a36Sopenharmony_ci	acm->port.in = ep;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
65762306a36Sopenharmony_ci	if (!ep)
65862306a36Sopenharmony_ci		goto fail;
65962306a36Sopenharmony_ci	acm->port.out = ep;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
66262306a36Sopenharmony_ci	if (!ep)
66362306a36Sopenharmony_ci		goto fail;
66462306a36Sopenharmony_ci	acm->notify = ep;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* allocate notification */
66762306a36Sopenharmony_ci	acm->notify_req = gs_alloc_req(ep,
66862306a36Sopenharmony_ci			sizeof(struct usb_cdc_notification) + 2,
66962306a36Sopenharmony_ci			GFP_KERNEL);
67062306a36Sopenharmony_ci	if (!acm->notify_req)
67162306a36Sopenharmony_ci		goto fail;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	acm->notify_req->complete = acm_cdc_notify_complete;
67462306a36Sopenharmony_ci	acm->notify_req->context = acm;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/* support all relevant hardware speeds... we expect that when
67762306a36Sopenharmony_ci	 * hardware is dual speed, all bulk-capable endpoints work at
67862306a36Sopenharmony_ci	 * both speeds
67962306a36Sopenharmony_ci	 */
68062306a36Sopenharmony_ci	acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
68162306a36Sopenharmony_ci	acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
68262306a36Sopenharmony_ci	acm_hs_notify_desc.bEndpointAddress =
68362306a36Sopenharmony_ci		acm_fs_notify_desc.bEndpointAddress;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
68662306a36Sopenharmony_ci	acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
68962306a36Sopenharmony_ci			acm_ss_function, acm_ss_function);
69062306a36Sopenharmony_ci	if (status)
69162306a36Sopenharmony_ci		goto fail;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	dev_dbg(&cdev->gadget->dev,
69462306a36Sopenharmony_ci		"acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n",
69562306a36Sopenharmony_ci		acm->port_num,
69662306a36Sopenharmony_ci		acm->port.in->name, acm->port.out->name,
69762306a36Sopenharmony_ci		acm->notify->name);
69862306a36Sopenharmony_ci	return 0;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cifail:
70162306a36Sopenharmony_ci	if (acm->notify_req)
70262306a36Sopenharmony_ci		gs_free_req(acm->notify, acm->notify_req);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	return status;
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic void acm_unbind(struct usb_configuration *c, struct usb_function *f)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct f_acm		*acm = func_to_acm(f);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	acm_string_defs[0].id = 0;
71462306a36Sopenharmony_ci	usb_free_all_descriptors(f);
71562306a36Sopenharmony_ci	if (acm->notify_req)
71662306a36Sopenharmony_ci		gs_free_req(acm->notify, acm->notify_req);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic void acm_free_func(struct usb_function *f)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct f_acm		*acm = func_to_acm(f);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	kfree(acm);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic void acm_resume(struct usb_function *f)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct f_acm *acm = func_to_acm(f);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	gserial_resume(&acm->port);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic void acm_suspend(struct usb_function *f)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct f_acm *acm = func_to_acm(f);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	gserial_suspend(&acm->port);
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct f_serial_opts *opts;
74362306a36Sopenharmony_ci	struct f_acm *acm;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	acm = kzalloc(sizeof(*acm), GFP_KERNEL);
74662306a36Sopenharmony_ci	if (!acm)
74762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	spin_lock_init(&acm->lock);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	acm->port.connect = acm_connect;
75262306a36Sopenharmony_ci	acm->port.disconnect = acm_disconnect;
75362306a36Sopenharmony_ci	acm->port.send_break = acm_send_break;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	acm->port.func.name = "acm";
75662306a36Sopenharmony_ci	acm->port.func.strings = acm_strings;
75762306a36Sopenharmony_ci	/* descriptors are per-instance copies */
75862306a36Sopenharmony_ci	acm->port.func.bind = acm_bind;
75962306a36Sopenharmony_ci	acm->port.func.set_alt = acm_set_alt;
76062306a36Sopenharmony_ci	acm->port.func.setup = acm_setup;
76162306a36Sopenharmony_ci	acm->port.func.disable = acm_disable;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	opts = container_of(fi, struct f_serial_opts, func_inst);
76462306a36Sopenharmony_ci	acm->port_num = opts->port_num;
76562306a36Sopenharmony_ci	acm->port.func.unbind = acm_unbind;
76662306a36Sopenharmony_ci	acm->port.func.free_func = acm_free_func;
76762306a36Sopenharmony_ci	acm->port.func.resume = acm_resume;
76862306a36Sopenharmony_ci	acm->port.func.suspend = acm_suspend;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return &acm->port.func;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	return container_of(to_config_group(item), struct f_serial_opts,
77662306a36Sopenharmony_ci			func_inst.group);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void acm_attr_release(struct config_item *item)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct f_serial_opts *opts = to_f_serial_opts(item);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	usb_put_function_instance(&opts->func_inst);
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic struct configfs_item_operations acm_item_ops = {
78762306a36Sopenharmony_ci	.release                = acm_attr_release,
78862306a36Sopenharmony_ci};
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci#ifdef CONFIG_U_SERIAL_CONSOLE
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic ssize_t f_acm_console_store(struct config_item *item,
79362306a36Sopenharmony_ci		const char *page, size_t count)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	return gserial_set_console(to_f_serial_opts(item)->port_num,
79662306a36Sopenharmony_ci				   page, count);
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic ssize_t f_acm_console_show(struct config_item *item, char *page)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	return gserial_get_console(to_f_serial_opts(item)->port_num, page);
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ciCONFIGFS_ATTR(f_acm_, console);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci#endif /* CONFIG_U_SERIAL_CONSOLE */
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic ssize_t f_acm_port_num_show(struct config_item *item, char *page)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ciCONFIGFS_ATTR_RO(f_acm_, port_num);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic struct configfs_attribute *acm_attrs[] = {
81662306a36Sopenharmony_ci#ifdef CONFIG_U_SERIAL_CONSOLE
81762306a36Sopenharmony_ci	&f_acm_attr_console,
81862306a36Sopenharmony_ci#endif
81962306a36Sopenharmony_ci	&f_acm_attr_port_num,
82062306a36Sopenharmony_ci	NULL,
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const struct config_item_type acm_func_type = {
82462306a36Sopenharmony_ci	.ct_item_ops    = &acm_item_ops,
82562306a36Sopenharmony_ci	.ct_attrs	= acm_attrs,
82662306a36Sopenharmony_ci	.ct_owner       = THIS_MODULE,
82762306a36Sopenharmony_ci};
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic void acm_free_instance(struct usb_function_instance *fi)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct f_serial_opts *opts;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	opts = container_of(fi, struct f_serial_opts, func_inst);
83462306a36Sopenharmony_ci	gserial_free_line(opts->port_num);
83562306a36Sopenharmony_ci	kfree(opts);
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic struct usb_function_instance *acm_alloc_instance(void)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct f_serial_opts *opts;
84162306a36Sopenharmony_ci	int ret;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
84462306a36Sopenharmony_ci	if (!opts)
84562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
84662306a36Sopenharmony_ci	opts->func_inst.free_func_inst = acm_free_instance;
84762306a36Sopenharmony_ci	ret = gserial_alloc_line(&opts->port_num);
84862306a36Sopenharmony_ci	if (ret) {
84962306a36Sopenharmony_ci		kfree(opts);
85062306a36Sopenharmony_ci		return ERR_PTR(ret);
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci	config_group_init_type_name(&opts->func_inst.group, "",
85362306a36Sopenharmony_ci			&acm_func_type);
85462306a36Sopenharmony_ci	return &opts->func_inst;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ciDECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
85762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
858