diff options
Diffstat (limited to 'sound/firewire/oxfw')
-rw-r--r-- | sound/firewire/oxfw/oxfw-hwdep.c | 12 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw-pcm.c | 8 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw-stream.c | 67 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.c | 283 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.h | 29 |
5 files changed, 201 insertions, 198 deletions
diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c index eba33d050060..a0fe99618554 100644 --- a/sound/firewire/oxfw/oxfw-hwdep.c +++ b/sound/firewire/oxfw/oxfw-hwdep.c @@ -35,13 +35,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, } memset(&event, 0, sizeof(event)); - if (oxfw->dev_lock_changed) { - event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; - event.lock_status.status = (oxfw->dev_lock_count > 0); - oxfw->dev_lock_changed = false; + event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; + event.lock_status.status = (oxfw->dev_lock_count > 0); + oxfw->dev_lock_changed = false; - count = min_t(long, count, sizeof(event.lock_status)); - } + count = min_t(long, count, sizeof(event.lock_status)); spin_unlock_irq(&oxfw->lock); @@ -79,7 +77,7 @@ static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg) info.card = dev->card->index; *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); - strlcpy(info.device_name, dev_name(&dev->device), + strscpy(info.device_name, dev_name(&dev->device), sizeof(info.device_name)); if (copy_to_user(arg, &info, sizeof(info))) diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 2dfa7e179cb6..5f43a0b826d2 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -239,7 +239,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); @@ -262,7 +262,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); @@ -286,7 +286,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); @@ -301,7 +301,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 80c9dc13f1b5..f4a702def397 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -9,7 +9,7 @@ #include <linux/delay.h> #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512 -#define CALLBACK_TIMEOUT 200 +#define READY_TIMEOUT_MS 600 /* * According to datasheet of Oxford Semiconductor: @@ -153,12 +153,30 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) struct cmp_connection *conn; enum cmp_direction c_dir; enum amdtp_stream_direction s_dir; + unsigned int flags = 0; int err; + if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION)) + flags |= CIP_NONBLOCKING; + else + flags |= CIP_BLOCKING; + + // OXFW 970/971 has no function to generate playback timing according to the sequence + // of value in syt field, thus the packet should include NO_INFO value in the field. + // However, some models just ignore data blocks in packet with NO_INFO for audio data + // processing. + if (!(oxfw->quirks & SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET)) + flags |= CIP_UNAWARE_SYT; + if (stream == &oxfw->tx_stream) { conn = &oxfw->out_conn; c_dir = CMP_OUTPUT; s_dir = AMDTP_IN_STREAM; + + if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) + flags |= CIP_JUMBO_PAYLOAD; + if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS) + flags |= CIP_WRONG_DBS; } else { conn = &oxfw->in_conn; c_dir = CMP_INPUT; @@ -169,24 +187,12 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) if (err < 0) return err; - err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); + err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags); if (err < 0) { cmp_connection_destroy(conn); return err; } - /* - * OXFW starts to transmit packets with non-zero dbc. - * OXFW postpone transferring packets till handling any asynchronous - * packets. As a result, next isochronous packet includes more data - * blocks than IEC 61883-6 defines. - */ - if (stream == &oxfw->tx_stream) { - oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD; - if (oxfw->wrong_dbs) - oxfw->tx_stream.flags |= CIP_WRONG_DBS; - } - return 0; } @@ -338,6 +344,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) } if (!amdtp_stream_running(&oxfw->rx_stream)) { + unsigned int tx_init_skip_cycles = 0; + bool replay_seq = false; + err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { dev_err(&oxfw->unit->device, @@ -353,26 +362,32 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) "fail to prepare tx stream: %d\n", err); goto error; } + + if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) { + // Just after changing sampling transfer frequency, many cycles are + // skipped for packet transmission. + tx_init_skip_cycles = 400; + } else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) { + // It takes a bit time for target device to adjust event frequency + // according to nominal event frequency in isochronous packets from + // ALSA oxfw driver. + tx_init_skip_cycles = 4000; + } else { + replay_seq = true; + } } - err = amdtp_domain_start(&oxfw->domain, 0); + // NOTE: The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false); if (err < 0) goto error; - // Wait first packet. - if (!amdtp_stream_wait_callback(&oxfw->rx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } - - if (oxfw->has_output) { - if (!amdtp_stream_wait_callback(&oxfw->tx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; - goto error; - } - } } return 0; diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 1f1e3236efb8..b496f87841ae 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -23,6 +23,9 @@ #define OUI_APOGEE 0x0003db #define MODEL_SATELLITE 0x00200f +#define MODEL_SCS1M 0x001000 +#define MODEL_DUET_FW 0x01dddd +#define MODEL_ONYX_1640I 0x001640 #define SPECIFIER_1394TA 0x00a02d #define VERSION_AVC 0x010001 @@ -46,8 +49,6 @@ static bool detect_loud_models(struct fw_unit *unit) "Onyx-i", "Onyx 1640i", "d.Pro", - "Mackie Onyx Satellite", - "Tapco LINK.firewire 4x6", "U.420"}; char model[32]; int err; @@ -60,7 +61,7 @@ static bool detect_loud_models(struct fw_unit *unit) return match_string(models, ARRAY_SIZE(models), model) >= 0; } -static int name_card(struct snd_oxfw *oxfw) +static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); const struct compat_info *info; @@ -88,10 +89,12 @@ static int name_card(struct snd_oxfw *oxfw) goto end; be32_to_cpus(&firmware); + if (firmware >> 20 == 0x970) + oxfw->quirks |= SND_OXFW_QUIRK_JUMBO_PAYLOAD; + /* to apply card definitions */ - if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || - oxfw->entry->vendor_id == VENDOR_LACIE) { - info = (const struct compat_info *)oxfw->entry->driver_data; + if (entry->vendor_id == VENDOR_GRIFFIN || entry->vendor_id == VENDOR_LACIE) { + info = (const struct compat_info *)entry->driver_data; d = info->driver_name; v = info->vendor_name; m = info->model_name; @@ -120,9 +123,12 @@ static void oxfw_card_free(struct snd_card *card) if (oxfw->has_output || oxfw->has_input) snd_oxfw_stream_destroy_duplex(oxfw); + + mutex_destroy(&oxfw->mutex); + fw_unit_put(oxfw->unit); } -static int detect_quirks(struct snd_oxfw *oxfw) +static int detect_quirks(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); struct fw_csr_iterator it; @@ -133,28 +139,37 @@ 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) + if (entry->vendor_id == VENDOR_GRIFFIN) return snd_oxfw_add_spkr(oxfw, false); - if (oxfw->entry->vendor_id == VENDOR_LACIE) + if (entry->vendor_id == VENDOR_LACIE) return snd_oxfw_add_spkr(oxfw, true); /* * Stanton models supports asynchronous transactions for unique MIDI * messages. */ - if (oxfw->entry->vendor_id == OUI_STANTON) { - /* No physical MIDI ports. */ + if (entry->vendor_id == OUI_STANTON) { + oxfw->quirks |= SND_OXFW_QUIRK_SCS_TRANSACTION; + if (entry->model_id == MODEL_SCS1M) + oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION; + + // No physical MIDI ports. oxfw->midi_input_ports = 0; oxfw->midi_output_ports = 0; return snd_oxfw_scs1x_add(oxfw); } + if (entry->vendor_id == OUI_APOGEE && entry->model_id == MODEL_DUET_FW) { + oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION | + SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET; + } + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. */ - if (oxfw->entry->vendor_id == VENDOR_TASCAM) { + if (entry->vendor_id == VENDOR_TASCAM) { oxfw->midi_input_ports++; oxfw->midi_output_ports++; return 0; @@ -170,32 +185,50 @@ static int detect_quirks(struct snd_oxfw *oxfw) model = val; } - /* - * Mackie Onyx Satellite with base station has a quirk to report a wrong - * value in 'dbs' field of CIP header against its format information. - */ - if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) - oxfw->wrong_dbs = true; + if (vendor == VENDOR_LOUD) { + // Mackie Onyx Satellite with base station has a quirk to report a wrong + // value in 'dbs' field of CIP header against its format information. + oxfw->quirks |= SND_OXFW_QUIRK_WRONG_DBS; + + // OXFW971-based models may transfer events by blocking method. + if (!(oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD)) + oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION; + + if (model == MODEL_ONYX_1640I) { + //Unless receiving packets without NOINFO packet, the device transfers + //mostly half of events in packets than expected. + oxfw->quirks |= SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET | + SND_OXFW_QUIRK_VOLUNTARY_RECOVERY; + } + } return 0; } -static void do_registration(struct work_struct *work) +static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); + struct snd_card *card; + struct snd_oxfw *oxfw; int err; - if (oxfw->registered) - return; + if (entry->vendor_id == VENDOR_LOUD && entry->model_id == 0 && !detect_loud_models(unit)) + return -ENODEV; - err = snd_card_new(&oxfw->unit->device, -1, NULL, THIS_MODULE, 0, - &oxfw->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*oxfw), &card); if (err < 0) - return; - oxfw->card->private_free = oxfw_card_free; - oxfw->card->private_data = oxfw; + return err; + card->private_free = oxfw_card_free; - err = name_card(oxfw); + oxfw = card->private_data; + oxfw->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, oxfw); + oxfw->card = card; + + mutex_init(&oxfw->mutex); + spin_lock_init(&oxfw->lock); + init_waitqueue_head(&oxfw->hwdep_wait); + + err = name_card(oxfw, entry); if (err < 0) goto error; @@ -203,7 +236,7 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = detect_quirks(oxfw); + err = detect_quirks(oxfw, entry); if (err < 0) goto error; @@ -227,85 +260,38 @@ static void do_registration(struct work_struct *work) goto error; } - err = snd_card_register(oxfw->card); + err = snd_card_register(card); if (err < 0) goto error; - oxfw->registered = true; - - return; -error: - snd_card_free(oxfw->card); - dev_info(&oxfw->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_oxfw *oxfw; - - if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) - return -ENODEV; - - /* Allocate this independent of sound card instance. */ - oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL); - if (!oxfw) - return -ENOMEM; - oxfw->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, oxfw); - - oxfw->entry = entry; - mutex_init(&oxfw->mutex); - spin_lock_init(&oxfw->lock); - init_waitqueue_head(&oxfw->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&oxfw->dwork, do_registration); - snd_fw_schedule_registration(unit, &oxfw->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void oxfw_bus_reset(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - if (!oxfw->registered) - snd_fw_schedule_registration(unit, &oxfw->dwork); - fcp_bus_reset(oxfw->unit); - if (oxfw->registered) { - if (oxfw->has_output || oxfw->has_input) { - mutex_lock(&oxfw->mutex); - snd_oxfw_stream_update_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - } - - if (oxfw->entry->vendor_id == OUI_STANTON) - snd_oxfw_scs1x_update(oxfw); + if (oxfw->has_output || oxfw->has_input) { + mutex_lock(&oxfw->mutex); + snd_oxfw_stream_update_duplex(oxfw); + mutex_unlock(&oxfw->mutex); } + + if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION) + snd_oxfw_scs1x_update(oxfw); } static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&oxfw->dwork); - - if (oxfw->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(oxfw->card); - } - - mutex_destroy(&oxfw->mutex); - fw_unit_put(oxfw->unit); + // Block till all of ALSA character devices are released. + snd_card_free(oxfw->card); } static const struct compat_info griffin_firewave = { @@ -320,82 +306,67 @@ static const struct compat_info lacie_speakers = { .model_name = "FireWire Speakers", }; +#define OXFW_DEV_ENTRY(vendor, model, data) \ +{ \ + .match_flags = IEEE1394_MATCH_VENDOR_ID | \ + IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | \ + IEEE1394_MATCH_VERSION, \ + .vendor_id = vendor, \ + .model_id = model, \ + .specifier_id = SPECIFIER_1394TA, \ + .version = VERSION_AVC, \ + .driver_data = (kernel_ulong_t)data, \ +} + static const struct ieee1394_device_id oxfw_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_GRIFFIN, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&griffin_firewave, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_LACIE, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&lacie_speakers, - }, - /* Behringer,F-Control Audio 202 */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = VENDOR_BEHRINGER, - .model_id = 0x00fc22, - }, - /* - * Any Mackie(Loud) models (name string/model id): - * Onyx-i series (former models): 0x081216 - * Mackie Onyx Satellite: 0x00200f - * Tapco LINK.firewire 4x6: 0x000460 - * d.2 pro: Unknown - * d.4 pro: Unknown - * U.420: Unknown - * U.420d: Unknown - */ + // + // OXFW970 devices: + // Initial firmware has a quirk to postpone isoc packet transmission during finishing async + // transaction. As a result, several isochronous cycles are skipped to transfer the packets + // and the audio data frames which should have been transferred during the cycles are put + // into packet at the first isoc cycle after the postpone. Furthermore, the value of SYT + // field in CIP header is not reliable as synchronization timing, + // + OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave), + OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers), + // Behringer,F-Control Audio 202. The value of SYT field is not reliable at all. + OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL), + // Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff. + OXFW_DEV_ENTRY(VENDOR_LOUD, 0x000460, NULL), + // Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is + // installed to avoid the postpone, the value of SYT field is always 0xffff. + OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL), + // Miglia HarmonyAudio. Not yet identified. + + // + // OXFW971 devices: + // The value of SYT field in CIP header is enough reliable. Both of blocking and non-blocking + // transmission methods are available. + // + // Any Mackie(Loud) models (name string/model id): + // Onyx-i series (former models): 0x081216 + // Onyx 1640i: 0x001640 + // d.2 pro/d.4 pro (built-in card): Unknown + // U.420: Unknown + // U.420d: Unknown { .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .vendor_id = VENDOR_LOUD, + .model_id = 0, .specifier_id = SPECIFIER_1394TA, .version = VERSION_AVC, }, - /* TASCAM, FireOne */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .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, - }, - // APOGEE, duet FireWire - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_APOGEE, - .model_id = 0x01dddd, - }, + // TASCAM, FireOne. + OXFW_DEV_ENTRY(VENDOR_TASCAM, 0x800007, NULL), + // Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m). + OXFW_DEV_ENTRY(OUI_STANTON, MODEL_SCS1M, NULL), + // Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d). + OXFW_DEV_ENTRY(OUI_STANTON, 0x002000, NULL), + // APOGEE, duet FireWire. + OXFW_DEV_ENTRY(OUI_APOGEE, MODEL_DUET_FW, NULL), { } }; MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index fa2d7f9e2dc3..d728e451a25c 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -32,6 +32,28 @@ #include "../amdtp-am824.h" #include "../cmp.h" +enum snd_oxfw_quirk { + // Postpone transferring packets during handling asynchronous transaction. As a result, + // next isochronous packet includes more events than one packet can include. + SND_OXFW_QUIRK_JUMBO_PAYLOAD = 0x01, + // The dbs field of CIP header in tx packet is wrong. + SND_OXFW_QUIRK_WRONG_DBS = 0x02, + // Blocking transmission mode is used. + SND_OXFW_QUIRK_BLOCKING_TRANSMISSION = 0x04, + // Stanton SCS1.d and SCS1.m support unique transaction. + SND_OXFW_QUIRK_SCS_TRANSACTION = 0x08, + // Apogee Duet FireWire ignores data blocks in packet with NO_INFO for audio data + // processing, while output level meter moves. Any value in syt field of packet takes + // the device to process audio data even if the value is invalid in a point of + // IEC 61883-1/6. + SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET = 0x10, + // Loud Technologies Mackie Onyx 1640i seems to configure OXFW971 ASIC so that it decides + // event frequency according to events in received isochronous packets. The device looks to + // performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO + // are ignored, thus driver should transfer packets with timestamp. + SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20, +}; + /* This is an arbitrary number for convinience. */ #define SND_OXFW_STREAM_FORMAT_ENTRIES 10 struct snd_oxfw { @@ -40,10 +62,8 @@ struct snd_oxfw { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - - bool wrong_dbs; + // The combination of snd_oxfw_quirk enumeration-constants. + unsigned int quirks; bool has_output; bool has_input; u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES]; @@ -62,7 +82,6 @@ struct snd_oxfw { bool dev_lock_changed; wait_queue_head_t hwdep_wait; - const struct ieee1394_device_id *entry; void *spec; struct amdtp_domain domain; |