Merge branch 'for-next'

This commit is contained in:
Takashi Iwai 2019-10-18 04:37:11 +02:00
commit 641c197a39
32 changed files with 266 additions and 85 deletions

View File

@ -52,10 +52,6 @@
#define CIP_FMT_AM 0x10
#define AMDTP_FDF_NO_DATA 0xff
/* TODO: make these configurable */
#define INTERRUPT_INTERVAL 16
#define QUEUE_LENGTH 48
// For iso header, tstamp and 2 CIP header.
#define IR_CTX_HEADER_SIZE_CIP 16
// For iso header and tstamp.
@ -180,6 +176,8 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
struct snd_pcm_runtime *runtime)
{
struct snd_pcm_hardware *hw = &runtime->hw;
unsigned int ctx_header_size;
unsigned int maximum_usec_per_period;
int err;
hw->info = SNDRV_PCM_INFO_BATCH |
@ -200,19 +198,36 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
hw->period_bytes_max = hw->period_bytes_min * 2048;
hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
/*
* Currently firewire-lib processes 16 packets in one software
* interrupt callback. This equals to 2msec but actually the
* interval of the interrupts has a jitter.
* Additionally, even if adding a constraint to fit period size to
* 2msec, actual calculated frames per period doesn't equal to 2msec,
* depending on sampling rate.
* Anyway, the interval to call snd_pcm_period_elapsed() cannot 2msec.
* Here let us use 5msec for safe period interrupt.
*/
// Linux driver for 1394 OHCI controller voluntarily flushes isoc
// context when total size of accumulated context header reaches
// PAGE_SIZE. This kicks tasklet for the isoc context and brings
// callback in the middle of scheduled interrupts.
// Although AMDTP streams in the same domain use the same events per
// IRQ, use the largest size of context header between IT/IR contexts.
// Here, use the value of context header in IR context is for both
// contexts.
if (!(s->flags & CIP_NO_HEADER))
ctx_header_size = IR_CTX_HEADER_SIZE_CIP;
else
ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP;
maximum_usec_per_period = USEC_PER_SEC * PAGE_SIZE /
CYCLES_PER_SECOND / ctx_header_size;
// In IEC 61883-6, one isoc packet can transfer events up to the value
// of syt interval. This comes from the interval of isoc cycle. As 1394
// OHCI controller can generate hardware IRQ per isoc packet, the
// interval is 125 usec.
// However, there are two ways of transmission in IEC 61883-6; blocking
// and non-blocking modes. In blocking mode, the sequence of isoc packet
// includes 'empty' or 'NODATA' packets which include no event. In
// non-blocking mode, the number of events per packet is variable up to
// the syt interval.
// Due to the above protocol design, the minimum PCM frames per
// interrupt should be double of the value of syt interval, thus it is
// 250 usec.
err = snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
5000, UINT_MAX);
250, maximum_usec_per_period);
if (err < 0)
goto end;
@ -436,11 +451,12 @@ static void pcm_period_tasklet(unsigned long data)
snd_pcm_period_elapsed(pcm);
}
static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params,
bool sched_irq)
{
int err;
params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
params->interrupt = sched_irq;
params->tag = s->tag;
params->sy = 0;
@ -451,28 +467,28 @@ static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
goto end;
}
if (++s->packet_index >= QUEUE_LENGTH)
if (++s->packet_index >= s->queue_size)
s->packet_index = 0;
end:
return err;
}
static inline int queue_out_packet(struct amdtp_stream *s,
struct fw_iso_packet *params)
struct fw_iso_packet *params, bool sched_irq)
{
params->skip =
!!(params->header_length == 0 && params->payload_length == 0);
return queue_packet(s, params);
return queue_packet(s, params, sched_irq);
}
static inline int queue_in_packet(struct amdtp_stream *s,
struct fw_iso_packet *params)
struct fw_iso_packet *params, bool sched_irq)
{
// Queue one packet for IR context.
params->header_length = s->ctx_data.tx.ctx_header_size;
params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
params->skip = false;
return queue_packet(s, params);
return queue_packet(s, params, sched_irq);
}
static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
@ -669,13 +685,14 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
}
// Align to actual cycle count for the packet which is going to be scheduled.
// This module queued the same number of isochronous cycle as QUEUE_LENGTH to
// skip isochronous cycle, therefore it's OK to just increment the cycle by
// QUEUE_LENGTH for scheduled cycle.
static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp)
// This module queued the same number of isochronous cycle as the size of queue
// to kip isochronous cycle, therefore it's OK to just increment the cycle by
// the size of queue for scheduled cycle.
static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp,
unsigned int queue_size)
{
u32 cycle = compute_cycle_count(ctx_header_tstamp);
return increment_cycle_count(cycle, QUEUE_LENGTH);
return increment_cycle_count(cycle, queue_size);
}
static int generate_device_pkt_descs(struct amdtp_stream *s,
@ -689,7 +706,7 @@ static int generate_device_pkt_descs(struct amdtp_stream *s,
for (i = 0; i < packets; ++i) {
struct pkt_desc *desc = descs + i;
unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
unsigned int index = (s->packet_index + i) % s->queue_size;
unsigned int cycle;
unsigned int payload_length;
unsigned int data_blocks;
@ -730,9 +747,9 @@ static void generate_ideal_pkt_descs(struct amdtp_stream *s,
for (i = 0; i < packets; ++i) {
struct pkt_desc *desc = descs + i;
unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
unsigned int index = (s->packet_index + i) % s->queue_size;
desc->cycle = compute_it_cycle(*ctx_header);
desc->cycle = compute_it_cycle(*ctx_header, s->queue_size);
desc->syt = calculate_syt(s, desc->cycle);
desc->data_blocks = calculate_data_blocks(s, desc->syt);
@ -779,12 +796,17 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
{
struct amdtp_stream *s = private_data;
const __be32 *ctx_header = header;
unsigned int packets = header_length / sizeof(*ctx_header);
unsigned int events_per_period = s->events_per_period;
unsigned int event_count = s->event_count;
unsigned int packets;
int i;
if (s->packet_index < 0)
return;
// Calculate the number of packets in buffer and check XRUN.
packets = header_length / sizeof(*ctx_header);
generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets);
process_ctx_payloads(s, s->pkt_descs, packets);
@ -796,6 +818,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
struct fw_iso_packet params;
__be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)];
} template = { {0}, {0} };
bool sched_irq = false;
if (s->ctx_data.rx.syt_override < 0)
syt = desc->syt;
@ -806,12 +829,20 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
desc->data_blocks, desc->data_block_counter,
syt, i);
if (queue_out_packet(s, &template.params) < 0) {
event_count += desc->data_blocks;
if (event_count >= events_per_period) {
event_count -= events_per_period;
sched_irq = true;
}
if (queue_out_packet(s, &template.params, sched_irq) < 0) {
cancel_stream(s);
return;
}
}
s->event_count = event_count;
fw_iso_context_queue_flush(s->context);
}
@ -820,15 +851,17 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
void *private_data)
{
struct amdtp_stream *s = private_data;
unsigned int packets;
__be32 *ctx_header = header;
unsigned int events_per_period = s->events_per_period;
unsigned int event_count = s->event_count;
unsigned int packets;
int i;
int err;
if (s->packet_index < 0)
return;
// The number of packets in buffer.
// Calculate the number of packets in buffer and check XRUN.
packets = header_length / s->ctx_data.tx.ctx_header_size;
err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets);
@ -842,14 +875,29 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
}
for (i = 0; i < packets; ++i) {
const struct pkt_desc *desc = s->pkt_descs + i;
struct fw_iso_packet params = {0};
bool sched_irq = false;
if (queue_in_packet(s, &params) < 0) {
if (err >= 0) {
event_count += desc->data_blocks;
if (event_count >= events_per_period) {
event_count -= events_per_period;
sched_irq = true;
}
} else {
sched_irq =
!((s->packet_index + 1) % s->idle_irq_interval);
}
if (queue_in_packet(s, &params, sched_irq) < 0) {
cancel_stream(s);
return;
}
}
s->event_count = event_count;
fw_iso_context_queue_flush(s->context);
}
@ -874,7 +922,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
context->callback.sc = in_stream_callback;
} else {
cycle = compute_it_cycle(*ctx_header);
cycle = compute_it_cycle(*ctx_header, s->queue_size);
context->callback.sc = out_stream_callback;
}
@ -894,7 +942,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
* amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
* device can be started.
*/
static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
struct amdtp_domain *d)
{
static const struct {
unsigned int data_block;
@ -908,6 +957,8 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
[CIP_SFC_88200] = { 0, 67 },
[CIP_SFC_176400] = { 0, 67 },
};
unsigned int events_per_buffer = d->events_per_buffer;
unsigned int events_per_period = d->events_per_period;
unsigned int ctx_header_size;
unsigned int max_ctx_payload_size;
enum dma_data_direction dir;
@ -953,7 +1004,23 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
}
err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
// This is a case that AMDTP streams in domain run just for MIDI
// substream. Use the number of events equivalent to 10 msec as
// interval of hardware IRQ.
if (events_per_period == 0)
events_per_period = amdtp_rate_table[s->sfc] / 100;
if (events_per_buffer == 0)
events_per_buffer = events_per_period * 3;
s->idle_irq_interval =
DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period,
amdtp_rate_table[s->sfc]);
s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
amdtp_rate_table[s->sfc]);
s->events_per_period = events_per_period;
s->event_count = 0;
err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size,
max_ctx_payload_size, dir);
if (err < 0)
goto err_unlock;
@ -981,7 +1048,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
else
s->tag = TAG_CIP;
s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs),
s->pkt_descs = kcalloc(s->queue_size, sizeof(*s->pkt_descs),
GFP_KERNEL);
if (!s->pkt_descs) {
err = -ENOMEM;
@ -991,12 +1058,15 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
s->packet_index = 0;
do {
struct fw_iso_packet params;
bool sched_irq;
sched_irq = !((s->packet_index + 1) % s->idle_irq_interval);
if (s->direction == AMDTP_IN_STREAM) {
err = queue_in_packet(s, &params);
err = queue_in_packet(s, &params, sched_irq);
} else {
params.header_length = 0;
params.payload_length = 0;
err = queue_out_packet(s, &params);
err = queue_out_packet(s, &params, sched_irq);
}
if (err < 0)
goto err_pkt_descs;
@ -1196,7 +1266,7 @@ int amdtp_domain_start(struct amdtp_domain *d)
int err = 0;
list_for_each_entry(s, &d->streams, list) {
err = amdtp_stream_start(s, s->channel, s->speed);
err = amdtp_stream_start(s, s->channel, s->speed, d);
if (err < 0)
break;
}

View File

@ -117,6 +117,7 @@ struct amdtp_stream {
/* For packet processing. */
struct fw_iso_context *context;
struct iso_packets_buffer buffer;
unsigned int queue_size;
int packet_index;
struct pkt_desc *pkt_descs;
int tag;
@ -144,6 +145,9 @@ struct amdtp_stream {
int syt_override;
} rx;
} ctx_data;
unsigned int event_count;
unsigned int events_per_period;
unsigned int idle_irq_interval;
/* For CIP headers. */
unsigned int source_node_id_field;
@ -274,6 +278,7 @@ struct amdtp_domain {
struct list_head streams;
unsigned int events_per_period;
unsigned int events_per_buffer;
};
int amdtp_domain_init(struct amdtp_domain *d);
@ -286,9 +291,11 @@ int amdtp_domain_start(struct amdtp_domain *d);
void amdtp_domain_stop(struct amdtp_domain *d);
static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
unsigned int events_per_period)
unsigned int events_per_period,
unsigned int events_per_buffer)
{
d->events_per_period = events_per_period;
d->events_per_buffer = events_per_buffer;
return 0;
}

View File

@ -218,7 +218,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
int snd_bebob_stream_discover(struct snd_bebob *bebob);
int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);

View File

@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
return err;
mutex_lock(&bebob->mutex);
err = snd_bebob_stream_reserve_duplex(bebob, 0, 0);
err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
if (err >= 0) {
++bebob->substreams_counter;
err = snd_bebob_stream_start_duplex(bebob);

View File

@ -157,6 +157,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
(bebob->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 sampling_rate;
err = spec->get(bebob, &sampling_rate);
@ -178,6 +179,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&bebob->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(&bebob->mutex);
goto err_locked;
}
}
}
@ -213,10 +222,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&bebob->mutex);
err = snd_bebob_stream_reserve_duplex(bebob, rate,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err >= 0)
++bebob->substreams_counter;
mutex_unlock(&bebob->mutex);

View File

@ -555,7 +555,8 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
}
int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
int err;
@ -610,7 +611,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
}
err = amdtp_domain_set_events_per_period(&bebob->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
cmp_connection_release(&bebob->out_conn);
cmp_connection_release(&bebob->in_conn);

View File

@ -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, 0);
err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0);
if (err >= 0) {
++dice->substreams_counter;
err = snd_dice_stream_start_duplex(dice);

View File

@ -204,6 +204,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (!internal ||
(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);
@ -217,8 +218,10 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (frames_per_period > 0) {
// For double_pcm_frame quirk.
if (rate > 96000)
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,
@ -227,6 +230,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
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;
}
}
}
@ -263,13 +274,16 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
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);
// For double_pcm_frame quirk.
if (rate > 96000)
if (rate > 96000) {
events_per_period /= 2;
events_per_buffer /= 2;
}
err = snd_dice_stream_reserve_duplex(dice, rate,
events_per_period);
events_per_period, events_per_buffer);
if (err >= 0)
++dice->substreams_counter;
mutex_unlock(&dice->mutex);

View File

@ -279,7 +279,8 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
}
int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
unsigned int events_per_period)
unsigned int events_per_period,
unsigned int events_per_buffer)
{
unsigned int curr_rate;
int err;
@ -327,7 +328,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
goto error;
err = amdtp_domain_set_events_per_period(&dice->domain,
events_per_period);
events_per_period, events_per_buffer);
if (err < 0)
goto error;
}

View File

@ -211,7 +211,8 @@ 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,
unsigned int events_per_period);
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);

View File

@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
return err;
mutex_lock(&dg00x->mutex);
err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0);
err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
if (err >= 0) {
++dg00x->substreams_counter;
err = snd_dg00x_stream_start_duplex(dg00x);

View File

@ -135,6 +135,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
(dg00x->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_dg00x_stream_get_external_rate(dg00x, &rate);
@ -153,6 +154,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&dg00x->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(&dg00x->mutex);
goto err_locked;
}
}
}
@ -189,10 +198,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&dg00x->mutex);
err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err >= 0)
++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);

View File

@ -284,7 +284,8 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
}
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
int err;
@ -318,7 +319,7 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
}
err = amdtp_domain_set_events_per_period(&dg00x->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
fw_iso_resources_free(&dg00x->rx_resources);
fw_iso_resources_free(&dg00x->tx_resources);

View File

@ -142,7 +142,8 @@ int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
bool *detect);
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);

View File

@ -180,6 +180,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
} else {
if (ff->substreams_counter > 0) {
unsigned int frames_per_period = d->events_per_period;
unsigned int frames_per_buffer = d->events_per_buffer;
rate = amdtp_rate_table[ff->rx_stream.sfc];
substream->runtime->hw.rate_min = rate;
@ -192,6 +193,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&ff->mutex);
goto release_lock;
}
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(&ff->mutex);
goto release_lock;
}
}
}
@ -229,9 +238,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&ff->mutex);
err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period);
err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
frames_per_buffer);
if (err >= 0)
++ff->substreams_counter;
mutex_unlock(&ff->mutex);

View File

@ -107,7 +107,8 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
}
int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
enum snd_ff_clock_src src;
@ -153,7 +154,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
return err;
err = amdtp_domain_set_events_per_period(&ff->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
fw_iso_resources_free(&ff->tx_resources);
fw_iso_resources_free(&ff->rx_resources);

View File

@ -140,7 +140,8 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
int snd_ff_stream_init_duplex(struct snd_ff *ff);
void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
void snd_ff_stream_stop_duplex(struct snd_ff *ff);
void snd_ff_stream_update_duplex(struct snd_ff *ff);

View File

@ -208,7 +208,8 @@ int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
int snd_efw_stream_init_duplex(struct snd_efw *efw);
int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_efw_stream_start_duplex(struct snd_efw *efw);
void snd_efw_stream_stop_duplex(struct snd_efw *efw);
void snd_efw_stream_update_duplex(struct snd_efw *efw);

View File

@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
goto end;
mutex_lock(&efw->mutex);
err = snd_efw_stream_reserve_duplex(efw, 0, 0);
err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0);
if (err >= 0) {
++efw->substreams_counter;
err = snd_efw_stream_start_duplex(efw);

View File

@ -197,6 +197,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||
(efw->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 sampling_rate;
err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);
@ -215,6 +216,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&efw->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(&efw->mutex);
goto err_locked;
}
}
}
@ -249,10 +258,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&efw->mutex);
err = snd_efw_stream_reserve_duplex(efw, rate,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err >= 0)
++efw->substreams_counter;
mutex_unlock(&efw->mutex);

View File

@ -182,7 +182,8 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
}
int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
int err;
@ -231,7 +232,7 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
}
err = amdtp_domain_set_events_per_period(&efw->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
cmp_connection_release(&efw->in_conn);
cmp_connection_release(&efw->out_conn);

View File

@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
mutex_lock(&motu->mutex);
err = snd_motu_stream_reserve_duplex(motu, 0, 0);
err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
if (err >= 0) {
++motu->substreams_counter;
err = snd_motu_stream_start_duplex(motu);

View File

@ -162,6 +162,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL ||
(motu->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 = protocol->get_clock_rate(motu, &rate);
@ -179,6 +180,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&motu->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(&motu->mutex);
goto err_locked;
}
}
}
@ -216,10 +225,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&motu->mutex);
err = snd_motu_stream_reserve_duplex(motu, rate,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err >= 0)
++motu->substreams_counter;
mutex_unlock(&motu->mutex);

View File

@ -134,7 +134,8 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
}
int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
int err;
@ -174,7 +175,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
}
err = amdtp_domain_set_events_per_period(&motu->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
fw_iso_resources_free(&motu->tx_resources);
fw_iso_resources_free(&motu->rx_resources);

View File

@ -155,7 +155,8 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu);
void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
int snd_motu_stream_cache_packet_formats(struct snd_motu *motu);
int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_motu_stream_start_duplex(struct snd_motu *motu);
void snd_motu_stream_stop_duplex(struct snd_motu *motu);
int snd_motu_stream_lock_try(struct snd_motu *motu);

View File

@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
if (err >= 0) {
++oxfw->substreams_count;
err = snd_oxfw_stream_start_duplex(oxfw);
@ -45,7 +45,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
if (err >= 0) {
++oxfw->substreams_count;
err = snd_oxfw_stream_start_duplex(oxfw);

View File

@ -188,6 +188,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
// at current one.
if (oxfw->substreams_count > 0 && d->events_per_period > 0) {
unsigned int frames_per_period = d->events_per_period;
unsigned int frames_per_buffer = d->events_per_buffer;
err = limit_to_current_params(substream);
if (err < 0) {
@ -203,6 +204,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&oxfw->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(&oxfw->mutex);
goto err_locked;
}
}
}
@ -239,10 +248,12 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
unsigned int rate = params_rate(hw_params);
unsigned int channels = params_channels(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
rate, channels, frames_per_period);
rate, channels, frames_per_period,
frames_per_buffer);
if (err >= 0)
++oxfw->substreams_count;
mutex_unlock(&oxfw->mutex);
@ -265,10 +276,12 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
unsigned int rate = params_rate(hw_params);
unsigned int channels = params_channels(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
rate, channels, frames_per_period);
rate, channels, frames_per_period,
frames_per_buffer);
if (err >= 0)
++oxfw->substreams_count;
mutex_unlock(&oxfw->mutex);

View File

@ -245,7 +245,8 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
struct amdtp_stream *stream,
unsigned int rate, unsigned int pcm_channels,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
struct snd_oxfw_stream_formation formation;
enum avc_general_plug_dir dir;
@ -308,7 +309,7 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
}
err = amdtp_domain_set_events_per_period(&oxfw->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
cmp_connection_release(&oxfw->in_conn);
if (oxfw->has_output)

View File

@ -104,7 +104,8 @@ int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw);
int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
struct amdtp_stream *stream,
unsigned int rate, unsigned int pcm_channels,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw);
void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw);
void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw);

View File

@ -66,6 +66,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
// at current one.
if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) {
unsigned int frames_per_period = d->events_per_period;
unsigned int frames_per_buffer = d->events_per_buffer;
unsigned int rate;
err = snd_tscm_stream_get_rate(tscm, &rate);
@ -83,6 +84,14 @@ static int pcm_open(struct snd_pcm_substream *substream)
mutex_unlock(&tscm->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(&tscm->mutex);
goto err_locked;
}
}
mutex_unlock(&tscm->mutex);
@ -118,10 +127,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
mutex_lock(&tscm->mutex);
err = snd_tscm_stream_reserve_duplex(tscm, rate,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err >= 0)
++tscm->substreams_counter;
mutex_unlock(&tscm->mutex);

View File

@ -384,7 +384,8 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
}
int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
unsigned int frames_per_period)
unsigned int frames_per_period,
unsigned int frames_per_buffer)
{
unsigned int curr_rate;
int err;
@ -416,7 +417,7 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
}
err = amdtp_domain_set_events_per_period(&tscm->domain,
frames_per_period);
frames_per_period, frames_per_buffer);
if (err < 0) {
fw_iso_resources_free(&tscm->tx_resources);
fw_iso_resources_free(&tscm->rx_resources);

View File

@ -169,7 +169,8 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
unsigned int frames_per_period);
unsigned int frames_per_period,
unsigned int frames_per_buffer);
int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);