Skip to content

Commit

Permalink
ALSA: bebob: detect the number of available MIDI ports
Browse files Browse the repository at this point in the history
Current implementation counts the number of input/output plugs for MIDI
type and uses the count as the number of physical MIDI ports. However,
the number of channels of the port represents the count.

This commit fixes the bug by additional vendor-specific AVC command
extension.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20210321032831.340278-3-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Sakamoto authored and Takashi Iwai committed Mar 22, 2021
1 parent caa2715 commit 5c6ea94
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 32 deletions.
2 changes: 2 additions & 0 deletions sound/firewire/bebob/bebob.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
int avc_bridgeco_get_plug_type(struct fw_unit *unit,
u8 addr[AVC_BRIDGECO_ADDR_BYTES],
enum avc_bridgeco_plug_type *type);
int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
unsigned int *ch_count);
int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
u8 addr[AVC_BRIDGECO_ADDR_BYTES],
unsigned int id, u8 *type);
Expand Down
36 changes: 36 additions & 0 deletions sound/firewire/bebob/bebob_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,42 @@ int avc_bridgeco_get_plug_type(struct fw_unit *unit,
return err;
}

int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
unsigned int *ch_count)
{
u8 *buf;
int err;

buf = kzalloc(12, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;

// Info type is 'plug type'.
avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x02);

err = fcp_avc_transaction(unit, buf, 12, buf, 12,
BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
BIT(6) | BIT(7) | BIT(9));
if (err < 0)
;
else if (err < 11)
err = -EIO;
else if (buf[0] == 0x08) // NOT IMPLEMENTED
err = -ENOSYS;
else if (buf[0] == 0x0a) // REJECTED
err = -EINVAL;
else if (buf[0] == 0x0b) // IN TRANSITION
err = -EAGAIN;
if (err < 0)
goto end;

*ch_count = buf[10];
err = 0;
end:
kfree(buf);
return err;
}

int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
u8 addr[AVC_BRIDGECO_ADDR_BYTES],
u8 *buf, unsigned int len)
Expand Down
83 changes: 51 additions & 32 deletions sound/firewire/bebob/bebob_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,49 @@ static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_
return err;
}

static int detect_midi_ports(struct snd_bebob *bebob,
const struct snd_bebob_stream_formation *formats,
u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_dir plug_dir,
unsigned int plug_count, unsigned int *midi_ports)
{
int i;
int err = 0;

*midi_ports = 0;

/// Detect the number of available MIDI ports when packet has MIDI conformant data channel.
for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; ++i) {
if (formats[i].midi > 0)
break;
}
if (i >= SND_BEBOB_STRM_FMT_ENTRIES)
return 0;

for (i = 0; i < plug_count; ++i) {
enum avc_bridgeco_plug_type plug_type;
unsigned int ch_count;

avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_EXT, i);

err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to get type for external %d plug %d: %d\n",
plug_dir, i, err);
break;
} else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_MIDI) {
continue;
}

err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count);
if (err < 0)
break;
*midi_ports += ch_count;
}

return err;
}

static int
seek_msu_sync_input_plug(struct snd_bebob *bebob)
{
Expand Down Expand Up @@ -886,8 +929,6 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob)
{
const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
enum avc_bridgeco_plug_type type;
unsigned int i;
int err;

/* the number of plugs for isoc in/out, ext in/out */
Expand Down Expand Up @@ -918,37 +959,15 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob)
if (err < 0)
goto end;

/* count external input plugs for MIDI */
bebob->midi_input_ports = 0;
for (i = 0; i < plugs[2]; i++) {
avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
AVC_BRIDGECO_PLUG_UNIT_EXT, i);
err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to get type for external in plug %d: %d\n",
i, err);
goto end;
} else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
bebob->midi_input_ports++;
}
}
err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
plugs[2], &bebob->midi_input_ports);
if (err < 0)
goto end;

/* count external output plugs for MIDI */
bebob->midi_output_ports = 0;
for (i = 0; i < plugs[3]; i++) {
avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
AVC_BRIDGECO_PLUG_UNIT_EXT, i);
err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to get type for external out plug %d: %d\n",
i, err);
goto end;
} else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
bebob->midi_output_ports++;
}
}
err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
plugs[3], &bebob->midi_output_ports);
if (err < 0)
goto end;

/* for check source of clock later */
if (!clk_spec)
Expand Down

0 comments on commit 5c6ea94

Please sign in to comment.