Commit 3149ac48 authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: bebob: Add support for M-Audio special Firewire series

This commit allows this driver to support some models which M-Audio produces
with DM1000 but its firmware is special. They are:
 - Firewire 1814
 - ProjectMix I/O

They have heavily customized firmware. The usual operations can't be applied to
them. For this reason, this commit adds a model specific member to 'struct
snd_bebob' and some model specific functions. Some parameters are write-only so
this commit also adds control interface for applications to set them.

M-Audio special firmware quirks:
 - Just after powering on, they wait to download firmware. This state is
   changed when receiving cue. Then bus reset is generated and the device is
   recognized as a different model with the uploaded firmware.
 - They don't respond against BridgeCo AV/C extension commands. So drivers
   can't get their stream formations and so on.
 - They do not start to transmit packets only by establishing connection but
   also by receiving SIGNAL FORMAT command.
 - After booting up, they often fail to send response against driver's request
   due to mismatch of gap_count.

This module don't support to upload firmware.

Tested-by: Darren Anderson <darrena092@gmail.com> (ProjectMix I/O)
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 9076c22d
...@@ -115,6 +115,7 @@ config SND_BEBOB ...@@ -115,6 +115,7 @@ config SND_BEBOB
* Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO * Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO
* M-Audio Firewire410/AudioPhile/Solo * M-Audio Firewire410/AudioPhile/Solo
* M-Audio Ozonic/NRV10/ProfireLightBridge * M-Audio Ozonic/NRV10/ProfireLightBridge
* M-Audio Firewire 1814/ProjectMix IO
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called snd-bebob. will be called snd-bebob.
......
...@@ -60,6 +60,8 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); ...@@ -60,6 +60,8 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000 #define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000
#define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060 #define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060
#define MODEL_MAUDIO_FW1814 0x00010071
#define MODEL_MAUDIO_PROJECTMIX 0x00010091
static int static int
name_device(struct snd_bebob *bebob, unsigned int vendor_id) name_device(struct snd_bebob *bebob, unsigned int vendor_id)
...@@ -210,6 +212,13 @@ bebob_probe(struct fw_unit *unit, ...@@ -210,6 +212,13 @@ bebob_probe(struct fw_unit *unit,
if (err < 0) if (err < 0)
goto error; goto error;
if ((entry->vendor_id == VEN_MAUDIO1) &&
(entry->model_id == MODEL_MAUDIO_FW1814))
err = snd_bebob_maudio_special_discover(bebob, true);
else if ((entry->vendor_id == VEN_MAUDIO1) &&
(entry->model_id == MODEL_MAUDIO_PROJECTMIX))
err = snd_bebob_maudio_special_discover(bebob, false);
else
err = snd_bebob_stream_discover(bebob); err = snd_bebob_stream_discover(bebob);
if (err < 0) if (err < 0)
goto error; goto error;
...@@ -270,6 +279,8 @@ static void bebob_remove(struct fw_unit *unit) ...@@ -270,6 +279,8 @@ static void bebob_remove(struct fw_unit *unit)
if (bebob == NULL) if (bebob == NULL)
return; return;
kfree(bebob->maudio_special_quirk);
snd_bebob_stream_destroy_duplex(bebob); snd_bebob_stream_destroy_duplex(bebob);
snd_card_disconnect(bebob->card); snd_card_disconnect(bebob->card);
snd_card_free_when_closed(bebob->card); snd_card_free_when_closed(bebob->card);
...@@ -375,6 +386,12 @@ static const struct ieee1394_device_id bebob_id_table[] = { ...@@ -375,6 +386,12 @@ static const struct ieee1394_device_id bebob_id_table[] = {
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec), SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec),
/* M-Audio, ProFireLightbridge */ /* M-Audio, ProFireLightbridge */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal), SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal),
/* Firewire 1814 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814,
&maudio_special_spec),
/* M-Audio ProjectMix */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX,
&maudio_special_spec),
/* IDs are unknown but able to be supported */ /* IDs are unknown but able to be supported */
/* Apogee, Mini-ME Firewire */ /* Apogee, Mini-ME Firewire */
/* Apogee, Mini-DAC Firewire */ /* Apogee, Mini-DAC Firewire */
......
...@@ -106,6 +106,9 @@ struct snd_bebob { ...@@ -106,6 +106,9 @@ struct snd_bebob {
int dev_lock_count; int dev_lock_count;
bool dev_lock_changed; bool dev_lock_changed;
wait_queue_head_t hwdep_wait; wait_queue_head_t hwdep_wait;
/* for M-Audio special devices */
void *maudio_special_quirk;
}; };
static inline int static inline int
...@@ -237,6 +240,8 @@ extern struct snd_bebob_spec maudio_audiophile_spec; ...@@ -237,6 +240,8 @@ extern struct snd_bebob_spec maudio_audiophile_spec;
extern struct snd_bebob_spec maudio_solo_spec; extern struct snd_bebob_spec maudio_solo_spec;
extern struct snd_bebob_spec maudio_ozonic_spec; extern struct snd_bebob_spec maudio_ozonic_spec;
extern struct snd_bebob_spec maudio_nrv10_spec; extern struct snd_bebob_spec maudio_nrv10_spec;
extern struct snd_bebob_spec maudio_special_spec;
int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ #define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
{ \ { \
......
This diff is collapsed.
...@@ -389,6 +389,10 @@ break_both_connections(struct snd_bebob *bebob) ...@@ -389,6 +389,10 @@ break_both_connections(struct snd_bebob *bebob)
cmp_connection_break(&bebob->out_conn); cmp_connection_break(&bebob->out_conn);
bebob->connected = false; bebob->connected = false;
/* These models seems to be in transition state for a longer time. */
if (bebob->maudio_special_quirk != NULL)
msleep(200);
} }
static void static void
...@@ -421,9 +425,11 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream, ...@@ -421,9 +425,11 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream,
conn = &bebob->out_conn; conn = &bebob->out_conn;
/* channel mapping */ /* channel mapping */
if (bebob->maudio_special_quirk == NULL) {
err = map_data_channels(bebob, stream); err = map_data_channels(bebob, stream);
if (err < 0) if (err < 0)
goto end; goto end;
}
/* start amdtp stream */ /* start amdtp stream */
err = amdtp_stream_start(stream, err = amdtp_stream_start(stream,
...@@ -555,7 +561,10 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) ...@@ -555,7 +561,10 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate)
* NOTE: * NOTE:
* If establishing connections at first, Yamaha GO46 * If establishing connections at first, Yamaha GO46
* (and maybe Terratec X24) don't generate sound. * (and maybe Terratec X24) don't generate sound.
*
* For firmware customized by M-Audio, refer to next NOTE.
*/ */
if (bebob->maudio_special_quirk == NULL) {
err = rate_spec->set(bebob, rate); err = rate_spec->set(bebob, rate);
if (err < 0) { if (err < 0) {
dev_err(&bebob->unit->device, dev_err(&bebob->unit->device,
...@@ -563,6 +572,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) ...@@ -563,6 +572,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate)
err); err);
goto end; goto end;
} }
}
err = make_both_connections(bebob, rate); err = make_both_connections(bebob, rate);
if (err < 0) if (err < 0)
...@@ -576,6 +586,23 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) ...@@ -576,6 +586,23 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate)
goto end; goto end;
} }
/*
* NOTE:
* The firmware customized by M-Audio uses these commands to
* start transmitting stream. This is not usual way.
*/
if (bebob->maudio_special_quirk != NULL) {
err = rate_spec->set(bebob, rate);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to ensure sampling rate: %d\n",
err);
amdtp_stream_stop(master);
break_both_connections(bebob);
goto end;
}
}
/* wait first callback */ /* wait first callback */
if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) { if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) {
amdtp_stream_stop(master); amdtp_stream_stop(master);
......
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