Merge branch 'for-next' into for-linus

This commit is contained in:
Takashi Iwai
2015-11-02 09:00:37 +01:00
307 changed files with 21207 additions and 3313 deletions
+11 -2
View File
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
#include <linux/dma/pxa-dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -43,7 +44,11 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.reset = pxa2xx_ac97_reset,
};
static unsigned long pxa2xx_ac97_pcm_out_req = 12;
static struct pxad_param pxa2xx_ac97_pcm_out_req = {
.prio = PXAD_PRIO_LOWEST,
.drcmr = 12,
};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -51,7 +56,11 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
.filter_data = &pxa2xx_ac97_pcm_out_req,
};
static unsigned long pxa2xx_ac97_pcm_in_req = 11;
static struct pxad_param pxa2xx_ac97_pcm_in_req = {
.prio = PXAD_PRIO_LOWEST,
.drcmr = 11,
};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+36 -165
View File
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dma/pxa-dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -15,8 +16,6 @@
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
#include <mach/dma.h>
#include "pxa2xx-pcm.h"
static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
@@ -31,7 +30,7 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
.period_bytes_min = 32,
.period_bytes_max = 8192 - 32,
.periods_min = 1,
.periods_max = PAGE_SIZE/sizeof(pxa_dma_desc),
.periods_max = 256,
.buffer_bytes_max = 128 * 1024,
.fifo_size = 32,
};
@@ -39,65 +38,29 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd = runtime->private_data;
size_t totsize = params_buffer_bytes(params);
size_t period = params_period_bytes(params);
pxa_dma_desc *dma_desc;
dma_addr_t dma_buff_phys, next_desc_phys;
u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_dmaengine_dai_dma_data *dma_params;
struct dma_slave_config config;
int ret;
/* temporary transition hack */
switch (rtd->params->addr_width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE:
dcmd |= DCMD_WIDTH1;
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
dcmd |= DCMD_WIDTH2;
break;
case DMA_SLAVE_BUSWIDTH_4_BYTES:
dcmd |= DCMD_WIDTH4;
break;
default:
/* can't happen */
break;
}
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!dma_params)
return 0;
switch (rtd->params->maxburst) {
case 8:
dcmd |= DCMD_BURST8;
break;
case 16:
dcmd |= DCMD_BURST16;
break;
case 32:
dcmd |= DCMD_BURST32;
break;
}
ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
if (ret)
return ret;
snd_dmaengine_pcm_set_config_from_dai_data(substream,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
&config);
ret = dmaengine_slave_config(chan, &config);
if (ret)
return ret;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = totsize;
dma_desc = rtd->dma_desc_array;
next_desc_phys = rtd->dma_desc_array_phys;
dma_buff_phys = runtime->dma_addr;
do {
next_desc_phys += sizeof(pxa_dma_desc);
dma_desc->ddadr = next_desc_phys;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_desc->dsadr = dma_buff_phys;
dma_desc->dtadr = rtd->params->addr;
} else {
dma_desc->dsadr = rtd->params->addr;
dma_desc->dtadr = dma_buff_phys;
}
if (period > totsize)
period = totsize;
dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
dma_desc++;
dma_buff_phys += period;
} while (totsize -= period);
dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
return 0;
}
@@ -105,13 +68,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
if (rtd && rtd->params && rtd->params->filter_data) {
unsigned long req = *(unsigned long *) rtd->params->filter_data;
DRCMR(req) = 0;
}
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
@@ -119,100 +75,36 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
DCSR(prtd->dma_ch) = DCSR_RUN;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
DCSR(prtd->dma_ch) &= ~DCSR_RUN;
break;
case SNDRV_PCM_TRIGGER_RESUME:
DCSR(prtd->dma_ch) |= DCSR_RUN;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
DCSR(prtd->dma_ch) |= DCSR_RUN;
break;
default:
ret = -EINVAL;
}
return ret;
return snd_dmaengine_pcm_trigger(substream, cmd);
}
EXPORT_SYMBOL(pxa2xx_pcm_trigger);
snd_pcm_uframes_t
pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *prtd = runtime->private_data;
dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
if (x == runtime->buffer_size)
x = 0;
return x;
return snd_dmaengine_pcm_pointer(substream);
}
EXPORT_SYMBOL(pxa2xx_pcm_pointer);
int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
unsigned long req;
if (!prtd || !prtd->params)
return 0;
if (prtd->dma_ch == -1)
return -EINVAL;
DCSR(prtd->dma_ch) &= ~DCSR_RUN;
DCSR(prtd->dma_ch) = 0;
DCMD(prtd->dma_ch) = 0;
req = *(unsigned long *) prtd->params->filter_data;
DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
return 0;
}
EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
int dcsr;
dcsr = DCSR(dma_ch);
DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
if (dcsr & DCSR_ENDINTR) {
snd_pcm_period_elapsed(substream);
} else {
printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
dma_ch, dcsr);
snd_pcm_stop_xrun(substream);
}
}
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd;
struct snd_dmaengine_dai_dma_data *dma_params;
int ret;
runtime->hw = pxa2xx_pcm_hardware;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!dma_params)
return 0;
/*
* For mysterious reasons (and despite what the manual says)
* playback samples are lost if the DMA count is not a multiple
@@ -221,48 +113,27 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
if (ret)
goto out;
return ret;
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
if (ret)
goto out;
return ret;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
return ret;
ret = -ENOMEM;
rtd = kzalloc(sizeof(*rtd), GFP_KERNEL);
if (!rtd)
goto out;
rtd->dma_desc_array =
dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
&rtd->dma_desc_array_phys, GFP_KERNEL);
if (!rtd->dma_desc_array)
goto err1;
rtd->dma_ch = -1;
runtime->private_data = rtd;
return 0;
err1:
kfree(rtd);
out:
return ret;
return snd_dmaengine_pcm_open_request_chan(substream,
pxad_filter_fn,
dma_params->filter_data);
}
EXPORT_SYMBOL(__pxa2xx_pcm_open);
int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd = runtime->private_data;
dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
rtd->dma_desc_array, rtd->dma_desc_array_phys);
kfree(rtd);
return 0;
return snd_dmaengine_pcm_close_release_chan(substream);
}
EXPORT_SYMBOL(__pxa2xx_pcm_close);
+3 -9
View File
@@ -46,17 +46,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
client->playback_params : client->capture_params;
ret = pxa_request_dma("dma", DMA_PRIO_LOW,
pxa2xx_pcm_dma_irq, substream);
if (ret < 0)
goto err2;
rtd->dma_ch = ret;
ret = client->startup(substream);
if (!ret)
goto out;
goto err2;
return 0;
pxa_free_dma(rtd->dma_ch);
err2:
__pxa2xx_pcm_close(substream);
out:
@@ -66,9 +62,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
{
struct pxa2xx_pcm_client *client = substream->private_data;
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
pxa_free_dma(rtd->dma_ch);
client->shutdown(substream);
return __pxa2xx_pcm_close(substream);
-2
View File
@@ -13,8 +13,6 @@
struct pxa2xx_runtime_data {
int dma_ch;
struct snd_dmaengine_dai_dma_data *params;
struct pxa_dma_desc *dma_desc_array;
dma_addr_t dma_desc_array_phys;
};
struct pxa2xx_pcm_client {
+12 -1
View File
@@ -4,7 +4,7 @@ config SND_TIMER
config SND_PCM
tristate
select SND_TIMER
select SND_TIMER if SND_PCM_TIMER
config SND_PCM_ELD
bool
@@ -93,6 +93,17 @@ config SND_PCM_OSS_PLUGINS
support conversion of channels, formats and rates. It will
behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
config SND_PCM_TIMER
bool "PCM timer interface" if EXPERT
default y
help
If you disable this option, pcm timer will be inavailable, so
those stubs used pcm timer (e.g. dmix, dsnoop & co) may work
incorrectlly.
For some embedded device, we may disable it to reduce memory
footprint, about 20KB on x86_64 platform.
config SND_SEQUENCER_OSS
bool "OSS Sequencer API"
depends on SND_SEQUENCER
+2 -1
View File
@@ -13,8 +13,9 @@ snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
snd-$(CONFIG_SND_VMASTER) += vmaster.o
snd-$(CONFIG_SND_JACK) += ctljack.o jack.o
snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_misc.o \
pcm_memory.o memalloc.o
snd-pcm-$(CONFIG_SND_PCM_TIMER) += pcm_timer.o
snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o
snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
+2 -1
View File
@@ -1177,7 +1177,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
struct snd_mixer_oss *mixer = entry->private_data;
char line[128], str[32], idxstr[16];
const char *cptr;
int ch, idx;
unsigned int idx;
int ch;
struct snd_mixer_oss_assign_table *tbl;
struct slot *slot;
-3
View File
@@ -1014,9 +1014,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
snd_free_pages((void*)runtime->control,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
kfree(runtime->hw_constraints.rules);
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
kfree(runtime->hwptr_log);
#endif
kfree(runtime);
substream->runtime = NULL;
put_pid(substream->pid);
+11 -13
View File
@@ -801,7 +801,7 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
* negative error code.
*/
int snd_interval_ratnum(struct snd_interval *i,
unsigned int rats_count, struct snd_ratnum *rats,
unsigned int rats_count, const struct snd_ratnum *rats,
unsigned int *nump, unsigned int *denp)
{
unsigned int best_num, best_den;
@@ -920,7 +920,8 @@ EXPORT_SYMBOL(snd_interval_ratnum);
* negative error code.
*/
static int snd_interval_ratden(struct snd_interval *i,
unsigned int rats_count, struct snd_ratden *rats,
unsigned int rats_count,
const struct snd_ratden *rats,
unsigned int *nump, unsigned int *denp)
{
unsigned int best_num, best_diff, best_den;
@@ -1339,7 +1340,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_pcm_hw_constraint_ratnums *r = rule->private;
const struct snd_pcm_hw_constraint_ratnums *r = rule->private;
unsigned int num = 0, den = 0;
int err;
err = snd_interval_ratnum(hw_param_interval(params, rule->var),
@@ -1363,10 +1364,10 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
struct snd_pcm_hw_constraint_ratnums *r)
const struct snd_pcm_hw_constraint_ratnums *r)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
snd_pcm_hw_rule_ratnums, r,
snd_pcm_hw_rule_ratnums, (void *)r,
var, -1);
}
@@ -1375,7 +1376,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_pcm_hw_constraint_ratdens *r = rule->private;
const struct snd_pcm_hw_constraint_ratdens *r = rule->private;
unsigned int num = 0, den = 0;
int err = snd_interval_ratden(hw_param_interval(params, rule->var),
r->nrats, r->rats, &num, &den);
@@ -1398,10 +1399,10 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
struct snd_pcm_hw_constraint_ratdens *r)
const struct snd_pcm_hw_constraint_ratdens *r)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
snd_pcm_hw_rule_ratdens, r,
snd_pcm_hw_rule_ratdens, (void *)r,
var, -1);
}
@@ -1875,20 +1876,17 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
return;
runtime = substream->runtime;
if (runtime->transfer_ack_begin)
runtime->transfer_ack_begin(substream);
snd_pcm_stream_lock_irqsave(substream, flags);
if (!snd_pcm_running(substream) ||
snd_pcm_update_hw_ptr0(substream, 1) < 0)
goto _end;
#ifdef CONFIG_SND_PCM_TIMER
if (substream->timer_running)
snd_timer_interrupt(substream->timer, 1);
#endif
_end:
snd_pcm_stream_unlock_irqrestore(substream, flags);
if (runtime->transfer_ack_end)
runtime->transfer_ack_end(substream);
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
}
+20 -22
View File
@@ -486,6 +486,16 @@ static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
snd_pcm_stream_unlock_irq(substream);
}
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
int event)
{
#ifdef CONFIG_SND_PCM_TIMER
if (substream->timer)
snd_timer_notify(substream->timer, event,
&substream->runtime->trigger_tstamp);
#endif
}
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -650,7 +660,8 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
}
snd_pcm_stream_unlock_irq(substream);
if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
if (params->tstamp_mode < 0 ||
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
return -EINVAL;
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
@@ -1042,9 +1053,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
static struct action_ops snd_pcm_action_start = {
@@ -1092,9 +1101,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
if (runtime->status->state != state) {
snd_pcm_trigger_tstamp(substream);
runtime->status->state = state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
}
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
@@ -1208,18 +1215,12 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
snd_pcm_trigger_tstamp(substream);
if (push) {
runtime->status->state = SNDRV_PCM_STATE_PAUSED;
if (substream->timer)
snd_timer_notify(substream->timer,
SNDRV_TIMER_EVENT_MPAUSE,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE);
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
} else {
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
if (substream->timer)
snd_timer_notify(substream->timer,
SNDRV_TIMER_EVENT_MCONTINUE,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE);
}
}
@@ -1267,9 +1268,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
snd_pcm_trigger_tstamp(substream);
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND);
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
}
@@ -1373,9 +1372,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
runtime->status->state = runtime->status->suspended_state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
&runtime->trigger_tstamp);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
}
static struct action_ops snd_pcm_action_resume = {
@@ -2226,7 +2223,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
snd_pcm_drop(substream);
if (substream->hw_opened) {
if (substream->ops->hw_free != NULL)
if (substream->ops->hw_free &&
substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
substream->ops->hw_free(substream);
substream->ops->close(substream);
substream->hw_opened = 0;
+2 -4
View File
@@ -91,8 +91,7 @@ snd_seq_oss_readq_clear(struct seq_oss_readq *q)
q->head = q->tail = 0;
}
/* if someone sleeping, wake'em up */
if (waitqueue_active(&q->midi_sleep))
wake_up(&q->midi_sleep);
wake_up(&q->midi_sleep);
q->input_time = (unsigned long)-1;
}
@@ -138,8 +137,7 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
q->qlen++;
/* wake up sleeper */
if (waitqueue_active(&q->midi_sleep))
wake_up(&q->midi_sleep);
wake_up(&q->midi_sleep);
spin_unlock_irqrestore(&q->lock, flags);
+1 -3
View File
@@ -138,9 +138,7 @@ snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
spin_lock_irqsave(&q->sync_lock, flags);
q->sync_time = time;
q->sync_event_put = 0;
if (waitqueue_active(&q->sync_sleep)) {
wake_up(&q->sync_sleep);
}
wake_up(&q->sync_sleep);
spin_unlock_irqrestore(&q->sync_lock, flags);
}
+27
View File
@@ -120,4 +120,31 @@ config SND_BEBOB
To compile this driver as a module, choose M here: the module
will be called snd-bebob.
config SND_FIREWIRE_DIGI00X
tristate "Digidesign Digi 002/003 family support"
select SND_FIREWIRE_LIB
select SND_HWDEP
help
Say Y here to include support for Digidesign Digi 002/003 family.
* Digi 002 Console
* Digi 002 Rack
* Digi 003 Console
* Digi 003 Rack
* Digi 003 Rack+
To compile this driver as a module, choose M here: the module
will be called snd-firewire-digi00x.
config SND_FIREWIRE_TASCAM
tristate "TASCAM FireWire series support"
select SND_FIREWIRE_LIB
select SND_HWDEP
help
Say Y here to include support for TASCAM.
* FW-1884
* FW-1082
To compile this driver as a module, choose M here: the module
will be called snd-firewire-tascam.
endif # SND_FIREWIRE
+3 -2
View File
@@ -1,6 +1,5 @@
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp.o
snd-oxfw-objs := oxfw.o
fcp.o cmp.o amdtp-stream.o amdtp-am824.o
snd-isight-objs := isight.o
snd-scs1x-objs := scs1x.o
@@ -11,3 +10,5 @@ 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/
obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/
+465
View File
@@ -0,0 +1,465 @@
/*
* AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6)
*
* 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 <linux/slab.h>
#include "amdtp-am824.h"
#define CIP_FMT_AM 0x10
/* "Clock-based rate control mode" is just supported. */
#define AMDTP_FDF_AM824 0x00
/*
* Nominally 3125 bytes/second, but the MIDI port's clock might be
* 1% too slow, and the bus clock 100 ppm too fast.
*/
#define MIDI_BYTES_PER_SECOND 3093
/*
* Several devices look only at the first eight data blocks.
* In any case, this is more than enough for the MIDI data rate.
*/
#define MAX_MIDI_RX_BLOCKS 8
struct amdtp_am824 {
struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8];
int midi_fifo_limit;
int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8];
unsigned int pcm_channels;
unsigned int midi_ports;
u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM];
u8 midi_position;
void (*transfer_samples)(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames);
unsigned int frame_multiplier;
};
/**
* amdtp_am824_set_parameters - set stream parameters
* @s: the AMDTP stream to configure
* @rate: the sample rate
* @pcm_channels: the number of PCM samples in each data block, to be encoded
* as AM824 multi-bit linear audio
* @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
* @double_pcm_frames: one data block transfers two PCM frames
*
* The parameters must be set before the stream is started, and must not be
* changed while the stream is running.
*/
int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int pcm_channels,
unsigned int midi_ports,
bool double_pcm_frames)
{
struct amdtp_am824 *p = s->protocol;
unsigned int midi_channels;
unsigned int i;
int err;
if (amdtp_stream_running(s))
return -EINVAL;
if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM)
return -EINVAL;
midi_channels = DIV_ROUND_UP(midi_ports, 8);
if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)
return -EINVAL;
if (WARN_ON(amdtp_stream_running(s)) ||
WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) ||
WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI))
return -EINVAL;
err = amdtp_stream_set_parameters(s, rate,
pcm_channels + midi_channels);
if (err < 0)
return err;
s->fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
p->midi_ports = midi_ports;
/*
* In IEC 61883-6, one data block represents one event. In ALSA, one
* event equals to one PCM frame. But Dice has a quirk at higher
* sampling rate to transfer two PCM frames in one data block.
*/
if (double_pcm_frames)
p->frame_multiplier = 2;
else
p->frame_multiplier = 1;
/* init the position map for PCM and MIDI channels */
for (i = 0; i < pcm_channels; i++)
p->pcm_positions[i] = i;
p->midi_position = p->pcm_channels;
/*
* We do not know the actual MIDI FIFO size of most devices. Just
* assume two bytes, i.e., one byte can be received over the bus while
* the previous one is transmitted over MIDI.
* (The value here is adjusted for midi_ratelimit_per_packet().)
*/
p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
return 0;
}
EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
/**
* amdtp_am824_set_pcm_position - set an index of data channel for a channel
* of PCM frame
* @s: the AMDTP stream
* @index: the index of data channel in an data block
* @position: the channel of PCM frame
*/
void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
unsigned int position)
{
struct amdtp_am824 *p = s->protocol;
if (index < p->pcm_channels)
p->pcm_positions[index] = position;
}
EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position);
/**
* amdtp_am824_set_midi_position - set a index of data channel for MIDI
* conformant data channel
* @s: the AMDTP stream
* @position: the index of data channel in an data block
*/
void amdtp_am824_set_midi_position(struct amdtp_stream *s,
unsigned int position)
{
struct amdtp_am824 *p = s->protocol;
p->midi_position = position;
}
EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position);
static void write_pcm_s32(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
struct snd_pcm_runtime *runtime = pcm->runtime;
unsigned int channels, remaining_frames, i, c;
const u32 *src;
channels = p->pcm_channels;
src = (void *)runtime->dma_area +
frames_to_bytes(runtime, s->pcm_buffer_pointer);
remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
for (i = 0; i < frames; ++i) {
for (c = 0; c < channels; ++c) {
buffer[p->pcm_positions[c]] =
cpu_to_be32((*src >> 8) | 0x40000000);
src++;
}
buffer += s->data_block_quadlets;
if (--remaining_frames == 0)
src = (void *)runtime->dma_area;
}
}
static void write_pcm_s16(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
struct snd_pcm_runtime *runtime = pcm->runtime;
unsigned int channels, remaining_frames, i, c;
const u16 *src;
channels = p->pcm_channels;
src = (void *)runtime->dma_area +
frames_to_bytes(runtime, s->pcm_buffer_pointer);
remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
for (i = 0; i < frames; ++i) {
for (c = 0; c < channels; ++c) {
buffer[p->pcm_positions[c]] =
cpu_to_be32((*src << 8) | 0x42000000);
src++;
}
buffer += s->data_block_quadlets;
if (--remaining_frames == 0)
src = (void *)runtime->dma_area;
}
}
static void read_pcm_s32(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
struct snd_pcm_runtime *runtime = pcm->runtime;
unsigned int channels, remaining_frames, i, c;
u32 *dst;
channels = p->pcm_channels;
dst = (void *)runtime->dma_area +
frames_to_bytes(runtime, s->pcm_buffer_pointer);
remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
for (i = 0; i < frames; ++i) {
for (c = 0; c < channels; ++c) {
*dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8;
dst++;
}
buffer += s->data_block_quadlets;
if (--remaining_frames == 0)
dst = (void *)runtime->dma_area;
}
}
static void write_pcm_silence(struct amdtp_stream *s,
__be32 *buffer, unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
unsigned int i, c, channels = p->pcm_channels;
for (i = 0; i < frames; ++i) {
for (c = 0; c < channels; ++c)
buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000);
buffer += s->data_block_quadlets;
}
}
/**
* amdtp_am824_set_pcm_format - set the PCM format
* @s: the AMDTP stream to configure
* @format: the format of the ALSA PCM device
*
* The sample format must be set after the other parameters (rate/PCM channels/
* MIDI) and before the stream is started, and must not be changed while the
* stream is running.
*/
void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
{
struct amdtp_am824 *p = s->protocol;
if (WARN_ON(amdtp_stream_pcm_running(s)))
return;
switch (format) {
default:
WARN_ON(1);
/* fall through */
case SNDRV_PCM_FORMAT_S16:
if (s->direction == AMDTP_OUT_STREAM) {
p->transfer_samples = write_pcm_s16;
break;
}
WARN_ON(1);
/* fall through */
case SNDRV_PCM_FORMAT_S32:
if (s->direction == AMDTP_OUT_STREAM)
p->transfer_samples = write_pcm_s32;
else
p->transfer_samples = read_pcm_s32;
break;
}
}
EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format);
/**
* amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream
* @s: the AMDTP stream for AM824 data block, must be initialized.
* @runtime: the PCM substream runtime
*
*/
int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
struct snd_pcm_runtime *runtime)
{
int err;
err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
if (err < 0)
return err;
/* AM824 in IEC 61883-6 can deliver 24bit data. */
return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
}
EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints);
/**
* amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device
* @s: the AMDTP stream
* @port: index of MIDI port
* @midi: the MIDI device to be started, or %NULL to stop the current device
*
* Call this function on a running isochronous stream to enable the actual
* transmission of MIDI data. This function should be called from the MIDI
* device's .trigger callback.
*/
void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
struct snd_rawmidi_substream *midi)
{
struct amdtp_am824 *p = s->protocol;
if (port < p->midi_ports)
ACCESS_ONCE(p->midi[port]) = midi;
}
EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
/*
* To avoid sending MIDI bytes at too high a rate, assume that the receiving
* device has a FIFO, and track how much it is filled. This values increases
* by one whenever we send one byte in a packet, but the FIFO empties at
* a constant rate independent of our packet rate. One packet has syt_interval
* samples, so the number of bytes that empty out of the FIFO, per packet(!),
* is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing
* fractional values, the values in midi_fifo_used[] are measured in bytes
* multiplied by the sample rate.
*/
static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
{
struct amdtp_am824 *p = s->protocol;
int used;
used = p->midi_fifo_used[port];
if (used == 0) /* common shortcut */
return true;
used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
used = max(used, 0);
p->midi_fifo_used[port] = used;
return used < p->midi_fifo_limit;
}
static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
{
struct amdtp_am824 *p = s->protocol;
p->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
}
static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
unsigned int f, port;
u8 *b;
for (f = 0; f < frames; f++) {
b = (u8 *)&buffer[p->midi_position];
port = (s->data_block_counter + f) % 8;
if (f < MAX_MIDI_RX_BLOCKS &&
midi_ratelimit_per_packet(s, port) &&
p->midi[port] != NULL &&
snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) {
midi_rate_use_one_byte(s, port);
b[0] = 0x81;
} else {
b[0] = 0x80;
b[1] = 0;
}
b[2] = 0;
b[3] = 0;
buffer += s->data_block_quadlets;
}
}
static void read_midi_messages(struct amdtp_stream *s,
__be32 *buffer, unsigned int frames)
{
struct amdtp_am824 *p = s->protocol;
unsigned int f, port;
int len;
u8 *b;
for (f = 0; f < frames; f++) {
port = (s->data_block_counter + f) % 8;
b = (u8 *)&buffer[p->midi_position];
len = b[0] - 0x80;
if ((1 <= len) && (len <= 3) && (p->midi[port]))
snd_rawmidi_receive(p->midi[port], b + 1, len);
buffer += s->data_block_quadlets;
}
}
static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
unsigned int data_blocks, unsigned int *syt)
{
struct amdtp_am824 *p = s->protocol;
struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
unsigned int pcm_frames;
if (pcm) {
p->transfer_samples(s, pcm, buffer, data_blocks);
pcm_frames = data_blocks * p->frame_multiplier;
} else {
write_pcm_silence(s, buffer, data_blocks);
pcm_frames = 0;
}
if (p->midi_ports)
write_midi_messages(s, buffer, data_blocks);
return pcm_frames;
}
static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
unsigned int data_blocks, unsigned int *syt)
{
struct amdtp_am824 *p = s->protocol;
struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
unsigned int pcm_frames;
if (pcm) {
p->transfer_samples(s, pcm, buffer, data_blocks);
pcm_frames = data_blocks * p->frame_multiplier;
} else {
pcm_frames = 0;
}
if (p->midi_ports)
read_midi_messages(s, buffer, data_blocks);
return pcm_frames;
}
/**
* amdtp_am824_init - initialize an AMDTP stream structure to handle AM824
* data block
* @s: the AMDTP stream to initialize
* @unit: the target of the stream
* @dir: the direction of stream
* @flags: the packet transmission method to use
*/
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags)
{
amdtp_stream_process_data_blocks_t process_data_blocks;
if (dir == AMDTP_IN_STREAM)
process_data_blocks = process_tx_data_blocks;
else
process_data_blocks = process_rx_data_blocks;
return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
process_data_blocks,
sizeof(struct amdtp_am824));
}
EXPORT_SYMBOL_GPL(amdtp_am824_init);
+52
View File
@@ -0,0 +1,52 @@
#ifndef SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
#define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include "amdtp-stream.h"
#define AM824_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32
#define AM824_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \
SNDRV_PCM_FMTBIT_S32)
/*
* This module supports maximum 64 PCM channels for one PCM stream
* This is for our convenience.
*/
#define AM824_MAX_CHANNELS_FOR_PCM 64
/*
* AMDTP packet can include channels for MIDI conformant data.
* Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
* Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
*
* This module supports maximum 1 MIDI conformant data channels.
* Then this AMDTP packets can transfer maximum 8 MIDI data streams.
*/
#define AM824_MAX_CHANNELS_FOR_MIDI 1
int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int pcm_channels,
unsigned int midi_ports,
bool double_pcm_frames);
void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
unsigned int position);
void amdtp_am824_set_midi_position(struct amdtp_stream *s,
unsigned int position);
int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
struct snd_pcm_runtime *runtime);
void amdtp_am824_set_pcm_format(struct amdtp_stream *s,
snd_pcm_format_t format);
void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
struct snd_rawmidi_substream *midi);
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags);
#endif
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,7 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <sound/asound.h>
#include "packets-buffer.h"
@@ -80,100 +81,78 @@ enum cip_sfc {
CIP_SFC_COUNT
};
#define AMDTP_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32
#define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \
SNDRV_PCM_FMTBIT_S32)
/*
* This module supports maximum 64 PCM channels for one PCM stream
* This is for our convenience.
*/
#define AMDTP_MAX_CHANNELS_FOR_PCM 64
/*
* AMDTP packet can include channels for MIDI conformant data.
* Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
* Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
*
* This module supports maximum 1 MIDI conformant data channels.
* Then this AMDTP packets can transfer maximum 8 MIDI data streams.
*/
#define AMDTP_MAX_CHANNELS_FOR_MIDI 1
struct fw_unit;
struct fw_iso_context;
struct snd_pcm_substream;
struct snd_pcm_runtime;
struct snd_rawmidi_substream;
enum amdtp_stream_direction {
AMDTP_OUT_STREAM = 0,
AMDTP_IN_STREAM
};
struct amdtp_stream;
typedef unsigned int (*amdtp_stream_process_data_blocks_t)(
struct amdtp_stream *s,
__be32 *buffer,
unsigned int data_blocks,
unsigned int *syt);
struct amdtp_stream {
struct fw_unit *unit;
enum cip_flags flags;
enum amdtp_stream_direction direction;
struct fw_iso_context *context;
struct mutex mutex;
enum cip_sfc sfc;
unsigned int data_block_quadlets;
unsigned int pcm_channels;
unsigned int midi_ports;
void (*transfer_samples)(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames);
u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM];
u8 midi_position;
unsigned int syt_interval;
unsigned int transfer_delay;
unsigned int source_node_id_field;
/* For packet processing. */
struct fw_iso_context *context;
struct iso_packets_buffer buffer;
struct snd_pcm_substream *pcm;
struct tasklet_struct period_tasklet;
int packet_index;
/* For CIP headers. */
unsigned int source_node_id_field;
unsigned int data_block_quadlets;
unsigned int data_block_counter;
unsigned int data_block_state;
unsigned int last_syt_offset;
unsigned int syt_offset_state;
unsigned int pcm_buffer_pointer;
unsigned int pcm_period_pointer;
bool pointer_flush;
bool double_pcm_frames;
struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
int midi_fifo_limit;
int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
unsigned int fmt;
unsigned int fdf;
/* quirk: fixed interval of dbc between previos/current packets. */
unsigned int tx_dbc_interval;
/* quirk: indicate the value of dbc field in a first packet. */
unsigned int tx_first_dbc;
/* Internal flags. */
enum cip_sfc sfc;
unsigned int syt_interval;
unsigned int transfer_delay;
unsigned int data_block_state;
unsigned int last_syt_offset;
unsigned int syt_offset_state;
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
struct tasklet_struct period_tasklet;
unsigned int pcm_buffer_pointer;
unsigned int pcm_period_pointer;
bool pointer_flush;
/* To wait for first packet. */
bool callbacked;
wait_queue_head_t callback_wait;
struct amdtp_stream *sync_slave;
/* For backends to process data blocks. */
void *protocol;
amdtp_stream_process_data_blocks_t process_data_blocks;
};
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
enum cip_flags flags);
enum amdtp_stream_direction dir, enum cip_flags flags,
unsigned int fmt,
amdtp_stream_process_data_blocks_t process_data_blocks,
unsigned int protocol_size);
void amdtp_stream_destroy(struct amdtp_stream *s);
void amdtp_stream_set_parameters(struct amdtp_stream *s,
unsigned int rate,
unsigned int pcm_channels,
unsigned int midi_ports);
int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int data_block_quadlets);
unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed);
@@ -182,8 +161,7 @@ void amdtp_stream_stop(struct amdtp_stream *s);
int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
struct snd_pcm_runtime *runtime);
void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
snd_pcm_format_t format);
void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
void amdtp_stream_pcm_abort(struct amdtp_stream *s);
@@ -240,24 +218,6 @@ static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s,
ACCESS_ONCE(s->pcm) = pcm;
}
/**
* amdtp_stream_midi_trigger - start/stop playback/capture with a MIDI device
* @s: the AMDTP stream
* @port: index of MIDI port
* @midi: the MIDI device to be started, or %NULL to stop the current device
*
* Call this function on a running isochronous stream to enable the actual
* transmission of MIDI data. This function should be called from the MIDI
* device's .trigger callback.
*/
static inline void amdtp_stream_midi_trigger(struct amdtp_stream *s,
unsigned int port,
struct snd_rawmidi_substream *midi)
{
if (port < s->midi_ports)
ACCESS_ONCE(s->midi[port]) = midi;
}
static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
{
return sfc & 1;
+1 -1
View File
@@ -1,4 +1,4 @@
snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \
bebob_focusrite.o bebob_maudio.o bebob.o
obj-m += snd-bebob.o
obj-$(CONFIG_SND_BEBOB) += snd-bebob.o
+5 -4
View File
@@ -41,7 +41,8 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define VEN_EDIROL 0x000040ab
#define VEN_PRESONUS 0x00000a92
#define VEN_BRIDGECO 0x000007f5
#define VEN_MACKIE 0x0000000f
#define VEN_MACKIE1 0x0000000f
#define VEN_MACKIE2 0x00000ff2
#define VEN_STANTON 0x00001260
#define VEN_TASCAM 0x0000022e
#define VEN_BEHRINGER 0x00001564
@@ -334,7 +335,7 @@ static void bebob_remove(struct fw_unit *unit)
snd_card_free_when_closed(bebob->card);
}
static struct snd_bebob_rate_spec normal_rate_spec = {
static const struct snd_bebob_rate_spec normal_rate_spec = {
.get = &snd_bebob_stream_get_rate,
.set = &snd_bebob_stream_set_rate
};
@@ -360,9 +361,9 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* BridgeCo, Audio5 */
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
/* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal),
/* Mackie, d.2 (Firewire Option) */
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal),
/* Stanton, ScratchAmp */
SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
/* Tascam, IF-FW DM */

Some files were not shown because too many files have changed in this diff Show More