Commit a85ff0db authored by Takashi Iwai's avatar Takashi Iwai Committed by Greg Kroah-Hartman

usb: gadget: midi2: More flexible MIDI 1.0 configuration

This patch allows users to set up MIDI 1.0 ports more flexibly.
Namely, instead of the fixed mapping only from FB 0, now multiple
block definitions are applied to build up the MIDI 1.0 mapping.

The each block config has midi1_first_group and midi1_num_groups
attributes, and those specify which Groups are used for MIDI 1.0.
Those fields must be within the UMP Groups defined in the block
itself.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20230725062206.9674-8-tiwai@suse.deSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1b437d2f
...@@ -39,14 +39,16 @@ Description: ...@@ -39,14 +39,16 @@ Description:
The attributes: The attributes:
=============== =============================================== ================= ==============================================
name Function Block name string name Function Block name string
direction 1: input, 2: output, 3: bidirectional direction 1: input, 2: output, 3: bidirectional
first_group The first UMP Group number (0-15) first_group The first UMP Group number (0-15)
num_groups The number of groups in this FB (1-16) num_groups The number of groups in this FB (1-16)
ui_hint 0: unknown, 1: receiver, 2: sender, 3: both midi1_first_group The first UMP Group number for MIDI 1.0 (0-15)
midi_ci_verison Supported MIDI-CI version number (8 bit) midi1_num_groups The number of groups for MIDI 1.0 (0-16)
is_midi1 Legacy MIDI 1.0 device (0, 1 or 2) ui_hint 0: unknown, 1: receiver, 2: sender, 3: both
sysex8_streams Max number of SysEx8 streams (8 bit) midi_ci_verison Supported MIDI-CI version number (8 bit)
active Active FB flag (0 or 1) is_midi1 Legacy MIDI 1.0 device (0, 1 or 2)
=============== =============================================== sysex8_streams Max number of SysEx8 streams (8 bit)
active Active FB flag (0 or 1)
================= ==============================================
...@@ -1009,22 +1009,24 @@ Each Endpoint subdirectory contains a subdirectory "block.0", which ...@@ -1009,22 +1009,24 @@ Each Endpoint subdirectory contains a subdirectory "block.0", which
represents the Function Block for Block 0 information. represents the Function Block for Block 0 information.
Its attributes are: Its attributes are:
=============== =============================================== ================= ===============================================
name Function Block name string name Function Block name string
direction Direction of this FB direction Direction of this FB
1: input, 2: output, or 3: bidirectional 1: input, 2: output, or 3: bidirectional
first_group The first UMP Group number (0-15) first_group The first UMP Group number (0-15)
num_groups The number of groups in this FB (1-16) num_groups The number of groups in this FB (1-16)
ui_hint UI-hint of this FB midi1_first_group The first UMP Group number for MIDI 1.0 (0-15)
0: unknown, 1: receiver, 2: sender, 3: both midi1_num_groups The number of groups for MIDI 1.0 (0-16)
midi_ci_verison Supported MIDI-CI version number (8 bit) ui_hint UI-hint of this FB
is_midi1 Legacy MIDI 1.0 device (0-2) 0: unknown, 1: receiver, 2: sender, 3: both
0: MIDI 2.0 device, midi_ci_verison Supported MIDI-CI version number (8 bit)
1: MIDI 1.0 without restriction, or is_midi1 Legacy MIDI 1.0 device (0-2)
2: MIDI 1.0 with low speed 0: MIDI 2.0 device,
sysex8_streams Max number of SysEx8 streams (8 bit) 1: MIDI 1.0 without restriction, or
active Bool flag for FB activity (0 or 1) 2: MIDI 1.0 with low speed
=============== =============================================== sysex8_streams Max number of SysEx8 streams (8 bit)
active Bool flag for FB activity (0 or 1)
================= ===============================================
If multiple Function Blocks are required, you can add more Function If multiple Function Blocks are required, you can add more Function
Blocks by creating subdirectories "block.<num>" with the corresponding Blocks by creating subdirectories "block.<num>" with the corresponding
......
...@@ -84,6 +84,8 @@ struct f_midi2_ep { ...@@ -84,6 +84,8 @@ struct f_midi2_ep {
struct f_midi2_usb_ep ep_in; /* USB MIDI EP-in */ struct f_midi2_usb_ep ep_in; /* USB MIDI EP-in */
struct f_midi2_usb_ep ep_out; /* USB MIDI EP-out */ struct f_midi2_usb_ep ep_out; /* USB MIDI EP-out */
u8 in_group_to_cable[SNDRV_UMP_MAX_GROUPS]; /* map to cable; 1-based! */
}; };
/* indices for USB strings */ /* indices for USB strings */
...@@ -95,6 +97,13 @@ enum { ...@@ -95,6 +97,13 @@ enum {
/* 1-based GTB id to string id */ /* 1-based GTB id to string id */
#define gtb_to_str_id(id) (STR_GTB1 + (id) - 1) #define gtb_to_str_id(id) (STR_GTB1 + (id) - 1)
/* mapping from MIDI 1.0 cable to UMP group */
struct midi1_cable_mapping {
struct f_midi2_ep *ep;
unsigned char block;
unsigned char group;
};
/* operation mode */ /* operation mode */
enum { enum {
MIDI_OP_MODE_UNSET, /* no altset set yet */ MIDI_OP_MODE_UNSET, /* no altset set yet */
...@@ -112,10 +121,17 @@ struct f_midi2 { ...@@ -112,10 +121,17 @@ struct f_midi2 {
struct f_midi2_usb_ep midi1_ep_in; struct f_midi2_usb_ep midi1_ep_in;
struct f_midi2_usb_ep midi1_ep_out; struct f_midi2_usb_ep midi1_ep_out;
/* number of MIDI 1.0 I/O cables */
unsigned int num_midi1_in;
unsigned int num_midi1_out;
/* conversion for MIDI 1.0 EP-in */ /* conversion for MIDI 1.0 EP-in */
struct f_midi2_midi1_port midi1_port[MAX_CABLES]; struct f_midi2_midi1_port midi1_port[MAX_CABLES];
/* conversion for MIDI 1.0 EP-out */ /* conversion for MIDI 1.0 EP-out */
struct ump_cvt_to_ump midi1_ump_cvt; struct ump_cvt_to_ump midi1_ump_cvt;
/* mapping between cables and UMP groups */
struct midi1_cable_mapping in_cable_mapping[MAX_CABLES];
struct midi1_cable_mapping out_cable_mapping[MAX_CABLES];
int midi_if; /* USB MIDI interface number */ int midi_if; /* USB MIDI interface number */
int operation_mode; /* current operation mode */ int operation_mode; /* current operation mode */
...@@ -917,8 +933,7 @@ static bool process_midi1_pending_buf(struct f_midi2 *midi2, ...@@ -917,8 +933,7 @@ static bool process_midi1_pending_buf(struct f_midi2 *midi2,
{ {
unsigned int cable, c; unsigned int cable, c;
for (cable = 0; cable < midi2->midi2_eps[0].blks[0].info.num_groups; for (cable = 0; cable < midi2->num_midi1_in; cable++) {
cable++) {
struct f_midi2_midi1_port *port = &midi2->midi1_port[cable]; struct f_midi2_midi1_port *port = &midi2->midi1_port[cable];
if (!port->pending) if (!port->pending)
...@@ -960,8 +975,8 @@ static void process_midi1_transmit(struct f_midi2 *midi2) ...@@ -960,8 +975,8 @@ static void process_midi1_transmit(struct f_midi2 *midi2)
struct usb_request *req = NULL; struct usb_request *req = NULL;
/* 12 is the largest outcome (4 MIDI1 cmds) for a single UMP packet */ /* 12 is the largest outcome (4 MIDI1 cmds) for a single UMP packet */
unsigned char outbuf[12]; unsigned char outbuf[12];
unsigned char group; unsigned char group, cable;
int len, size, cable; int len, size;
u32 ump; u32 ump;
if (!usb_ep->usb_ep || !usb_ep->usb_ep->enabled) if (!usb_ep->usb_ep || !usb_ep->usb_ep->enabled)
...@@ -986,9 +1001,10 @@ static void process_midi1_transmit(struct f_midi2 *midi2) ...@@ -986,9 +1001,10 @@ static void process_midi1_transmit(struct f_midi2 *midi2)
&group); &group);
if (size <= 0) if (size <= 0)
continue; continue;
cable = group - ep->blks[0].info.first_group; cable = ep->in_group_to_cable[group];
if (cable < 0 || cable >= ep->blks[0].info.num_groups) if (!cable)
continue; continue;
cable--; /* to 0-base */
fill_midi1_pending_buf(midi2, cable, outbuf, size); fill_midi1_pending_buf(midi2, cable, outbuf, size);
} }
...@@ -1025,12 +1041,12 @@ static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep, ...@@ -1025,12 +1041,12 @@ static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep,
{ {
struct f_midi2_req_ctx *ctx = req->context; struct f_midi2_req_ctx *ctx = req->context;
struct f_midi2 *midi2 = ctx->usb_ep->card; struct f_midi2 *midi2 = ctx->usb_ep->card;
struct f_midi2_ep *ep = &midi2->midi2_eps[0]; struct f_midi2_ep *ep;
struct ump_cvt_to_ump *cvt = &midi2->midi1_ump_cvt; struct ump_cvt_to_ump *cvt = &midi2->midi1_ump_cvt;
static const u8 midi1_packet_bytes[16] = { static const u8 midi1_packet_bytes[16] = {
0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
}; };
unsigned int group, bytes, c, len; unsigned int group, cable, bytes, c, len;
int status = req->status; int status = req->status;
const u8 *buf = req->buf; const u8 *buf = req->buf;
...@@ -1042,10 +1058,11 @@ static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep, ...@@ -1042,10 +1058,11 @@ static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep,
len = req->actual >> 2; len = req->actual >> 2;
for (; len; len--, buf += 4) { for (; len; len--, buf += 4) {
group = *buf >> 4; cable = *buf >> 4;
if (group >= ep->blks[0].info.num_groups) ep = midi2->out_cable_mapping[cable].ep;
if (!ep)
continue; continue;
group += ep->blks[0].info.first_group; group = midi2->out_cable_mapping[cable].group;
bytes = midi1_packet_bytes[*buf & 0x0f]; bytes = midi1_packet_bytes[*buf & 0x0f];
for (c = 0; c < bytes; c++) { for (c = 0; c < bytes; c++) {
snd_ump_convert_to_ump(cvt, group, ep->info.protocol, snd_ump_convert_to_ump(cvt, group, ep->info.protocol,
...@@ -1641,6 +1658,7 @@ static int append_configs(struct f_midi2_usb_config *config, void **d) ...@@ -1641,6 +1658,7 @@ static int append_configs(struct f_midi2_usb_config *config, void **d)
static int append_midi1_in_jack(struct f_midi2 *midi2, static int append_midi1_in_jack(struct f_midi2 *midi2,
struct f_midi2_usb_config *config, struct f_midi2_usb_config *config,
struct midi1_cable_mapping *map,
unsigned int type) unsigned int type)
{ {
struct usb_midi_in_jack_descriptor *jack = struct usb_midi_in_jack_descriptor *jack =
...@@ -1653,7 +1671,9 @@ static int append_midi1_in_jack(struct f_midi2 *midi2, ...@@ -1653,7 +1671,9 @@ static int append_midi1_in_jack(struct f_midi2 *midi2,
jack->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; jack->bDescriptorSubtype = USB_MS_MIDI_IN_JACK;
jack->bJackType = type; jack->bJackType = type;
jack->bJackID = id; jack->bJackID = id;
jack->iJack = midi2->strings[STR_GTB1].id; // TODO: better names? /* use the corresponding block name as jack name */
if (map->ep)
jack->iJack = map->ep->blks[map->block].string_id;
err = append_config(config, jack); err = append_config(config, jack);
if (err < 0) if (err < 0)
...@@ -1663,6 +1683,7 @@ static int append_midi1_in_jack(struct f_midi2 *midi2, ...@@ -1663,6 +1683,7 @@ static int append_midi1_in_jack(struct f_midi2 *midi2,
static int append_midi1_out_jack(struct f_midi2 *midi2, static int append_midi1_out_jack(struct f_midi2 *midi2,
struct f_midi2_usb_config *config, struct f_midi2_usb_config *config,
struct midi1_cable_mapping *map,
unsigned int type, unsigned int source) unsigned int type, unsigned int source)
{ {
struct usb_midi_out_jack_descriptor_1 *jack = struct usb_midi_out_jack_descriptor_1 *jack =
...@@ -1678,7 +1699,9 @@ static int append_midi1_out_jack(struct f_midi2 *midi2, ...@@ -1678,7 +1699,9 @@ static int append_midi1_out_jack(struct f_midi2 *midi2,
jack->bNrInputPins = 1; jack->bNrInputPins = 1;
jack->pins[0].baSourceID = source; jack->pins[0].baSourceID = source;
jack->pins[0].baSourcePin = 0x01; jack->pins[0].baSourcePin = 0x01;
jack->iJack = midi2->strings[STR_GTB1].id; // TODO: better names? /* use the corresponding block name as jack name */
if (map->ep)
jack->iJack = map->ep->blks[map->block].string_id;
err = append_config(config, jack); err = append_config(config, jack);
if (err < 0) if (err < 0)
...@@ -1690,7 +1713,6 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2, ...@@ -1690,7 +1713,6 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
struct f_midi2_usb_config *config, struct f_midi2_usb_config *config,
int speed) int speed)
{ {
struct f_midi2_block *blk = &midi2->midi2_eps[0].blks[0];
void **midi1_in_eps, **midi1_out_eps; void **midi1_in_eps, **midi1_out_eps;
int i, jack, total; int i, jack, total;
int err; int err;
...@@ -1724,56 +1746,55 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2, ...@@ -1724,56 +1746,55 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
if (err < 0) if (err < 0)
return err; return err;
switch (blk->info.direction) { if (midi2->num_midi1_in && midi2->num_midi1_out)
case SNDRV_UMP_DIR_INPUT:
case SNDRV_UMP_DIR_OUTPUT:
midi2_midi1_if_desc.bNumEndpoints = 1;
break;
default:
midi2_midi1_if_desc.bNumEndpoints = 2; midi2_midi1_if_desc.bNumEndpoints = 2;
break; else
} midi2_midi1_if_desc.bNumEndpoints = 1;
err = append_configs(config, midi2_midi1_descs); err = append_configs(config, midi2_midi1_descs);
if (err < 0) if (err < 0)
return err; return err;
total = USB_DT_MS_HEADER_SIZE; total = USB_DT_MS_HEADER_SIZE;
if (blk->info.direction != SNDRV_UMP_DIR_INPUT) { if (midi2->num_midi1_out) {
midi2_midi1_ep_out_class_desc.bLength = midi2_midi1_ep_out_class_desc.bLength =
USB_DT_MS_ENDPOINT_SIZE(blk->info.num_groups); USB_DT_MS_ENDPOINT_SIZE(midi2->num_midi1_out);
total += midi2_midi1_ep_out_class_desc.bLength; total += midi2_midi1_ep_out_class_desc.bLength;
midi2_midi1_ep_out_class_desc.bNumEmbMIDIJack = midi2_midi1_ep_out_class_desc.bNumEmbMIDIJack =
blk->info.num_groups; midi2->num_midi1_out;
total += blk->info.num_groups * total += midi2->num_midi1_out *
(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1)); (USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
for (i = 0; i < blk->info.num_groups; i++) { for (i = 0; i < midi2->num_midi1_out; i++) {
jack = append_midi1_in_jack(midi2, config, jack = append_midi1_in_jack(midi2, config,
&midi2->in_cable_mapping[i],
USB_MS_EMBEDDED); USB_MS_EMBEDDED);
if (jack < 0) if (jack < 0)
return jack; return jack;
midi2_midi1_ep_out_class_desc.baAssocJackID[i] = jack; midi2_midi1_ep_out_class_desc.baAssocJackID[i] = jack;
jack = append_midi1_out_jack(midi2, config, jack = append_midi1_out_jack(midi2, config,
&midi2->in_cable_mapping[i],
USB_MS_EXTERNAL, jack); USB_MS_EXTERNAL, jack);
if (jack < 0) if (jack < 0)
return jack; return jack;
} }
} }
if (blk->info.direction != SNDRV_UMP_DIR_OUTPUT) { if (midi2->num_midi1_in) {
midi2_midi1_ep_in_class_desc.bLength = midi2_midi1_ep_in_class_desc.bLength =
USB_DT_MS_ENDPOINT_SIZE(blk->info.num_groups); USB_DT_MS_ENDPOINT_SIZE(midi2->num_midi1_in);
total += midi2_midi1_ep_in_class_desc.bLength; total += midi2_midi1_ep_in_class_desc.bLength;
midi2_midi1_ep_in_class_desc.bNumEmbMIDIJack = midi2_midi1_ep_in_class_desc.bNumEmbMIDIJack =
blk->info.num_groups; midi2->num_midi1_in;
total += blk->info.num_groups * total += midi2->num_midi1_in *
(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1)); (USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
for (i = 0; i < blk->info.num_groups; i++) { for (i = 0; i < midi2->num_midi1_in; i++) {
jack = append_midi1_in_jack(midi2, config, jack = append_midi1_in_jack(midi2, config,
&midi2->out_cable_mapping[i],
USB_MS_EXTERNAL); USB_MS_EXTERNAL);
if (jack < 0) if (jack < 0)
return jack; return jack;
jack = append_midi1_out_jack(midi2, config, jack = append_midi1_out_jack(midi2, config,
&midi2->out_cable_mapping[i],
USB_MS_EMBEDDED, jack); USB_MS_EMBEDDED, jack);
if (jack < 0) if (jack < 0)
return jack; return jack;
...@@ -1783,12 +1804,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2, ...@@ -1783,12 +1804,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
midi2_midi1_class_desc.wTotalLength = cpu_to_le16(total); midi2_midi1_class_desc.wTotalLength = cpu_to_le16(total);
if (blk->info.direction != SNDRV_UMP_DIR_INPUT) { if (midi2->num_midi1_out) {
err = append_configs(config, midi1_out_eps); err = append_configs(config, midi1_out_eps);
if (err < 0) if (err < 0)
return err; return err;
} }
if (blk->info.direction != SNDRV_UMP_DIR_OUTPUT) { if (midi2->num_midi1_in) {
err = append_configs(config, midi1_in_eps); err = append_configs(config, midi1_in_eps);
if (err < 0) if (err < 0)
return err; return err;
...@@ -2236,6 +2257,8 @@ CONFIGFS_ATTR(f_midi2_block_opts_, name) ...@@ -2236,6 +2257,8 @@ CONFIGFS_ATTR(f_midi2_block_opts_, name)
F_MIDI2_BLOCK_OPT(direction, "0x%x", 1, 3); F_MIDI2_BLOCK_OPT(direction, "0x%x", 1, 3);
F_MIDI2_BLOCK_OPT(first_group, "0x%x", 0, 15); F_MIDI2_BLOCK_OPT(first_group, "0x%x", 0, 15);
F_MIDI2_BLOCK_OPT(num_groups, "0x%x", 1, 16); F_MIDI2_BLOCK_OPT(num_groups, "0x%x", 1, 16);
F_MIDI2_BLOCK_OPT(midi1_first_group, "0x%x", 0, 15);
F_MIDI2_BLOCK_OPT(midi1_num_groups, "0x%x", 0, 16);
F_MIDI2_BLOCK_OPT(ui_hint, "0x%x", 0, 3); F_MIDI2_BLOCK_OPT(ui_hint, "0x%x", 0, 3);
F_MIDI2_BLOCK_OPT(midi_ci_version, "%u", 0, 1); F_MIDI2_BLOCK_OPT(midi_ci_version, "%u", 0, 1);
F_MIDI2_BLOCK_OPT(sysex8_streams, "%u", 0, 255); F_MIDI2_BLOCK_OPT(sysex8_streams, "%u", 0, 255);
...@@ -2265,6 +2288,8 @@ static struct configfs_attribute *f_midi2_block_attrs[] = { ...@@ -2265,6 +2288,8 @@ static struct configfs_attribute *f_midi2_block_attrs[] = {
&f_midi2_block_opts_attr_direction, &f_midi2_block_opts_attr_direction,
&f_midi2_block_opts_attr_first_group, &f_midi2_block_opts_attr_first_group,
&f_midi2_block_opts_attr_num_groups, &f_midi2_block_opts_attr_num_groups,
&f_midi2_block_opts_attr_midi1_first_group,
&f_midi2_block_opts_attr_midi1_num_groups,
&f_midi2_block_opts_attr_ui_hint, &f_midi2_block_opts_attr_ui_hint,
&f_midi2_block_opts_attr_midi_ci_version, &f_midi2_block_opts_attr_midi_ci_version,
&f_midi2_block_opts_attr_sysex8_streams, &f_midi2_block_opts_attr_sysex8_streams,
...@@ -2644,6 +2669,9 @@ static struct usb_function_instance *f_midi2_alloc_inst(void) ...@@ -2644,6 +2669,9 @@ static struct usb_function_instance *f_midi2_alloc_inst(void)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/* set up the default MIDI1 (that is mandatory) */
block_opts->info.midi1_num_groups = 1;
config_group_init_type_name(&opts->func_inst.group, "", config_group_init_type_name(&opts->func_inst.group, "",
&f_midi2_func_type); &f_midi2_func_type);
...@@ -2707,6 +2735,16 @@ static int verify_parameters(struct f_midi2_opts *opts) ...@@ -2707,6 +2735,16 @@ static int verify_parameters(struct f_midi2_opts *opts)
i, j); i, j);
return -EINVAL; return -EINVAL;
} }
if (bp->midi1_num_groups) {
if (bp->midi1_first_group < bp->first_group ||
bp->midi1_first_group + bp->midi1_num_groups >
bp->first_group + bp->num_groups) {
pr_err("f_midi2: Invalid MIDI1 group definitions for block %d:%d\n",
i, j);
return -EINVAL;
}
}
} }
} }
if (!num_blks) { if (!num_blks) {
...@@ -2717,6 +2755,46 @@ static int verify_parameters(struct f_midi2_opts *opts) ...@@ -2717,6 +2755,46 @@ static int verify_parameters(struct f_midi2_opts *opts)
return num_eps; return num_eps;
} }
/* fill mapping between MIDI 1.0 cable and UMP EP/group */
static void fill_midi1_cable_mapping(struct f_midi2 *midi2,
struct f_midi2_ep *ep,
int blk)
{
const struct f_midi2_block_info *binfo = &ep->blks[blk].info;
struct midi1_cable_mapping *map;
int i, group;
if (!binfo->midi1_num_groups)
return;
if (binfo->direction != SNDRV_UMP_DIR_OUTPUT) {
group = binfo->midi1_first_group;
map = midi2->in_cable_mapping + midi2->num_midi1_in;
for (i = 0; i < binfo->midi1_num_groups; i++, group++, map++) {
if (midi2->num_midi1_in >= MAX_CABLES)
break;
map->ep = ep;
map->block = blk;
map->group = group;
midi2->num_midi1_in++;
/* store 1-based cable number */
ep->in_group_to_cable[group] = midi2->num_midi1_in;
}
}
if (binfo->direction != SNDRV_UMP_DIR_INPUT) {
group = binfo->midi1_first_group;
map = midi2->out_cable_mapping + midi2->num_midi1_out;
for (i = 0; i < binfo->midi1_num_groups; i++, group++, map++) {
if (midi2->num_midi1_out >= MAX_CABLES)
break;
map->ep = ep;
map->block = blk;
map->group = group;
midi2->num_midi1_out++;
}
}
}
/* gadget alloc callback */ /* gadget alloc callback */
static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi) static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
{ {
...@@ -2786,9 +2864,17 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi) ...@@ -2786,9 +2864,17 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
bp = &ep->blks[blk]; bp = &ep->blks[blk];
midi2->string_defs[gtb_to_str_id(bp->gtb_id)].s = midi2->string_defs[gtb_to_str_id(bp->gtb_id)].s =
ump_fb_name(&bp->info); ump_fb_name(&bp->info);
fill_midi1_cable_mapping(midi2, ep, blk);
} }
} }
if (!midi2->num_midi1_in && !midi2->num_midi1_out) {
pr_err("f_midi2: MIDI1 definition is missing\n");
do_f_midi2_free(midi2, opts);
return ERR_PTR(-EINVAL);
}
return &midi2->func; return &midi2->func;
} }
......
...@@ -18,6 +18,8 @@ struct f_midi2_block_info { ...@@ -18,6 +18,8 @@ struct f_midi2_block_info {
unsigned int direction; /* FB direction: 1-3 */ unsigned int direction; /* FB direction: 1-3 */
unsigned int first_group; /* first UMP group: 0-15 */ unsigned int first_group; /* first UMP group: 0-15 */
unsigned int num_groups; /* number of UMP groups: 1-16 */ unsigned int num_groups; /* number of UMP groups: 1-16 */
unsigned int midi1_first_group; /* first UMP group for MIDI 1.0 */
unsigned int midi1_num_groups; /* number of UMP groups for MIDI 1.0 */
unsigned int ui_hint; /* UI-hint: 0-3 */ unsigned int ui_hint; /* UI-hint: 0-3 */
unsigned int midi_ci_version; /* MIDI-CI version: 0-255 */ unsigned int midi_ci_version; /* MIDI-CI version: 0-255 */
unsigned int sysex8_streams; /* number of sysex8 streams: 0-255 */ unsigned int sysex8_streams; /* number of sysex8 streams: 0-255 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment