18b645922STakashi Iwai // SPDX-License-Identifier: GPL-2.0+
28b645922STakashi Iwai /*
38b645922STakashi Iwai  * f_midi2.c -- USB MIDI 2.0 class function driver
48b645922STakashi Iwai  */
58b645922STakashi Iwai 
68b645922STakashi Iwai #include <linux/device.h>
78b645922STakashi Iwai #include <linux/kernel.h>
88b645922STakashi Iwai #include <linux/module.h>
98b645922STakashi Iwai #include <linux/slab.h>
108b645922STakashi Iwai 
118b645922STakashi Iwai #include <sound/core.h>
121b437d2fSTakashi Iwai #include <sound/control.h>
138b645922STakashi Iwai #include <sound/ump.h>
148b645922STakashi Iwai #include <sound/ump_msg.h>
15d6468be7STakashi Iwai #include <sound/ump_convert.h>
168b645922STakashi Iwai 
178b645922STakashi Iwai #include <linux/usb/ch9.h>
188b645922STakashi Iwai #include <linux/usb/gadget.h>
198b645922STakashi Iwai #include <linux/usb/audio.h>
208b645922STakashi Iwai #include <linux/usb/midi-v2.h>
218b645922STakashi Iwai 
228b645922STakashi Iwai #include "u_f.h"
238b645922STakashi Iwai #include "u_midi2.h"
248b645922STakashi Iwai 
258b645922STakashi Iwai struct f_midi2;
268b645922STakashi Iwai struct f_midi2_ep;
278b645922STakashi Iwai struct f_midi2_usb_ep;
288b645922STakashi Iwai 
298b645922STakashi Iwai /* Context for each USB request */
308b645922STakashi Iwai struct f_midi2_req_ctx {
318b645922STakashi Iwai 	struct f_midi2_usb_ep *usb_ep;	/* belonging USB EP */
328b645922STakashi Iwai 	unsigned int index;		/* array index: 0-31 */
338b645922STakashi Iwai 	struct usb_request *req;	/* assigned request */
348b645922STakashi Iwai };
358b645922STakashi Iwai 
368b645922STakashi Iwai /* Resources for a USB Endpoint */
378b645922STakashi Iwai struct f_midi2_usb_ep {
388b645922STakashi Iwai 	struct f_midi2 *card;		/* belonging card */
398b645922STakashi Iwai 	struct f_midi2_ep *ep;		/* belonging UMP EP (optional) */
408b645922STakashi Iwai 	struct usb_ep *usb_ep;		/* assigned USB EP */
418b645922STakashi Iwai 	void (*complete)(struct usb_ep *usb_ep, struct usb_request *req);
428b645922STakashi Iwai 	unsigned long free_reqs;	/* bitmap for unused requests */
438b645922STakashi Iwai 	unsigned int num_reqs;		/* number of allocated requests */
448b645922STakashi Iwai 	struct f_midi2_req_ctx *reqs;	/* request context array */
458b645922STakashi Iwai };
468b645922STakashi Iwai 
478b645922STakashi Iwai /* Resources for UMP Function Block (and USB Group Terminal Block) */
488b645922STakashi Iwai struct f_midi2_block {
498b645922STakashi Iwai 	struct f_midi2_block_info info;	/* FB info, copied from configfs */
508b645922STakashi Iwai 	struct snd_ump_block *fb;	/* assigned FB */
518b645922STakashi Iwai 	unsigned int gtb_id;		/* assigned GTB id */
528b645922STakashi Iwai 	unsigned int string_id;		/* assigned string id */
538b645922STakashi Iwai };
548b645922STakashi Iwai 
55d6468be7STakashi Iwai /* Temporary buffer for altset 0 MIDI 1.0 handling */
56d6468be7STakashi Iwai struct f_midi2_midi1_port {
57d6468be7STakashi Iwai 	unsigned int pending; /* pending bytes on the input buffer */
58d6468be7STakashi Iwai 	u8 buf[32];	/* raw MIDI 1.0 byte input */
59d6468be7STakashi Iwai 	u8 state;	/* running status */
60d6468be7STakashi Iwai 	u8 data[2];	/* rendered USB MIDI 1.0 packet data */
61d6468be7STakashi Iwai };
62d6468be7STakashi Iwai 
63d6468be7STakashi Iwai /* MIDI 1.0 message states */
64d6468be7STakashi Iwai enum {
65d6468be7STakashi Iwai 	STATE_INITIAL = 0,	/* pseudo state */
66d6468be7STakashi Iwai 	STATE_1PARAM,
67d6468be7STakashi Iwai 	STATE_2PARAM_1,
68d6468be7STakashi Iwai 	STATE_2PARAM_2,
69d6468be7STakashi Iwai 	STATE_SYSEX_0,
70d6468be7STakashi Iwai 	STATE_SYSEX_1,
71d6468be7STakashi Iwai 	STATE_SYSEX_2,
72d6468be7STakashi Iwai 	STATE_REAL_TIME,
73d6468be7STakashi Iwai 	STATE_FINISHED,		/* pseudo state */
74d6468be7STakashi Iwai };
75d6468be7STakashi Iwai 
768b645922STakashi Iwai /* Resources for UMP Endpoint */
778b645922STakashi Iwai struct f_midi2_ep {
788b645922STakashi Iwai 	struct snd_ump_endpoint *ump;	/* assigned UMP EP */
798b645922STakashi Iwai 	struct f_midi2 *card;		/* belonging MIDI 2.0 device */
808b645922STakashi Iwai 
818b645922STakashi Iwai 	struct f_midi2_ep_info info;	/* UMP EP info, copied from configfs */
828b645922STakashi Iwai 	unsigned int num_blks;		/* number of FBs */
838b645922STakashi Iwai 	struct f_midi2_block blks[SNDRV_UMP_MAX_BLOCKS];	/* UMP FBs */
848b645922STakashi Iwai 
858b645922STakashi Iwai 	struct f_midi2_usb_ep ep_in;	/* USB MIDI EP-in */
868b645922STakashi Iwai 	struct f_midi2_usb_ep ep_out;	/* USB MIDI EP-out */
87a85ff0dbSTakashi Iwai 
88a85ff0dbSTakashi Iwai 	u8 in_group_to_cable[SNDRV_UMP_MAX_GROUPS]; /* map to cable; 1-based! */
898b645922STakashi Iwai };
908b645922STakashi Iwai 
918b645922STakashi Iwai /* indices for USB strings */
928b645922STakashi Iwai enum {
938b645922STakashi Iwai 	STR_IFACE = 0,
948b645922STakashi Iwai 	STR_GTB1 = 1,
958b645922STakashi Iwai };
968b645922STakashi Iwai 
978b645922STakashi Iwai /* 1-based GTB id to string id */
988b645922STakashi Iwai #define gtb_to_str_id(id)	(STR_GTB1 + (id) - 1)
998b645922STakashi Iwai 
100a85ff0dbSTakashi Iwai /* mapping from MIDI 1.0 cable to UMP group */
101a85ff0dbSTakashi Iwai struct midi1_cable_mapping {
102a85ff0dbSTakashi Iwai 	struct f_midi2_ep *ep;
103a85ff0dbSTakashi Iwai 	unsigned char block;
104a85ff0dbSTakashi Iwai 	unsigned char group;
105a85ff0dbSTakashi Iwai };
106a85ff0dbSTakashi Iwai 
1078b645922STakashi Iwai /* operation mode */
1088b645922STakashi Iwai enum {
1098b645922STakashi Iwai 	MIDI_OP_MODE_UNSET,	/* no altset set yet */
1108b645922STakashi Iwai 	MIDI_OP_MODE_MIDI1,	/* MIDI 1.0 (altset 0) is used */
1118b645922STakashi Iwai 	MIDI_OP_MODE_MIDI2,	/* MIDI 2.0 (altset 1) is used */
1128b645922STakashi Iwai };
1138b645922STakashi Iwai 
1148b645922STakashi Iwai /* Resources for MIDI 2.0 Device */
1158b645922STakashi Iwai struct f_midi2 {
1168b645922STakashi Iwai 	struct usb_function func;
1178b645922STakashi Iwai 	struct usb_gadget *gadget;
1188b645922STakashi Iwai 	struct snd_card *card;
1198b645922STakashi Iwai 
1208b645922STakashi Iwai 	/* MIDI 1.0 in/out USB EPs */
1218b645922STakashi Iwai 	struct f_midi2_usb_ep midi1_ep_in;
1228b645922STakashi Iwai 	struct f_midi2_usb_ep midi1_ep_out;
1238b645922STakashi Iwai 
124a85ff0dbSTakashi Iwai 	/* number of MIDI 1.0 I/O cables */
125a85ff0dbSTakashi Iwai 	unsigned int num_midi1_in;
126a85ff0dbSTakashi Iwai 	unsigned int num_midi1_out;
127a85ff0dbSTakashi Iwai 
128d6468be7STakashi Iwai 	/* conversion for MIDI 1.0 EP-in */
129d6468be7STakashi Iwai 	struct f_midi2_midi1_port midi1_port[MAX_CABLES];
130d6468be7STakashi Iwai 	/* conversion for MIDI 1.0 EP-out */
131d6468be7STakashi Iwai 	struct ump_cvt_to_ump midi1_ump_cvt;
132a85ff0dbSTakashi Iwai 	/* mapping between cables and UMP groups */
133a85ff0dbSTakashi Iwai 	struct midi1_cable_mapping in_cable_mapping[MAX_CABLES];
134a85ff0dbSTakashi Iwai 	struct midi1_cable_mapping out_cable_mapping[MAX_CABLES];
135d6468be7STakashi Iwai 
1368b645922STakashi Iwai 	int midi_if;			/* USB MIDI interface number */
1378b645922STakashi Iwai 	int operation_mode;		/* current operation mode */
1388b645922STakashi Iwai 
1398b645922STakashi Iwai 	spinlock_t queue_lock;
1408b645922STakashi Iwai 
1418b645922STakashi Iwai 	struct f_midi2_card_info info;	/* card info, copied from configfs */
1428b645922STakashi Iwai 
1438b645922STakashi Iwai 	unsigned int num_eps;
1448b645922STakashi Iwai 	struct f_midi2_ep midi2_eps[MAX_UMP_EPS];
1458b645922STakashi Iwai 
1468b645922STakashi Iwai 	unsigned int total_blocks;	/* total number of blocks of all EPs */
1478b645922STakashi Iwai 	struct usb_string *string_defs;
1488b645922STakashi Iwai 	struct usb_string *strings;
1498b645922STakashi Iwai };
1508b645922STakashi Iwai 
1518b645922STakashi Iwai #define func_to_midi2(f)	container_of(f, struct f_midi2, func)
1528b645922STakashi Iwai 
1538b645922STakashi Iwai /* get EP name string */
ump_ep_name(const struct f_midi2_ep * ep)1548b645922STakashi Iwai static const char *ump_ep_name(const struct f_midi2_ep *ep)
1558b645922STakashi Iwai {
1568b645922STakashi Iwai 	return ep->info.ep_name ? ep->info.ep_name : "MIDI 2.0 Gadget";
1578b645922STakashi Iwai }
1588b645922STakashi Iwai 
1598b645922STakashi Iwai /* get EP product ID string */
ump_product_id(const struct f_midi2_ep * ep)1608b645922STakashi Iwai static const char *ump_product_id(const struct f_midi2_ep *ep)
1618b645922STakashi Iwai {
1628b645922STakashi Iwai 	return ep->info.product_id ? ep->info.product_id : "Unique Product ID";
1638b645922STakashi Iwai }
1648b645922STakashi Iwai 
1658b645922STakashi Iwai /* get FB name string */
ump_fb_name(const struct f_midi2_block_info * info)1668b645922STakashi Iwai static const char *ump_fb_name(const struct f_midi2_block_info *info)
1678b645922STakashi Iwai {
1688b645922STakashi Iwai 	return info->name ? info->name : "MIDI 2.0 Gadget I/O";
1698b645922STakashi Iwai }
1708b645922STakashi Iwai 
1718b645922STakashi Iwai /*
1728b645922STakashi Iwai  * USB Descriptor Definitions
1738b645922STakashi Iwai  */
1748b645922STakashi Iwai /* GTB header descriptor */
1758b645922STakashi Iwai static struct usb_ms20_gr_trm_block_header_descriptor gtb_header_desc = {
1768b645922STakashi Iwai 	.bLength =		sizeof(gtb_header_desc),
1778b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_GR_TRM_BLOCK,
1788b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_GR_TRM_BLOCK_HEADER,
1798b645922STakashi Iwai 	.wTotalLength =		__cpu_to_le16(0x12), // to be filled
1808b645922STakashi Iwai };
1818b645922STakashi Iwai 
1828b645922STakashi Iwai /* GTB descriptor template: most items are replaced dynamically */
1838b645922STakashi Iwai static struct usb_ms20_gr_trm_block_descriptor gtb_desc = {
1848b645922STakashi Iwai 	.bLength =		sizeof(gtb_desc),
1858b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_GR_TRM_BLOCK,
1868b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_GR_TRM_BLOCK,
1878b645922STakashi Iwai 	.bGrpTrmBlkID =		0x01,
1888b645922STakashi Iwai 	.bGrpTrmBlkType =	USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL,
1898b645922STakashi Iwai 	.nGroupTrm =		0x00,
1908b645922STakashi Iwai 	.nNumGroupTrm =		1,
1918b645922STakashi Iwai 	.iBlockItem =		0,
1928b645922STakashi Iwai 	.bMIDIProtocol =	USB_MS_MIDI_PROTO_1_0_64,
1938b645922STakashi Iwai 	.wMaxInputBandwidth =	0,
1948b645922STakashi Iwai 	.wMaxOutputBandwidth =	0,
1958b645922STakashi Iwai };
1968b645922STakashi Iwai 
1978b645922STakashi Iwai DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
198856fa444STakashi Iwai DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
1998b645922STakashi Iwai DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
2008b645922STakashi Iwai DECLARE_USB_MS20_ENDPOINT_DESCRIPTOR(32);
2018b645922STakashi Iwai 
2028b645922STakashi Iwai #define EP_MAX_PACKET_INT	8
2038b645922STakashi Iwai 
2048b645922STakashi Iwai /* Audio Control Interface */
2058b645922STakashi Iwai static struct usb_interface_descriptor midi2_audio_if_desc = {
2068b645922STakashi Iwai 	.bLength =		USB_DT_INTERFACE_SIZE,
2078b645922STakashi Iwai 	.bDescriptorType =	USB_DT_INTERFACE,
2088b645922STakashi Iwai 	.bInterfaceNumber =	0, // to be filled
2098b645922STakashi Iwai 	.bNumEndpoints =	0,
2108b645922STakashi Iwai 	.bInterfaceClass =	USB_CLASS_AUDIO,
2118b645922STakashi Iwai 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
2128b645922STakashi Iwai 	.bInterfaceProtocol =	0,
2138b645922STakashi Iwai 	.iInterface =		0,
2148b645922STakashi Iwai };
2158b645922STakashi Iwai 
2168b645922STakashi Iwai static struct uac1_ac_header_descriptor_1 midi2_audio_class_desc = {
2178b645922STakashi Iwai 	.bLength =		0x09,
2188b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_INTERFACE,
2198b645922STakashi Iwai 	.bDescriptorSubtype =	0x01,
2208b645922STakashi Iwai 	.bcdADC =		__cpu_to_le16(0x0100),
2218b645922STakashi Iwai 	.wTotalLength =		__cpu_to_le16(0x0009),
2228b645922STakashi Iwai 	.bInCollection =	0x01,
2238b645922STakashi Iwai 	.baInterfaceNr =	{ 0x01 }, // to be filled
2248b645922STakashi Iwai };
2258b645922STakashi Iwai 
2268b645922STakashi Iwai /* MIDI 1.0 Streaming Interface (altset 0) */
2278b645922STakashi Iwai static struct usb_interface_descriptor midi2_midi1_if_desc = {
2288b645922STakashi Iwai 	.bLength =		USB_DT_INTERFACE_SIZE,
2298b645922STakashi Iwai 	.bDescriptorType =	USB_DT_INTERFACE,
2308b645922STakashi Iwai 	.bInterfaceNumber =	0, // to be filled
2318b645922STakashi Iwai 	.bAlternateSetting =	0,
232856fa444STakashi Iwai 	.bNumEndpoints =	2, // to be filled
2338b645922STakashi Iwai 	.bInterfaceClass =	USB_CLASS_AUDIO,
2348b645922STakashi Iwai 	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,
2358b645922STakashi Iwai 	.bInterfaceProtocol =	0,
2368b645922STakashi Iwai 	.iInterface =		0, // to be filled
2378b645922STakashi Iwai };
2388b645922STakashi Iwai 
2398b645922STakashi Iwai static struct usb_ms_header_descriptor midi2_midi1_class_desc = {
2408b645922STakashi Iwai 	.bLength =		0x07,
2418b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_INTERFACE,
2428b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_HEADER,
2438b645922STakashi Iwai 	.bcdMSC =		__cpu_to_le16(0x0100),
2448b645922STakashi Iwai 	.wTotalLength =		__cpu_to_le16(0x41), // to be calculated
2458b645922STakashi Iwai };
2468b645922STakashi Iwai 
2478b645922STakashi Iwai /* MIDI 1.0 EP OUT */
2488b645922STakashi Iwai static struct usb_endpoint_descriptor midi2_midi1_ep_out_desc = {
2498b645922STakashi Iwai 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
2508b645922STakashi Iwai 	.bDescriptorType =	USB_DT_ENDPOINT,
2518b645922STakashi Iwai 	.bEndpointAddress =	USB_DIR_OUT | 0, // set up dynamically
2528b645922STakashi Iwai 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
2538b645922STakashi Iwai };
2548b645922STakashi Iwai 
2558b645922STakashi Iwai static struct usb_ss_ep_comp_descriptor midi2_midi1_ep_out_ss_comp_desc = {
2568b645922STakashi Iwai 	.bLength                = sizeof(midi2_midi1_ep_out_ss_comp_desc),
2578b645922STakashi Iwai 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
2588b645922STakashi Iwai };
2598b645922STakashi Iwai 
260856fa444STakashi Iwai static struct usb_ms_endpoint_descriptor_16 midi2_midi1_ep_out_class_desc = {
261856fa444STakashi Iwai 	.bLength =		0x05, // to be filled
2628b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
2638b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_GENERAL,
2648b645922STakashi Iwai 	.bNumEmbMIDIJack =	1,
2658b645922STakashi Iwai 	.baAssocJackID =	{ 0x01 },
2668b645922STakashi Iwai };
2678b645922STakashi Iwai 
2688b645922STakashi Iwai /* MIDI 1.0 EP IN */
2698b645922STakashi Iwai static struct usb_endpoint_descriptor midi2_midi1_ep_in_desc = {
2708b645922STakashi Iwai 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
2718b645922STakashi Iwai 	.bDescriptorType =	USB_DT_ENDPOINT,
2728b645922STakashi Iwai 	.bEndpointAddress =	USB_DIR_IN | 0, // set up dynamically
2738b645922STakashi Iwai 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
2748b645922STakashi Iwai };
2758b645922STakashi Iwai 
2768b645922STakashi Iwai static struct usb_ss_ep_comp_descriptor midi2_midi1_ep_in_ss_comp_desc = {
2778b645922STakashi Iwai 	.bLength                = sizeof(midi2_midi1_ep_in_ss_comp_desc),
2788b645922STakashi Iwai 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
2798b645922STakashi Iwai };
2808b645922STakashi Iwai 
281856fa444STakashi Iwai static struct usb_ms_endpoint_descriptor_16 midi2_midi1_ep_in_class_desc = {
282856fa444STakashi Iwai 	.bLength =		0x05, // to be filled
2838b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
2848b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_GENERAL,
2858b645922STakashi Iwai 	.bNumEmbMIDIJack =	1,
2868b645922STakashi Iwai 	.baAssocJackID =	{ 0x03 },
2878b645922STakashi Iwai };
2888b645922STakashi Iwai 
2898b645922STakashi Iwai /* MIDI 2.0 Streaming Interface (altset 1) */
2908b645922STakashi Iwai static struct usb_interface_descriptor midi2_midi2_if_desc = {
2918b645922STakashi Iwai 	.bLength =		USB_DT_INTERFACE_SIZE,
2928b645922STakashi Iwai 	.bDescriptorType =	USB_DT_INTERFACE,
2938b645922STakashi Iwai 	.bInterfaceNumber =	0, // to be filled
2948b645922STakashi Iwai 	.bAlternateSetting =	1,
29529ee7a4dSTakashi Iwai 	.bNumEndpoints =	2, // to be filled
2968b645922STakashi Iwai 	.bInterfaceClass =	USB_CLASS_AUDIO,
2978b645922STakashi Iwai 	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,
2988b645922STakashi Iwai 	.bInterfaceProtocol =	0,
2998b645922STakashi Iwai 	.iInterface =		0, // to be filled
3008b645922STakashi Iwai };
3018b645922STakashi Iwai 
3028b645922STakashi Iwai static struct usb_ms_header_descriptor midi2_midi2_class_desc = {
3038b645922STakashi Iwai 	.bLength =		0x07,
3048b645922STakashi Iwai 	.bDescriptorType =	USB_DT_CS_INTERFACE,
3058b645922STakashi Iwai 	.bDescriptorSubtype =	USB_MS_HEADER,
3068b645922STakashi Iwai 	.bcdMSC =		__cpu_to_le16(0x0200),
3078b645922STakashi Iwai 	.wTotalLength =		__cpu_to_le16(0x07),
3088b645922STakashi Iwai };
3098b645922STakashi Iwai 
3108b645922STakashi Iwai /* MIDI 2.0 EP OUT */
3118b645922STakashi Iwai static struct usb_endpoint_descriptor midi2_midi2_ep_out_desc[MAX_UMP_EPS];
3128b645922STakashi Iwai 
3138b645922STakashi Iwai static struct usb_ss_ep_comp_descriptor midi2_midi2_ep_out_ss_comp_desc = {
3148b645922STakashi Iwai 	.bLength                = sizeof(midi2_midi1_ep_out_ss_comp_desc),
3158b645922STakashi Iwai 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
3168b645922STakashi Iwai };
3178b645922STakashi Iwai 
3188b645922STakashi Iwai static struct usb_ms20_endpoint_descriptor_32 midi2_midi2_ep_out_class_desc[MAX_UMP_EPS];
3198b645922STakashi Iwai 
3208b645922STakashi Iwai /* MIDI 2.0 EP IN */
3218b645922STakashi Iwai static struct usb_endpoint_descriptor midi2_midi2_ep_in_desc[MAX_UMP_EPS];
3228b645922STakashi Iwai 
3238b645922STakashi Iwai static struct usb_ss_ep_comp_descriptor midi2_midi2_ep_in_ss_comp_desc = {
3248b645922STakashi Iwai 	.bLength                = sizeof(midi2_midi2_ep_in_ss_comp_desc),
3258b645922STakashi Iwai 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
3268b645922STakashi Iwai };
3278b645922STakashi Iwai 
3288b645922STakashi Iwai static struct usb_ms20_endpoint_descriptor_32 midi2_midi2_ep_in_class_desc[MAX_UMP_EPS];
3298b645922STakashi Iwai 
3308b645922STakashi Iwai /* Arrays of descriptors to be created */
3318b645922STakashi Iwai static void *midi2_audio_descs[] = {
3328b645922STakashi Iwai 	&midi2_audio_if_desc,
3338b645922STakashi Iwai 	&midi2_audio_class_desc,
3348b645922STakashi Iwai 	NULL
3358b645922STakashi Iwai };
3368b645922STakashi Iwai 
3378b645922STakashi Iwai static void *midi2_midi1_descs[] = {
3388b645922STakashi Iwai 	&midi2_midi1_if_desc,
3398b645922STakashi Iwai 	&midi2_midi1_class_desc,
3408b645922STakashi Iwai 	NULL
3418b645922STakashi Iwai };
3428b645922STakashi Iwai 
343856fa444STakashi Iwai static void *midi2_midi1_ep_out_descs[] = {
3448b645922STakashi Iwai 	&midi2_midi1_ep_out_desc,
3458b645922STakashi Iwai 	&midi2_midi1_ep_out_class_desc,
346856fa444STakashi Iwai 	NULL
347856fa444STakashi Iwai };
348856fa444STakashi Iwai 
349856fa444STakashi Iwai static void *midi2_midi1_ep_in_descs[] = {
3508b645922STakashi Iwai 	&midi2_midi1_ep_in_desc,
3518b645922STakashi Iwai 	&midi2_midi1_ep_in_class_desc,
3528b645922STakashi Iwai 	NULL
3538b645922STakashi Iwai };
3548b645922STakashi Iwai 
355856fa444STakashi Iwai static void *midi2_midi1_ep_out_ss_descs[] = {
3568b645922STakashi Iwai 	&midi2_midi1_ep_out_desc,
3578b645922STakashi Iwai 	&midi2_midi1_ep_out_ss_comp_desc,
3588b645922STakashi Iwai 	&midi2_midi1_ep_out_class_desc,
359856fa444STakashi Iwai 	NULL
360856fa444STakashi Iwai };
361856fa444STakashi Iwai 
362856fa444STakashi Iwai static void *midi2_midi1_ep_in_ss_descs[] = {
3638b645922STakashi Iwai 	&midi2_midi1_ep_in_desc,
3648b645922STakashi Iwai 	&midi2_midi1_ep_in_ss_comp_desc,
3658b645922STakashi Iwai 	&midi2_midi1_ep_in_class_desc,
3668b645922STakashi Iwai 	NULL
3678b645922STakashi Iwai };
3688b645922STakashi Iwai 
3698b645922STakashi Iwai static void *midi2_midi2_descs[] = {
3708b645922STakashi Iwai 	&midi2_midi2_if_desc,
3718b645922STakashi Iwai 	&midi2_midi2_class_desc,
3728b645922STakashi Iwai 	NULL
3738b645922STakashi Iwai };
3748b645922STakashi Iwai 
3758b645922STakashi Iwai /*
3768b645922STakashi Iwai  * USB request handling
3778b645922STakashi Iwai  */
3788b645922STakashi Iwai 
3798b645922STakashi Iwai /* get an empty request for the given EP */
get_empty_request(struct f_midi2_usb_ep * usb_ep)3808b645922STakashi Iwai static struct usb_request *get_empty_request(struct f_midi2_usb_ep *usb_ep)
3818b645922STakashi Iwai {
3828b645922STakashi Iwai 	struct usb_request *req = NULL;
3838b645922STakashi Iwai 	unsigned long flags;
3848b645922STakashi Iwai 	int index;
3858b645922STakashi Iwai 
3868b645922STakashi Iwai 	spin_lock_irqsave(&usb_ep->card->queue_lock, flags);
3878b645922STakashi Iwai 	if (!usb_ep->free_reqs)
3888b645922STakashi Iwai 		goto unlock;
3898b645922STakashi Iwai 	index = find_first_bit(&usb_ep->free_reqs, usb_ep->num_reqs);
3908b645922STakashi Iwai 	if (index >= usb_ep->num_reqs)
3918b645922STakashi Iwai 		goto unlock;
3928b645922STakashi Iwai 	req = usb_ep->reqs[index].req;
3938b645922STakashi Iwai 	if (!req)
3948b645922STakashi Iwai 		goto unlock;
3958b645922STakashi Iwai 	clear_bit(index, &usb_ep->free_reqs);
3968b645922STakashi Iwai 	req->length = 0;
3978b645922STakashi Iwai  unlock:
3988b645922STakashi Iwai 	spin_unlock_irqrestore(&usb_ep->card->queue_lock, flags);
3998b645922STakashi Iwai 	return req;
4008b645922STakashi Iwai }
4018b645922STakashi Iwai 
4028b645922STakashi Iwai /* put the empty request back */
put_empty_request(struct usb_request * req)4038b645922STakashi Iwai static void put_empty_request(struct usb_request *req)
4048b645922STakashi Iwai {
4058b645922STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
4068b645922STakashi Iwai 	unsigned long flags;
4078b645922STakashi Iwai 
4088b645922STakashi Iwai 	spin_lock_irqsave(&ctx->usb_ep->card->queue_lock, flags);
4098b645922STakashi Iwai 	set_bit(ctx->index, &ctx->usb_ep->free_reqs);
4108b645922STakashi Iwai 	spin_unlock_irqrestore(&ctx->usb_ep->card->queue_lock, flags);
4118b645922STakashi Iwai }
4128b645922STakashi Iwai 
4138b645922STakashi Iwai /*
4148b645922STakashi Iwai  * UMP v1.1 Stream message handling
4158b645922STakashi Iwai  */
4168b645922STakashi Iwai 
4178b645922STakashi Iwai /* queue a request to UMP EP; request is either queued or freed after this */
queue_request_ep_raw(struct usb_request * req)4188b645922STakashi Iwai static int queue_request_ep_raw(struct usb_request *req)
4198b645922STakashi Iwai {
4208b645922STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
4218b645922STakashi Iwai 	int err;
4228b645922STakashi Iwai 
4238b645922STakashi Iwai 	req->complete = ctx->usb_ep->complete;
4248b645922STakashi Iwai 	err = usb_ep_queue(ctx->usb_ep->usb_ep, req, GFP_ATOMIC);
4258b645922STakashi Iwai 	if (err) {
4268b645922STakashi Iwai 		put_empty_request(req);
4278b645922STakashi Iwai 		return err;
4288b645922STakashi Iwai 	}
4298b645922STakashi Iwai 	return 0;
4308b645922STakashi Iwai }
4318b645922STakashi Iwai 
4328b645922STakashi Iwai /* queue a request with endianness conversion */
queue_request_ep_in(struct usb_request * req)4338b645922STakashi Iwai static int queue_request_ep_in(struct usb_request *req)
4348b645922STakashi Iwai {
4358b645922STakashi Iwai 	/* UMP packets have to be converted to little-endian */
4368b645922STakashi Iwai 	cpu_to_le32_array((u32 *)req->buf, req->length >> 2);
4378b645922STakashi Iwai 	return queue_request_ep_raw(req);
4388b645922STakashi Iwai }
4398b645922STakashi Iwai 
4408b645922STakashi Iwai /* reply a UMP packet via EP-in */
reply_ep_in(struct f_midi2_ep * ep,const void * buf,int len)4418b645922STakashi Iwai static int reply_ep_in(struct f_midi2_ep *ep, const void *buf, int len)
4428b645922STakashi Iwai {
4438b645922STakashi Iwai 	struct f_midi2_usb_ep *usb_ep = &ep->ep_in;
4448b645922STakashi Iwai 	struct usb_request *req;
4458b645922STakashi Iwai 
4468b645922STakashi Iwai 	req = get_empty_request(usb_ep);
4478b645922STakashi Iwai 	if (!req)
4488b645922STakashi Iwai 		return -ENOSPC;
4498b645922STakashi Iwai 
4508b645922STakashi Iwai 	req->length = len;
4518b645922STakashi Iwai 	memcpy(req->buf, buf, len);
4528b645922STakashi Iwai 	return queue_request_ep_in(req);
4538b645922STakashi Iwai }
4548b645922STakashi Iwai 
4558b645922STakashi Iwai /* reply a UMP stream EP info */
reply_ump_stream_ep_info(struct f_midi2_ep * ep)4568b645922STakashi Iwai static void reply_ump_stream_ep_info(struct f_midi2_ep *ep)
4578b645922STakashi Iwai {
4588b645922STakashi Iwai 	struct snd_ump_stream_msg_ep_info rep = {
4598b645922STakashi Iwai 		.type = UMP_MSG_TYPE_STREAM,
4608b645922STakashi Iwai 		.status = UMP_STREAM_MSG_STATUS_EP_INFO,
4618b645922STakashi Iwai 		.ump_version_major = 0x01,
4628b645922STakashi Iwai 		.ump_version_minor = 0x01,
4638b645922STakashi Iwai 		.num_function_blocks = ep->num_blks,
4648b645922STakashi Iwai 		.static_function_block = !!ep->card->info.static_block,
4658b645922STakashi Iwai 		.protocol = (UMP_STREAM_MSG_EP_INFO_CAP_MIDI1 |
4668b645922STakashi Iwai 			     UMP_STREAM_MSG_EP_INFO_CAP_MIDI2) >> 8,
4678b645922STakashi Iwai 	};
4688b645922STakashi Iwai 
4698b645922STakashi Iwai 	reply_ep_in(ep, &rep, sizeof(rep));
4708b645922STakashi Iwai }
4718b645922STakashi Iwai 
4728b645922STakashi Iwai /* reply a UMP EP device info */
reply_ump_stream_ep_device(struct f_midi2_ep * ep)4738b645922STakashi Iwai static void reply_ump_stream_ep_device(struct f_midi2_ep *ep)
4748b645922STakashi Iwai {
4758b645922STakashi Iwai 	struct snd_ump_stream_msg_devince_info rep = {
4768b645922STakashi Iwai 		.type = UMP_MSG_TYPE_STREAM,
4778b645922STakashi Iwai 		.status = UMP_STREAM_MSG_STATUS_DEVICE_INFO,
4788b645922STakashi Iwai 		.manufacture_id = ep->info.manufacturer,
4798b645922STakashi Iwai 		.family_lsb = ep->info.family & 0xff,
4808b645922STakashi Iwai 		.family_msb = (ep->info.family >> 8) & 0xff,
4818b645922STakashi Iwai 		.model_lsb = ep->info.model & 0xff,
4828b645922STakashi Iwai 		.model_msb = (ep->info.model >> 8) & 0xff,
4838b645922STakashi Iwai 		.sw_revision = ep->info.sw_revision,
4848b645922STakashi Iwai 	};
4858b645922STakashi Iwai 
4868b645922STakashi Iwai 	reply_ep_in(ep, &rep, sizeof(rep));
4878b645922STakashi Iwai }
4888b645922STakashi Iwai 
4898b645922STakashi Iwai #define UMP_STREAM_PKT_BYTES	16	/* UMP stream packet size = 16 bytes*/
4908b645922STakashi Iwai #define UMP_STREAM_EP_STR_OFF	2	/* offset of name string for EP info */
4918b645922STakashi Iwai #define UMP_STREAM_FB_STR_OFF	3	/* offset of name string for FB info */
4928b645922STakashi Iwai 
4938b645922STakashi Iwai /* Helper to replay a string */
reply_ump_stream_string(struct f_midi2_ep * ep,const u8 * name,unsigned int type,unsigned int extra,unsigned int start_ofs)4948b645922STakashi Iwai static void reply_ump_stream_string(struct f_midi2_ep *ep, const u8 *name,
4958b645922STakashi Iwai 				    unsigned int type, unsigned int extra,
4968b645922STakashi Iwai 				    unsigned int start_ofs)
4978b645922STakashi Iwai {
4988b645922STakashi Iwai 	struct f_midi2_usb_ep *usb_ep = &ep->ep_in;
4998b645922STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
5008b645922STakashi Iwai 	struct usb_request *req;
5018b645922STakashi Iwai 	unsigned int pos;
5028b645922STakashi Iwai 	u32 *buf;
5038b645922STakashi Iwai 
5048b645922STakashi Iwai 	if (!*name)
5058b645922STakashi Iwai 		return;
5068b645922STakashi Iwai 	req = get_empty_request(usb_ep);
5078b645922STakashi Iwai 	if (!req)
5088b645922STakashi Iwai 		return;
5098b645922STakashi Iwai 
5108b645922STakashi Iwai 	buf = (u32 *)req->buf;
5118b645922STakashi Iwai 	pos = start_ofs;
5128b645922STakashi Iwai 	for (;;) {
5138b645922STakashi Iwai 		if (pos == start_ofs) {
5148b645922STakashi Iwai 			memset(buf, 0, UMP_STREAM_PKT_BYTES);
5158b645922STakashi Iwai 			buf[0] = ump_stream_compose(type, 0) | extra;
5168b645922STakashi Iwai 		}
5178b645922STakashi Iwai 		buf[pos / 4] |= *name++ << ((3 - (pos % 4)) * 8);
5188b645922STakashi Iwai 		if (!*name) {
5198b645922STakashi Iwai 			if (req->length)
5208b645922STakashi Iwai 				buf[0] |= UMP_STREAM_MSG_FORMAT_END << 26;
5218b645922STakashi Iwai 			req->length += UMP_STREAM_PKT_BYTES;
5228b645922STakashi Iwai 			break;
5238b645922STakashi Iwai 		}
5248b645922STakashi Iwai 		if (++pos == UMP_STREAM_PKT_BYTES) {
5258b645922STakashi Iwai 			if (!req->length)
5268b645922STakashi Iwai 				buf[0] |= UMP_STREAM_MSG_FORMAT_START << 26;
5278b645922STakashi Iwai 			else
5288b645922STakashi Iwai 				buf[0] |= UMP_STREAM_MSG_FORMAT_CONTINUE << 26;
5298b645922STakashi Iwai 			req->length += UMP_STREAM_PKT_BYTES;
5308b645922STakashi Iwai 			if (midi2->info.req_buf_size - req->length < UMP_STREAM_PKT_BYTES)
5318b645922STakashi Iwai 				break;
5328b645922STakashi Iwai 			buf += 4;
5338b645922STakashi Iwai 			pos = start_ofs;
5348b645922STakashi Iwai 		}
5358b645922STakashi Iwai 	}
5368b645922STakashi Iwai 
5378b645922STakashi Iwai 	if (req->length)
5388b645922STakashi Iwai 		queue_request_ep_in(req);
5398b645922STakashi Iwai 	else
5408b645922STakashi Iwai 		put_empty_request(req);
5418b645922STakashi Iwai }
5428b645922STakashi Iwai 
5438b645922STakashi Iwai /* Reply a UMP EP name string */
reply_ump_stream_ep_name(struct f_midi2_ep * ep)5448b645922STakashi Iwai static void reply_ump_stream_ep_name(struct f_midi2_ep *ep)
5458b645922STakashi Iwai {
5468b645922STakashi Iwai 	reply_ump_stream_string(ep, ump_ep_name(ep),
5478b645922STakashi Iwai 				UMP_STREAM_MSG_STATUS_EP_NAME, 0,
5488b645922STakashi Iwai 				UMP_STREAM_EP_STR_OFF);
5498b645922STakashi Iwai }
5508b645922STakashi Iwai 
5518b645922STakashi Iwai /* Reply a UMP EP product ID string */
reply_ump_stream_ep_pid(struct f_midi2_ep * ep)5528b645922STakashi Iwai static void reply_ump_stream_ep_pid(struct f_midi2_ep *ep)
5538b645922STakashi Iwai {
5548b645922STakashi Iwai 	reply_ump_stream_string(ep, ump_product_id(ep),
5558b645922STakashi Iwai 				UMP_STREAM_MSG_STATUS_PRODUCT_ID, 0,
5568b645922STakashi Iwai 				UMP_STREAM_EP_STR_OFF);
5578b645922STakashi Iwai }
5588b645922STakashi Iwai 
5598b645922STakashi Iwai /* Reply a UMP EP stream config */
reply_ump_stream_ep_config(struct f_midi2_ep * ep)5608b645922STakashi Iwai static void reply_ump_stream_ep_config(struct f_midi2_ep *ep)
5618b645922STakashi Iwai {
5628b645922STakashi Iwai 	struct snd_ump_stream_msg_stream_cfg rep = {
5638b645922STakashi Iwai 		.type = UMP_MSG_TYPE_STREAM,
5648b645922STakashi Iwai 		.status = UMP_STREAM_MSG_STATUS_STREAM_CFG,
5658b645922STakashi Iwai 	};
5668b645922STakashi Iwai 
5678b645922STakashi Iwai 	if ((ep->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK) ==
5688b645922STakashi Iwai 	    SNDRV_UMP_EP_INFO_PROTO_MIDI2)
5698b645922STakashi Iwai 		rep.protocol = UMP_STREAM_MSG_EP_INFO_CAP_MIDI2 >> 8;
5708b645922STakashi Iwai 	else
5718b645922STakashi Iwai 		rep.protocol = UMP_STREAM_MSG_EP_INFO_CAP_MIDI1 >> 8;
5728b645922STakashi Iwai 
5738b645922STakashi Iwai 	reply_ep_in(ep, &rep, sizeof(rep));
5748b645922STakashi Iwai }
5758b645922STakashi Iwai 
5768b645922STakashi Iwai /* Reply a UMP FB info */
reply_ump_stream_fb_info(struct f_midi2_ep * ep,int blk)5778b645922STakashi Iwai static void reply_ump_stream_fb_info(struct f_midi2_ep *ep, int blk)
5788b645922STakashi Iwai {
5798b645922STakashi Iwai 	struct f_midi2_block_info *b = &ep->blks[blk].info;
5808b645922STakashi Iwai 	struct snd_ump_stream_msg_fb_info rep = {
5818b645922STakashi Iwai 		.type = UMP_MSG_TYPE_STREAM,
5828b645922STakashi Iwai 		.status = UMP_STREAM_MSG_STATUS_FB_INFO,
5838b645922STakashi Iwai 		.active = !!b->active,
5848b645922STakashi Iwai 		.function_block_id = blk,
5858b645922STakashi Iwai 		.ui_hint = b->ui_hint,
5868b645922STakashi Iwai 		.midi_10 = b->is_midi1,
5878b645922STakashi Iwai 		.direction = b->direction,
5888b645922STakashi Iwai 		.first_group = b->first_group,
5898b645922STakashi Iwai 		.num_groups = b->num_groups,
5908b645922STakashi Iwai 		.midi_ci_version = b->midi_ci_version,
5918b645922STakashi Iwai 		.sysex8_streams = b->sysex8_streams,
5928b645922STakashi Iwai 	};
5938b645922STakashi Iwai 
5948b645922STakashi Iwai 	reply_ep_in(ep, &rep, sizeof(rep));
5958b645922STakashi Iwai }
5968b645922STakashi Iwai 
5978b645922STakashi Iwai /* Reply a FB name string */
reply_ump_stream_fb_name(struct f_midi2_ep * ep,unsigned int blk)5988b645922STakashi Iwai static void reply_ump_stream_fb_name(struct f_midi2_ep *ep, unsigned int blk)
5998b645922STakashi Iwai {
6008b645922STakashi Iwai 	reply_ump_stream_string(ep, ump_fb_name(&ep->blks[blk].info),
6018b645922STakashi Iwai 				UMP_STREAM_MSG_STATUS_FB_NAME, blk << 8,
6028b645922STakashi Iwai 				UMP_STREAM_FB_STR_OFF);
6038b645922STakashi Iwai }
6048b645922STakashi Iwai 
6058b645922STakashi Iwai /* Process a UMP Stream message */
process_ump_stream_msg(struct f_midi2_ep * ep,const u32 * data)6068b645922STakashi Iwai static void process_ump_stream_msg(struct f_midi2_ep *ep, const u32 *data)
6078b645922STakashi Iwai {
6088b645922STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
6098b645922STakashi Iwai 	unsigned int format, status, blk;
6108b645922STakashi Iwai 
6118b645922STakashi Iwai 	format = ump_stream_message_format(*data);
6128b645922STakashi Iwai 	status = ump_stream_message_status(*data);
6138b645922STakashi Iwai 	switch (status) {
6148b645922STakashi Iwai 	case UMP_STREAM_MSG_STATUS_EP_DISCOVERY:
6158b645922STakashi Iwai 		if (format)
6168b645922STakashi Iwai 			return; // invalid
6178b645922STakashi Iwai 		if (data[1] & UMP_STREAM_MSG_REQUEST_EP_INFO)
6188b645922STakashi Iwai 			reply_ump_stream_ep_info(ep);
6198b645922STakashi Iwai 		if (data[1] & UMP_STREAM_MSG_REQUEST_DEVICE_INFO)
6208b645922STakashi Iwai 			reply_ump_stream_ep_device(ep);
6218b645922STakashi Iwai 		if (data[1] & UMP_STREAM_MSG_REQUEST_EP_NAME)
6228b645922STakashi Iwai 			reply_ump_stream_ep_name(ep);
6238b645922STakashi Iwai 		if (data[1] & UMP_STREAM_MSG_REQUEST_PRODUCT_ID)
6248b645922STakashi Iwai 			reply_ump_stream_ep_pid(ep);
6258b645922STakashi Iwai 		if (data[1] & UMP_STREAM_MSG_REQUEST_STREAM_CFG)
6268b645922STakashi Iwai 			reply_ump_stream_ep_config(ep);
6278b645922STakashi Iwai 		return;
6288b645922STakashi Iwai 	case UMP_STREAM_MSG_STATUS_STREAM_CFG_REQUEST:
6298b645922STakashi Iwai 		if (*data & UMP_STREAM_MSG_EP_INFO_CAP_MIDI2) {
6308b645922STakashi Iwai 			ep->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI2;
6318b645922STakashi Iwai 			DBG(midi2, "Switching Protocol to MIDI2\n");
6328b645922STakashi Iwai 		} else {
6338b645922STakashi Iwai 			ep->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1;
6348b645922STakashi Iwai 			DBG(midi2, "Switching Protocol to MIDI1\n");
6358b645922STakashi Iwai 		}
6368b645922STakashi Iwai 		snd_ump_switch_protocol(ep->ump, ep->info.protocol);
6378b645922STakashi Iwai 		reply_ump_stream_ep_config(ep);
6388b645922STakashi Iwai 		return;
6398b645922STakashi Iwai 	case UMP_STREAM_MSG_STATUS_FB_DISCOVERY:
6408b645922STakashi Iwai 		if (format)
6418b645922STakashi Iwai 			return; // invalid
6428b645922STakashi Iwai 		blk = (*data >> 8) & 0xff;
6438b645922STakashi Iwai 		if (blk >= ep->num_blks)
6448b645922STakashi Iwai 			return;
6458b645922STakashi Iwai 		if (*data & UMP_STREAM_MSG_REQUEST_FB_INFO)
6468b645922STakashi Iwai 			reply_ump_stream_fb_info(ep, blk);
6478b645922STakashi Iwai 		if (*data & UMP_STREAM_MSG_REQUEST_FB_NAME)
6488b645922STakashi Iwai 			reply_ump_stream_fb_name(ep, blk);
6498b645922STakashi Iwai 		return;
6508b645922STakashi Iwai 	}
6518b645922STakashi Iwai }
6528b645922STakashi Iwai 
6538b645922STakashi Iwai /* Process UMP messages included in a USB request */
process_ump(struct f_midi2_ep * ep,const struct usb_request * req)6548b645922STakashi Iwai static void process_ump(struct f_midi2_ep *ep, const struct usb_request *req)
6558b645922STakashi Iwai {
6568b645922STakashi Iwai 	const u32 *data = (u32 *)req->buf;
6578b645922STakashi Iwai 	int len = req->actual >> 2;
6588b645922STakashi Iwai 	const u32 *in_buf = ep->ump->input_buf;
6598b645922STakashi Iwai 
6608b645922STakashi Iwai 	for (; len > 0; len--, data++) {
6618b645922STakashi Iwai 		if (snd_ump_receive_ump_val(ep->ump, *data) <= 0)
6628b645922STakashi Iwai 			continue;
6638b645922STakashi Iwai 		if (ump_message_type(*in_buf) == UMP_MSG_TYPE_STREAM)
6648b645922STakashi Iwai 			process_ump_stream_msg(ep, in_buf);
6658b645922STakashi Iwai 	}
6668b645922STakashi Iwai }
6678b645922STakashi Iwai 
6688b645922STakashi Iwai /*
6698b645922STakashi Iwai  * MIDI 2.0 UMP USB request handling
6708b645922STakashi Iwai  */
6718b645922STakashi Iwai 
6728b645922STakashi Iwai /* complete handler for UMP EP-out requests */
f_midi2_ep_out_complete(struct usb_ep * usb_ep,struct usb_request * req)6738b645922STakashi Iwai static void f_midi2_ep_out_complete(struct usb_ep *usb_ep,
6748b645922STakashi Iwai 				    struct usb_request *req)
6758b645922STakashi Iwai {
6768b645922STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
6778b645922STakashi Iwai 	struct f_midi2_ep *ep = ctx->usb_ep->ep;
6788b645922STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
6798b645922STakashi Iwai 	int status = req->status;
6808b645922STakashi Iwai 
6818b645922STakashi Iwai 	if (status) {
6828b645922STakashi Iwai 		DBG(midi2, "%s complete error %d: %d/%d\n",
6838b645922STakashi Iwai 		    usb_ep->name, status, req->actual, req->length);
6848b645922STakashi Iwai 		goto error;
6858b645922STakashi Iwai 	}
6868b645922STakashi Iwai 
6878b645922STakashi Iwai 	/* convert to UMP packet in native endianness */
6888b645922STakashi Iwai 	le32_to_cpu_array((u32 *)req->buf, req->actual >> 2);
6898b645922STakashi Iwai 
6908b645922STakashi Iwai 	if (midi2->info.process_ump)
6918b645922STakashi Iwai 		process_ump(ep, req);
6928b645922STakashi Iwai 
6938b645922STakashi Iwai 	snd_ump_receive(ep->ump, req->buf, req->actual & ~3);
6948b645922STakashi Iwai 
6958b645922STakashi Iwai 	if (midi2->operation_mode != MIDI_OP_MODE_MIDI2)
6968b645922STakashi Iwai 		goto error;
6978b645922STakashi Iwai 
6988b645922STakashi Iwai 	if (queue_request_ep_raw(req))
6998b645922STakashi Iwai 		goto error;
7008b645922STakashi Iwai 	return;
7018b645922STakashi Iwai 
7028b645922STakashi Iwai  error:
7038b645922STakashi Iwai 	put_empty_request(req);
7048b645922STakashi Iwai }
7058b645922STakashi Iwai 
7068b645922STakashi Iwai /* Transmit UMP packets received from user-space to the gadget */
process_ump_transmit(struct f_midi2_ep * ep)7078b645922STakashi Iwai static void process_ump_transmit(struct f_midi2_ep *ep)
7088b645922STakashi Iwai {
7098b645922STakashi Iwai 	struct f_midi2_usb_ep *usb_ep = &ep->ep_in;
7108b645922STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
7118b645922STakashi Iwai 	struct usb_request *req;
7128b645922STakashi Iwai 	int len;
7138b645922STakashi Iwai 
7148b645922STakashi Iwai 	if (!usb_ep->usb_ep->enabled)
7158b645922STakashi Iwai 		return;
7168b645922STakashi Iwai 
7178b645922STakashi Iwai 	for (;;) {
7188b645922STakashi Iwai 		req = get_empty_request(usb_ep);
7198b645922STakashi Iwai 		if (!req)
7208b645922STakashi Iwai 			break;
7218b645922STakashi Iwai 		len = snd_ump_transmit(ep->ump, (u32 *)req->buf,
7228b645922STakashi Iwai 				       midi2->info.req_buf_size);
7238b645922STakashi Iwai 		if (len <= 0) {
7248b645922STakashi Iwai 			put_empty_request(req);
7258b645922STakashi Iwai 			break;
7268b645922STakashi Iwai 		}
7278b645922STakashi Iwai 
7288b645922STakashi Iwai 		req->length = len;
7298b645922STakashi Iwai 		if (queue_request_ep_in(req) < 0)
7308b645922STakashi Iwai 			break;
7318b645922STakashi Iwai 	}
7328b645922STakashi Iwai }
7338b645922STakashi Iwai 
7348b645922STakashi Iwai /* Complete handler for UMP EP-in requests */
f_midi2_ep_in_complete(struct usb_ep * usb_ep,struct usb_request * req)7358b645922STakashi Iwai static void f_midi2_ep_in_complete(struct usb_ep *usb_ep,
7368b645922STakashi Iwai 				   struct usb_request *req)
7378b645922STakashi Iwai {
7388b645922STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
7398b645922STakashi Iwai 	struct f_midi2_ep *ep = ctx->usb_ep->ep;
7408b645922STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
7418b645922STakashi Iwai 	int status = req->status;
7428b645922STakashi Iwai 
7438b645922STakashi Iwai 	put_empty_request(req);
7448b645922STakashi Iwai 
7458b645922STakashi Iwai 	if (status) {
7468b645922STakashi Iwai 		DBG(midi2, "%s complete error %d: %d/%d\n",
7478b645922STakashi Iwai 		    usb_ep->name, status, req->actual, req->length);
7488b645922STakashi Iwai 		return;
7498b645922STakashi Iwai 	}
7508b645922STakashi Iwai 
7518b645922STakashi Iwai 	process_ump_transmit(ep);
7528b645922STakashi Iwai }
7538b645922STakashi Iwai 
754d6468be7STakashi Iwai /*
755d6468be7STakashi Iwai  * MIDI1 (altset 0) USB request handling
756d6468be7STakashi Iwai  */
757d6468be7STakashi Iwai 
758d6468be7STakashi Iwai /* process one MIDI byte -- copied from f_midi.c
759d6468be7STakashi Iwai  *
760d6468be7STakashi Iwai  * fill the packet or request if needed
761d6468be7STakashi Iwai  * returns true if the request became empty (queued)
762d6468be7STakashi Iwai  */
process_midi1_byte(struct f_midi2 * midi2,u8 cable,u8 b,struct usb_request ** req_p)763d6468be7STakashi Iwai static bool process_midi1_byte(struct f_midi2 *midi2, u8 cable, u8 b,
764d6468be7STakashi Iwai 			       struct usb_request **req_p)
765d6468be7STakashi Iwai {
766d6468be7STakashi Iwai 	struct f_midi2_midi1_port *port = &midi2->midi1_port[cable];
767d6468be7STakashi Iwai 	u8 p[4] = { cable << 4, 0, 0, 0 };
768d6468be7STakashi Iwai 	int next_state = STATE_INITIAL;
769d6468be7STakashi Iwai 	struct usb_request *req = *req_p;
770d6468be7STakashi Iwai 
771d6468be7STakashi Iwai 	switch (b) {
772d6468be7STakashi Iwai 	case 0xf8 ... 0xff:
773d6468be7STakashi Iwai 		/* System Real-Time Messages */
774d6468be7STakashi Iwai 		p[0] |= 0x0f;
775d6468be7STakashi Iwai 		p[1] = b;
776d6468be7STakashi Iwai 		next_state = port->state;
777d6468be7STakashi Iwai 		port->state = STATE_REAL_TIME;
778d6468be7STakashi Iwai 		break;
779d6468be7STakashi Iwai 
780d6468be7STakashi Iwai 	case 0xf7:
781d6468be7STakashi Iwai 		/* End of SysEx */
782d6468be7STakashi Iwai 		switch (port->state) {
783d6468be7STakashi Iwai 		case STATE_SYSEX_0:
784d6468be7STakashi Iwai 			p[0] |= 0x05;
785d6468be7STakashi Iwai 			p[1] = 0xf7;
786d6468be7STakashi Iwai 			next_state = STATE_FINISHED;
787d6468be7STakashi Iwai 			break;
788d6468be7STakashi Iwai 		case STATE_SYSEX_1:
789d6468be7STakashi Iwai 			p[0] |= 0x06;
790d6468be7STakashi Iwai 			p[1] = port->data[0];
791d6468be7STakashi Iwai 			p[2] = 0xf7;
792d6468be7STakashi Iwai 			next_state = STATE_FINISHED;
793d6468be7STakashi Iwai 			break;
794d6468be7STakashi Iwai 		case STATE_SYSEX_2:
795d6468be7STakashi Iwai 			p[0] |= 0x07;
796d6468be7STakashi Iwai 			p[1] = port->data[0];
797d6468be7STakashi Iwai 			p[2] = port->data[1];
798d6468be7STakashi Iwai 			p[3] = 0xf7;
799d6468be7STakashi Iwai 			next_state = STATE_FINISHED;
800d6468be7STakashi Iwai 			break;
801d6468be7STakashi Iwai 		default:
802d6468be7STakashi Iwai 			/* Ignore byte */
803d6468be7STakashi Iwai 			next_state = port->state;
804d6468be7STakashi Iwai 			port->state = STATE_INITIAL;
805d6468be7STakashi Iwai 		}
806d6468be7STakashi Iwai 		break;
807d6468be7STakashi Iwai 
808d6468be7STakashi Iwai 	case 0xf0 ... 0xf6:
809d6468be7STakashi Iwai 		/* System Common Messages */
810d6468be7STakashi Iwai 		port->data[0] = port->data[1] = 0;
811d6468be7STakashi Iwai 		port->state = STATE_INITIAL;
812d6468be7STakashi Iwai 		switch (b) {
813d6468be7STakashi Iwai 		case 0xf0:
814d6468be7STakashi Iwai 			port->data[0] = b;
815d6468be7STakashi Iwai 			port->data[1] = 0;
816d6468be7STakashi Iwai 			next_state = STATE_SYSEX_1;
817d6468be7STakashi Iwai 			break;
818d6468be7STakashi Iwai 		case 0xf1:
819d6468be7STakashi Iwai 		case 0xf3:
820d6468be7STakashi Iwai 			port->data[0] = b;
821d6468be7STakashi Iwai 			next_state = STATE_1PARAM;
822d6468be7STakashi Iwai 			break;
823d6468be7STakashi Iwai 		case 0xf2:
824d6468be7STakashi Iwai 			port->data[0] = b;
825d6468be7STakashi Iwai 			next_state = STATE_2PARAM_1;
826d6468be7STakashi Iwai 			break;
827d6468be7STakashi Iwai 		case 0xf4:
828d6468be7STakashi Iwai 		case 0xf5:
829d6468be7STakashi Iwai 			next_state = STATE_INITIAL;
830d6468be7STakashi Iwai 			break;
831d6468be7STakashi Iwai 		case 0xf6:
832d6468be7STakashi Iwai 			p[0] |= 0x05;
833d6468be7STakashi Iwai 			p[1] = 0xf6;
834d6468be7STakashi Iwai 			next_state = STATE_FINISHED;
835d6468be7STakashi Iwai 			break;
836d6468be7STakashi Iwai 		}
837d6468be7STakashi Iwai 		break;
838d6468be7STakashi Iwai 
839d6468be7STakashi Iwai 	case 0x80 ... 0xef:
840d6468be7STakashi Iwai 		/*
841d6468be7STakashi Iwai 		 * Channel Voice Messages, Channel Mode Messages
842d6468be7STakashi Iwai 		 * and Control Change Messages.
843d6468be7STakashi Iwai 		 */
844d6468be7STakashi Iwai 		port->data[0] = b;
845d6468be7STakashi Iwai 		port->data[1] = 0;
846d6468be7STakashi Iwai 		port->state = STATE_INITIAL;
847d6468be7STakashi Iwai 		if (b >= 0xc0 && b <= 0xdf)
848d6468be7STakashi Iwai 			next_state = STATE_1PARAM;
849d6468be7STakashi Iwai 		else
850d6468be7STakashi Iwai 			next_state = STATE_2PARAM_1;
851d6468be7STakashi Iwai 		break;
852d6468be7STakashi Iwai 
853d6468be7STakashi Iwai 	case 0x00 ... 0x7f:
854d6468be7STakashi Iwai 		/* Message parameters */
855d6468be7STakashi Iwai 		switch (port->state) {
856d6468be7STakashi Iwai 		case STATE_1PARAM:
857d6468be7STakashi Iwai 			if (port->data[0] < 0xf0)
858d6468be7STakashi Iwai 				p[0] |= port->data[0] >> 4;
859d6468be7STakashi Iwai 			else
860d6468be7STakashi Iwai 				p[0] |= 0x02;
861d6468be7STakashi Iwai 
862d6468be7STakashi Iwai 			p[1] = port->data[0];
863d6468be7STakashi Iwai 			p[2] = b;
864d6468be7STakashi Iwai 			/* This is to allow Running State Messages */
865d6468be7STakashi Iwai 			next_state = STATE_1PARAM;
866d6468be7STakashi Iwai 			break;
867d6468be7STakashi Iwai 		case STATE_2PARAM_1:
868d6468be7STakashi Iwai 			port->data[1] = b;
869d6468be7STakashi Iwai 			next_state = STATE_2PARAM_2;
870d6468be7STakashi Iwai 			break;
871d6468be7STakashi Iwai 		case STATE_2PARAM_2:
872d6468be7STakashi Iwai 			if (port->data[0] < 0xf0)
873d6468be7STakashi Iwai 				p[0] |= port->data[0] >> 4;
874d6468be7STakashi Iwai 			else
875d6468be7STakashi Iwai 				p[0] |= 0x03;
876d6468be7STakashi Iwai 
877d6468be7STakashi Iwai 			p[1] = port->data[0];
878d6468be7STakashi Iwai 			p[2] = port->data[1];
879d6468be7STakashi Iwai 			p[3] = b;
880d6468be7STakashi Iwai 			/* This is to allow Running State Messages */
881d6468be7STakashi Iwai 			next_state = STATE_2PARAM_1;
882d6468be7STakashi Iwai 			break;
883d6468be7STakashi Iwai 		case STATE_SYSEX_0:
884d6468be7STakashi Iwai 			port->data[0] = b;
885d6468be7STakashi Iwai 			next_state = STATE_SYSEX_1;
886d6468be7STakashi Iwai 			break;
887d6468be7STakashi Iwai 		case STATE_SYSEX_1:
888d6468be7STakashi Iwai 			port->data[1] = b;
889d6468be7STakashi Iwai 			next_state = STATE_SYSEX_2;
890d6468be7STakashi Iwai 			break;
891d6468be7STakashi Iwai 		case STATE_SYSEX_2:
892d6468be7STakashi Iwai 			p[0] |= 0x04;
893d6468be7STakashi Iwai 			p[1] = port->data[0];
894d6468be7STakashi Iwai 			p[2] = port->data[1];
895d6468be7STakashi Iwai 			p[3] = b;
896d6468be7STakashi Iwai 			next_state = STATE_SYSEX_0;
897d6468be7STakashi Iwai 			break;
898d6468be7STakashi Iwai 		}
899d6468be7STakashi Iwai 		break;
900d6468be7STakashi Iwai 	}
901d6468be7STakashi Iwai 
902d6468be7STakashi Iwai 	/* States where we have to write into the USB request */
903d6468be7STakashi Iwai 	if (next_state == STATE_FINISHED ||
904d6468be7STakashi Iwai 	    port->state == STATE_SYSEX_2 ||
905d6468be7STakashi Iwai 	    port->state == STATE_1PARAM ||
906d6468be7STakashi Iwai 	    port->state == STATE_2PARAM_2 ||
907d6468be7STakashi Iwai 	    port->state == STATE_REAL_TIME) {
908d6468be7STakashi Iwai 		memcpy(req->buf + req->length, p, sizeof(p));
909d6468be7STakashi Iwai 		req->length += sizeof(p);
910d6468be7STakashi Iwai 
911d6468be7STakashi Iwai 		if (next_state == STATE_FINISHED) {
912d6468be7STakashi Iwai 			next_state = STATE_INITIAL;
913d6468be7STakashi Iwai 			port->data[0] = port->data[1] = 0;
914d6468be7STakashi Iwai 		}
915d6468be7STakashi Iwai 
916d6468be7STakashi Iwai 		if (midi2->info.req_buf_size - req->length <= 4) {
917d6468be7STakashi Iwai 			queue_request_ep_raw(req);
918d6468be7STakashi Iwai 			*req_p = NULL;
919d6468be7STakashi Iwai 			return true;
920d6468be7STakashi Iwai 		}
921d6468be7STakashi Iwai 	}
922d6468be7STakashi Iwai 
923d6468be7STakashi Iwai 	port->state = next_state;
924d6468be7STakashi Iwai 	return false;
925d6468be7STakashi Iwai }
926d6468be7STakashi Iwai 
927d6468be7STakashi Iwai /* process all pending MIDI bytes in the internal buffer;
928d6468be7STakashi Iwai  * returns true if the request gets empty
929d6468be7STakashi Iwai  * returns false if all have been processed
930d6468be7STakashi Iwai  */
process_midi1_pending_buf(struct f_midi2 * midi2,struct usb_request ** req_p)931d6468be7STakashi Iwai static bool process_midi1_pending_buf(struct f_midi2 *midi2,
932d6468be7STakashi Iwai 				      struct usb_request **req_p)
933d6468be7STakashi Iwai {
934d6468be7STakashi Iwai 	unsigned int cable, c;
935d6468be7STakashi Iwai 
936a85ff0dbSTakashi Iwai 	for (cable = 0; cable < midi2->num_midi1_in; cable++) {
937d6468be7STakashi Iwai 		struct f_midi2_midi1_port *port = &midi2->midi1_port[cable];
938d6468be7STakashi Iwai 
939d6468be7STakashi Iwai 		if (!port->pending)
940d6468be7STakashi Iwai 			continue;
941d6468be7STakashi Iwai 		for (c = 0; c < port->pending; c++) {
942d6468be7STakashi Iwai 			if (process_midi1_byte(midi2, cable, port->buf[c],
943d6468be7STakashi Iwai 					       req_p)) {
944d6468be7STakashi Iwai 				port->pending -= c;
945d6468be7STakashi Iwai 				if (port->pending)
946d6468be7STakashi Iwai 					memmove(port->buf, port->buf + c,
947d6468be7STakashi Iwai 						port->pending);
948d6468be7STakashi Iwai 				return true;
949d6468be7STakashi Iwai 			}
950d6468be7STakashi Iwai 		}
951d6468be7STakashi Iwai 		port->pending = 0;
952d6468be7STakashi Iwai 	}
953d6468be7STakashi Iwai 
954d6468be7STakashi Iwai 	return false;
955d6468be7STakashi Iwai }
956d6468be7STakashi Iwai 
957d6468be7STakashi Iwai /* fill the MIDI bytes onto the temporary buffer
958d6468be7STakashi Iwai  */
fill_midi1_pending_buf(struct f_midi2 * midi2,u8 cable,u8 * buf,unsigned int size)959d6468be7STakashi Iwai static void fill_midi1_pending_buf(struct f_midi2 *midi2, u8 cable, u8 *buf,
960d6468be7STakashi Iwai 				   unsigned int size)
961d6468be7STakashi Iwai {
962d6468be7STakashi Iwai 	struct f_midi2_midi1_port *port = &midi2->midi1_port[cable];
963d6468be7STakashi Iwai 
964d6468be7STakashi Iwai 	if (port->pending + size > sizeof(port->buf))
965d6468be7STakashi Iwai 		return;
966d6468be7STakashi Iwai 	memcpy(port->buf + port->pending, buf, size);
967d6468be7STakashi Iwai 	port->pending += size;
968d6468be7STakashi Iwai }
969d6468be7STakashi Iwai 
970d6468be7STakashi Iwai /* try to process data given from the associated UMP stream */
process_midi1_transmit(struct f_midi2 * midi2)971d6468be7STakashi Iwai static void process_midi1_transmit(struct f_midi2 *midi2)
972d6468be7STakashi Iwai {
973d6468be7STakashi Iwai 	struct f_midi2_usb_ep *usb_ep = &midi2->midi1_ep_in;
974d6468be7STakashi Iwai 	struct f_midi2_ep *ep = &midi2->midi2_eps[0];
975d6468be7STakashi Iwai 	struct usb_request *req = NULL;
976d6468be7STakashi Iwai 	/* 12 is the largest outcome (4 MIDI1 cmds) for a single UMP packet */
977d6468be7STakashi Iwai 	unsigned char outbuf[12];
978a85ff0dbSTakashi Iwai 	unsigned char group, cable;
979a85ff0dbSTakashi Iwai 	int len, size;
980d6468be7STakashi Iwai 	u32 ump;
981d6468be7STakashi Iwai 
982d6468be7STakashi Iwai 	if (!usb_ep->usb_ep || !usb_ep->usb_ep->enabled)
983d6468be7STakashi Iwai 		return;
984d6468be7STakashi Iwai 
985d6468be7STakashi Iwai 	for (;;) {
986d6468be7STakashi Iwai 		if (!req) {
987d6468be7STakashi Iwai 			req = get_empty_request(usb_ep);
988d6468be7STakashi Iwai 			if (!req)
989d6468be7STakashi Iwai 				break;
990d6468be7STakashi Iwai 		}
991d6468be7STakashi Iwai 
992d6468be7STakashi Iwai 		if (process_midi1_pending_buf(midi2, &req))
993d6468be7STakashi Iwai 			continue;
994d6468be7STakashi Iwai 
995d6468be7STakashi Iwai 		len = snd_ump_transmit(ep->ump, &ump, 4);
996d6468be7STakashi Iwai 		if (len <= 0)
997d6468be7STakashi Iwai 			break;
998d6468be7STakashi Iwai 		if (snd_ump_receive_ump_val(ep->ump, ump) <= 0)
999d6468be7STakashi Iwai 			continue;
1000d6468be7STakashi Iwai 		size = snd_ump_convert_from_ump(ep->ump->input_buf, outbuf,
1001d6468be7STakashi Iwai 						&group);
1002d6468be7STakashi Iwai 		if (size <= 0)
1003d6468be7STakashi Iwai 			continue;
1004a85ff0dbSTakashi Iwai 		cable = ep->in_group_to_cable[group];
1005a85ff0dbSTakashi Iwai 		if (!cable)
1006d6468be7STakashi Iwai 			continue;
1007a85ff0dbSTakashi Iwai 		cable--; /* to 0-base */
1008d6468be7STakashi Iwai 		fill_midi1_pending_buf(midi2, cable, outbuf, size);
1009d6468be7STakashi Iwai 	}
1010d6468be7STakashi Iwai 
1011d6468be7STakashi Iwai 	if (req) {
1012d6468be7STakashi Iwai 		if (req->length)
1013d6468be7STakashi Iwai 			queue_request_ep_raw(req);
1014d6468be7STakashi Iwai 		else
1015d6468be7STakashi Iwai 			put_empty_request(req);
1016d6468be7STakashi Iwai 	}
1017d6468be7STakashi Iwai }
1018d6468be7STakashi Iwai 
1019d6468be7STakashi Iwai /* complete handler for MIDI1 EP-in requests */
f_midi2_midi1_ep_in_complete(struct usb_ep * usb_ep,struct usb_request * req)1020d6468be7STakashi Iwai static void f_midi2_midi1_ep_in_complete(struct usb_ep *usb_ep,
1021d6468be7STakashi Iwai 					 struct usb_request *req)
1022d6468be7STakashi Iwai {
1023d6468be7STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
1024d6468be7STakashi Iwai 	struct f_midi2 *midi2 = ctx->usb_ep->card;
1025d6468be7STakashi Iwai 	int status = req->status;
1026d6468be7STakashi Iwai 
1027d6468be7STakashi Iwai 	put_empty_request(req);
1028d6468be7STakashi Iwai 
1029d6468be7STakashi Iwai 	if (status) {
1030d6468be7STakashi Iwai 		DBG(midi2, "%s complete error %d: %d/%d\n",
1031d6468be7STakashi Iwai 		    usb_ep->name, status, req->actual, req->length);
1032d6468be7STakashi Iwai 		return;
1033d6468be7STakashi Iwai 	}
1034d6468be7STakashi Iwai 
1035d6468be7STakashi Iwai 	process_midi1_transmit(midi2);
1036d6468be7STakashi Iwai }
1037d6468be7STakashi Iwai 
1038d6468be7STakashi Iwai /* complete handler for MIDI1 EP-out requests */
f_midi2_midi1_ep_out_complete(struct usb_ep * usb_ep,struct usb_request * req)1039d6468be7STakashi Iwai static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep,
1040d6468be7STakashi Iwai 					  struct usb_request *req)
1041d6468be7STakashi Iwai {
1042d6468be7STakashi Iwai 	struct f_midi2_req_ctx *ctx = req->context;
1043d6468be7STakashi Iwai 	struct f_midi2 *midi2 = ctx->usb_ep->card;
1044a85ff0dbSTakashi Iwai 	struct f_midi2_ep *ep;
1045d6468be7STakashi Iwai 	struct ump_cvt_to_ump *cvt = &midi2->midi1_ump_cvt;
1046d6468be7STakashi Iwai 	static const u8 midi1_packet_bytes[16] = {
1047d6468be7STakashi Iwai 		0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
1048d6468be7STakashi Iwai 	};
1049a85ff0dbSTakashi Iwai 	unsigned int group, cable, bytes, c, len;
1050d6468be7STakashi Iwai 	int status = req->status;
1051d6468be7STakashi Iwai 	const u8 *buf = req->buf;
1052d6468be7STakashi Iwai 
1053d6468be7STakashi Iwai 	if (status) {
1054d6468be7STakashi Iwai 		DBG(midi2, "%s complete error %d: %d/%d\n",
1055d6468be7STakashi Iwai 		    usb_ep->name, status, req->actual, req->length);
1056d6468be7STakashi Iwai 		goto error;
1057d6468be7STakashi Iwai 	}
1058d6468be7STakashi Iwai 
1059d6468be7STakashi Iwai 	len = req->actual >> 2;
1060d6468be7STakashi Iwai 	for (; len; len--, buf += 4) {
1061a85ff0dbSTakashi Iwai 		cable = *buf >> 4;
1062a85ff0dbSTakashi Iwai 		ep = midi2->out_cable_mapping[cable].ep;
1063a85ff0dbSTakashi Iwai 		if (!ep)
1064d6468be7STakashi Iwai 			continue;
1065a85ff0dbSTakashi Iwai 		group = midi2->out_cable_mapping[cable].group;
1066d6468be7STakashi Iwai 		bytes = midi1_packet_bytes[*buf & 0x0f];
1067d6468be7STakashi Iwai 		for (c = 0; c < bytes; c++) {
1068d6468be7STakashi Iwai 			snd_ump_convert_to_ump(cvt, group, ep->info.protocol,
1069d6468be7STakashi Iwai 					       buf[c + 1]);
1070d6468be7STakashi Iwai 			if (cvt->ump_bytes) {
1071d6468be7STakashi Iwai 				snd_ump_receive(ep->ump, cvt->ump,
1072d6468be7STakashi Iwai 						cvt->ump_bytes);
1073d6468be7STakashi Iwai 				cvt->ump_bytes = 0;
1074d6468be7STakashi Iwai 			}
1075d6468be7STakashi Iwai 		}
1076d6468be7STakashi Iwai 	}
1077d6468be7STakashi Iwai 
1078d6468be7STakashi Iwai 	if (midi2->operation_mode != MIDI_OP_MODE_MIDI1)
1079d6468be7STakashi Iwai 		goto error;
1080d6468be7STakashi Iwai 
1081d6468be7STakashi Iwai 	if (queue_request_ep_raw(req))
1082d6468be7STakashi Iwai 		goto error;
1083d6468be7STakashi Iwai 	return;
1084d6468be7STakashi Iwai 
1085d6468be7STakashi Iwai  error:
1086d6468be7STakashi Iwai 	put_empty_request(req);
1087d6468be7STakashi Iwai }
1088d6468be7STakashi Iwai 
1089d6468be7STakashi Iwai /*
1090d6468be7STakashi Iwai  * Common EP handling helpers
1091d6468be7STakashi Iwai  */
1092d6468be7STakashi Iwai 
10938b645922STakashi Iwai /* Start MIDI EP */
f_midi2_start_ep(struct f_midi2_usb_ep * usb_ep,struct usb_function * fn)10948b645922STakashi Iwai static int f_midi2_start_ep(struct f_midi2_usb_ep *usb_ep,
10958b645922STakashi Iwai 			    struct usb_function *fn)
10968b645922STakashi Iwai {
10978b645922STakashi Iwai 	int err;
10988b645922STakashi Iwai 
1099d6468be7STakashi Iwai 	if (!usb_ep->usb_ep)
1100d6468be7STakashi Iwai 		return 0;
1101d6468be7STakashi Iwai 
11028b645922STakashi Iwai 	usb_ep_disable(usb_ep->usb_ep);
11038b645922STakashi Iwai 	err = config_ep_by_speed(usb_ep->card->gadget, fn, usb_ep->usb_ep);
11048b645922STakashi Iwai 	if (err)
11058b645922STakashi Iwai 		return err;
11068b645922STakashi Iwai 	return usb_ep_enable(usb_ep->usb_ep);
11078b645922STakashi Iwai }
11088b645922STakashi Iwai 
11098b645922STakashi Iwai /* Drop pending requests */
f_midi2_drop_reqs(struct f_midi2_usb_ep * usb_ep)11108b645922STakashi Iwai static void f_midi2_drop_reqs(struct f_midi2_usb_ep *usb_ep)
11118b645922STakashi Iwai {
11128b645922STakashi Iwai 	int i;
11138b645922STakashi Iwai 
1114d6468be7STakashi Iwai 	if (!usb_ep->usb_ep || !usb_ep->num_reqs)
11158b645922STakashi Iwai 		return;
11168b645922STakashi Iwai 
11178b645922STakashi Iwai 	for (i = 0; i < usb_ep->num_reqs; i++) {
11188b645922STakashi Iwai 		if (!test_bit(i, &usb_ep->free_reqs) && usb_ep->reqs[i].req) {
11198b645922STakashi Iwai 			usb_ep_dequeue(usb_ep->usb_ep, usb_ep->reqs[i].req);
11208b645922STakashi Iwai 			set_bit(i, &usb_ep->free_reqs);
11218b645922STakashi Iwai 		}
11228b645922STakashi Iwai 	}
11238b645922STakashi Iwai }
11248b645922STakashi Iwai 
11258b645922STakashi Iwai /* Allocate requests for the given EP */
f_midi2_alloc_ep_reqs(struct f_midi2_usb_ep * usb_ep)11268b645922STakashi Iwai static int f_midi2_alloc_ep_reqs(struct f_midi2_usb_ep *usb_ep)
11278b645922STakashi Iwai {
11288b645922STakashi Iwai 	struct f_midi2 *midi2 = usb_ep->card;
11298b645922STakashi Iwai 	int i;
11308b645922STakashi Iwai 
1131d6468be7STakashi Iwai 	if (!usb_ep->usb_ep)
1132d6468be7STakashi Iwai 		return 0;
11338b645922STakashi Iwai 	if (!usb_ep->reqs)
11348b645922STakashi Iwai 		return -EINVAL;
11358b645922STakashi Iwai 
11368b645922STakashi Iwai 	for (i = 0; i < midi2->info.num_reqs; i++) {
11378b645922STakashi Iwai 		if (usb_ep->reqs[i].req)
11388b645922STakashi Iwai 			continue;
11398b645922STakashi Iwai 		usb_ep->reqs[i].req = alloc_ep_req(usb_ep->usb_ep,
11408b645922STakashi Iwai 						   midi2->info.req_buf_size);
11418b645922STakashi Iwai 		if (!usb_ep->reqs[i].req)
11428b645922STakashi Iwai 			return -ENOMEM;
11438b645922STakashi Iwai 		usb_ep->reqs[i].req->context = &usb_ep->reqs[i];
11448b645922STakashi Iwai 	}
11458b645922STakashi Iwai 	return 0;
11468b645922STakashi Iwai }
11478b645922STakashi Iwai 
11488b645922STakashi Iwai /* Free allocated requests */
f_midi2_free_ep_reqs(struct f_midi2_usb_ep * usb_ep)11498b645922STakashi Iwai static void f_midi2_free_ep_reqs(struct f_midi2_usb_ep *usb_ep)
11508b645922STakashi Iwai {
11518b645922STakashi Iwai 	struct f_midi2 *midi2 = usb_ep->card;
11528b645922STakashi Iwai 	int i;
11538b645922STakashi Iwai 
11548b645922STakashi Iwai 	for (i = 0; i < midi2->info.num_reqs; i++) {
11558b645922STakashi Iwai 		if (!usb_ep->reqs[i].req)
11568b645922STakashi Iwai 			continue;
11578b645922STakashi Iwai 		free_ep_req(usb_ep->usb_ep, usb_ep->reqs[i].req);
11588b645922STakashi Iwai 		usb_ep->reqs[i].req = NULL;
11598b645922STakashi Iwai 	}
11608b645922STakashi Iwai }
11618b645922STakashi Iwai 
11628b645922STakashi Iwai /* Initialize EP */
f_midi2_init_ep(struct f_midi2 * midi2,struct f_midi2_ep * ep,struct f_midi2_usb_ep * usb_ep,void * desc,void (* complete)(struct usb_ep * usb_ep,struct usb_request * req))11638b645922STakashi Iwai static int f_midi2_init_ep(struct f_midi2 *midi2, struct f_midi2_ep *ep,
11648b645922STakashi Iwai 			   struct f_midi2_usb_ep *usb_ep,
1165d6468be7STakashi Iwai 			   void *desc,
11668b645922STakashi Iwai 			   void (*complete)(struct usb_ep *usb_ep,
11678b645922STakashi Iwai 					    struct usb_request *req))
11688b645922STakashi Iwai {
11698b645922STakashi Iwai 	int i;
11708b645922STakashi Iwai 
11718b645922STakashi Iwai 	usb_ep->card = midi2;
11728b645922STakashi Iwai 	usb_ep->ep = ep;
11738b645922STakashi Iwai 	usb_ep->usb_ep = usb_ep_autoconfig(midi2->gadget, desc);
11748b645922STakashi Iwai 	if (!usb_ep->usb_ep)
11758b645922STakashi Iwai 		return -ENODEV;
11768b645922STakashi Iwai 	usb_ep->complete = complete;
11778b645922STakashi Iwai 
1178d6468be7STakashi Iwai 	usb_ep->reqs = kcalloc(midi2->info.num_reqs, sizeof(*usb_ep->reqs),
11798b645922STakashi Iwai 			       GFP_KERNEL);
11808b645922STakashi Iwai 	if (!usb_ep->reqs)
11818b645922STakashi Iwai 		return -ENOMEM;
1182d6468be7STakashi Iwai 	for (i = 0; i < midi2->info.num_reqs; i++) {
11838b645922STakashi Iwai 		usb_ep->reqs[i].index = i;
11848b645922STakashi Iwai 		usb_ep->reqs[i].usb_ep = usb_ep;
11858b645922STakashi Iwai 		set_bit(i, &usb_ep->free_reqs);
11868b645922STakashi Iwai 		usb_ep->num_reqs++;
11878b645922STakashi Iwai 	}
11888b645922STakashi Iwai 
11898b645922STakashi Iwai 	return 0;
11908b645922STakashi Iwai }
11918b645922STakashi Iwai 
11928b645922STakashi Iwai /* Free EP */
f_midi2_free_ep(struct f_midi2_usb_ep * usb_ep)11938b645922STakashi Iwai static void f_midi2_free_ep(struct f_midi2_usb_ep *usb_ep)
11948b645922STakashi Iwai {
11958b645922STakashi Iwai 	f_midi2_drop_reqs(usb_ep);
11968b645922STakashi Iwai 
11978b645922STakashi Iwai 	f_midi2_free_ep_reqs(usb_ep);
11988b645922STakashi Iwai 
11998b645922STakashi Iwai 	kfree(usb_ep->reqs);
12008b645922STakashi Iwai 	usb_ep->num_reqs = 0;
12018b645922STakashi Iwai 	usb_ep->free_reqs = 0;
12028b645922STakashi Iwai 	usb_ep->reqs = NULL;
12038b645922STakashi Iwai }
12048b645922STakashi Iwai 
12058b645922STakashi Iwai /* Queue requests for EP-out at start */
f_midi2_queue_out_reqs(struct f_midi2_usb_ep * usb_ep)12068b645922STakashi Iwai static void f_midi2_queue_out_reqs(struct f_midi2_usb_ep *usb_ep)
12078b645922STakashi Iwai {
12088b645922STakashi Iwai 	int i, err;
12098b645922STakashi Iwai 
1210d6468be7STakashi Iwai 	if (!usb_ep->usb_ep)
1211d6468be7STakashi Iwai 		return;
1212d6468be7STakashi Iwai 
12138b645922STakashi Iwai 	for (i = 0; i < usb_ep->num_reqs; i++) {
12148b645922STakashi Iwai 		if (!test_bit(i, &usb_ep->free_reqs) || !usb_ep->reqs[i].req)
12158b645922STakashi Iwai 			continue;
12168b645922STakashi Iwai 		usb_ep->reqs[i].req->complete = usb_ep->complete;
12178b645922STakashi Iwai 		err = usb_ep_queue(usb_ep->usb_ep, usb_ep->reqs[i].req,
12188b645922STakashi Iwai 				   GFP_ATOMIC);
12198b645922STakashi Iwai 		if (!err)
12208b645922STakashi Iwai 			clear_bit(i, &usb_ep->free_reqs);
12218b645922STakashi Iwai 	}
12228b645922STakashi Iwai }
12238b645922STakashi Iwai 
12248b645922STakashi Iwai /*
12258b645922STakashi Iwai  * Gadget Function callbacks
12268b645922STakashi Iwai  */
12278b645922STakashi Iwai 
1228d6468be7STakashi Iwai /* stop both IN and OUT EPs */
f_midi2_stop_eps(struct f_midi2_usb_ep * ep_in,struct f_midi2_usb_ep * ep_out)1229d6468be7STakashi Iwai static void f_midi2_stop_eps(struct f_midi2_usb_ep *ep_in,
1230d6468be7STakashi Iwai 			     struct f_midi2_usb_ep *ep_out)
1231d6468be7STakashi Iwai {
1232d6468be7STakashi Iwai 	f_midi2_drop_reqs(ep_in);
1233d6468be7STakashi Iwai 	f_midi2_drop_reqs(ep_out);
1234d6468be7STakashi Iwai 	f_midi2_free_ep_reqs(ep_in);
1235d6468be7STakashi Iwai 	f_midi2_free_ep_reqs(ep_out);
1236d6468be7STakashi Iwai }
1237d6468be7STakashi Iwai 
1238d6468be7STakashi Iwai /* start/queue both IN and OUT EPs */
f_midi2_start_eps(struct f_midi2_usb_ep * ep_in,struct f_midi2_usb_ep * ep_out,struct usb_function * fn)1239d6468be7STakashi Iwai static int f_midi2_start_eps(struct f_midi2_usb_ep *ep_in,
1240d6468be7STakashi Iwai 			     struct f_midi2_usb_ep *ep_out,
1241d6468be7STakashi Iwai 			     struct usb_function *fn)
1242d6468be7STakashi Iwai {
1243d6468be7STakashi Iwai 	int err;
1244d6468be7STakashi Iwai 
1245d6468be7STakashi Iwai 	err = f_midi2_start_ep(ep_in, fn);
1246d6468be7STakashi Iwai 	if (err)
1247d6468be7STakashi Iwai 		return err;
1248d6468be7STakashi Iwai 	err = f_midi2_start_ep(ep_out, fn);
1249d6468be7STakashi Iwai 	if (err)
1250d6468be7STakashi Iwai 		return err;
1251d6468be7STakashi Iwai 
1252d6468be7STakashi Iwai 	err = f_midi2_alloc_ep_reqs(ep_in);
1253d6468be7STakashi Iwai 	if (err)
1254d6468be7STakashi Iwai 		return err;
1255d6468be7STakashi Iwai 	err = f_midi2_alloc_ep_reqs(ep_out);
1256d6468be7STakashi Iwai 	if (err)
1257d6468be7STakashi Iwai 		return err;
1258d6468be7STakashi Iwai 
1259d6468be7STakashi Iwai 	f_midi2_queue_out_reqs(ep_out);
1260d6468be7STakashi Iwai 	return 0;
1261d6468be7STakashi Iwai }
1262d6468be7STakashi Iwai 
12638b645922STakashi Iwai /* gadget function set_alt callback */
f_midi2_set_alt(struct usb_function * fn,unsigned int intf,unsigned int alt)12648b645922STakashi Iwai static int f_midi2_set_alt(struct usb_function *fn, unsigned int intf,
12658b645922STakashi Iwai 			   unsigned int alt)
12668b645922STakashi Iwai {
12678b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(fn);
12688b645922STakashi Iwai 	struct f_midi2_ep *ep;
12698b645922STakashi Iwai 	int i, op_mode, err;
12708b645922STakashi Iwai 
12718b645922STakashi Iwai 	if (intf != midi2->midi_if || alt > 1)
12728b645922STakashi Iwai 		return 0;
12738b645922STakashi Iwai 
12748b645922STakashi Iwai 	if (alt == 0)
12758b645922STakashi Iwai 		op_mode = MIDI_OP_MODE_MIDI1;
12768b645922STakashi Iwai 	else if (alt == 1)
12778b645922STakashi Iwai 		op_mode = MIDI_OP_MODE_MIDI2;
12788b645922STakashi Iwai 	else
12798b645922STakashi Iwai 		op_mode = MIDI_OP_MODE_UNSET;
12808b645922STakashi Iwai 
12818b645922STakashi Iwai 	if (midi2->operation_mode == op_mode)
12828b645922STakashi Iwai 		return 0;
12838b645922STakashi Iwai 
12848b645922STakashi Iwai 	midi2->operation_mode = op_mode;
12858b645922STakashi Iwai 
1286d6468be7STakashi Iwai 	if (op_mode != MIDI_OP_MODE_MIDI1)
1287d6468be7STakashi Iwai 		f_midi2_stop_eps(&midi2->midi1_ep_in, &midi2->midi1_ep_out);
1288d6468be7STakashi Iwai 
12898b645922STakashi Iwai 	if (op_mode != MIDI_OP_MODE_MIDI2) {
12908b645922STakashi Iwai 		for (i = 0; i < midi2->num_eps; i++) {
12918b645922STakashi Iwai 			ep = &midi2->midi2_eps[i];
1292d6468be7STakashi Iwai 			f_midi2_stop_eps(&ep->ep_in, &ep->ep_out);
12938b645922STakashi Iwai 		}
12948b645922STakashi Iwai 	}
12958b645922STakashi Iwai 
1296d6468be7STakashi Iwai 	if (op_mode == MIDI_OP_MODE_MIDI1)
1297d6468be7STakashi Iwai 		return f_midi2_start_eps(&midi2->midi1_ep_in,
1298d6468be7STakashi Iwai 					 &midi2->midi1_ep_out, fn);
1299d6468be7STakashi Iwai 
1300d6468be7STakashi Iwai 	if (op_mode == MIDI_OP_MODE_MIDI2) {
13018b645922STakashi Iwai 		for (i = 0; i < midi2->num_eps; i++) {
13028b645922STakashi Iwai 			ep = &midi2->midi2_eps[i];
13038b645922STakashi Iwai 
1304d6468be7STakashi Iwai 			err = f_midi2_start_eps(&ep->ep_in, &ep->ep_out, fn);
13058b645922STakashi Iwai 			if (err)
13068b645922STakashi Iwai 				return err;
1307d6468be7STakashi Iwai 		}
13088b645922STakashi Iwai 	}
13098b645922STakashi Iwai 
13108b645922STakashi Iwai 	return 0;
13118b645922STakashi Iwai }
13128b645922STakashi Iwai 
13138b645922STakashi Iwai /* gadget function get_alt callback */
f_midi2_get_alt(struct usb_function * fn,unsigned int intf)13148b645922STakashi Iwai static int f_midi2_get_alt(struct usb_function *fn, unsigned int intf)
13158b645922STakashi Iwai {
13168b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(fn);
13178b645922STakashi Iwai 
13188b645922STakashi Iwai 	if (intf == midi2->midi_if &&
13198b645922STakashi Iwai 	    midi2->operation_mode == MIDI_OP_MODE_MIDI2)
13208b645922STakashi Iwai 		return 1;
13218b645922STakashi Iwai 	return 0;
13228b645922STakashi Iwai }
13238b645922STakashi Iwai 
13248b645922STakashi Iwai /* convert UMP direction to USB MIDI 2.0 direction */
ump_to_usb_dir(unsigned int ump_dir)13258b645922STakashi Iwai static unsigned int ump_to_usb_dir(unsigned int ump_dir)
13268b645922STakashi Iwai {
13278b645922STakashi Iwai 	switch (ump_dir) {
13288b645922STakashi Iwai 	case SNDRV_UMP_DIR_INPUT:
13298b645922STakashi Iwai 		return USB_MS_GR_TRM_BLOCK_TYPE_INPUT_ONLY;
13308b645922STakashi Iwai 	case SNDRV_UMP_DIR_OUTPUT:
13318b645922STakashi Iwai 		return USB_MS_GR_TRM_BLOCK_TYPE_OUTPUT_ONLY;
13328b645922STakashi Iwai 	default:
13338b645922STakashi Iwai 		return USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL;
13348b645922STakashi Iwai 	}
13358b645922STakashi Iwai }
13368b645922STakashi Iwai 
13378b645922STakashi Iwai /* assign GTB descriptors (for the given request) */
assign_block_descriptors(struct f_midi2 * midi2,struct usb_request * req,int max_len)13388b645922STakashi Iwai static void assign_block_descriptors(struct f_midi2 *midi2,
13398b645922STakashi Iwai 				     struct usb_request *req,
13408b645922STakashi Iwai 				     int max_len)
13418b645922STakashi Iwai {
13428b645922STakashi Iwai 	struct usb_ms20_gr_trm_block_header_descriptor header;
13438b645922STakashi Iwai 	struct usb_ms20_gr_trm_block_descriptor *desc;
13448b645922STakashi Iwai 	struct f_midi2_block_info *b;
13458b645922STakashi Iwai 	struct f_midi2_ep *ep;
13468b645922STakashi Iwai 	int i, blk, len;
13478b645922STakashi Iwai 	char *data;
13488b645922STakashi Iwai 
13498b645922STakashi Iwai 	len = sizeof(gtb_header_desc) + sizeof(gtb_desc) * midi2->total_blocks;
13508b645922STakashi Iwai 	if (WARN_ON(len > midi2->info.req_buf_size))
13518b645922STakashi Iwai 		return;
13528b645922STakashi Iwai 
13538b645922STakashi Iwai 	header = gtb_header_desc;
13548b645922STakashi Iwai 	header.wTotalLength = cpu_to_le16(len);
13558b645922STakashi Iwai 	if (max_len < len) {
13568b645922STakashi Iwai 		len = min_t(int, len, sizeof(header));
13578b645922STakashi Iwai 		memcpy(req->buf, &header, len);
13588b645922STakashi Iwai 		req->length = len;
13598b645922STakashi Iwai 		req->zero = len < max_len;
13608b645922STakashi Iwai 		return;
13618b645922STakashi Iwai 	}
13628b645922STakashi Iwai 
13638b645922STakashi Iwai 	memcpy(req->buf, &header, sizeof(header));
13648b645922STakashi Iwai 	data = req->buf + sizeof(header);
13658b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
13668b645922STakashi Iwai 		ep = &midi2->midi2_eps[i];
13678b645922STakashi Iwai 		for (blk = 0; blk < ep->num_blks; blk++) {
13688b645922STakashi Iwai 			b = &ep->blks[blk].info;
13698b645922STakashi Iwai 			desc = (struct usb_ms20_gr_trm_block_descriptor *)data;
13708b645922STakashi Iwai 
13718b645922STakashi Iwai 			*desc = gtb_desc;
13728b645922STakashi Iwai 			desc->bGrpTrmBlkID = ep->blks[blk].gtb_id;
13738b645922STakashi Iwai 			desc->bGrpTrmBlkType = ump_to_usb_dir(b->direction);
13748b645922STakashi Iwai 			desc->nGroupTrm = b->first_group;
13758b645922STakashi Iwai 			desc->nNumGroupTrm = b->num_groups;
13768b645922STakashi Iwai 			desc->iBlockItem = ep->blks[blk].string_id;
13778b645922STakashi Iwai 
13788b645922STakashi Iwai 			if (ep->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
13798b645922STakashi Iwai 				desc->bMIDIProtocol = USB_MS_MIDI_PROTO_2_0;
13808b645922STakashi Iwai 			else
13818b645922STakashi Iwai 				desc->bMIDIProtocol = USB_MS_MIDI_PROTO_1_0_128;
13828b645922STakashi Iwai 
13838b645922STakashi Iwai 			if (b->is_midi1 == 2) {
13848b645922STakashi Iwai 				desc->wMaxInputBandwidth = cpu_to_le16(1);
13858b645922STakashi Iwai 				desc->wMaxOutputBandwidth = cpu_to_le16(1);
13868b645922STakashi Iwai 			}
13878b645922STakashi Iwai 
13888b645922STakashi Iwai 			data += sizeof(*desc);
13898b645922STakashi Iwai 		}
13908b645922STakashi Iwai 	}
13918b645922STakashi Iwai 
13928b645922STakashi Iwai 	req->length = len;
13938b645922STakashi Iwai 	req->zero = len < max_len;
13948b645922STakashi Iwai }
13958b645922STakashi Iwai 
13968b645922STakashi Iwai /* gadget function setup callback: handle GTB requests */
f_midi2_setup(struct usb_function * fn,const struct usb_ctrlrequest * ctrl)13978b645922STakashi Iwai static int f_midi2_setup(struct usb_function *fn,
13988b645922STakashi Iwai 			 const struct usb_ctrlrequest *ctrl)
13998b645922STakashi Iwai {
14008b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(fn);
14018b645922STakashi Iwai 	struct usb_composite_dev *cdev = fn->config->cdev;
14028b645922STakashi Iwai 	struct usb_request *req = cdev->req;
14038b645922STakashi Iwai 	u16 value, length;
14048b645922STakashi Iwai 
14058b645922STakashi Iwai 	if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
14068b645922STakashi Iwai 	    ctrl->bRequest != USB_REQ_GET_DESCRIPTOR)
14078b645922STakashi Iwai 		return -EOPNOTSUPP;
14088b645922STakashi Iwai 
14098b645922STakashi Iwai 	value = le16_to_cpu(ctrl->wValue);
14108b645922STakashi Iwai 	length = le16_to_cpu(ctrl->wLength);
14118b645922STakashi Iwai 
14128b645922STakashi Iwai 	if ((value >> 8) != USB_DT_CS_GR_TRM_BLOCK)
14138b645922STakashi Iwai 		return -EOPNOTSUPP;
14148b645922STakashi Iwai 
14158b645922STakashi Iwai 	/* handle only altset 1 */
14168b645922STakashi Iwai 	if ((value & 0xff) != 1)
14178b645922STakashi Iwai 		return -EOPNOTSUPP;
14188b645922STakashi Iwai 
14198b645922STakashi Iwai 	assign_block_descriptors(midi2, req, length);
14208b645922STakashi Iwai 	return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
14218b645922STakashi Iwai }
14228b645922STakashi Iwai 
14238b645922STakashi Iwai /* gadget function disable callback */
f_midi2_disable(struct usb_function * fn)14248b645922STakashi Iwai static void f_midi2_disable(struct usb_function *fn)
14258b645922STakashi Iwai {
14268b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(fn);
14278b645922STakashi Iwai 
14288b645922STakashi Iwai 	midi2->operation_mode = MIDI_OP_MODE_UNSET;
14298b645922STakashi Iwai }
14308b645922STakashi Iwai 
14318b645922STakashi Iwai /*
14328b645922STakashi Iwai  * ALSA UMP ops: most of them are NOPs, only trigger for write is needed
14338b645922STakashi Iwai  */
f_midi2_ump_open(struct snd_ump_endpoint * ump,int dir)14348b645922STakashi Iwai static int f_midi2_ump_open(struct snd_ump_endpoint *ump, int dir)
14358b645922STakashi Iwai {
14368b645922STakashi Iwai 	return 0;
14378b645922STakashi Iwai }
14388b645922STakashi Iwai 
f_midi2_ump_close(struct snd_ump_endpoint * ump,int dir)14398b645922STakashi Iwai static void f_midi2_ump_close(struct snd_ump_endpoint *ump, int dir)
14408b645922STakashi Iwai {
14418b645922STakashi Iwai }
14428b645922STakashi Iwai 
f_midi2_ump_trigger(struct snd_ump_endpoint * ump,int dir,int up)14438b645922STakashi Iwai static void f_midi2_ump_trigger(struct snd_ump_endpoint *ump, int dir, int up)
14448b645922STakashi Iwai {
14458b645922STakashi Iwai 	struct f_midi2_ep *ep = ump->private_data;
1446d6468be7STakashi Iwai 	struct f_midi2 *midi2 = ep->card;
14478b645922STakashi Iwai 
1448d6468be7STakashi Iwai 	if (up && dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
1449d6468be7STakashi Iwai 		switch (midi2->operation_mode) {
1450d6468be7STakashi Iwai 		case MIDI_OP_MODE_MIDI1:
1451d6468be7STakashi Iwai 			process_midi1_transmit(midi2);
1452d6468be7STakashi Iwai 			break;
1453d6468be7STakashi Iwai 		case MIDI_OP_MODE_MIDI2:
14548b645922STakashi Iwai 			process_ump_transmit(ep);
1455d6468be7STakashi Iwai 			break;
1456d6468be7STakashi Iwai 		}
1457d6468be7STakashi Iwai 	}
14588b645922STakashi Iwai }
14598b645922STakashi Iwai 
f_midi2_ump_drain(struct snd_ump_endpoint * ump,int dir)14608b645922STakashi Iwai static void f_midi2_ump_drain(struct snd_ump_endpoint *ump, int dir)
14618b645922STakashi Iwai {
14628b645922STakashi Iwai }
14638b645922STakashi Iwai 
14648b645922STakashi Iwai static const struct snd_ump_ops f_midi2_ump_ops = {
14658b645922STakashi Iwai 	.open = f_midi2_ump_open,
14668b645922STakashi Iwai 	.close = f_midi2_ump_close,
14678b645922STakashi Iwai 	.trigger = f_midi2_ump_trigger,
14688b645922STakashi Iwai 	.drain = f_midi2_ump_drain,
14698b645922STakashi Iwai };
14708b645922STakashi Iwai 
14718b645922STakashi Iwai /*
14721b437d2fSTakashi Iwai  * "Operation Mode" control element
14731b437d2fSTakashi Iwai  */
f_midi2_operation_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)14741b437d2fSTakashi Iwai static int f_midi2_operation_mode_info(struct snd_kcontrol *kcontrol,
14751b437d2fSTakashi Iwai 				       struct snd_ctl_elem_info *uinfo)
14761b437d2fSTakashi Iwai {
14771b437d2fSTakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14781b437d2fSTakashi Iwai 	uinfo->count = 1;
14791b437d2fSTakashi Iwai 	uinfo->value.integer.min = MIDI_OP_MODE_UNSET;
14801b437d2fSTakashi Iwai 	uinfo->value.integer.max = MIDI_OP_MODE_MIDI2;
14811b437d2fSTakashi Iwai 	return 0;
14821b437d2fSTakashi Iwai }
14831b437d2fSTakashi Iwai 
f_midi2_operation_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)14841b437d2fSTakashi Iwai static int f_midi2_operation_mode_get(struct snd_kcontrol *kcontrol,
14851b437d2fSTakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
14861b437d2fSTakashi Iwai {
14871b437d2fSTakashi Iwai 	struct f_midi2 *midi2 = snd_kcontrol_chip(kcontrol);
14881b437d2fSTakashi Iwai 
14891b437d2fSTakashi Iwai 	ucontrol->value.integer.value[0] = midi2->operation_mode;
14901b437d2fSTakashi Iwai 	return 0;
14911b437d2fSTakashi Iwai }
14921b437d2fSTakashi Iwai 
14931b437d2fSTakashi Iwai static const struct snd_kcontrol_new operation_mode_ctl = {
14941b437d2fSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
14951b437d2fSTakashi Iwai 	.name = "Operation Mode",
14961b437d2fSTakashi Iwai 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
14971b437d2fSTakashi Iwai 	.info = f_midi2_operation_mode_info,
14981b437d2fSTakashi Iwai 	.get = f_midi2_operation_mode_get,
14991b437d2fSTakashi Iwai };
15001b437d2fSTakashi Iwai 
15011b437d2fSTakashi Iwai /*
15028b645922STakashi Iwai  * ALSA UMP instance creation / deletion
15038b645922STakashi Iwai  */
f_midi2_free_card(struct f_midi2 * midi2)15048b645922STakashi Iwai static void f_midi2_free_card(struct f_midi2 *midi2)
15058b645922STakashi Iwai {
15068b645922STakashi Iwai 	if (midi2->card) {
15078b645922STakashi Iwai 		snd_card_free_when_closed(midi2->card);
15088b645922STakashi Iwai 		midi2->card = NULL;
15098b645922STakashi Iwai 	}
15108b645922STakashi Iwai }
15118b645922STakashi Iwai 
15128b645922STakashi Iwai /* use a reverse direction for the gadget host */
reverse_dir(int dir)15138b645922STakashi Iwai static int reverse_dir(int dir)
15148b645922STakashi Iwai {
15158b645922STakashi Iwai 	if (!dir || dir == SNDRV_UMP_DIR_BIDIRECTION)
15168b645922STakashi Iwai 		return dir;
15178b645922STakashi Iwai 	return (dir == SNDRV_UMP_DIR_OUTPUT) ?
15188b645922STakashi Iwai 		SNDRV_UMP_DIR_INPUT : SNDRV_UMP_DIR_OUTPUT;
15198b645922STakashi Iwai }
15208b645922STakashi Iwai 
f_midi2_create_card(struct f_midi2 * midi2)15218b645922STakashi Iwai static int f_midi2_create_card(struct f_midi2 *midi2)
15228b645922STakashi Iwai {
15238b645922STakashi Iwai 	struct snd_card *card;
15248b645922STakashi Iwai 	struct snd_ump_endpoint *ump;
15258b645922STakashi Iwai 	struct f_midi2_ep *ep;
15268b645922STakashi Iwai 	int i, id, blk, err;
15278b645922STakashi Iwai 	__be32 sw;
15288b645922STakashi Iwai 
15298b645922STakashi Iwai 	err = snd_card_new(&midi2->gadget->dev, -1, NULL, THIS_MODULE, 0,
15308b645922STakashi Iwai 			   &card);
15318b645922STakashi Iwai 	if (err < 0)
15328b645922STakashi Iwai 		return err;
15338b645922STakashi Iwai 	midi2->card = card;
15348b645922STakashi Iwai 
15358b645922STakashi Iwai 	strcpy(card->driver, "f_midi2");
15368b645922STakashi Iwai 	strcpy(card->shortname, "MIDI 2.0 Gadget");
15378b645922STakashi Iwai 	strcpy(card->longname, "MIDI 2.0 Gadget");
15388b645922STakashi Iwai 
15398b645922STakashi Iwai 	id = 0;
15408b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
15418b645922STakashi Iwai 		ep = &midi2->midi2_eps[i];
15428b645922STakashi Iwai 		err = snd_ump_endpoint_new(card, "MIDI 2.0 Gadget", id,
15438b645922STakashi Iwai 					   1, 1, &ump);
15448b645922STakashi Iwai 		if (err < 0)
15458b645922STakashi Iwai 			goto error;
15468b645922STakashi Iwai 		id++;
15478b645922STakashi Iwai 
15488b645922STakashi Iwai 		ep->ump = ump;
15498b645922STakashi Iwai 		ump->no_process_stream = true;
15508b645922STakashi Iwai 		ump->private_data = ep;
15518b645922STakashi Iwai 		ump->ops = &f_midi2_ump_ops;
15528b645922STakashi Iwai 		if (midi2->info.static_block)
15538b645922STakashi Iwai 			ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS;
15548b645922STakashi Iwai 		ump->info.protocol_caps = (ep->info.protocol_caps & 3) << 8;
15558b645922STakashi Iwai 		ump->info.protocol = (ep->info.protocol & 3) << 8;
15568b645922STakashi Iwai 		ump->info.version = 0x0101;
15578b645922STakashi Iwai 		ump->info.family_id = ep->info.family;
15588b645922STakashi Iwai 		ump->info.model_id = ep->info.model;
15598b645922STakashi Iwai 		ump->info.manufacturer_id = ep->info.manufacturer & 0xffffff;
15608b645922STakashi Iwai 		sw = cpu_to_be32(ep->info.sw_revision);
15618b645922STakashi Iwai 		memcpy(ump->info.sw_revision, &sw, 4);
15628b645922STakashi Iwai 
15638b645922STakashi Iwai 		strscpy(ump->info.name, ump_ep_name(ep),
15648b645922STakashi Iwai 			sizeof(ump->info.name));
15658b645922STakashi Iwai 		strscpy(ump->info.product_id, ump_product_id(ep),
15668b645922STakashi Iwai 			sizeof(ump->info.product_id));
15678b645922STakashi Iwai 		strscpy(ump->core.name, ump->info.name, sizeof(ump->core.name));
15688b645922STakashi Iwai 
15698b645922STakashi Iwai 		for (blk = 0; blk < ep->num_blks; blk++) {
15708b645922STakashi Iwai 			const struct f_midi2_block_info *b = &ep->blks[blk].info;
15718b645922STakashi Iwai 			struct snd_ump_block *fb;
15728b645922STakashi Iwai 
15738b645922STakashi Iwai 			err = snd_ump_block_new(ump, blk,
15748b645922STakashi Iwai 						reverse_dir(b->direction),
15758b645922STakashi Iwai 						b->first_group, b->num_groups,
15768b645922STakashi Iwai 						&ep->blks[blk].fb);
15778b645922STakashi Iwai 			if (err < 0)
15788b645922STakashi Iwai 				goto error;
15798b645922STakashi Iwai 			fb = ep->blks[blk].fb;
15808b645922STakashi Iwai 			fb->info.active = !!b->active;
15818b645922STakashi Iwai 			fb->info.midi_ci_version = b->midi_ci_version;
15828b645922STakashi Iwai 			fb->info.ui_hint = reverse_dir(b->ui_hint);
15838b645922STakashi Iwai 			fb->info.sysex8_streams = b->sysex8_streams;
15848b645922STakashi Iwai 			fb->info.flags |= b->is_midi1;
15858b645922STakashi Iwai 			strscpy(fb->info.name, ump_fb_name(b),
15868b645922STakashi Iwai 				sizeof(fb->info.name));
15878b645922STakashi Iwai 		}
15888b645922STakashi Iwai 	}
15898b645922STakashi Iwai 
15908b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
15918b645922STakashi Iwai 		err = snd_ump_attach_legacy_rawmidi(midi2->midi2_eps[i].ump,
15928b645922STakashi Iwai 						    "Legacy MIDI", id);
15938b645922STakashi Iwai 		if (err < 0)
15948b645922STakashi Iwai 			goto error;
15958b645922STakashi Iwai 		id++;
15968b645922STakashi Iwai 	}
15978b645922STakashi Iwai 
15981b437d2fSTakashi Iwai 	err = snd_ctl_add(card, snd_ctl_new1(&operation_mode_ctl, midi2));
15991b437d2fSTakashi Iwai 	if (err < 0)
16001b437d2fSTakashi Iwai 		goto error;
16011b437d2fSTakashi Iwai 
16028b645922STakashi Iwai 	err = snd_card_register(card);
16038b645922STakashi Iwai 	if (err < 0)
16048b645922STakashi Iwai 		goto error;
16058b645922STakashi Iwai 
16068b645922STakashi Iwai 	return 0;
16078b645922STakashi Iwai 
16088b645922STakashi Iwai  error:
16098b645922STakashi Iwai 	f_midi2_free_card(midi2);
16108b645922STakashi Iwai 	return err;
16118b645922STakashi Iwai }
16128b645922STakashi Iwai 
16138b645922STakashi Iwai /*
16148b645922STakashi Iwai  * Creation of USB descriptors
16158b645922STakashi Iwai  */
16168b645922STakashi Iwai struct f_midi2_usb_config {
16178b645922STakashi Iwai 	struct usb_descriptor_header **list;
16188b645922STakashi Iwai 	unsigned int size;
16198b645922STakashi Iwai 	unsigned int alloc;
1620856fa444STakashi Iwai 
1621856fa444STakashi Iwai 	/* MIDI 1.0 jacks */
1622856fa444STakashi Iwai 	unsigned char jack_in, jack_out, jack_id;
1623d6468be7STakashi Iwai 	struct usb_midi_in_jack_descriptor jack_ins[MAX_CABLES];
1624d6468be7STakashi Iwai 	struct usb_midi_out_jack_descriptor_1 jack_outs[MAX_CABLES];
16258b645922STakashi Iwai };
16268b645922STakashi Iwai 
append_config(struct f_midi2_usb_config * config,void * d)16278b645922STakashi Iwai static int append_config(struct f_midi2_usb_config *config, void *d)
16288b645922STakashi Iwai {
16298b645922STakashi Iwai 	unsigned int size;
16308b645922STakashi Iwai 	void *buf;
16318b645922STakashi Iwai 
16328b645922STakashi Iwai 	if (config->size + 2 >= config->alloc) {
16338b645922STakashi Iwai 		size = config->size + 16;
16348b645922STakashi Iwai 		buf = krealloc(config->list, size * sizeof(void *), GFP_KERNEL);
16358b645922STakashi Iwai 		if (!buf)
16368b645922STakashi Iwai 			return -ENOMEM;
16378b645922STakashi Iwai 		config->list = buf;
16388b645922STakashi Iwai 		config->alloc = size;
16398b645922STakashi Iwai 	}
16408b645922STakashi Iwai 
16418b645922STakashi Iwai 	config->list[config->size] = d;
16428b645922STakashi Iwai 	config->size++;
16438b645922STakashi Iwai 	config->list[config->size] = NULL;
16448b645922STakashi Iwai 	return 0;
16458b645922STakashi Iwai }
16468b645922STakashi Iwai 
append_configs(struct f_midi2_usb_config * config,void ** d)16478b645922STakashi Iwai static int append_configs(struct f_midi2_usb_config *config, void **d)
16488b645922STakashi Iwai {
16498b645922STakashi Iwai 	int err;
16508b645922STakashi Iwai 
16518b645922STakashi Iwai 	for (; *d; d++) {
16528b645922STakashi Iwai 		err = append_config(config, *d);
16538b645922STakashi Iwai 		if (err)
16548b645922STakashi Iwai 			return err;
16558b645922STakashi Iwai 	}
16568b645922STakashi Iwai 	return 0;
16578b645922STakashi Iwai }
16588b645922STakashi Iwai 
append_midi1_in_jack(struct f_midi2 * midi2,struct f_midi2_usb_config * config,struct midi1_cable_mapping * map,unsigned int type)1659856fa444STakashi Iwai static int append_midi1_in_jack(struct f_midi2 *midi2,
1660856fa444STakashi Iwai 				struct f_midi2_usb_config *config,
1661a85ff0dbSTakashi Iwai 				struct midi1_cable_mapping *map,
1662856fa444STakashi Iwai 				unsigned int type)
1663856fa444STakashi Iwai {
1664856fa444STakashi Iwai 	struct usb_midi_in_jack_descriptor *jack =
1665856fa444STakashi Iwai 		&config->jack_ins[config->jack_in++];
1666856fa444STakashi Iwai 	int id = ++config->jack_id;
1667856fa444STakashi Iwai 	int err;
1668856fa444STakashi Iwai 
1669856fa444STakashi Iwai 	jack->bLength = 0x06;
1670856fa444STakashi Iwai 	jack->bDescriptorType = USB_DT_CS_INTERFACE;
1671856fa444STakashi Iwai 	jack->bDescriptorSubtype = USB_MS_MIDI_IN_JACK;
1672856fa444STakashi Iwai 	jack->bJackType = type;
1673856fa444STakashi Iwai 	jack->bJackID = id;
1674a85ff0dbSTakashi Iwai 	/* use the corresponding block name as jack name */
1675a85ff0dbSTakashi Iwai 	if (map->ep)
1676a85ff0dbSTakashi Iwai 		jack->iJack = map->ep->blks[map->block].string_id;
1677856fa444STakashi Iwai 
1678856fa444STakashi Iwai 	err = append_config(config, jack);
1679856fa444STakashi Iwai 	if (err < 0)
1680856fa444STakashi Iwai 		return err;
1681856fa444STakashi Iwai 	return id;
1682856fa444STakashi Iwai }
1683856fa444STakashi Iwai 
append_midi1_out_jack(struct f_midi2 * midi2,struct f_midi2_usb_config * config,struct midi1_cable_mapping * map,unsigned int type,unsigned int source)1684856fa444STakashi Iwai static int append_midi1_out_jack(struct f_midi2 *midi2,
1685856fa444STakashi Iwai 				 struct f_midi2_usb_config *config,
1686a85ff0dbSTakashi Iwai 				 struct midi1_cable_mapping *map,
1687856fa444STakashi Iwai 				 unsigned int type, unsigned int source)
1688856fa444STakashi Iwai {
1689856fa444STakashi Iwai 	struct usb_midi_out_jack_descriptor_1 *jack =
1690856fa444STakashi Iwai 		&config->jack_outs[config->jack_out++];
1691856fa444STakashi Iwai 	int id = ++config->jack_id;
1692856fa444STakashi Iwai 	int err;
1693856fa444STakashi Iwai 
1694856fa444STakashi Iwai 	jack->bLength = 0x09;
1695856fa444STakashi Iwai 	jack->bDescriptorType = USB_DT_CS_INTERFACE;
1696856fa444STakashi Iwai 	jack->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK;
1697856fa444STakashi Iwai 	jack->bJackType = type;
1698856fa444STakashi Iwai 	jack->bJackID = id;
1699856fa444STakashi Iwai 	jack->bNrInputPins = 1;
1700856fa444STakashi Iwai 	jack->pins[0].baSourceID = source;
1701856fa444STakashi Iwai 	jack->pins[0].baSourcePin = 0x01;
1702a85ff0dbSTakashi Iwai 	/* use the corresponding block name as jack name */
1703a85ff0dbSTakashi Iwai 	if (map->ep)
1704a85ff0dbSTakashi Iwai 		jack->iJack = map->ep->blks[map->block].string_id;
1705856fa444STakashi Iwai 
1706856fa444STakashi Iwai 	err = append_config(config, jack);
1707856fa444STakashi Iwai 	if (err < 0)
1708856fa444STakashi Iwai 		return err;
1709856fa444STakashi Iwai 	return id;
1710856fa444STakashi Iwai }
1711856fa444STakashi Iwai 
f_midi2_create_usb_configs(struct f_midi2 * midi2,struct f_midi2_usb_config * config,int speed)17128b645922STakashi Iwai static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
17138b645922STakashi Iwai 				      struct f_midi2_usb_config *config,
17148b645922STakashi Iwai 				      int speed)
17158b645922STakashi Iwai {
1716856fa444STakashi Iwai 	void **midi1_in_eps, **midi1_out_eps;
1717856fa444STakashi Iwai 	int i, jack, total;
1718856fa444STakashi Iwai 	int err;
17198b645922STakashi Iwai 
17208b645922STakashi Iwai 	switch (speed) {
17218b645922STakashi Iwai 	default:
17228b645922STakashi Iwai 	case USB_SPEED_HIGH:
17238b645922STakashi Iwai 		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(512);
17248b645922STakashi Iwai 		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(512);
17258b645922STakashi Iwai 		for (i = 0; i < midi2->num_eps; i++)
17268b645922STakashi Iwai 			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
17278b645922STakashi Iwai 				cpu_to_le16(512);
17288b645922STakashi Iwai 		fallthrough;
17298b645922STakashi Iwai 	case USB_SPEED_FULL:
1730856fa444STakashi Iwai 		midi1_in_eps = midi2_midi1_ep_in_descs;
1731856fa444STakashi Iwai 		midi1_out_eps = midi2_midi1_ep_out_descs;
17328b645922STakashi Iwai 		break;
17338b645922STakashi Iwai 	case USB_SPEED_SUPER:
17348b645922STakashi Iwai 		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(1024);
17358b645922STakashi Iwai 		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(1024);
17368b645922STakashi Iwai 		for (i = 0; i < midi2->num_eps; i++)
17378b645922STakashi Iwai 			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
17388b645922STakashi Iwai 				cpu_to_le16(1024);
1739856fa444STakashi Iwai 		midi1_in_eps = midi2_midi1_ep_in_ss_descs;
1740856fa444STakashi Iwai 		midi1_out_eps = midi2_midi1_ep_out_ss_descs;
17418b645922STakashi Iwai 		break;
17428b645922STakashi Iwai 	}
17438b645922STakashi Iwai 
17448b645922STakashi Iwai 	err = append_configs(config, midi2_audio_descs);
17458b645922STakashi Iwai 	if (err < 0)
17468b645922STakashi Iwai 		return err;
1747856fa444STakashi Iwai 
1748a85ff0dbSTakashi Iwai 	if (midi2->num_midi1_in && midi2->num_midi1_out)
1749856fa444STakashi Iwai 		midi2_midi1_if_desc.bNumEndpoints = 2;
1750a85ff0dbSTakashi Iwai 	else
1751a85ff0dbSTakashi Iwai 		midi2_midi1_if_desc.bNumEndpoints = 1;
1752856fa444STakashi Iwai 
17538b645922STakashi Iwai 	err = append_configs(config, midi2_midi1_descs);
17548b645922STakashi Iwai 	if (err < 0)
17558b645922STakashi Iwai 		return err;
1756856fa444STakashi Iwai 
1757856fa444STakashi Iwai 	total = USB_DT_MS_HEADER_SIZE;
1758a85ff0dbSTakashi Iwai 	if (midi2->num_midi1_out) {
1759856fa444STakashi Iwai 		midi2_midi1_ep_out_class_desc.bLength =
1760a85ff0dbSTakashi Iwai 			USB_DT_MS_ENDPOINT_SIZE(midi2->num_midi1_out);
1761856fa444STakashi Iwai 		total += midi2_midi1_ep_out_class_desc.bLength;
1762856fa444STakashi Iwai 		midi2_midi1_ep_out_class_desc.bNumEmbMIDIJack =
1763a85ff0dbSTakashi Iwai 			midi2->num_midi1_out;
1764a85ff0dbSTakashi Iwai 		total += midi2->num_midi1_out *
1765856fa444STakashi Iwai 			(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
1766a85ff0dbSTakashi Iwai 		for (i = 0; i < midi2->num_midi1_out; i++) {
1767856fa444STakashi Iwai 			jack = append_midi1_in_jack(midi2, config,
1768a85ff0dbSTakashi Iwai 						    &midi2->in_cable_mapping[i],
1769856fa444STakashi Iwai 						    USB_MS_EMBEDDED);
1770856fa444STakashi Iwai 			if (jack < 0)
1771856fa444STakashi Iwai 				return jack;
1772856fa444STakashi Iwai 			midi2_midi1_ep_out_class_desc.baAssocJackID[i] = jack;
1773856fa444STakashi Iwai 			jack = append_midi1_out_jack(midi2, config,
1774a85ff0dbSTakashi Iwai 						     &midi2->in_cable_mapping[i],
1775856fa444STakashi Iwai 						     USB_MS_EXTERNAL, jack);
1776856fa444STakashi Iwai 			if (jack < 0)
1777856fa444STakashi Iwai 				return jack;
1778856fa444STakashi Iwai 		}
1779856fa444STakashi Iwai 	}
1780856fa444STakashi Iwai 
1781a85ff0dbSTakashi Iwai 	if (midi2->num_midi1_in) {
1782856fa444STakashi Iwai 		midi2_midi1_ep_in_class_desc.bLength =
1783a85ff0dbSTakashi Iwai 			USB_DT_MS_ENDPOINT_SIZE(midi2->num_midi1_in);
1784856fa444STakashi Iwai 		total += midi2_midi1_ep_in_class_desc.bLength;
1785856fa444STakashi Iwai 		midi2_midi1_ep_in_class_desc.bNumEmbMIDIJack =
1786a85ff0dbSTakashi Iwai 			midi2->num_midi1_in;
1787a85ff0dbSTakashi Iwai 		total += midi2->num_midi1_in *
1788856fa444STakashi Iwai 			(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
1789a85ff0dbSTakashi Iwai 		for (i = 0; i < midi2->num_midi1_in; i++) {
1790856fa444STakashi Iwai 			jack = append_midi1_in_jack(midi2, config,
1791a85ff0dbSTakashi Iwai 						    &midi2->out_cable_mapping[i],
1792856fa444STakashi Iwai 						    USB_MS_EXTERNAL);
1793856fa444STakashi Iwai 			if (jack < 0)
1794856fa444STakashi Iwai 				return jack;
1795856fa444STakashi Iwai 			jack = append_midi1_out_jack(midi2, config,
1796a85ff0dbSTakashi Iwai 						     &midi2->out_cable_mapping[i],
1797856fa444STakashi Iwai 						     USB_MS_EMBEDDED, jack);
1798856fa444STakashi Iwai 			if (jack < 0)
1799856fa444STakashi Iwai 				return jack;
1800856fa444STakashi Iwai 			midi2_midi1_ep_in_class_desc.baAssocJackID[i] = jack;
1801856fa444STakashi Iwai 		}
1802856fa444STakashi Iwai 	}
1803856fa444STakashi Iwai 
1804856fa444STakashi Iwai 	midi2_midi1_class_desc.wTotalLength = cpu_to_le16(total);
1805856fa444STakashi Iwai 
1806a85ff0dbSTakashi Iwai 	if (midi2->num_midi1_out) {
1807856fa444STakashi Iwai 		err = append_configs(config, midi1_out_eps);
18088b645922STakashi Iwai 		if (err < 0)
18098b645922STakashi Iwai 			return err;
1810856fa444STakashi Iwai 	}
1811a85ff0dbSTakashi Iwai 	if (midi2->num_midi1_in) {
1812856fa444STakashi Iwai 		err = append_configs(config, midi1_in_eps);
1813856fa444STakashi Iwai 		if (err < 0)
1814856fa444STakashi Iwai 			return err;
1815856fa444STakashi Iwai 	}
1816856fa444STakashi Iwai 
18178b645922STakashi Iwai 	err = append_configs(config, midi2_midi2_descs);
18188b645922STakashi Iwai 	if (err < 0)
18198b645922STakashi Iwai 		return err;
18208b645922STakashi Iwai 
18218b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
18228b645922STakashi Iwai 		err = append_config(config, &midi2_midi2_ep_out_desc[i]);
18238b645922STakashi Iwai 		if (err < 0)
18248b645922STakashi Iwai 			return err;
18258b645922STakashi Iwai 		if (speed == USB_SPEED_SUPER || speed == USB_SPEED_SUPER_PLUS) {
18268b645922STakashi Iwai 			err = append_config(config, &midi2_midi2_ep_out_ss_comp_desc);
18278b645922STakashi Iwai 			if (err < 0)
18288b645922STakashi Iwai 				return err;
18298b645922STakashi Iwai 		}
18308b645922STakashi Iwai 		err = append_config(config, &midi2_midi2_ep_out_class_desc[i]);
18318b645922STakashi Iwai 		if (err < 0)
18328b645922STakashi Iwai 			return err;
18338b645922STakashi Iwai 		err = append_config(config, &midi2_midi2_ep_in_desc[i]);
18348b645922STakashi Iwai 		if (err < 0)
18358b645922STakashi Iwai 			return err;
18368b645922STakashi Iwai 		if (speed == USB_SPEED_SUPER || speed == USB_SPEED_SUPER_PLUS) {
18378b645922STakashi Iwai 			err = append_config(config, &midi2_midi2_ep_in_ss_comp_desc);
18388b645922STakashi Iwai 			if (err < 0)
18398b645922STakashi Iwai 				return err;
18408b645922STakashi Iwai 		}
18418b645922STakashi Iwai 		err = append_config(config, &midi2_midi2_ep_in_class_desc[i]);
18428b645922STakashi Iwai 		if (err < 0)
18438b645922STakashi Iwai 			return err;
18448b645922STakashi Iwai 	}
18458b645922STakashi Iwai 
18468b645922STakashi Iwai 	return 0;
18478b645922STakashi Iwai }
18488b645922STakashi Iwai 
f_midi2_free_usb_configs(struct f_midi2_usb_config * config)18498b645922STakashi Iwai static void f_midi2_free_usb_configs(struct f_midi2_usb_config *config)
18508b645922STakashi Iwai {
18518b645922STakashi Iwai 	kfree(config->list);
18528b645922STakashi Iwai 	memset(config, 0, sizeof(*config));
18538b645922STakashi Iwai }
18548b645922STakashi Iwai 
18558b645922STakashi Iwai /* as we use the static descriptors for simplicity, serialize bind call */
18568b645922STakashi Iwai static DEFINE_MUTEX(f_midi2_desc_mutex);
18578b645922STakashi Iwai 
18588b645922STakashi Iwai /* fill MIDI2 EP class-specific descriptor */
fill_midi2_class_desc(struct f_midi2_ep * ep,struct usb_ms20_endpoint_descriptor_32 * cdesc)18598b645922STakashi Iwai static void fill_midi2_class_desc(struct f_midi2_ep *ep,
18608b645922STakashi Iwai 				  struct usb_ms20_endpoint_descriptor_32 *cdesc)
18618b645922STakashi Iwai {
18628b645922STakashi Iwai 	int blk;
18638b645922STakashi Iwai 
18648b645922STakashi Iwai 	cdesc->bLength = USB_DT_MS20_ENDPOINT_SIZE(ep->num_blks);
18658b645922STakashi Iwai 	cdesc->bDescriptorType = USB_DT_CS_ENDPOINT;
18668b645922STakashi Iwai 	cdesc->bDescriptorSubtype = USB_MS_GENERAL_2_0;
18678b645922STakashi Iwai 	cdesc->bNumGrpTrmBlock = ep->num_blks;
18688b645922STakashi Iwai 	for (blk = 0; blk < ep->num_blks; blk++)
18698b645922STakashi Iwai 		cdesc->baAssoGrpTrmBlkID[blk] = ep->blks[blk].gtb_id;
18708b645922STakashi Iwai }
18718b645922STakashi Iwai 
18728b645922STakashi Iwai /* initialize MIDI2 EP-in */
f_midi2_init_midi2_ep_in(struct f_midi2 * midi2,int index)18738b645922STakashi Iwai static int f_midi2_init_midi2_ep_in(struct f_midi2 *midi2, int index)
18748b645922STakashi Iwai {
18758b645922STakashi Iwai 	struct f_midi2_ep *ep = &midi2->midi2_eps[index];
18768b645922STakashi Iwai 	struct usb_endpoint_descriptor *desc = &midi2_midi2_ep_in_desc[index];
18778b645922STakashi Iwai 
18788b645922STakashi Iwai 	desc->bLength = USB_DT_ENDPOINT_SIZE;
18798b645922STakashi Iwai 	desc->bDescriptorType = USB_DT_ENDPOINT;
18808b645922STakashi Iwai 	desc->bEndpointAddress = USB_DIR_IN;
18818b645922STakashi Iwai 	desc->bmAttributes = USB_ENDPOINT_XFER_INT;
18828b645922STakashi Iwai 	desc->wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET_INT);
18838b645922STakashi Iwai 	desc->bInterval = 1;
18848b645922STakashi Iwai 
18858b645922STakashi Iwai 	fill_midi2_class_desc(ep, &midi2_midi2_ep_in_class_desc[index]);
18868b645922STakashi Iwai 
18878b645922STakashi Iwai 	return f_midi2_init_ep(midi2, ep, &ep->ep_in, desc,
1888d6468be7STakashi Iwai 			       f_midi2_ep_in_complete);
18898b645922STakashi Iwai }
18908b645922STakashi Iwai 
18918b645922STakashi Iwai /* initialize MIDI2 EP-out */
f_midi2_init_midi2_ep_out(struct f_midi2 * midi2,int index)18928b645922STakashi Iwai static int f_midi2_init_midi2_ep_out(struct f_midi2 *midi2, int index)
18938b645922STakashi Iwai {
18948b645922STakashi Iwai 	struct f_midi2_ep *ep = &midi2->midi2_eps[index];
18958b645922STakashi Iwai 	struct usb_endpoint_descriptor *desc = &midi2_midi2_ep_out_desc[index];
18968b645922STakashi Iwai 
18978b645922STakashi Iwai 	desc->bLength = USB_DT_ENDPOINT_SIZE;
18988b645922STakashi Iwai 	desc->bDescriptorType = USB_DT_ENDPOINT;
18998b645922STakashi Iwai 	desc->bEndpointAddress = USB_DIR_OUT;
19008b645922STakashi Iwai 	desc->bmAttributes = USB_ENDPOINT_XFER_BULK;
19018b645922STakashi Iwai 
19028b645922STakashi Iwai 	fill_midi2_class_desc(ep, &midi2_midi2_ep_out_class_desc[index]);
19038b645922STakashi Iwai 
19048b645922STakashi Iwai 	return f_midi2_init_ep(midi2, ep, &ep->ep_out, desc,
1905d6468be7STakashi Iwai 			       f_midi2_ep_out_complete);
19068b645922STakashi Iwai }
19078b645922STakashi Iwai 
19088b645922STakashi Iwai /* gadget function bind callback */
f_midi2_bind(struct usb_configuration * c,struct usb_function * f)19098b645922STakashi Iwai static int f_midi2_bind(struct usb_configuration *c, struct usb_function *f)
19108b645922STakashi Iwai {
19118b645922STakashi Iwai 	struct usb_composite_dev *cdev = c->cdev;
19128b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(f);
19138b645922STakashi Iwai 	struct f_midi2_ep *ep;
19148b645922STakashi Iwai 	struct f_midi2_usb_config config = {};
19158b645922STakashi Iwai 	struct usb_gadget_strings string_fn = {
19168b645922STakashi Iwai 		.language = 0x0409,	/* en-us */
19178b645922STakashi Iwai 		.strings = midi2->string_defs,
19188b645922STakashi Iwai 	};
19198b645922STakashi Iwai 	struct usb_gadget_strings *strings[] = {
19208b645922STakashi Iwai 		&string_fn,
19218b645922STakashi Iwai 		NULL,
19228b645922STakashi Iwai 	};
19238b645922STakashi Iwai 	int i, blk, status;
19248b645922STakashi Iwai 
19258b645922STakashi Iwai 	midi2->gadget = cdev->gadget;
19268b645922STakashi Iwai 	midi2->operation_mode = MIDI_OP_MODE_UNSET;
19278b645922STakashi Iwai 
19288b645922STakashi Iwai 	status = f_midi2_create_card(midi2);
19298b645922STakashi Iwai 	if (status < 0)
19308b645922STakashi Iwai 		goto fail_register;
19318b645922STakashi Iwai 
19328b645922STakashi Iwai 	/* maybe allocate device-global string ID */
19338b645922STakashi Iwai 	midi2->strings = usb_gstrings_attach(c->cdev, strings,
19348b645922STakashi Iwai 					     midi2->total_blocks + 1);
19358b645922STakashi Iwai 	if (IS_ERR(midi2->strings)) {
19368b645922STakashi Iwai 		status = PTR_ERR(midi2->strings);
19378b645922STakashi Iwai 		goto fail_string;
19388b645922STakashi Iwai 	}
19398b645922STakashi Iwai 
19408b645922STakashi Iwai 	mutex_lock(&f_midi2_desc_mutex);
19418b645922STakashi Iwai 	midi2_midi1_if_desc.iInterface = midi2->strings[STR_IFACE].id;
19428b645922STakashi Iwai 	midi2_midi2_if_desc.iInterface = midi2->strings[STR_IFACE].id;
19438b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
19448b645922STakashi Iwai 		ep = &midi2->midi2_eps[i];
19458b645922STakashi Iwai 		for (blk = 0; blk < ep->num_blks; blk++)
19468b645922STakashi Iwai 			ep->blks[blk].string_id =
19478b645922STakashi Iwai 				midi2->strings[gtb_to_str_id(ep->blks[blk].gtb_id)].id;
19488b645922STakashi Iwai 	}
19498b645922STakashi Iwai 
195029ee7a4dSTakashi Iwai 	midi2_midi2_if_desc.bNumEndpoints = midi2->num_eps * 2;
195129ee7a4dSTakashi Iwai 
19528b645922STakashi Iwai 	/* audio interface */
19538b645922STakashi Iwai 	status = usb_interface_id(c, f);
19548b645922STakashi Iwai 	if (status < 0)
19558b645922STakashi Iwai 		goto fail;
19568b645922STakashi Iwai 	midi2_audio_if_desc.bInterfaceNumber = status;
19578b645922STakashi Iwai 
19588b645922STakashi Iwai 	/* MIDI streaming */
19598b645922STakashi Iwai 	status = usb_interface_id(c, f);
19608b645922STakashi Iwai 	if (status < 0)
19618b645922STakashi Iwai 		goto fail;
19628b645922STakashi Iwai 	midi2->midi_if = status;
19638b645922STakashi Iwai 	midi2_midi1_if_desc.bInterfaceNumber = status;
19648b645922STakashi Iwai 	midi2_midi2_if_desc.bInterfaceNumber = status;
19658b645922STakashi Iwai 	midi2_audio_class_desc.baInterfaceNr[0] = status;
19668b645922STakashi Iwai 
19678b645922STakashi Iwai 	/* allocate instance-specific endpoints */
1968856fa444STakashi Iwai 	if (midi2->midi2_eps[0].blks[0].info.direction != SNDRV_UMP_DIR_OUTPUT) {
19698b645922STakashi Iwai 		status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_in,
1970d6468be7STakashi Iwai 					 &midi2_midi1_ep_in_desc,
1971d6468be7STakashi Iwai 					 f_midi2_midi1_ep_in_complete);
19728b645922STakashi Iwai 		if (status)
19738b645922STakashi Iwai 			goto fail;
1974856fa444STakashi Iwai 	}
1975856fa444STakashi Iwai 
1976856fa444STakashi Iwai 	if (midi2->midi2_eps[0].blks[0].info.direction != SNDRV_UMP_DIR_INPUT) {
19778b645922STakashi Iwai 		status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_out,
1978d6468be7STakashi Iwai 					 &midi2_midi1_ep_out_desc,
1979d6468be7STakashi Iwai 					 f_midi2_midi1_ep_out_complete);
19808b645922STakashi Iwai 		if (status)
19818b645922STakashi Iwai 			goto fail;
1982856fa444STakashi Iwai 	}
19838b645922STakashi Iwai 
19848b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
19858b645922STakashi Iwai 		status = f_midi2_init_midi2_ep_in(midi2, i);
19868b645922STakashi Iwai 		if (status)
19878b645922STakashi Iwai 			goto fail;
19888b645922STakashi Iwai 		status = f_midi2_init_midi2_ep_out(midi2, i);
19898b645922STakashi Iwai 		if (status)
19908b645922STakashi Iwai 			goto fail;
19918b645922STakashi Iwai 	}
19928b645922STakashi Iwai 
19938b645922STakashi Iwai 	status = f_midi2_create_usb_configs(midi2, &config, USB_SPEED_FULL);
19948b645922STakashi Iwai 	if (status < 0)
19958b645922STakashi Iwai 		goto fail;
19968b645922STakashi Iwai 	f->fs_descriptors = usb_copy_descriptors(config.list);
19978b645922STakashi Iwai 	if (!f->fs_descriptors) {
19988b645922STakashi Iwai 		status = -ENOMEM;
19998b645922STakashi Iwai 		goto fail;
20008b645922STakashi Iwai 	}
20018b645922STakashi Iwai 	f_midi2_free_usb_configs(&config);
20028b645922STakashi Iwai 
20038b645922STakashi Iwai 	status = f_midi2_create_usb_configs(midi2, &config, USB_SPEED_HIGH);
20048b645922STakashi Iwai 	if (status < 0)
20058b645922STakashi Iwai 		goto fail;
20068b645922STakashi Iwai 	f->hs_descriptors = usb_copy_descriptors(config.list);
20078b645922STakashi Iwai 	if (!f->hs_descriptors) {
20088b645922STakashi Iwai 		status = -ENOMEM;
20098b645922STakashi Iwai 		goto fail;
20108b645922STakashi Iwai 	}
20118b645922STakashi Iwai 	f_midi2_free_usb_configs(&config);
20128b645922STakashi Iwai 
20138b645922STakashi Iwai 	status = f_midi2_create_usb_configs(midi2, &config, USB_SPEED_SUPER);
20148b645922STakashi Iwai 	if (status < 0)
20158b645922STakashi Iwai 		goto fail;
20168b645922STakashi Iwai 	f->ss_descriptors = usb_copy_descriptors(config.list);
20178b645922STakashi Iwai 	if (!f->ss_descriptors) {
20188b645922STakashi Iwai 		status = -ENOMEM;
20198b645922STakashi Iwai 		goto fail;
20208b645922STakashi Iwai 	}
20218b645922STakashi Iwai 	f_midi2_free_usb_configs(&config);
20228b645922STakashi Iwai 
20238b645922STakashi Iwai 	mutex_unlock(&f_midi2_desc_mutex);
20248b645922STakashi Iwai 	return 0;
20258b645922STakashi Iwai 
20268b645922STakashi Iwai fail:
20278b645922STakashi Iwai 	f_midi2_free_usb_configs(&config);
20288b645922STakashi Iwai 	mutex_unlock(&f_midi2_desc_mutex);
20298b645922STakashi Iwai 	usb_free_all_descriptors(f);
20308b645922STakashi Iwai fail_string:
20318b645922STakashi Iwai 	f_midi2_free_card(midi2);
20328b645922STakashi Iwai fail_register:
20338b645922STakashi Iwai 	ERROR(midi2, "%s: can't bind, err %d\n", f->name, status);
20348b645922STakashi Iwai 	return status;
20358b645922STakashi Iwai }
20368b645922STakashi Iwai 
20378b645922STakashi Iwai /* gadget function unbind callback */
f_midi2_unbind(struct usb_configuration * c,struct usb_function * f)20388b645922STakashi Iwai static void f_midi2_unbind(struct usb_configuration *c, struct usb_function *f)
20398b645922STakashi Iwai {
20408b645922STakashi Iwai 	struct f_midi2 *midi2 = func_to_midi2(f);
20418b645922STakashi Iwai 	int i;
20428b645922STakashi Iwai 
20438b645922STakashi Iwai 	f_midi2_free_card(midi2);
20448b645922STakashi Iwai 
20458b645922STakashi Iwai 	f_midi2_free_ep(&midi2->midi1_ep_in);
20468b645922STakashi Iwai 	f_midi2_free_ep(&midi2->midi1_ep_out);
20478b645922STakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
20488b645922STakashi Iwai 		f_midi2_free_ep(&midi2->midi2_eps[i].ep_in);
20498b645922STakashi Iwai 		f_midi2_free_ep(&midi2->midi2_eps[i].ep_out);
20508b645922STakashi Iwai 	}
20518b645922STakashi Iwai 
20528b645922STakashi Iwai 	usb_free_all_descriptors(f);
20538b645922STakashi Iwai }
20548b645922STakashi Iwai 
205529ee7a4dSTakashi Iwai /*
205629ee7a4dSTakashi Iwai  * ConfigFS interface
205729ee7a4dSTakashi Iwai  */
205829ee7a4dSTakashi Iwai 
205929ee7a4dSTakashi Iwai /* type conversion helpers */
to_f_midi2_opts(struct config_item * item)206029ee7a4dSTakashi Iwai static inline struct f_midi2_opts *to_f_midi2_opts(struct config_item *item)
206129ee7a4dSTakashi Iwai {
206229ee7a4dSTakashi Iwai 	return container_of(to_config_group(item), struct f_midi2_opts,
206329ee7a4dSTakashi Iwai 			    func_inst.group);
206429ee7a4dSTakashi Iwai }
206529ee7a4dSTakashi Iwai 
206629ee7a4dSTakashi Iwai static inline struct f_midi2_ep_opts *
to_f_midi2_ep_opts(struct config_item * item)206729ee7a4dSTakashi Iwai to_f_midi2_ep_opts(struct config_item *item)
206829ee7a4dSTakashi Iwai {
206929ee7a4dSTakashi Iwai 	return container_of(to_config_group(item), struct f_midi2_ep_opts,
207029ee7a4dSTakashi Iwai 			    group);
207129ee7a4dSTakashi Iwai }
207229ee7a4dSTakashi Iwai 
207329ee7a4dSTakashi Iwai static inline struct f_midi2_block_opts *
to_f_midi2_block_opts(struct config_item * item)207429ee7a4dSTakashi Iwai to_f_midi2_block_opts(struct config_item *item)
207529ee7a4dSTakashi Iwai {
207629ee7a4dSTakashi Iwai 	return container_of(to_config_group(item), struct f_midi2_block_opts,
207729ee7a4dSTakashi Iwai 			    group);
207829ee7a4dSTakashi Iwai }
207929ee7a4dSTakashi Iwai 
208029ee7a4dSTakashi Iwai /* trim the string to be usable for EP and FB name strings */
make_name_string(char * s)208129ee7a4dSTakashi Iwai static void make_name_string(char *s)
208229ee7a4dSTakashi Iwai {
208329ee7a4dSTakashi Iwai 	char *p;
208429ee7a4dSTakashi Iwai 
208529ee7a4dSTakashi Iwai 	p = strchr(s, '\n');
208629ee7a4dSTakashi Iwai 	if (p)
208729ee7a4dSTakashi Iwai 		*p = 0;
208829ee7a4dSTakashi Iwai 
208929ee7a4dSTakashi Iwai 	p = s + strlen(s);
209029ee7a4dSTakashi Iwai 	for (; p > s && isspace(*p); p--)
209129ee7a4dSTakashi Iwai 		*p = 0;
209229ee7a4dSTakashi Iwai }
209329ee7a4dSTakashi Iwai 
209429ee7a4dSTakashi Iwai /* configfs helpers: generic show/store for unisnged int */
f_midi2_opts_uint_show(struct f_midi2_opts * opts,u32 val,const char * format,char * page)209529ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_uint_show(struct f_midi2_opts *opts,
209629ee7a4dSTakashi Iwai 				      u32 val, const char *format, char *page)
209729ee7a4dSTakashi Iwai {
209829ee7a4dSTakashi Iwai 	int result;
209929ee7a4dSTakashi Iwai 
210029ee7a4dSTakashi Iwai 	mutex_lock(&opts->lock);
210129ee7a4dSTakashi Iwai 	result = sprintf(page, format, val);
210229ee7a4dSTakashi Iwai 	mutex_unlock(&opts->lock);
210329ee7a4dSTakashi Iwai 	return result;
210429ee7a4dSTakashi Iwai }
210529ee7a4dSTakashi Iwai 
f_midi2_opts_uint_store(struct f_midi2_opts * opts,u32 * valp,u32 minval,u32 maxval,const char * page,size_t len)210629ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_uint_store(struct f_midi2_opts *opts,
210729ee7a4dSTakashi Iwai 				       u32 *valp, u32 minval, u32 maxval,
210829ee7a4dSTakashi Iwai 				       const char *page, size_t len)
210929ee7a4dSTakashi Iwai {
211029ee7a4dSTakashi Iwai 	int ret;
211129ee7a4dSTakashi Iwai 	u32 val;
211229ee7a4dSTakashi Iwai 
211329ee7a4dSTakashi Iwai 	mutex_lock(&opts->lock);
211429ee7a4dSTakashi Iwai 	if (opts->refcnt) {
211529ee7a4dSTakashi Iwai 		ret = -EBUSY;
211629ee7a4dSTakashi Iwai 		goto end;
211729ee7a4dSTakashi Iwai 	}
211829ee7a4dSTakashi Iwai 
211929ee7a4dSTakashi Iwai 	ret = kstrtou32(page, 0, &val);
212029ee7a4dSTakashi Iwai 	if (ret)
212129ee7a4dSTakashi Iwai 		goto end;
212229ee7a4dSTakashi Iwai 	if (val < minval || val > maxval) {
212329ee7a4dSTakashi Iwai 		ret = -EINVAL;
212429ee7a4dSTakashi Iwai 		goto end;
212529ee7a4dSTakashi Iwai 	}
212629ee7a4dSTakashi Iwai 
212729ee7a4dSTakashi Iwai 	*valp = val;
212829ee7a4dSTakashi Iwai 	ret = len;
212929ee7a4dSTakashi Iwai 
213029ee7a4dSTakashi Iwai end:
213129ee7a4dSTakashi Iwai 	mutex_unlock(&opts->lock);
213229ee7a4dSTakashi Iwai 	return ret;
213329ee7a4dSTakashi Iwai }
213429ee7a4dSTakashi Iwai 
213529ee7a4dSTakashi Iwai /* generic store for bool */
f_midi2_opts_bool_store(struct f_midi2_opts * opts,bool * valp,const char * page,size_t len)213629ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_bool_store(struct f_midi2_opts *opts,
213729ee7a4dSTakashi Iwai 				       bool *valp, const char *page, size_t len)
213829ee7a4dSTakashi Iwai {
213929ee7a4dSTakashi Iwai 	int ret;
214029ee7a4dSTakashi Iwai 	bool val;
214129ee7a4dSTakashi Iwai 
214229ee7a4dSTakashi Iwai 	mutex_lock(&opts->lock);
214329ee7a4dSTakashi Iwai 	if (opts->refcnt) {
214429ee7a4dSTakashi Iwai 		ret = -EBUSY;
214529ee7a4dSTakashi Iwai 		goto end;
214629ee7a4dSTakashi Iwai 	}
214729ee7a4dSTakashi Iwai 
214829ee7a4dSTakashi Iwai 	ret = kstrtobool(page, &val);
214929ee7a4dSTakashi Iwai 	if (ret)
215029ee7a4dSTakashi Iwai 		goto end;
215129ee7a4dSTakashi Iwai 	*valp = val;
215229ee7a4dSTakashi Iwai 	ret = len;
215329ee7a4dSTakashi Iwai 
215429ee7a4dSTakashi Iwai end:
215529ee7a4dSTakashi Iwai 	mutex_unlock(&opts->lock);
215629ee7a4dSTakashi Iwai 	return ret;
215729ee7a4dSTakashi Iwai }
215829ee7a4dSTakashi Iwai 
215929ee7a4dSTakashi Iwai /* generic show/store for string */
f_midi2_opts_str_show(struct f_midi2_opts * opts,const char * str,char * page)216029ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_str_show(struct f_midi2_opts *opts,
216129ee7a4dSTakashi Iwai 				     const char *str, char *page)
216229ee7a4dSTakashi Iwai {
216329ee7a4dSTakashi Iwai 	int result = 0;
216429ee7a4dSTakashi Iwai 
216529ee7a4dSTakashi Iwai 	mutex_lock(&opts->lock);
216629ee7a4dSTakashi Iwai 	if (str)
216729ee7a4dSTakashi Iwai 		result = scnprintf(page, PAGE_SIZE, "%s\n", str);
216829ee7a4dSTakashi Iwai 	mutex_unlock(&opts->lock);
216929ee7a4dSTakashi Iwai 	return result;
217029ee7a4dSTakashi Iwai }
217129ee7a4dSTakashi Iwai 
f_midi2_opts_str_store(struct f_midi2_opts * opts,const char ** strp,size_t maxlen,const char * page,size_t len)217229ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_str_store(struct f_midi2_opts *opts,
217329ee7a4dSTakashi Iwai 				      const char **strp, size_t maxlen,
217429ee7a4dSTakashi Iwai 				      const char *page, size_t len)
217529ee7a4dSTakashi Iwai {
217629ee7a4dSTakashi Iwai 	char *c;
217729ee7a4dSTakashi Iwai 	int ret;
217829ee7a4dSTakashi Iwai 
217929ee7a4dSTakashi Iwai 	mutex_lock(&opts->lock);
218029ee7a4dSTakashi Iwai 	if (opts->refcnt) {
218129ee7a4dSTakashi Iwai 		ret = -EBUSY;
218229ee7a4dSTakashi Iwai 		goto end;
218329ee7a4dSTakashi Iwai 	}
218429ee7a4dSTakashi Iwai 
218529ee7a4dSTakashi Iwai 	c = kstrndup(page, min(len, maxlen), GFP_KERNEL);
218629ee7a4dSTakashi Iwai 	if (!c) {
218729ee7a4dSTakashi Iwai 		ret = -ENOMEM;
218829ee7a4dSTakashi Iwai 		goto end;
218929ee7a4dSTakashi Iwai 	}
219029ee7a4dSTakashi Iwai 
219129ee7a4dSTakashi Iwai 	kfree(*strp);
219229ee7a4dSTakashi Iwai 	make_name_string(c);
219329ee7a4dSTakashi Iwai 	*strp = c;
219429ee7a4dSTakashi Iwai 	ret = len;
219529ee7a4dSTakashi Iwai 
219629ee7a4dSTakashi Iwai end:
219729ee7a4dSTakashi Iwai 	mutex_unlock(&opts->lock);
219829ee7a4dSTakashi Iwai 	return ret;
219929ee7a4dSTakashi Iwai }
220029ee7a4dSTakashi Iwai 
220129ee7a4dSTakashi Iwai /*
220229ee7a4dSTakashi Iwai  * Definitions for UMP Block config
220329ee7a4dSTakashi Iwai  */
220429ee7a4dSTakashi Iwai 
220529ee7a4dSTakashi Iwai /* define an uint option for block */
220629ee7a4dSTakashi Iwai #define F_MIDI2_BLOCK_OPT(name, format, minval, maxval)			\
220729ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_##name##_show(struct config_item *item,\
220829ee7a4dSTakashi Iwai 					  char *page)			\
220929ee7a4dSTakashi Iwai {									\
221029ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);	\
221129ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_show(opts->ep->opts, opts->info.name,	\
221229ee7a4dSTakashi Iwai 				      format "\n", page);		\
221329ee7a4dSTakashi Iwai }									\
221429ee7a4dSTakashi Iwai 									\
221529ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_##name##_store(struct config_item *item,\
221629ee7a4dSTakashi Iwai 					 const char *page, size_t len)	\
221729ee7a4dSTakashi Iwai {									\
221829ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);	\
221929ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_store(opts->ep->opts, &opts->info.name,\
222029ee7a4dSTakashi Iwai 				       minval, maxval, page, len);	\
222129ee7a4dSTakashi Iwai }									\
222229ee7a4dSTakashi Iwai 									\
222329ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_block_opts_, name)
222429ee7a4dSTakashi Iwai 
222529ee7a4dSTakashi Iwai /* define a boolean option for block */
222629ee7a4dSTakashi Iwai #define F_MIDI2_BLOCK_BOOL_OPT(name)					\
222729ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_##name##_show(struct config_item *item,\
222829ee7a4dSTakashi Iwai 					  char *page)			\
222929ee7a4dSTakashi Iwai {									\
223029ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);	\
223129ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_show(opts->ep->opts, opts->info.name,	\
223229ee7a4dSTakashi Iwai 				      "%u\n", page);			\
223329ee7a4dSTakashi Iwai }									\
223429ee7a4dSTakashi Iwai 									\
223529ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_##name##_store(struct config_item *item,\
223629ee7a4dSTakashi Iwai 					 const char *page, size_t len)	\
223729ee7a4dSTakashi Iwai {									\
223829ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);	\
223929ee7a4dSTakashi Iwai 	return f_midi2_opts_bool_store(opts->ep->opts, &opts->info.name,\
224029ee7a4dSTakashi Iwai 				       page, len);			\
224129ee7a4dSTakashi Iwai }									\
224229ee7a4dSTakashi Iwai 									\
224329ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_block_opts_, name)
224429ee7a4dSTakashi Iwai 
224529ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(direction, "0x%x", 1, 3);
224629ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(first_group, "0x%x", 0, 15);
224729ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(num_groups, "0x%x", 1, 16);
2248a85ff0dbSTakashi Iwai F_MIDI2_BLOCK_OPT(midi1_first_group, "0x%x", 0, 15);
2249a85ff0dbSTakashi Iwai F_MIDI2_BLOCK_OPT(midi1_num_groups, "0x%x", 0, 16);
225029ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(ui_hint, "0x%x", 0, 3);
225129ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(midi_ci_version, "%u", 0, 1);
225229ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(sysex8_streams, "%u", 0, 255);
225329ee7a4dSTakashi Iwai F_MIDI2_BLOCK_OPT(is_midi1, "%u", 0, 2);
225429ee7a4dSTakashi Iwai F_MIDI2_BLOCK_BOOL_OPT(active);
225529ee7a4dSTakashi Iwai 
f_midi2_block_opts_name_show(struct config_item * item,char * page)225629ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_name_show(struct config_item *item,
225729ee7a4dSTakashi Iwai 					    char *page)
225829ee7a4dSTakashi Iwai {
225929ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);
226029ee7a4dSTakashi Iwai 
226129ee7a4dSTakashi Iwai 	return f_midi2_opts_str_show(opts->ep->opts, opts->info.name, page);
226229ee7a4dSTakashi Iwai }
226329ee7a4dSTakashi Iwai 
f_midi2_block_opts_name_store(struct config_item * item,const char * page,size_t len)226429ee7a4dSTakashi Iwai static ssize_t f_midi2_block_opts_name_store(struct config_item *item,
226529ee7a4dSTakashi Iwai 					     const char *page, size_t len)
226629ee7a4dSTakashi Iwai {
226729ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);
226829ee7a4dSTakashi Iwai 
226929ee7a4dSTakashi Iwai 	return f_midi2_opts_str_store(opts->ep->opts, &opts->info.name, 128,
227029ee7a4dSTakashi Iwai 				      page, len);
227129ee7a4dSTakashi Iwai }
227229ee7a4dSTakashi Iwai 
227329ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_block_opts_, name);
227429ee7a4dSTakashi Iwai 
227529ee7a4dSTakashi Iwai static struct configfs_attribute *f_midi2_block_attrs[] = {
227629ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_direction,
227729ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_first_group,
227829ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_num_groups,
2279a85ff0dbSTakashi Iwai 	&f_midi2_block_opts_attr_midi1_first_group,
2280a85ff0dbSTakashi Iwai 	&f_midi2_block_opts_attr_midi1_num_groups,
228129ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_ui_hint,
228229ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_midi_ci_version,
228329ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_sysex8_streams,
228429ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_is_midi1,
228529ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_active,
228629ee7a4dSTakashi Iwai 	&f_midi2_block_opts_attr_name,
228729ee7a4dSTakashi Iwai 	NULL,
228829ee7a4dSTakashi Iwai };
228929ee7a4dSTakashi Iwai 
f_midi2_block_opts_release(struct config_item * item)229029ee7a4dSTakashi Iwai static void f_midi2_block_opts_release(struct config_item *item)
229129ee7a4dSTakashi Iwai {
229229ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *opts = to_f_midi2_block_opts(item);
229329ee7a4dSTakashi Iwai 
229429ee7a4dSTakashi Iwai 	kfree(opts->info.name);
229529ee7a4dSTakashi Iwai 	kfree(opts);
229629ee7a4dSTakashi Iwai }
229729ee7a4dSTakashi Iwai 
229829ee7a4dSTakashi Iwai static struct configfs_item_operations f_midi2_block_item_ops = {
229929ee7a4dSTakashi Iwai 	.release	= f_midi2_block_opts_release,
230029ee7a4dSTakashi Iwai };
230129ee7a4dSTakashi Iwai 
230229ee7a4dSTakashi Iwai static const struct config_item_type f_midi2_block_type = {
230329ee7a4dSTakashi Iwai 	.ct_item_ops	= &f_midi2_block_item_ops,
230429ee7a4dSTakashi Iwai 	.ct_attrs	= f_midi2_block_attrs,
230529ee7a4dSTakashi Iwai 	.ct_owner	= THIS_MODULE,
230629ee7a4dSTakashi Iwai };
230729ee7a4dSTakashi Iwai 
23088b645922STakashi Iwai /* create a f_midi2_block_opts instance for the given block number */
f_midi2_block_opts_create(struct f_midi2_ep_opts * ep_opts,unsigned int blk,struct f_midi2_block_opts ** block_p)23098b645922STakashi Iwai static int f_midi2_block_opts_create(struct f_midi2_ep_opts *ep_opts,
23108b645922STakashi Iwai 				     unsigned int blk,
23118b645922STakashi Iwai 				     struct f_midi2_block_opts **block_p)
23128b645922STakashi Iwai {
23138b645922STakashi Iwai 	struct f_midi2_block_opts *block_opts;
231429ee7a4dSTakashi Iwai 	int ret = 0;
231529ee7a4dSTakashi Iwai 
231629ee7a4dSTakashi Iwai 	mutex_lock(&ep_opts->opts->lock);
231729ee7a4dSTakashi Iwai 	if (ep_opts->opts->refcnt || ep_opts->blks[blk]) {
231829ee7a4dSTakashi Iwai 		ret = -EBUSY;
231929ee7a4dSTakashi Iwai 		goto out;
232029ee7a4dSTakashi Iwai 	}
23218b645922STakashi Iwai 
23228b645922STakashi Iwai 	block_opts = kzalloc(sizeof(*block_opts), GFP_KERNEL);
232329ee7a4dSTakashi Iwai 	if (!block_opts) {
232429ee7a4dSTakashi Iwai 		ret = -ENOMEM;
232529ee7a4dSTakashi Iwai 		goto out;
232629ee7a4dSTakashi Iwai 	}
23278b645922STakashi Iwai 
23288b645922STakashi Iwai 	block_opts->ep = ep_opts;
23298b645922STakashi Iwai 	block_opts->id = blk;
23308b645922STakashi Iwai 
23318b645922STakashi Iwai 	/* set up the default values */
23328b645922STakashi Iwai 	block_opts->info.direction = SNDRV_UMP_DIR_BIDIRECTION;
23338b645922STakashi Iwai 	block_opts->info.first_group = 0;
23348b645922STakashi Iwai 	block_opts->info.num_groups = 1;
23358b645922STakashi Iwai 	block_opts->info.ui_hint = SNDRV_UMP_BLOCK_UI_HINT_BOTH;
23368b645922STakashi Iwai 	block_opts->info.active = 1;
23378b645922STakashi Iwai 
23388b645922STakashi Iwai 	ep_opts->blks[blk] = block_opts;
23398b645922STakashi Iwai 	*block_p = block_opts;
234029ee7a4dSTakashi Iwai 
234129ee7a4dSTakashi Iwai  out:
2342*6bb75eb9SYang Yingliang 	mutex_unlock(&ep_opts->opts->lock);
234329ee7a4dSTakashi Iwai 	return ret;
23448b645922STakashi Iwai }
23458b645922STakashi Iwai 
234629ee7a4dSTakashi Iwai /* make_group callback for a block */
234729ee7a4dSTakashi Iwai static struct config_group *
f_midi2_opts_block_make(struct config_group * group,const char * name)234829ee7a4dSTakashi Iwai f_midi2_opts_block_make(struct config_group *group, const char *name)
234929ee7a4dSTakashi Iwai {
235029ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *ep_opts;
235129ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *block_opts;
235229ee7a4dSTakashi Iwai 	unsigned int blk;
235329ee7a4dSTakashi Iwai 	int ret;
235429ee7a4dSTakashi Iwai 
235529ee7a4dSTakashi Iwai 	if (strncmp(name, "block.", 6))
235629ee7a4dSTakashi Iwai 		return ERR_PTR(-EINVAL);
235729ee7a4dSTakashi Iwai 	ret = kstrtouint(name + 6, 10, &blk);
235829ee7a4dSTakashi Iwai 	if (ret)
235929ee7a4dSTakashi Iwai 		return ERR_PTR(ret);
236029ee7a4dSTakashi Iwai 
236129ee7a4dSTakashi Iwai 	ep_opts = to_f_midi2_ep_opts(&group->cg_item);
236229ee7a4dSTakashi Iwai 
236329ee7a4dSTakashi Iwai 	if (blk >= SNDRV_UMP_MAX_BLOCKS)
236429ee7a4dSTakashi Iwai 		return ERR_PTR(-EINVAL);
236529ee7a4dSTakashi Iwai 	if (ep_opts->blks[blk])
236629ee7a4dSTakashi Iwai 		return ERR_PTR(-EBUSY);
236729ee7a4dSTakashi Iwai 	ret = f_midi2_block_opts_create(ep_opts, blk, &block_opts);
236829ee7a4dSTakashi Iwai 	if (ret)
236929ee7a4dSTakashi Iwai 		return ERR_PTR(ret);
237029ee7a4dSTakashi Iwai 
237129ee7a4dSTakashi Iwai 	config_group_init_type_name(&block_opts->group, name,
237229ee7a4dSTakashi Iwai 				    &f_midi2_block_type);
237329ee7a4dSTakashi Iwai 	return &block_opts->group;
237429ee7a4dSTakashi Iwai }
237529ee7a4dSTakashi Iwai 
237629ee7a4dSTakashi Iwai /* drop_item callback for a block */
237729ee7a4dSTakashi Iwai static void
f_midi2_opts_block_drop(struct config_group * group,struct config_item * item)237829ee7a4dSTakashi Iwai f_midi2_opts_block_drop(struct config_group *group, struct config_item *item)
237929ee7a4dSTakashi Iwai {
238029ee7a4dSTakashi Iwai 	struct f_midi2_block_opts *block_opts = to_f_midi2_block_opts(item);
238129ee7a4dSTakashi Iwai 
238229ee7a4dSTakashi Iwai 	mutex_lock(&block_opts->ep->opts->lock);
238329ee7a4dSTakashi Iwai 	block_opts->ep->blks[block_opts->id] = NULL;
238429ee7a4dSTakashi Iwai 	mutex_unlock(&block_opts->ep->opts->lock);
238529ee7a4dSTakashi Iwai 	config_item_put(item);
238629ee7a4dSTakashi Iwai }
238729ee7a4dSTakashi Iwai 
238829ee7a4dSTakashi Iwai /*
238929ee7a4dSTakashi Iwai  * Definitions for UMP Endpoint config
239029ee7a4dSTakashi Iwai  */
239129ee7a4dSTakashi Iwai 
239229ee7a4dSTakashi Iwai /* define an uint option for EP */
239329ee7a4dSTakashi Iwai #define F_MIDI2_EP_OPT(name, format, minval, maxval)			\
239429ee7a4dSTakashi Iwai static ssize_t f_midi2_ep_opts_##name##_show(struct config_item *item,	\
239529ee7a4dSTakashi Iwai 					     char *page)		\
239629ee7a4dSTakashi Iwai {									\
239729ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);	\
239829ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_show(opts->opts, opts->info.name,	\
239929ee7a4dSTakashi Iwai 				      format "\n", page);		\
240029ee7a4dSTakashi Iwai }									\
240129ee7a4dSTakashi Iwai 									\
240229ee7a4dSTakashi Iwai static ssize_t f_midi2_ep_opts_##name##_store(struct config_item *item,	\
240329ee7a4dSTakashi Iwai 					   const char *page, size_t len)\
240429ee7a4dSTakashi Iwai {									\
240529ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);	\
240629ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_store(opts->opts, &opts->info.name,	\
240729ee7a4dSTakashi Iwai 				       minval, maxval, page, len);	\
240829ee7a4dSTakashi Iwai }									\
240929ee7a4dSTakashi Iwai 									\
241029ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_ep_opts_, name)
241129ee7a4dSTakashi Iwai 
241229ee7a4dSTakashi Iwai /* define a string option for EP */
241329ee7a4dSTakashi Iwai #define F_MIDI2_EP_STR_OPT(name, maxlen)				\
241429ee7a4dSTakashi Iwai static ssize_t f_midi2_ep_opts_##name##_show(struct config_item *item,	\
241529ee7a4dSTakashi Iwai 					     char *page)		\
241629ee7a4dSTakashi Iwai {									\
241729ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);	\
241829ee7a4dSTakashi Iwai 	return f_midi2_opts_str_show(opts->opts, opts->info.name, page);\
241929ee7a4dSTakashi Iwai }									\
242029ee7a4dSTakashi Iwai 									\
242129ee7a4dSTakashi Iwai static ssize_t f_midi2_ep_opts_##name##_store(struct config_item *item,	\
242229ee7a4dSTakashi Iwai 					 const char *page, size_t len)	\
242329ee7a4dSTakashi Iwai {									\
242429ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);	\
242529ee7a4dSTakashi Iwai 	return f_midi2_opts_str_store(opts->opts, &opts->info.name, maxlen,\
242629ee7a4dSTakashi Iwai 				      page, len);			\
242729ee7a4dSTakashi Iwai }									\
242829ee7a4dSTakashi Iwai 									\
242929ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_ep_opts_, name)
243029ee7a4dSTakashi Iwai 
243129ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(protocol, "0x%x", 1, 2);
243229ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(protocol_caps, "0x%x", 1, 3);
243329ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(manufacturer, "0x%x", 0, 0xffffff);
243429ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(family, "0x%x", 0, 0xffff);
243529ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(model, "0x%x", 0, 0xffff);
243629ee7a4dSTakashi Iwai F_MIDI2_EP_OPT(sw_revision, "0x%x", 0, 0xffffffff);
243729ee7a4dSTakashi Iwai F_MIDI2_EP_STR_OPT(ep_name, 128);
243829ee7a4dSTakashi Iwai F_MIDI2_EP_STR_OPT(product_id, 128);
243929ee7a4dSTakashi Iwai 
244029ee7a4dSTakashi Iwai static struct configfs_attribute *f_midi2_ep_attrs[] = {
244129ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_protocol,
244229ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_protocol_caps,
244329ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_ep_name,
244429ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_product_id,
244529ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_manufacturer,
244629ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_family,
244729ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_model,
244829ee7a4dSTakashi Iwai 	&f_midi2_ep_opts_attr_sw_revision,
244929ee7a4dSTakashi Iwai 	NULL,
245029ee7a4dSTakashi Iwai };
245129ee7a4dSTakashi Iwai 
f_midi2_ep_opts_release(struct config_item * item)245229ee7a4dSTakashi Iwai static void f_midi2_ep_opts_release(struct config_item *item)
245329ee7a4dSTakashi Iwai {
245429ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);
245529ee7a4dSTakashi Iwai 
245629ee7a4dSTakashi Iwai 	kfree(opts->info.ep_name);
245729ee7a4dSTakashi Iwai 	kfree(opts->info.product_id);
245829ee7a4dSTakashi Iwai 	kfree(opts);
245929ee7a4dSTakashi Iwai }
246029ee7a4dSTakashi Iwai 
246129ee7a4dSTakashi Iwai static struct configfs_item_operations f_midi2_ep_item_ops = {
246229ee7a4dSTakashi Iwai 	.release	= f_midi2_ep_opts_release,
246329ee7a4dSTakashi Iwai };
246429ee7a4dSTakashi Iwai 
246529ee7a4dSTakashi Iwai static struct configfs_group_operations f_midi2_ep_group_ops = {
246629ee7a4dSTakashi Iwai 	.make_group	= f_midi2_opts_block_make,
246729ee7a4dSTakashi Iwai 	.drop_item	= f_midi2_opts_block_drop,
246829ee7a4dSTakashi Iwai };
246929ee7a4dSTakashi Iwai 
247029ee7a4dSTakashi Iwai static const struct config_item_type f_midi2_ep_type = {
247129ee7a4dSTakashi Iwai 	.ct_item_ops	= &f_midi2_ep_item_ops,
247229ee7a4dSTakashi Iwai 	.ct_group_ops	= &f_midi2_ep_group_ops,
247329ee7a4dSTakashi Iwai 	.ct_attrs	= f_midi2_ep_attrs,
247429ee7a4dSTakashi Iwai 	.ct_owner	= THIS_MODULE,
247529ee7a4dSTakashi Iwai };
247629ee7a4dSTakashi Iwai 
24778b645922STakashi Iwai /* create a f_midi2_ep_opts instance */
f_midi2_ep_opts_create(struct f_midi2_opts * opts,unsigned int index,struct f_midi2_ep_opts ** ep_p)24788b645922STakashi Iwai static int f_midi2_ep_opts_create(struct f_midi2_opts *opts,
24798b645922STakashi Iwai 				  unsigned int index,
24808b645922STakashi Iwai 				  struct f_midi2_ep_opts **ep_p)
24818b645922STakashi Iwai {
24828b645922STakashi Iwai 	struct f_midi2_ep_opts *ep_opts;
24838b645922STakashi Iwai 
24848b645922STakashi Iwai 	ep_opts = kzalloc(sizeof(*ep_opts), GFP_KERNEL);
24858b645922STakashi Iwai 	if (!ep_opts)
24868b645922STakashi Iwai 		return -ENOMEM;
24878b645922STakashi Iwai 
24888b645922STakashi Iwai 	ep_opts->opts = opts;
24898b645922STakashi Iwai 	ep_opts->index = index;
24908b645922STakashi Iwai 
24918b645922STakashi Iwai 	/* set up the default values */
24928b645922STakashi Iwai 	ep_opts->info.protocol = 2;
24938b645922STakashi Iwai 	ep_opts->info.protocol_caps = 3;
24948b645922STakashi Iwai 
24958b645922STakashi Iwai 	opts->eps[index] = ep_opts;
24968b645922STakashi Iwai 	*ep_p = ep_opts;
24978b645922STakashi Iwai 	return 0;
24988b645922STakashi Iwai }
24998b645922STakashi Iwai 
250029ee7a4dSTakashi Iwai /* make_group callback for an EP */
250129ee7a4dSTakashi Iwai static struct config_group *
f_midi2_opts_ep_make(struct config_group * group,const char * name)250229ee7a4dSTakashi Iwai f_midi2_opts_ep_make(struct config_group *group, const char *name)
250329ee7a4dSTakashi Iwai {
250429ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts;
250529ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *ep_opts;
250629ee7a4dSTakashi Iwai 	unsigned int index;
250729ee7a4dSTakashi Iwai 	int ret;
250829ee7a4dSTakashi Iwai 
250929ee7a4dSTakashi Iwai 	if (strncmp(name, "ep.", 3))
251029ee7a4dSTakashi Iwai 		return ERR_PTR(-EINVAL);
251129ee7a4dSTakashi Iwai 	ret = kstrtouint(name + 3, 10, &index);
251229ee7a4dSTakashi Iwai 	if (ret)
251329ee7a4dSTakashi Iwai 		return ERR_PTR(ret);
251429ee7a4dSTakashi Iwai 
251529ee7a4dSTakashi Iwai 	opts = to_f_midi2_opts(&group->cg_item);
251629ee7a4dSTakashi Iwai 	if (index >= MAX_UMP_EPS)
251729ee7a4dSTakashi Iwai 		return ERR_PTR(-EINVAL);
251829ee7a4dSTakashi Iwai 	if (opts->eps[index])
251929ee7a4dSTakashi Iwai 		return ERR_PTR(-EBUSY);
252029ee7a4dSTakashi Iwai 	ret = f_midi2_ep_opts_create(opts, index, &ep_opts);
252129ee7a4dSTakashi Iwai 	if (ret)
252229ee7a4dSTakashi Iwai 		return ERR_PTR(ret);
252329ee7a4dSTakashi Iwai 
252429ee7a4dSTakashi Iwai 	config_group_init_type_name(&ep_opts->group, name, &f_midi2_ep_type);
252529ee7a4dSTakashi Iwai 	return &ep_opts->group;
252629ee7a4dSTakashi Iwai }
252729ee7a4dSTakashi Iwai 
252829ee7a4dSTakashi Iwai /* drop_item callback for an EP */
252929ee7a4dSTakashi Iwai static void
f_midi2_opts_ep_drop(struct config_group * group,struct config_item * item)253029ee7a4dSTakashi Iwai f_midi2_opts_ep_drop(struct config_group *group, struct config_item *item)
253129ee7a4dSTakashi Iwai {
253229ee7a4dSTakashi Iwai 	struct f_midi2_ep_opts *ep_opts = to_f_midi2_ep_opts(item);
253329ee7a4dSTakashi Iwai 
253429ee7a4dSTakashi Iwai 	mutex_lock(&ep_opts->opts->lock);
253529ee7a4dSTakashi Iwai 	ep_opts->opts->eps[ep_opts->index] = NULL;
253629ee7a4dSTakashi Iwai 	mutex_unlock(&ep_opts->opts->lock);
253729ee7a4dSTakashi Iwai 	config_item_put(item);
253829ee7a4dSTakashi Iwai }
253929ee7a4dSTakashi Iwai 
254029ee7a4dSTakashi Iwai /*
254129ee7a4dSTakashi Iwai  * Definitions for card config
254229ee7a4dSTakashi Iwai  */
254329ee7a4dSTakashi Iwai 
254429ee7a4dSTakashi Iwai /* define a bool option for card */
254529ee7a4dSTakashi Iwai #define F_MIDI2_BOOL_OPT(name)						\
254629ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_##name##_show(struct config_item *item,	\
254729ee7a4dSTakashi Iwai 					  char *page)			\
254829ee7a4dSTakashi Iwai {									\
254929ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts = to_f_midi2_opts(item);		\
255029ee7a4dSTakashi Iwai 	return f_midi2_opts_uint_show(opts, opts->info.name,		\
255129ee7a4dSTakashi Iwai 				      "%u\n", page);			\
255229ee7a4dSTakashi Iwai }									\
255329ee7a4dSTakashi Iwai 									\
255429ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_##name##_store(struct config_item *item,	\
255529ee7a4dSTakashi Iwai 					 const char *page, size_t len)	\
255629ee7a4dSTakashi Iwai {									\
255729ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts = to_f_midi2_opts(item);		\
255829ee7a4dSTakashi Iwai 	return f_midi2_opts_bool_store(opts, &opts->info.name,		\
255929ee7a4dSTakashi Iwai 				       page, len);			\
256029ee7a4dSTakashi Iwai }									\
256129ee7a4dSTakashi Iwai 									\
256229ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_opts_, name)
256329ee7a4dSTakashi Iwai 
256429ee7a4dSTakashi Iwai F_MIDI2_BOOL_OPT(process_ump);
256529ee7a4dSTakashi Iwai F_MIDI2_BOOL_OPT(static_block);
256629ee7a4dSTakashi Iwai 
f_midi2_opts_iface_name_show(struct config_item * item,char * page)256729ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_iface_name_show(struct config_item *item,
256829ee7a4dSTakashi Iwai 					    char *page)
256929ee7a4dSTakashi Iwai {
257029ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts = to_f_midi2_opts(item);
257129ee7a4dSTakashi Iwai 
257229ee7a4dSTakashi Iwai 	return f_midi2_opts_str_show(opts, opts->info.iface_name, page);
257329ee7a4dSTakashi Iwai }
257429ee7a4dSTakashi Iwai 
f_midi2_opts_iface_name_store(struct config_item * item,const char * page,size_t len)257529ee7a4dSTakashi Iwai static ssize_t f_midi2_opts_iface_name_store(struct config_item *item,
257629ee7a4dSTakashi Iwai 					     const char *page, size_t len)
257729ee7a4dSTakashi Iwai {
257829ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts = to_f_midi2_opts(item);
257929ee7a4dSTakashi Iwai 
258029ee7a4dSTakashi Iwai 	return f_midi2_opts_str_store(opts, &opts->info.iface_name, 128,
258129ee7a4dSTakashi Iwai 				      page, len);
258229ee7a4dSTakashi Iwai }
258329ee7a4dSTakashi Iwai 
258429ee7a4dSTakashi Iwai CONFIGFS_ATTR(f_midi2_opts_, iface_name);
258529ee7a4dSTakashi Iwai 
258629ee7a4dSTakashi Iwai static struct configfs_attribute *f_midi2_attrs[] = {
258729ee7a4dSTakashi Iwai 	&f_midi2_opts_attr_process_ump,
258829ee7a4dSTakashi Iwai 	&f_midi2_opts_attr_static_block,
258929ee7a4dSTakashi Iwai 	&f_midi2_opts_attr_iface_name,
259029ee7a4dSTakashi Iwai 	NULL
259129ee7a4dSTakashi Iwai };
259229ee7a4dSTakashi Iwai 
f_midi2_opts_release(struct config_item * item)259329ee7a4dSTakashi Iwai static void f_midi2_opts_release(struct config_item *item)
259429ee7a4dSTakashi Iwai {
259529ee7a4dSTakashi Iwai 	struct f_midi2_opts *opts = to_f_midi2_opts(item);
259629ee7a4dSTakashi Iwai 
259729ee7a4dSTakashi Iwai 	usb_put_function_instance(&opts->func_inst);
259829ee7a4dSTakashi Iwai }
259929ee7a4dSTakashi Iwai 
260029ee7a4dSTakashi Iwai static struct configfs_item_operations f_midi2_item_ops = {
260129ee7a4dSTakashi Iwai 	.release	= f_midi2_opts_release,
260229ee7a4dSTakashi Iwai };
260329ee7a4dSTakashi Iwai 
260429ee7a4dSTakashi Iwai static struct configfs_group_operations f_midi2_group_ops = {
260529ee7a4dSTakashi Iwai 	.make_group	= f_midi2_opts_ep_make,
260629ee7a4dSTakashi Iwai 	.drop_item	= f_midi2_opts_ep_drop,
260729ee7a4dSTakashi Iwai };
260829ee7a4dSTakashi Iwai 
26098b645922STakashi Iwai static const struct config_item_type f_midi2_func_type = {
261029ee7a4dSTakashi Iwai 	.ct_item_ops	= &f_midi2_item_ops,
261129ee7a4dSTakashi Iwai 	.ct_group_ops	= &f_midi2_group_ops,
261229ee7a4dSTakashi Iwai 	.ct_attrs	= f_midi2_attrs,
26138b645922STakashi Iwai 	.ct_owner	= THIS_MODULE,
26148b645922STakashi Iwai };
26158b645922STakashi Iwai 
f_midi2_free_inst(struct usb_function_instance * f)26168b645922STakashi Iwai static void f_midi2_free_inst(struct usb_function_instance *f)
26178b645922STakashi Iwai {
26188b645922STakashi Iwai 	struct f_midi2_opts *opts;
26198b645922STakashi Iwai 
26208b645922STakashi Iwai 	opts = container_of(f, struct f_midi2_opts, func_inst);
26218b645922STakashi Iwai 
262229ee7a4dSTakashi Iwai 	kfree(opts->info.iface_name);
26238b645922STakashi Iwai 	kfree(opts);
26248b645922STakashi Iwai }
26258b645922STakashi Iwai 
26268b645922STakashi Iwai /* gadget alloc_inst */
f_midi2_alloc_inst(void)26278b645922STakashi Iwai static struct usb_function_instance *f_midi2_alloc_inst(void)
26288b645922STakashi Iwai {
26298b645922STakashi Iwai 	struct f_midi2_opts *opts;
26308b645922STakashi Iwai 	struct f_midi2_ep_opts *ep_opts;
26318b645922STakashi Iwai 	struct f_midi2_block_opts *block_opts;
26328b645922STakashi Iwai 	int ret;
26338b645922STakashi Iwai 
26348b645922STakashi Iwai 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
26358b645922STakashi Iwai 	if (!opts)
26368b645922STakashi Iwai 		return ERR_PTR(-ENOMEM);
26378b645922STakashi Iwai 
26388b645922STakashi Iwai 	mutex_init(&opts->lock);
26398b645922STakashi Iwai 	opts->func_inst.free_func_inst = f_midi2_free_inst;
26408b645922STakashi Iwai 	opts->info.process_ump = true;
26418b645922STakashi Iwai 	opts->info.static_block = true;
26428b645922STakashi Iwai 	opts->info.num_reqs = 32;
26438b645922STakashi Iwai 	opts->info.req_buf_size = 512;
26448b645922STakashi Iwai 
264529ee7a4dSTakashi Iwai 	/* create the default ep */
26468b645922STakashi Iwai 	ret = f_midi2_ep_opts_create(opts, 0, &ep_opts);
26478b645922STakashi Iwai 	if (ret) {
26488b645922STakashi Iwai 		kfree(opts);
26498b645922STakashi Iwai 		return ERR_PTR(ret);
26508b645922STakashi Iwai 	}
26518b645922STakashi Iwai 
26528b645922STakashi Iwai 	/* create the default block */
26538b645922STakashi Iwai 	ret = f_midi2_block_opts_create(ep_opts, 0, &block_opts);
26548b645922STakashi Iwai 	if (ret) {
26558b645922STakashi Iwai 		kfree(ep_opts);
26568b645922STakashi Iwai 		kfree(opts);
26578b645922STakashi Iwai 		return ERR_PTR(ret);
26588b645922STakashi Iwai 	}
26598b645922STakashi Iwai 
2660a85ff0dbSTakashi Iwai 	/* set up the default MIDI1 (that is mandatory) */
2661a85ff0dbSTakashi Iwai 	block_opts->info.midi1_num_groups = 1;
2662a85ff0dbSTakashi Iwai 
26638b645922STakashi Iwai 	config_group_init_type_name(&opts->func_inst.group, "",
26648b645922STakashi Iwai 				    &f_midi2_func_type);
266529ee7a4dSTakashi Iwai 
266629ee7a4dSTakashi Iwai 	config_group_init_type_name(&ep_opts->group, "ep.0",
266729ee7a4dSTakashi Iwai 				    &f_midi2_ep_type);
266829ee7a4dSTakashi Iwai 	configfs_add_default_group(&ep_opts->group, &opts->func_inst.group);
266929ee7a4dSTakashi Iwai 
267029ee7a4dSTakashi Iwai 	config_group_init_type_name(&block_opts->group, "block.0",
267129ee7a4dSTakashi Iwai 				    &f_midi2_block_type);
267229ee7a4dSTakashi Iwai 	configfs_add_default_group(&block_opts->group, &ep_opts->group);
267329ee7a4dSTakashi Iwai 
26748b645922STakashi Iwai 	return &opts->func_inst;
26758b645922STakashi Iwai }
26768b645922STakashi Iwai 
do_f_midi2_free(struct f_midi2 * midi2,struct f_midi2_opts * opts)26778b645922STakashi Iwai static void do_f_midi2_free(struct f_midi2 *midi2, struct f_midi2_opts *opts)
26788b645922STakashi Iwai {
26798b645922STakashi Iwai 	mutex_lock(&opts->lock);
26808b645922STakashi Iwai 	--opts->refcnt;
26818b645922STakashi Iwai 	mutex_unlock(&opts->lock);
26828b645922STakashi Iwai 	kfree(midi2->string_defs);
26838b645922STakashi Iwai 	kfree(midi2);
26848b645922STakashi Iwai }
26858b645922STakashi Iwai 
f_midi2_free(struct usb_function * f)26868b645922STakashi Iwai static void f_midi2_free(struct usb_function *f)
26878b645922STakashi Iwai {
26888b645922STakashi Iwai 	do_f_midi2_free(func_to_midi2(f),
26898b645922STakashi Iwai 			container_of(f->fi, struct f_midi2_opts, func_inst));
26908b645922STakashi Iwai }
26918b645922STakashi Iwai 
269229ee7a4dSTakashi Iwai /* verify the parameters set up via configfs;
269329ee7a4dSTakashi Iwai  * return the number of EPs or a negative error
269429ee7a4dSTakashi Iwai  */
verify_parameters(struct f_midi2_opts * opts)269529ee7a4dSTakashi Iwai static int verify_parameters(struct f_midi2_opts *opts)
269629ee7a4dSTakashi Iwai {
269729ee7a4dSTakashi Iwai 	int i, j, num_eps, num_blks;
269829ee7a4dSTakashi Iwai 	struct f_midi2_ep_info *ep;
269929ee7a4dSTakashi Iwai 	struct f_midi2_block_info *bp;
270029ee7a4dSTakashi Iwai 
270129ee7a4dSTakashi Iwai 	for (num_eps = 0; num_eps < MAX_UMP_EPS && opts->eps[num_eps];
270229ee7a4dSTakashi Iwai 	     num_eps++)
270329ee7a4dSTakashi Iwai 		;
270429ee7a4dSTakashi Iwai 	if (!num_eps) {
270529ee7a4dSTakashi Iwai 		pr_err("f_midi2: No EP is defined\n");
270629ee7a4dSTakashi Iwai 		return -EINVAL;
270729ee7a4dSTakashi Iwai 	}
270829ee7a4dSTakashi Iwai 
270929ee7a4dSTakashi Iwai 	num_blks = 0;
271029ee7a4dSTakashi Iwai 	for (i = 0; i < num_eps; i++) {
271129ee7a4dSTakashi Iwai 		ep = &opts->eps[i]->info;
271229ee7a4dSTakashi Iwai 		if (!(ep->protocol_caps & ep->protocol)) {
271329ee7a4dSTakashi Iwai 			pr_err("f_midi2: Invalid protocol 0x%x (caps 0x%x) for EP %d\n",
271429ee7a4dSTakashi Iwai 			       ep->protocol, ep->protocol_caps, i);
271529ee7a4dSTakashi Iwai 			return -EINVAL;
271629ee7a4dSTakashi Iwai 		}
271729ee7a4dSTakashi Iwai 
271829ee7a4dSTakashi Iwai 		for (j = 0; j < SNDRV_UMP_MAX_BLOCKS && opts->eps[i]->blks[j];
271929ee7a4dSTakashi Iwai 		     j++, num_blks++) {
272029ee7a4dSTakashi Iwai 			bp = &opts->eps[i]->blks[j]->info;
272129ee7a4dSTakashi Iwai 			if (bp->first_group + bp->num_groups > SNDRV_UMP_MAX_GROUPS) {
272229ee7a4dSTakashi Iwai 				pr_err("f_midi2: Invalid group definitions for block %d:%d\n",
272329ee7a4dSTakashi Iwai 				       i, j);
272429ee7a4dSTakashi Iwai 				return -EINVAL;
272529ee7a4dSTakashi Iwai 			}
2726a85ff0dbSTakashi Iwai 
2727a85ff0dbSTakashi Iwai 			if (bp->midi1_num_groups) {
2728a85ff0dbSTakashi Iwai 				if (bp->midi1_first_group < bp->first_group ||
2729a85ff0dbSTakashi Iwai 				    bp->midi1_first_group + bp->midi1_num_groups >
2730a85ff0dbSTakashi Iwai 				    bp->first_group + bp->num_groups) {
2731a85ff0dbSTakashi Iwai 					pr_err("f_midi2: Invalid MIDI1 group definitions for block %d:%d\n",
2732a85ff0dbSTakashi Iwai 					       i, j);
2733a85ff0dbSTakashi Iwai 					return -EINVAL;
2734a85ff0dbSTakashi Iwai 				}
2735a85ff0dbSTakashi Iwai 			}
273629ee7a4dSTakashi Iwai 		}
273729ee7a4dSTakashi Iwai 	}
273829ee7a4dSTakashi Iwai 	if (!num_blks) {
273929ee7a4dSTakashi Iwai 		pr_err("f_midi2: No block is defined\n");
274029ee7a4dSTakashi Iwai 		return -EINVAL;
274129ee7a4dSTakashi Iwai 	}
274229ee7a4dSTakashi Iwai 
274329ee7a4dSTakashi Iwai 	return num_eps;
274429ee7a4dSTakashi Iwai }
274529ee7a4dSTakashi Iwai 
2746a85ff0dbSTakashi Iwai /* fill mapping between MIDI 1.0 cable and UMP EP/group */
fill_midi1_cable_mapping(struct f_midi2 * midi2,struct f_midi2_ep * ep,int blk)2747a85ff0dbSTakashi Iwai static void fill_midi1_cable_mapping(struct f_midi2 *midi2,
2748a85ff0dbSTakashi Iwai 				     struct f_midi2_ep *ep,
2749a85ff0dbSTakashi Iwai 				     int blk)
2750a85ff0dbSTakashi Iwai {
2751a85ff0dbSTakashi Iwai 	const struct f_midi2_block_info *binfo = &ep->blks[blk].info;
2752a85ff0dbSTakashi Iwai 	struct midi1_cable_mapping *map;
2753a85ff0dbSTakashi Iwai 	int i, group;
2754a85ff0dbSTakashi Iwai 
2755a85ff0dbSTakashi Iwai 	if (!binfo->midi1_num_groups)
2756a85ff0dbSTakashi Iwai 		return;
2757a85ff0dbSTakashi Iwai 	if (binfo->direction != SNDRV_UMP_DIR_OUTPUT) {
2758a85ff0dbSTakashi Iwai 		group = binfo->midi1_first_group;
2759a85ff0dbSTakashi Iwai 		map = midi2->in_cable_mapping + midi2->num_midi1_in;
2760a85ff0dbSTakashi Iwai 		for (i = 0; i < binfo->midi1_num_groups; i++, group++, map++) {
2761a85ff0dbSTakashi Iwai 			if (midi2->num_midi1_in >= MAX_CABLES)
2762a85ff0dbSTakashi Iwai 				break;
2763a85ff0dbSTakashi Iwai 			map->ep = ep;
2764a85ff0dbSTakashi Iwai 			map->block = blk;
2765a85ff0dbSTakashi Iwai 			map->group = group;
2766a85ff0dbSTakashi Iwai 			midi2->num_midi1_in++;
2767a85ff0dbSTakashi Iwai 			/* store 1-based cable number */
2768a85ff0dbSTakashi Iwai 			ep->in_group_to_cable[group] = midi2->num_midi1_in;
2769a85ff0dbSTakashi Iwai 		}
2770a85ff0dbSTakashi Iwai 	}
2771a85ff0dbSTakashi Iwai 
2772a85ff0dbSTakashi Iwai 	if (binfo->direction != SNDRV_UMP_DIR_INPUT) {
2773a85ff0dbSTakashi Iwai 		group = binfo->midi1_first_group;
2774a85ff0dbSTakashi Iwai 		map = midi2->out_cable_mapping + midi2->num_midi1_out;
2775a85ff0dbSTakashi Iwai 		for (i = 0; i < binfo->midi1_num_groups; i++, group++, map++) {
2776a85ff0dbSTakashi Iwai 			if (midi2->num_midi1_out >= MAX_CABLES)
2777a85ff0dbSTakashi Iwai 				break;
2778a85ff0dbSTakashi Iwai 			map->ep = ep;
2779a85ff0dbSTakashi Iwai 			map->block = blk;
2780a85ff0dbSTakashi Iwai 			map->group = group;
2781a85ff0dbSTakashi Iwai 			midi2->num_midi1_out++;
2782a85ff0dbSTakashi Iwai 		}
2783a85ff0dbSTakashi Iwai 	}
2784a85ff0dbSTakashi Iwai }
2785a85ff0dbSTakashi Iwai 
27868b645922STakashi Iwai /* gadget alloc callback */
f_midi2_alloc(struct usb_function_instance * fi)27878b645922STakashi Iwai static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
27888b645922STakashi Iwai {
27898b645922STakashi Iwai 	struct f_midi2 *midi2;
27908b645922STakashi Iwai 	struct f_midi2_opts *opts;
279129ee7a4dSTakashi Iwai 	struct f_midi2_ep *ep;
279229ee7a4dSTakashi Iwai 	struct f_midi2_block *bp;
279329ee7a4dSTakashi Iwai 	int i, num_eps, blk;
27948b645922STakashi Iwai 
27958b645922STakashi Iwai 	midi2 = kzalloc(sizeof(*midi2), GFP_KERNEL);
27968b645922STakashi Iwai 	if (!midi2)
27978b645922STakashi Iwai 		return ERR_PTR(-ENOMEM);
27988b645922STakashi Iwai 
27998b645922STakashi Iwai 	opts = container_of(fi, struct f_midi2_opts, func_inst);
28008b645922STakashi Iwai 	mutex_lock(&opts->lock);
280129ee7a4dSTakashi Iwai 	num_eps = verify_parameters(opts);
280229ee7a4dSTakashi Iwai 	if (num_eps < 0) {
280329ee7a4dSTakashi Iwai 		mutex_unlock(&opts->lock);
280429ee7a4dSTakashi Iwai 		kfree(midi2);
280529ee7a4dSTakashi Iwai 		return ERR_PTR(num_eps);
280629ee7a4dSTakashi Iwai 	}
28078b645922STakashi Iwai 	++opts->refcnt;
28088b645922STakashi Iwai 	mutex_unlock(&opts->lock);
28098b645922STakashi Iwai 
28108b645922STakashi Iwai 	spin_lock_init(&midi2->queue_lock);
28118b645922STakashi Iwai 
28128b645922STakashi Iwai 	midi2->func.name = "midi2_func";
28138b645922STakashi Iwai 	midi2->func.bind = f_midi2_bind;
28148b645922STakashi Iwai 	midi2->func.unbind = f_midi2_unbind;
28158b645922STakashi Iwai 	midi2->func.get_alt = f_midi2_get_alt;
28168b645922STakashi Iwai 	midi2->func.set_alt = f_midi2_set_alt;
28178b645922STakashi Iwai 	midi2->func.setup = f_midi2_setup;
28188b645922STakashi Iwai 	midi2->func.disable = f_midi2_disable;
28198b645922STakashi Iwai 	midi2->func.free_func = f_midi2_free;
28208b645922STakashi Iwai 
28218b645922STakashi Iwai 	midi2->info = opts->info;
282229ee7a4dSTakashi Iwai 	midi2->num_eps = num_eps;
28238b645922STakashi Iwai 
282429ee7a4dSTakashi Iwai 	for (i = 0; i < num_eps; i++) {
282529ee7a4dSTakashi Iwai 		ep = &midi2->midi2_eps[i];
282629ee7a4dSTakashi Iwai 		ep->info = opts->eps[i]->info;
282729ee7a4dSTakashi Iwai 		ep->card = midi2;
282829ee7a4dSTakashi Iwai 		for (blk = 0; blk < SNDRV_UMP_MAX_BLOCKS &&
282929ee7a4dSTakashi Iwai 			     opts->eps[i]->blks[blk]; blk++) {
283029ee7a4dSTakashi Iwai 			bp = &ep->blks[blk];
283129ee7a4dSTakashi Iwai 			ep->num_blks++;
283229ee7a4dSTakashi Iwai 			bp->info = opts->eps[i]->blks[blk]->info;
283329ee7a4dSTakashi Iwai 			bp->gtb_id = ++midi2->total_blocks;
283429ee7a4dSTakashi Iwai 		}
283529ee7a4dSTakashi Iwai 	}
28368b645922STakashi Iwai 
28378b645922STakashi Iwai 	midi2->string_defs = kcalloc(midi2->total_blocks + 1,
28388b645922STakashi Iwai 				     sizeof(*midi2->string_defs), GFP_KERNEL);
28398b645922STakashi Iwai 	if (!midi2->string_defs) {
28408b645922STakashi Iwai 		do_f_midi2_free(midi2, opts);
28418b645922STakashi Iwai 		return ERR_PTR(-ENOMEM);
28428b645922STakashi Iwai 	}
28438b645922STakashi Iwai 
28448b645922STakashi Iwai 	if (opts->info.iface_name && *opts->info.iface_name)
284529ee7a4dSTakashi Iwai 		midi2->string_defs[STR_IFACE].s = opts->info.iface_name;
28468b645922STakashi Iwai 	else
284729ee7a4dSTakashi Iwai 		midi2->string_defs[STR_IFACE].s = ump_ep_name(&midi2->midi2_eps[0]);
284829ee7a4dSTakashi Iwai 
284929ee7a4dSTakashi Iwai 	for (i = 0; i < midi2->num_eps; i++) {
285029ee7a4dSTakashi Iwai 		ep = &midi2->midi2_eps[i];
285129ee7a4dSTakashi Iwai 		for (blk = 0; blk < ep->num_blks; blk++) {
285229ee7a4dSTakashi Iwai 			bp = &ep->blks[blk];
285329ee7a4dSTakashi Iwai 			midi2->string_defs[gtb_to_str_id(bp->gtb_id)].s =
285429ee7a4dSTakashi Iwai 				ump_fb_name(&bp->info);
2855a85ff0dbSTakashi Iwai 
2856a85ff0dbSTakashi Iwai 			fill_midi1_cable_mapping(midi2, ep, blk);
285729ee7a4dSTakashi Iwai 		}
285829ee7a4dSTakashi Iwai 	}
28598b645922STakashi Iwai 
2860a85ff0dbSTakashi Iwai 	if (!midi2->num_midi1_in && !midi2->num_midi1_out) {
2861a85ff0dbSTakashi Iwai 		pr_err("f_midi2: MIDI1 definition is missing\n");
2862a85ff0dbSTakashi Iwai 		do_f_midi2_free(midi2, opts);
2863a85ff0dbSTakashi Iwai 		return ERR_PTR(-EINVAL);
2864a85ff0dbSTakashi Iwai 	}
2865a85ff0dbSTakashi Iwai 
28668b645922STakashi Iwai 	return &midi2->func;
28678b645922STakashi Iwai }
28688b645922STakashi Iwai 
28698b645922STakashi Iwai DECLARE_USB_FUNCTION_INIT(midi2, f_midi2_alloc_inst, f_midi2_alloc);
28708b645922STakashi Iwai 
28718b645922STakashi Iwai MODULE_LICENSE("GPL");
2872