[alsa-devel] [RFC][PATCH 00/17 v2] ALSA: oxfw: refactoring and merging scs1x module
Hi,
This patchset update my previous post for merging ALSA scs1x module to oxfw module: [alsa-devel] [RFC][PATCH 0/9] ALSA: oxfw: merge scs1x module http://mailman.alsa-project.org/pipermail/alsa-devel/2015-November/100534.ht...
This patchset consists of three parts: * 01-05: code refactoring for OXFW module * 06-09: code refactoring for old firewire-speaker functionalities in OXFW module * 10-17: merge scs1x module
Changes: * split some patches for a fine granularity * drop a small framework I proposed in previous patch * rename functions for AV/C Audio Subunit command
After this patchset is applied, OXFW module is loaded instead of scs1x module. Then, some names except for rawmidi ID are changed, see patch 16. Currently, I find no advantage to keep them what they were. I'm welcome to receive your oppositions about it.
Takashi Sakamoto (17): ALSA: oxfw: rename a file for control elements so that it's for model-specific ALSA: oxfw: rename local functions for control elements so that they represent as local ALSA: oxfw: change function prototype for AV/C Audio Subunit command ALSA: oxfw: reuse driver entry to detect quirk ALSA: oxfw: gather model-dependent conditions to a function ALSA: oxfw: add memory allocation for model-specific structure ALSA: oxfw: move model-specific members from common structure ALSA: oxfw: move model-specific parameters from common structure ALSA: oxfw: rename a structure so that it means backward compatibility to old drivers ALSA: oxfw: add scs1x layer ALSA: oxfw: allocate own address region for SCS.1 series ALSA: oxfw: copy handlers of asynchronous transaction for MIDI capture ALSA: oxfw: add MIDI capture port for SCS.1 models ALSA: oxfw: copy handlers of asynchronous transaction for MIDI playback ALSA: oxfw: add MIDI playback port for SCS.1 models ALSA: oxfw: obsolete scs1x module ALSA: oxfw: add stream format quirk for SCS.1 models
sound/firewire/Kconfig | 12 +- sound/firewire/Makefile | 2 - sound/firewire/oxfw/Makefile | 4 +- sound/firewire/oxfw/oxfw-scs1x.c | 409 +++++++++++++++++++++ .../firewire/oxfw/{oxfw-control.c => oxfw-spkr.c} | 142 ++++--- sound/firewire/oxfw/oxfw.c | 110 ++++-- sound/firewire/oxfw/oxfw.h | 23 +- 7 files changed, 586 insertions(+), 116 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-scs1x.c rename sound/firewire/oxfw/{oxfw-control.c => oxfw-spkr.c} (55%)
In ALSA firewire stack, drivers basically has no control elements. This is due to the fact that each model has own functionality even if they use the same communication chipset. Implementing all of the functionalities in kernel space unreasonably increases our efforts to maintain the stack. In most case, these functionalities can be implemented in userspace via Linux fw character devices.
However, ALSA OXFW driver has control elements comes from old firewire-speakers driver. Adding the elements is in a file names as 'oxfw-control.c', while the elements are really model-specific. The name is confusing because it gives an idea to handle control elements for all of OXFW-based models.
This commit renames the file so that it's just for models supported by old firewire-speakers driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/Makefile | 4 ++-- sound/firewire/oxfw/{oxfw-control.c => oxfw-spkr.c} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename sound/firewire/oxfw/{oxfw-control.c => oxfw-spkr.c} (99%)
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 06ff50f..4e54ba9 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,3 +1,3 @@ -snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \ - oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o +snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \ + oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw.o obj-$(CONFIG_SND_OXFW) += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-spkr.c similarity index 99% rename from sound/firewire/oxfw/oxfw-control.c rename to sound/firewire/oxfw/oxfw-spkr.c index 02a1cb9..22d8536 100644 --- a/sound/firewire/oxfw/oxfw-control.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -1,5 +1,5 @@ /* - * oxfw_stream.c - a part of driver for OXFW970/971 based devices + * oxfw-spkr.c - a part of driver for OXFW970/971 based devices * * Copyright (c) Clemens Ladisch clemens@ladisch.de * Licensed under the terms of the GNU General Public License, version 2.
This commit renames local functions with prefix 'spkr_', so that they're for firewire-speakers.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-spkr.c | 40 ++++++++++++++++++++-------------------- sound/firewire/oxfw/oxfw.c | 2 +- sound/firewire/oxfw/oxfw.h | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index 22d8536..fde6b76 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -14,7 +14,7 @@ enum control_attribute { CTL_CURRENT = 0x10, };
-static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, +static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, enum control_action action) { u8 *buf; @@ -70,7 +70,7 @@ error: return err; }
-static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, +static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, unsigned int channel, enum control_attribute attribute, enum control_action action) @@ -131,7 +131,7 @@ error: return err; }
-static int oxfw_mute_get(struct snd_kcontrol *control, +static int spkr_mute_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -141,7 +141,7 @@ static int oxfw_mute_get(struct snd_kcontrol *control, return 0; }
-static int oxfw_mute_put(struct snd_kcontrol *control, +static int spkr_mute_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -153,7 +153,7 @@ static int oxfw_mute_put(struct snd_kcontrol *control, if (mute == oxfw->mute) return 0;
- err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + err = spkr_mute_command(oxfw, &mute, CTL_WRITE); if (err < 0) return err; oxfw->mute = mute; @@ -161,7 +161,7 @@ static int oxfw_mute_put(struct snd_kcontrol *control, return 1; }
-static int oxfw_volume_info(struct snd_kcontrol *control, +static int spkr_volume_info(struct snd_kcontrol *control, struct snd_ctl_elem_info *info) { struct snd_oxfw *oxfw = control->private_data; @@ -176,7 +176,7 @@ static int oxfw_volume_info(struct snd_kcontrol *control,
static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
-static int oxfw_volume_get(struct snd_kcontrol *control, +static int spkr_volume_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -188,7 +188,7 @@ static int oxfw_volume_get(struct snd_kcontrol *control, return 0; }
-static int oxfw_volume_put(struct snd_kcontrol *control, +static int spkr_volume_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -218,7 +218,7 @@ static int oxfw_volume_put(struct snd_kcontrol *control, for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, + err = spkr_volume_command(oxfw, &volume, i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; @@ -230,44 +230,44 @@ static int oxfw_volume_put(struct snd_kcontrol *control, return changed_channels != 0; }
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) { static const struct snd_kcontrol_new controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, + .get = spkr_mute_get, + .put = spkr_mute_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, + .info = spkr_volume_info, + .get = spkr_volume_get, + .put = spkr_volume_put, }, }; unsigned int i, first_ch; int err;
- err = oxfw_volume_command(oxfw, &oxfw->volume_min, + err = spkr_volume_command(oxfw, &oxfw->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, + err = spkr_volume_command(oxfw, &oxfw->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err;
- err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + err = spkr_mute_command(oxfw, &oxfw->mute, CTL_READ); if (err < 0) return err;
first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); + err = spkr_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 588b93f..0304d45 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -205,7 +205,7 @@ static int oxfw_probe(struct fw_unit *unit, goto error;
if (oxfw->device_info) { - err = snd_oxfw_create_mixer(oxfw); + err = snd_oxfw_add_spkr(oxfw); if (err < 0) goto error; } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 8392c42..9efdc02 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -138,10 +138,10 @@ void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw);
int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw); - void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); + +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw);
ALSA OXFW driver uses AV/C Audio Subunit commands to control some models. The commands get/set the state of Feature function block of the subunit. The commands are not specific to OXFW, thus there's a possibility to use them in the other drivers.
Currently, helper functions for the commands require 'struct snd_oxfw', although, it's necessarily required. It's better to change prototype of the functions without the structure for future use.
This commit changes the prototype.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-spkr.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index fde6b76..d733a15 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -14,8 +14,8 @@ enum control_attribute { CTL_CURRENT = 0x10, };
-static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) +static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value, + enum control_action action) { u8 *buf; u8 response_ok; @@ -35,7 +35,7 @@ static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = 0x10; /* control attribute: current */ buf[6] = 0x02; /* selector length */ buf[7] = 0x00; /* audio channel number */ @@ -46,16 +46,16 @@ static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, else buf[10] = *value ? 0x70 : 0x60;
- err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe); if (err < 0) goto error; if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); + dev_err(&unit->device, "mute command failed\n"); err = -EIO; goto error; } @@ -70,10 +70,10 @@ error: return err; }
-static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) +static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) { u8 *buf; u8 response_ok; @@ -93,7 +93,7 @@ static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = attribute; /* control attribute */ buf[6] = 0x02; /* selector length */ buf[7] = channel; /* audio channel number */ @@ -107,16 +107,16 @@ static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[11] = *value; }
- err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe); if (err < 0) goto error; if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); + dev_err(&unit->device, "volume command failed\n"); err = -EIO; goto error; } @@ -153,7 +153,8 @@ static int spkr_mute_put(struct snd_kcontrol *control, if (mute == oxfw->mute) return 0;
- err = spkr_mute_command(oxfw, &mute, CTL_WRITE); + err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, + &mute, CTL_WRITE); if (err < 0) return err; oxfw->mute = mute; @@ -218,8 +219,10 @@ static int spkr_volume_put(struct snd_kcontrol *control, for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { - err = spkr_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->mute_fb_id, + &volume, + i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; } @@ -251,22 +254,27 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) unsigned int i, first_ch; int err;
- err = spkr_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = spkr_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err;
- err = spkr_mute_command(oxfw, &oxfw->mute, CTL_READ); + err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, + &oxfw->mute, CTL_READ); if (err < 0) return err;
first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = spkr_volume_command(oxfw, &oxfw->volume[i], + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume[i], first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err;
Currently, assignment to model-dependent quirk is corresponding to asynchronous transactions on IEEE 1394 bus. This is also achieved with device entry.
This commit changes the processing of model-dependent quirk with the entry. As a result, the transactions are sent only for Loud models.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw.c | 38 ++++++++++++++++++++++---------------- sound/firewire/oxfw/oxfw.h | 2 ++ 2 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 0304d45..836d757 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -59,6 +59,7 @@ static bool detect_loud_models(struct fw_unit *unit) static int name_card(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); + const struct device_info *info; char vendor[24]; char model[32]; const char *d, *v, *m; @@ -84,10 +85,12 @@ static int name_card(struct snd_oxfw *oxfw) be32_to_cpus(&firmware);
/* to apply card definitions */ - if (oxfw->device_info) { - d = oxfw->device_info->driver_name; - v = oxfw->device_info->vendor_name; - m = oxfw->device_info->model_name; + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || + oxfw->entry->vendor_id == VENDOR_LACIE) { + info = (const struct device_info *)oxfw->entry->driver_data; + d = info->driver_name; + v = info->vendor_name; + m = info->model_name; } else { d = "OXFW"; v = vendor; @@ -139,6 +142,16 @@ static void detect_quirks(struct snd_oxfw *oxfw) int key, val; int vendor, model;
+ /* + * TASCAM FireOne has physical control and requires a pair of additional + * MIDI ports. + */ + if (oxfw->entry->vendor_id == VENDOR_TASCAM) { + oxfw->midi_input_ports++; + oxfw->midi_output_ports++; + return; + } + /* Seek from Root Directory of Config ROM. */ vendor = model = 0; fw_csr_iterator_init(&it, fw_dev->config_rom + 5); @@ -155,25 +168,16 @@ static void detect_quirks(struct snd_oxfw *oxfw) */ if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) oxfw->wrong_dbs = true; - - /* - * TASCAM FireOne has physical control and requires a pair of additional - * MIDI ports. - */ - if (vendor == VENDOR_TASCAM) { - oxfw->midi_input_ports++; - oxfw->midi_output_ports++; - } }
static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *id) + const struct ieee1394_device_id *entry) { struct snd_card *card; struct snd_oxfw *oxfw; int err;
- if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit)) + if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) return -ENODEV;
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, @@ -186,7 +190,7 @@ static int oxfw_probe(struct fw_unit *unit, oxfw->card = card; mutex_init(&oxfw->mutex); oxfw->unit = fw_unit_get(unit); - oxfw->device_info = (const struct device_info *)id->driver_data; + oxfw->entry = entry; spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait);
@@ -205,6 +209,8 @@ static int oxfw_probe(struct fw_unit *unit, goto error;
if (oxfw->device_info) { + oxfw->device_info = + (const struct device_info *)entry->driver_data; err = snd_oxfw_add_spkr(oxfw); if (err < 0) goto error; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 9efdc02..f3e14ff 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -72,6 +72,8 @@ struct snd_oxfw { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + const struct ieee1394_device_id *entry; };
/*
Adding control elements is just for models supported by old firewire-speakers modules. Therefore, the processing should be in a function to handle model-dependent quirk.
This commit moves the codes to the function. As a result, the function should handle error state, thus this commit also changes prototype of the function.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 836d757..d4fb3c1 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -135,7 +135,7 @@ static void oxfw_card_free(struct snd_card *card) mutex_destroy(&oxfw->mutex); }
-static void detect_quirks(struct snd_oxfw *oxfw) +static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); struct fw_csr_iterator it; @@ -143,13 +143,24 @@ static void detect_quirks(struct snd_oxfw *oxfw) int vendor, model;
/* + * Add ALSA control elements for two models to keep compatibility to + * old firewire-speaker module. + */ + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || + oxfw->entry->vendor_id == VENDOR_LACIE) { + oxfw->device_info = + (const struct device_info *)oxfw->entry->driver_data; + return snd_oxfw_add_spkr(oxfw); + } + + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. */ if (oxfw->entry->vendor_id == VENDOR_TASCAM) { oxfw->midi_input_ports++; oxfw->midi_output_ports++; - return; + return 0; }
/* Seek from Root Directory of Config ROM. */ @@ -168,6 +179,8 @@ static void detect_quirks(struct snd_oxfw *oxfw) */ if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) oxfw->wrong_dbs = true; + + return 0; }
static int oxfw_probe(struct fw_unit *unit, @@ -198,7 +211,9 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error;
- detect_quirks(oxfw); + err = detect_quirks(oxfw); + if (err < 0) + goto error;
err = name_card(oxfw); if (err < 0) @@ -208,14 +223,6 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error;
- if (oxfw->device_info) { - oxfw->device_info = - (const struct device_info *)entry->driver_data; - err = snd_oxfw_add_spkr(oxfw); - if (err < 0) - goto error; - } - snd_oxfw_proc_init(oxfw);
err = snd_oxfw_create_midi(oxfw);
ALSA OXFW driver should have backward compatibility to old firewire-speakers driver. Additionally, in future commit, scs1x driver will be merged to it. It's nice to add a pointer to have a memory block for model-specific structures.
This commit adds a member to 'struct snd_oxfw' for this aim. Deallocation is done at freeing ALSA card structure.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw.c | 1 + sound/firewire/oxfw/oxfw.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index d4fb3c1..7e50a4f 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -132,6 +132,7 @@ static void oxfw_card_free(struct snd_card *card) kfree(oxfw->rx_stream_formats[i]); }
+ kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); }
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index f3e14ff..9625661 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -74,6 +74,7 @@ struct snd_oxfw { wait_queue_head_t hwdep_wait;
const struct ieee1394_device_id *entry; + void *spec; };
/*
Currently, 'struct snd_oxfw' has some members for models supported by old firewire-speakers driver, while these members are useless to the other models.
This commit allocates new memory block and moves these members to model-specific structure.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-spkr.c | 48 +++++++++++++++++++++++++++++------------ sound/firewire/oxfw/oxfw.h | 5 ----- 2 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index d733a15..fbdd432 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -7,6 +7,13 @@
#include "oxfw.h"
+struct fw_spkr { + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; +}; + enum control_action { CTL_READ, CTL_WRITE }; enum control_attribute { CTL_MIN = 0x02, @@ -135,8 +142,9 @@ static int spkr_mute_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec;
- value->value.integer.value[0] = !oxfw->mute; + value->value.integer.value[0] = !spkr->mute;
return 0; } @@ -145,19 +153,20 @@ static int spkr_mute_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; bool mute; int err;
mute = !value->value.integer.value[0];
- if (mute == oxfw->mute) + if (mute == spkr->mute) return 0;
err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, &mute, CTL_WRITE); if (err < 0) return err; - oxfw->mute = mute; + spkr->mute = mute;
return 1; } @@ -166,11 +175,12 @@ static int spkr_volume_info(struct snd_kcontrol *control, struct snd_ctl_elem_info *info) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec;
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; + info->value.integer.min = spkr->volume_min; + info->value.integer.max = spkr->volume_max;
return 0; } @@ -181,10 +191,11 @@ static int spkr_volume_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i;
for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + value->value.integer.value[channel_map[i]] = spkr->volume[i];
return 0; } @@ -193,14 +204,15 @@ static int spkr_volume_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i, changed_channels; bool equal_values = true; s16 volume; int err;
for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) + if (value->value.integer.value[i] < spkr->volume_min || + value->value.integer.value[i] > spkr->volume_max) return -EINVAL; if (value->value.integer.value[i] != value->value.integer.value[0]) @@ -210,7 +222,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, changed_channels = 0; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) + spkr->volume[i]) changed_channels |= 1 << (i + 1);
if (equal_values && changed_channels != 0) @@ -227,7 +239,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, return err; } if (i > 0) - oxfw->volume[i - 1] = volume; + spkr->volume[i - 1] = volume; }
return changed_channels != 0; @@ -251,22 +263,30 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) .put = spkr_volume_put, }, }; + struct fw_spkr *spkr; unsigned int i, first_ch; int err;
+ spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL); + if (spkr == NULL) + return -ENOMEM; + oxfw->spec = spkr; + err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume_min, 0, CTL_MIN, CTL_READ); + &spkr->volume_min, + 0, CTL_MIN, CTL_READ); if (err < 0) return err; err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume_max, 0, CTL_MAX, CTL_READ); + &spkr->volume_max, + 0, CTL_MAX, CTL_READ); if (err < 0) return err;
err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &oxfw->mute, CTL_READ); + &spkr->mute, CTL_READ); if (err < 0) return err;
@@ -274,7 +294,7 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume[i], + &spkr->volume[i], first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 9625661..046cd33 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -64,11 +64,6 @@ struct snd_oxfw { unsigned int midi_input_ports; unsigned int midi_output_ports;
- bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; - int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait;
In previous commit, some members are moved from 'struct snd_oxfw' because they're model-specific. There are also the other model-specific parameters in 'struct device_info'.
This commit moves these members to model-specific structure.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-spkr.c | 60 +++++++++++++++++++++++------------------ sound/firewire/oxfw/oxfw.c | 16 +++-------- sound/firewire/oxfw/oxfw.h | 5 +--- 3 files changed, 39 insertions(+), 42 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index fbdd432..cb905af 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -12,6 +12,10 @@ struct fw_spkr { s16 volume[6]; s16 volume_min; s16 volume_max; + + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; };
enum control_action { CTL_READ, CTL_WRITE }; @@ -162,8 +166,8 @@ static int spkr_mute_put(struct snd_kcontrol *control, if (mute == spkr->mute) return 0;
- err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &mute, CTL_WRITE); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute, + CTL_WRITE); if (err < 0) return err; spkr->mute = mute; @@ -178,7 +182,7 @@ static int spkr_volume_info(struct snd_kcontrol *control, struct fw_spkr *spkr = oxfw->spec;
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; + info->count = spkr->mixer_channels; info->value.integer.min = spkr->volume_min; info->value.integer.max = spkr->volume_max;
@@ -194,7 +198,7 @@ static int spkr_volume_get(struct snd_kcontrol *control, struct fw_spkr *spkr = oxfw->spec; unsigned int i;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + for (i = 0; i < spkr->mixer_channels; ++i) value->value.integer.value[channel_map[i]] = spkr->volume[i];
return 0; @@ -210,7 +214,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, s16 volume; int err;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + for (i = 0; i < spkr->mixer_channels; ++i) { if (value->value.integer.value[i] < spkr->volume_min || value->value.integer.value[i] > spkr->volume_max) return -EINVAL; @@ -220,7 +224,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, }
changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + for (i = 0; i < spkr->mixer_channels; ++i) if (value->value.integer.value[channel_map[i]] != spkr->volume[i]) changed_channels |= 1 << (i + 1); @@ -228,12 +232,11 @@ static int spkr_volume_put(struct snd_kcontrol *control, if (equal_values && changed_channels != 0) changed_channels = 1 << 0;
- for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + for (i = 0; i <= spkr->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->mute_fb_id, - &volume, + spkr->volume_fb_id, &volume, i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; @@ -245,7 +248,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, return changed_channels != 0; }
-int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie) { static const struct snd_kcontrol_new controls[] = { { @@ -272,30 +275,35 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) return -ENOMEM; oxfw->spec = spkr;
- err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume_min, - 0, CTL_MIN, CTL_READ); + if (is_lacie) { + spkr->mixer_channels = 1; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x01; + } else { + spkr->mixer_channels = 6; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x02; + } + + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume_max, - 0, CTL_MAX, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err;
- err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &spkr->mute, CTL_READ); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute, + CTL_READ); if (err < 0) return err;
- first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); + first_ch = spkr->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < spkr->mixer_channels; ++i) { + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume[i], first_ch + i, + CTL_CURRENT, CTL_READ); if (err < 0) return err; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 7e50a4f..16ee6ea 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -147,12 +147,10 @@ static int detect_quirks(struct snd_oxfw *oxfw) * Add ALSA control elements for two models to keep compatibility to * old firewire-speaker module. */ - if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || - oxfw->entry->vendor_id == VENDOR_LACIE) { - oxfw->device_info = - (const struct device_info *)oxfw->entry->driver_data; - return snd_oxfw_add_spkr(oxfw); - } + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN) + return snd_oxfw_add_spkr(oxfw, false); + if (oxfw->entry->vendor_id == VENDOR_LACIE) + return snd_oxfw_add_spkr(oxfw, true);
/* * TASCAM FireOne has physical control and requires a pair of additional @@ -285,18 +283,12 @@ static const struct device_info griffin_firewave = { .driver_name = "FireWave", .vendor_name = "Griffin", .model_name = "FireWave", - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, };
static const struct device_info lacie_speakers = { .driver_name = "FWSpeakers", .vendor_name = "LaCie", .model_name = "FireWire Speakers", - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, };
static const struct ieee1394_device_id oxfw_id_table[] = { diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 046cd33..6038150 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -35,9 +35,6 @@ struct device_info { const char *driver_name; const char *vendor_name; const char *model_name; - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; };
/* This is an arbitrary number for convinience. */ @@ -142,4 +139,4 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
-int snd_oxfw_add_spkr(struct snd_oxfw *oxfw); +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie);
In former commits, some model-specific members are split from the structure. The structure is just to keep old names for compatibility to old drivers.
This commit arranges name of the structure and moves it to localize.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw.c | 14 ++++++++++---- sound/firewire/oxfw/oxfw.h | 6 ------ 2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 16ee6ea..96fbb78 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -30,6 +30,12 @@ MODULE_AUTHOR("Clemens Ladisch clemens@ladisch.de"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers");
+struct compat_info { + const char *driver_name; + const char *vendor_name; + const char *model_name; +}; + static bool detect_loud_models(struct fw_unit *unit) { const char *const models[] = { @@ -59,7 +65,7 @@ static bool detect_loud_models(struct fw_unit *unit) static int name_card(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); - const struct device_info *info; + const struct compat_info *info; char vendor[24]; char model[32]; const char *d, *v, *m; @@ -87,7 +93,7 @@ static int name_card(struct snd_oxfw *oxfw) /* to apply card definitions */ if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || oxfw->entry->vendor_id == VENDOR_LACIE) { - info = (const struct device_info *)oxfw->entry->driver_data; + info = (const struct compat_info *)oxfw->entry->driver_data; d = info->driver_name; v = info->vendor_name; m = info->model_name; @@ -279,13 +285,13 @@ static void oxfw_remove(struct fw_unit *unit) snd_card_free_when_closed(oxfw->card); }
-static const struct device_info griffin_firewave = { +static const struct compat_info griffin_firewave = { .driver_name = "FireWave", .vendor_name = "Griffin", .model_name = "FireWave", };
-static const struct device_info lacie_speakers = { +static const struct compat_info lacie_speakers = { .driver_name = "FWSpeakers", .vendor_name = "LaCie", .model_name = "FireWire Speakers", diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 6038150..1c9844a 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -31,12 +31,6 @@ #include "../amdtp-am824.h" #include "../cmp.h"
-struct device_info { - const char *driver_name; - const char *vendor_name; - const char *model_name; -}; - /* This is an arbitrary number for convinience. */ #define SND_OXFW_STREAM_FORMAT_ENTRIES 10 struct snd_oxfw {
Stanton Controllers and Systems 1 (SCS.1) series is supported by ALSA scs1x driver. This driver just supports MIDI functionality. On the other hand, models in this series are based on OXFW971 and ALSA OXFW driver can support them.
SCS.1 series has MIDI functionality to control its surface state such as LED lighting. When operating physical knobs and faders, the models generate MIDI messages. These MIDI messages are transferred by asynchronous transactions. These transactions are really model-specific and ALSA OXFW driver requires the functionality so as scs1x module implements.
This commit adds scs1x layer as a preparation to merge scs1x driver to oxfw driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/Makefile | 2 +- sound/firewire/oxfw/oxfw-scs1x.c | 26 ++++++++++++++++++++++++++ sound/firewire/oxfw/oxfw.c | 4 ++-- sound/firewire/oxfw/oxfw.h | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-scs1x.c
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 4e54ba9..b474da7 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,3 +1,3 @@ snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \ - oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw.o + oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o obj-$(CONFIG_SND_OXFW) += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c new file mode 100644 index 0000000..34db0d0 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -0,0 +1,26 @@ +/* + * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch clemens@ladisch.de + * Copyright (c) 2015 Takashi Sakamoto o-takashi@sakamocchi.jp + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) +{ + struct snd_rawmidi *rmidi; + int err; + + /* Use unique name for backward compatibility to scs1x module. */ + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); + if (err < 0) + return err; + + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", oxfw->card->shortname); + + return err; +} diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 96fbb78..b20e496 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -216,11 +216,11 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error;
- err = detect_quirks(oxfw); + err = name_card(oxfw); if (err < 0) goto error;
- err = name_card(oxfw); + err = detect_quirks(oxfw); if (err < 0) goto error;
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 1c9844a..cbf00ee 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -134,3 +134,4 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw); int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw);
When physical controls on SCS.1 models are operated, the models transfer MIDI messages in asynchronous transactions on IEEE 1394 bus. The models have a register to have an address for the transactions, and drivers can register own address for this purpose.
This commit keeps a region of address, registers it and adds a handler for the transactions.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-scs1x.c | 69 +++++++++++++++++++++++++++++++++++++++- sound/firewire/oxfw/oxfw.h | 1 + 2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 34db0d0..4a2a7ff 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -9,18 +9,85 @@
#include "oxfw.h"
+#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct fw_scs1x { + struct fw_address_handler hss_handler; +}; + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int register_address(struct snd_oxfw *oxfw) +{ + struct fw_scs1x *scs = oxfw->spec; + __be64 data; + + data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | + scs->hss_handler.offset); + return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, &data, sizeof(data), 0); +} + +static void remove_scs1x(struct snd_rawmidi *rmidi) +{ + struct fw_scs1x *scs = rmidi->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); + scs->hss_handler.length = 0; +} + +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw) +{ + struct fw_scs1x *scs = oxfw->spec; + + if (scs->hss_handler.length > 0) + register_address(oxfw); +} + int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) { struct snd_rawmidi *rmidi; + struct fw_scs1x *scs; int err;
+ scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); + if (scs == NULL) + return -ENOMEM; + oxfw->spec = scs; + + /* Allocate own handler for imcoming asynchronous transaction. */ + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + return err; + + err = register_address(oxfw); + if (err < 0) + goto err_allocated; + /* Use unique name for backward compatibility to scs1x module. */ err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); if (err < 0) - return err; + goto err_allocated; + rmidi->private_data = scs; + rmidi->private_free = remove_scs1x;
snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname);
+ return 0; +err_allocated: + fw_core_remove_address_handler(&scs->hss_handler); return err; } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index cbf00ee..9beecc2 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -135,3 +135,4 @@ int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw); +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw);
This commit copies some functions of asynchronous transactions for MIDI capture, to merge scs1x module. The features of payload in asynchronous transaction are:
* System exclusive messages for SCS.1 are encoded without ID data. In this encoding scheme, 4 bits in LSB are available. The bits are squashed in payload byte. Thus, one payload byte transfers two MIDI messages. * The first byte of payload byte means: * 0x00: depending on second payload byte * 0xf9: including escaped system exclusive messages for SCS.1, up to 3 byte (= 6 MIDI messages) * the others: including MIDI 1.0 messages * the others: including escaped system exclusive messages for SCS.1, up to 64 bytes
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-scs1x.c | 83 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-)
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 4a2a7ff..4060bf0 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -11,18 +11,99 @@
#define HSS1394_ADDRESS 0xc007dedadadaULL #define HSS1394_MAX_PACKET_SIZE 64 +#define HSS1394_TAG_USER_DATA 0x00 #define HSS1394_TAG_CHANGE_ADDRESS 0xf1
struct fw_scs1x { struct fw_address_handler hss_handler; + u8 input_escape_count; + struct snd_rawmidi_substream *input; };
+static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void midi_input_byte(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, u8 byte) +{ + const u8 eox = 0xf7; + + if (scs->input_escape_count > 0) { + midi_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + midi_input_escaped_byte(stream, 0x00); + midi_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void midi_input_packet(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + const u8 eox = 0xf7; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 1; i < bytes; ++i) + midi_input_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + midi_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } +} + static void handle_hss(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, unsigned long long offset, void *data, size_t length, void *callback_data) { - fw_send_response(card, request, RCODE_COMPLETE); + struct fw_scs1x *scs = callback_data; + struct snd_rawmidi_substream *stream; + int rcode; + + if (offset != scs->hss_handler.offset) { + rcode = RCODE_ADDRESS_ERROR; + goto end; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + rcode = RCODE_TYPE_ERROR; + goto end; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + midi_input_packet(scs, stream, data, length); + } + + rcode = RCODE_COMPLETE; +end: + fw_send_response(card, request, rcode); }
static int register_address(struct snd_oxfw *oxfw)
This commit adds MIDI capture so that scs1x driver has.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-scs1x.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 4060bf0..807009f 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -106,6 +106,33 @@ end: fw_send_response(card, request, rcode); }
+static int midi_capture_open(struct snd_rawmidi_substream *stream) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + scs->input_escape_count = 0; + + return 0; +} + +static int midi_capture_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->input) = up ? stream : NULL; +} + +static struct snd_rawmidi_ops midi_capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, +}; + static int register_address(struct snd_oxfw *oxfw) { struct fw_scs1x *scs = oxfw->spec; @@ -158,7 +185,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) goto err_allocated;
/* Use unique name for backward compatibility to scs1x module. */ - err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 1, &rmidi); if (err < 0) goto err_allocated; rmidi->private_data = scs; @@ -167,6 +194,10 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname);
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &midi_capture_ops); + return 0; err_allocated: fw_core_remove_address_handler(&scs->hss_handler);
This commit copies some functions of asynchronous transactions for MIDI playback, to merge scs1x module. The features of payload in asynchronous transaction are the same as captured MIDI messages.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-scs1x.c | 161 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+)
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 807009f..94477a5 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -18,6 +18,20 @@ struct fw_scs1x { struct fw_address_handler hss_handler; u8 input_escape_count; struct snd_rawmidi_substream *input; + + /* For MIDI playback. */ + struct snd_rawmidi_substream *output; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 buffer[HSS1394_MAX_PACKET_SIZE]; + bool transaction_running; + struct fw_transaction transaction; + struct fw_device *fw_dev; };
static const u8 sysex_escape_prefix[] = { @@ -106,6 +120,148 @@ end: fw_send_response(card, request, rcode); }
+static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct fw_scs1x *scs = callback_data; + + if (rcode == RCODE_GENERATION) + ; /* TODO: retry this packet */ + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct fw_scs1x *scs = (struct fw_scs1x *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status( + scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != + HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + generation = scs->fw_dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(scs->fw_dev->card, &scs->transaction, + TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id, + generation, scs->fw_dev->max_speed, HSS1394_ADDRESS, + scs->buffer, i, scs_write_callback, scs); +} + static int midi_capture_open(struct snd_rawmidi_substream *stream) { struct fw_scs1x *scs = stream->rmidi->private_data; @@ -169,6 +325,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); if (scs == NULL) return -ENOMEM; + scs->fw_dev = fw_parent_device(oxfw->unit); oxfw->spec = scs;
/* Allocate own handler for imcoming asynchronous transaction. */ @@ -198,6 +355,10 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &midi_capture_ops);
+ tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + return 0; err_allocated: fw_core_remove_address_handler(&scs->hss_handler);
This commit adds MIDI playback ports so that scs1x driver has.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-scs1x.c | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 94477a5..e755451 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -289,6 +289,45 @@ static struct snd_rawmidi_ops midi_capture_ops = { .trigger = midi_capture_trigger, };
+static int midi_playback_open(struct snd_rawmidi_substream *stream) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + + return 0; +} + +static int midi_playback_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->output) = up ? stream : NULL; + if (up) { + scs->output_idle = false; + tasklet_schedule(&scs->tasklet); + } +} +static void midi_playback_drain(struct snd_rawmidi_substream *stream) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + .drain = midi_playback_drain, +}; static int register_address(struct snd_oxfw *oxfw) { struct fw_scs1x *scs = oxfw->spec; @@ -342,7 +381,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) goto err_allocated;
/* Use unique name for backward compatibility to scs1x module. */ - err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 1, &rmidi); + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi); if (err < 0) goto err_allocated; rmidi->private_data = scs; @@ -351,9 +390,13 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname);
- rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT; + rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &midi_capture_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &midi_playback_ops);
tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); init_waitqueue_head(&scs->idle_wait);
Now ALSA oxfw driver gains functionalities which scs1x module has.
This commit obsoletes the scs1x module, and adds a line of MODULE_ALIAS to load oxfw module instead of scs1x module.
In scs1x module, the name of 'shortname' field is fixed as 'SCS1x'. This field is used to name MIDI ports for both of SCS.1m and SCS.1d. This is not good because typically some SCS.1m and SCS.1d are used in the same system. It's better to distinguish them according to name of the ports. This commit applies model name in config ROM to the 'shortname'.
For the name of 'driver' and 'longname', this commit uses the same way applied to the other models. This change may not bring disadvantages to users because userspace applications use ALSA rawmidi or seq interface and these interfaces are not influenced by them directly.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/Kconfig | 12 +----------- sound/firewire/Makefile | 2 -- sound/firewire/oxfw/oxfw.c | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index e92a6d9..2a779c2 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -39,6 +39,7 @@ config SND_OXFW * Mackie(Loud) d.2 pro/d.4 pro * Mackie(Loud) U.420/U.420d * TASCAM FireOne + * Stanton Controllers & Systems 1 Deck/Mixer
To compile this driver as a module, choose M here: the module will be called snd-oxfw. @@ -53,17 +54,6 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight.
-config SND_SCS1X - tristate "Stanton Control System 1 MIDI" - select SND_FIREWIRE_LIB - help - Say Y here to include support for the MIDI ports of the Stanton - SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled - by FFADO.) - - To compile this driver as a module, choose M here: the module - will be called snd-scs1x. - config SND_FIREWORKS tristate "Echo Fireworks board module support" select SND_FIREWIRE_LIB diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index f5fb625..003c090 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,13 +1,11 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp-stream.o amdtp-am824.o snd-isight-objs := isight.o -snd-scs1x-objs := scs1x.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_DICE) += dice/ obj-$(CONFIG_SND_OXFW) += oxfw/ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o -obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o obj-$(CONFIG_SND_FIREWORKS) += fireworks/ obj-$(CONFIG_SND_BEBOB) += bebob/ obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/ diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index b20e496..e7f2698 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -19,6 +19,7 @@ #define VENDOR_BEHRINGER 0x001564 #define VENDOR_LACIE 0x00d04b #define VENDOR_TASCAM 0x00022e +#define OUI_STANTON 0x001260
#define MODEL_SATELLITE 0x00200f
@@ -29,6 +30,7 @@ MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); MODULE_AUTHOR("Clemens Ladisch clemens@ladisch.de"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); +MODULE_ALIAS("snd-scs1x");
struct compat_info { const char *driver_name; @@ -159,6 +161,13 @@ static int detect_quirks(struct snd_oxfw *oxfw) return snd_oxfw_add_spkr(oxfw, true);
/* + * Stanton models supports asynchronous transactions for unique MIDI + * messages. + */ + if (oxfw->entry->vendor_id == OUI_STANTON) + return snd_oxfw_scs1x_add(oxfw); + + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. */ @@ -275,6 +284,9 @@ static void oxfw_bus_reset(struct fw_unit *unit) snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
mutex_unlock(&oxfw->mutex); + + if (oxfw->entry->vendor_id == OUI_STANTON) + snd_oxfw_scs1x_update(oxfw); }
static void oxfw_remove(struct fw_unit *unit) @@ -352,6 +364,20 @@ static const struct ieee1394_device_id oxfw_id_table[] = { .vendor_id = VENDOR_TASCAM, .model_id = 0x800007, }, + /* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x001000, + }, + /* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x002000, + }, { } }; MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
As long as I investigate SCS.1m, this model reports to transfer/receive PCM data channels/MIDI conformant data channels in tx/rx AMDTP packet. There's a contradiction that this model actually has no analog/digital capture port for PCM frames and no physical MIDI ports.
I guess that SCS.1d also has the contradiction. This model has no analog/digital ports for PCM frames and no physical MIDI ports, thus it requires no streaming functionality.
This commit adds some modification codes to handle the contradiction, as much as possible. Unfortunately, this module adds one PCM playback substream for SCS.1d so as SCS.1m.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index e7f2698..abedc22 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -164,8 +164,16 @@ static int detect_quirks(struct snd_oxfw *oxfw) * Stanton models supports asynchronous transactions for unique MIDI * messages. */ - if (oxfw->entry->vendor_id == OUI_STANTON) + if (oxfw->entry->vendor_id == OUI_STANTON) { + /* No physical MIDI ports. */ + oxfw->midi_input_ports = 0; + oxfw->midi_output_ports = 0; + + /* Output stream exists but no data channels are useful. */ + oxfw->has_output = false; + return snd_oxfw_scs1x_add(oxfw); + }
/* * TASCAM FireOne has physical control and requires a pair of additional
participants (1)
-
Takashi Sakamoto