diff options
Diffstat (limited to 'sound/firewire/dice')
-rw-r--r-- | sound/firewire/dice/dice-alesis.c | 26 | ||||
-rw-r--r-- | sound/firewire/dice/dice-extension.c | 5 | ||||
-rw-r--r-- | sound/firewire/dice/dice-midi.c | 2 | ||||
-rw-r--r-- | sound/firewire/dice/dice-pcm.c | 88 | ||||
-rw-r--r-- | sound/firewire/dice/dice-stream.c | 52 | ||||
-rw-r--r-- | sound/firewire/dice/dice.c | 8 | ||||
-rw-r--r-- | sound/firewire/dice/dice.h | 7 |
7 files changed, 141 insertions, 47 deletions
diff --git a/sound/firewire/dice/dice-alesis.c b/sound/firewire/dice/dice-alesis.c index 218292bdace6..0916864511d5 100644 --- a/sound/firewire/dice/dice-alesis.c +++ b/sound/firewire/dice/dice-alesis.c @@ -15,7 +15,7 @@ alesis_io14_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { static const unsigned int alesis_io26_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { - {10, 10, 8}, /* Tx0 = Analog + S/PDIF. */ + {10, 10, 4}, /* Tx0 = Analog + S/PDIF. */ {16, 8, 0}, /* Tx1 = ADAT1 + ADAT2. */ }; @@ -50,3 +50,27 @@ int snd_dice_detect_alesis_formats(struct snd_dice *dice) return 0; } + +int snd_dice_detect_alesis_mastercontrol_formats(struct snd_dice *dice) +{ + int i; + + dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_LOW] = 16; + dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_LOW] = 12; + dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_MIDDLE] = 12; + dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_MIDDLE] = 4; + dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_HIGH] = 8; + dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_HIGH] = 0; + + for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) { + dice->rx_pcm_chs[0][i] = 6; + dice->rx_pcm_chs[1][i] = 0; + } + + for (i = 0; i < MAX_STREAMS; ++i) { + dice->tx_midi_ports[i] = 2; + dice->rx_midi_ports[i] = 2; + } + + return 0; +} diff --git a/sound/firewire/dice/dice-extension.c b/sound/firewire/dice/dice-extension.c index a63fcbc875ad..02f4a8318e38 100644 --- a/sound/firewire/dice/dice-extension.c +++ b/sound/firewire/dice/dice-extension.c @@ -159,8 +159,11 @@ int snd_dice_detect_extension_formats(struct snd_dice *dice) int j; for (j = i + 1; j < 9; ++j) { - if (pointers[i * 2] == pointers[j * 2]) + if (pointers[i * 2] == pointers[j * 2]) { + // Fallback to limited functionality. + err = -ENXIO; goto end; + } } } diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index c9e19bddfc09..4c2998034313 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, 0); + err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0); if (err >= 0) { ++dice->substreams_counter; err = snd_dice_stream_start_duplex(dice); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 94a4dccfc381..af8a90ee40f3 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -164,13 +164,14 @@ static int init_hw_info(struct snd_dice *dice, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; + struct amdtp_domain *d = &dice->domain; unsigned int source; bool internal; int err; err = snd_dice_stream_lock_try(dice); if (err < 0) - goto end; + return err; err = init_hw_info(dice, substream); if (err < 0) @@ -195,27 +196,56 @@ static int pcm_open(struct snd_pcm_substream *substream) break; } - /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ + mutex_lock(&dice->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (!internal || - amdtp_stream_pcm_running(&dice->tx_stream[0]) || - amdtp_stream_pcm_running(&dice->tx_stream[1]) || - amdtp_stream_pcm_running(&dice->rx_stream[0]) || - amdtp_stream_pcm_running(&dice->rx_stream[1])) { + (dice->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int rate; err = snd_dice_transaction_get_rate(dice, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&dice->mutex); goto err_locked; + } + substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + // For double_pcm_frame quirk. + if (rate > 96000) { + frames_per_period *= 2; + frames_per_buffer *= 2; + } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&dice->mutex); + goto err_locked; + } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&dice->mutex); + goto err_locked; + } + } } + mutex_unlock(&dice->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_dice_stream_lock_release(dice); return err; @@ -234,18 +264,21 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; + int err = 0; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int events_per_period = params_period_size(hw_params); + unsigned int events_per_buffer = params_buffer_size(hw_params); mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, rate); + // For double_pcm_frame quirk. + if (rate > 96000) { + events_per_period /= 2; + events_per_buffer /= 2; + } + err = snd_dice_stream_reserve_duplex(dice, rate, + events_per_period, events_per_buffer); if (err >= 0) ++dice->substreams_counter; mutex_unlock(&dice->mutex); @@ -267,7 +300,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&dice->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return 0; } static int capture_prepare(struct snd_pcm_substream *substream) @@ -341,14 +374,14 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; - return amdtp_stream_pcm_pointer(stream); + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); } static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; - return amdtp_stream_pcm_pointer(stream); + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); } static int capture_ack(struct snd_pcm_substream *substream) @@ -356,7 +389,7 @@ static int capture_ack(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; - return amdtp_stream_pcm_ack(stream); + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); } static int playback_ack(struct snd_pcm_substream *substream) @@ -364,7 +397,7 @@ static int playback_ack(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; - return amdtp_stream_pcm_ack(stream); + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); } int snd_dice_create_pcm(struct snd_dice *dice) @@ -372,26 +405,22 @@ int snd_dice_create_pcm(struct snd_dice *dice) static const struct snd_pcm_ops capture_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = capture_prepare, .trigger = capture_trigger, .pointer = capture_pointer, .ack = capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = playback_prepare, .trigger = playback_trigger, .pointer = playback_pointer, .ack = playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; unsigned int capture, playback; @@ -421,6 +450,9 @@ int snd_dice_create_pcm(struct snd_dice *dice) if (playback > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); } return 0; diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index a9f0c77734c3..8e0c0380b4c4 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -154,14 +154,10 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, for (i = 0; i < params->count; i++) { reg = cpu_to_be32((u32)-1); if (dir == AMDTP_IN_STREAM) { - amdtp_stream_stop(&dice->tx_stream[i]); - snd_dice_transaction_write_tx(dice, params->size * i + TX_ISOCHRONOUS, ®, sizeof(reg)); } else { - amdtp_stream_stop(&dice->rx_stream[i]); - snd_dice_transaction_write_rx(dice, params->size * i + RX_ISOCHRONOUS, ®, sizeof(reg)); @@ -228,7 +224,6 @@ static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, struct amdtp_stream *stream; struct fw_iso_resources *resources; unsigned int pcm_cache; - unsigned int midi_cache; unsigned int pcm_chs; unsigned int midi_ports; @@ -237,7 +232,6 @@ static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, resources = &dice->tx_resources[i]; pcm_cache = dice->tx_pcm_chs[i][mode]; - midi_cache = dice->tx_midi_ports[i]; err = snd_dice_transaction_read_tx(dice, params->size * i + TX_NUMBER_AUDIO, reg, sizeof(reg)); @@ -246,7 +240,6 @@ static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, resources = &dice->rx_resources[i]; pcm_cache = dice->rx_pcm_chs[i][mode]; - midi_cache = dice->rx_midi_ports[i]; err = snd_dice_transaction_read_rx(dice, params->size * i + RX_NUMBER_AUDIO, reg, sizeof(reg)); @@ -257,10 +250,10 @@ static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, midi_ports = be32_to_cpu(reg[1]); // These are important for developer of this driver. - if (pcm_chs != pcm_cache || midi_ports != midi_cache) { + if (pcm_chs != pcm_cache) { dev_info(&dice->unit->device, - "cache mismatch: pcm: %u:%u, midi: %u:%u\n", - pcm_chs, pcm_cache, midi_ports, midi_cache); + "cache mismatch: pcm: %u:%u, midi: %u\n", + pcm_chs, pcm_cache, midi_ports); return -EPROTO; } @@ -282,7 +275,9 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, snd_dice_transaction_clear_enable(dice); } -int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period, + unsigned int events_per_buffer) { unsigned int curr_rate; int err; @@ -297,10 +292,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) if (dice->substreams_counter == 0 || curr_rate != rate) { struct reg_params tx_params, rx_params; + amdtp_domain_stop(&dice->domain); + err = get_register_params(dice, &tx_params, &rx_params); if (err < 0) return err; - finish_session(dice, &tx_params, &rx_params); release_resources(dice); @@ -327,6 +323,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) &rx_params); if (err < 0) goto error; + + err = amdtp_domain_set_events_per_period(&dice->domain, + events_per_period, events_per_buffer); + if (err < 0) + goto error; } return 0; @@ -377,7 +378,8 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return err; } - err = amdtp_stream_start(stream, resources->channel, max_speed); + err = amdtp_domain_add_stream(&dice->domain, stream, + resources->channel, max_speed); if (err < 0) return err; } @@ -410,6 +412,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) for (i = 0; i < MAX_STREAMS; ++i) { if (amdtp_streaming_error(&dice->tx_stream[i]) || amdtp_streaming_error(&dice->rx_stream[i])) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); break; } @@ -456,6 +459,10 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; } + err = amdtp_domain_start(&dice->domain, 0); + if (err < 0) + goto error; + for (i = 0; i < MAX_STREAMS; i++) { if ((i < tx_params.count && !amdtp_stream_wait_callback(&dice->tx_stream[i], @@ -471,6 +478,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) return 0; error: + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); return err; } @@ -485,8 +493,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) struct reg_params tx_params, rx_params; if (dice->substreams_counter == 0) { - if (get_register_params(dice, &tx_params, &rx_params) >= 0) + if (get_register_params(dice, &tx_params, &rx_params) >= 0) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); + } release_resources(dice); } @@ -564,7 +574,15 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) destroy_stream(dice, AMDTP_OUT_STREAM, i); for (i = 0; i < MAX_STREAMS; i++) destroy_stream(dice, AMDTP_IN_STREAM, i); - break; + goto end; + } + } + + err = amdtp_domain_init(&dice->domain); + if (err < 0) { + for (i = 0; i < MAX_STREAMS; ++i) { + destroy_stream(dice, AMDTP_OUT_STREAM, i); + destroy_stream(dice, AMDTP_IN_STREAM, i); } } end: @@ -579,6 +597,8 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) destroy_stream(dice, AMDTP_IN_STREAM, i); destroy_stream(dice, AMDTP_OUT_STREAM, i); } + + amdtp_domain_destroy(&dice->domain); } void snd_dice_stream_update_duplex(struct snd_dice *dice) @@ -596,6 +616,8 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice) dice->global_enabled = false; if (get_register_params(dice, &tx_params, &rx_params) == 0) { + amdtp_domain_stop(&dice->domain); + stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); } diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 13eeb3f52bb6..06c94f009dfb 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -355,6 +355,14 @@ static const struct ieee1394_device_id dice_id_table[] = { .model_id = MODEL_ALESIS_IO_BOTH, .driver_data = (kernel_ulong_t)snd_dice_detect_alesis_formats, }, + // Alesis MasterControl. + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_ALESIS, + .model_id = 0x000002, + .driver_data = (kernel_ulong_t)snd_dice_detect_alesis_mastercontrol_formats, + }, /* Mytek Stereo 192 DSD-DAC. */ { .match_flags = IEEE1394_MATCH_VENDOR_ID | diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index c6304e5e9fc4..7fbffcab94c2 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -112,6 +112,8 @@ struct snd_dice { bool global_enabled; struct completion clock_accepted; unsigned int substreams_counter; + + struct amdtp_domain domain; }; enum snd_dice_addr_type { @@ -208,7 +210,9 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice); void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); -int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate); +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period, + unsigned int events_per_buffer); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice); @@ -225,6 +229,7 @@ int snd_dice_create_midi(struct snd_dice *dice); int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice); int snd_dice_detect_alesis_formats(struct snd_dice *dice); +int snd_dice_detect_alesis_mastercontrol_formats(struct snd_dice *dice); int snd_dice_detect_extension_formats(struct snd_dice *dice); int snd_dice_detect_mytek_formats(struct snd_dice *dice); int snd_dice_detect_presonus_formats(struct snd_dice *dice); |