Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 65785
b: refs/heads/master
c: 05b2723
h: refs/heads/master
i:
  65783: 53749ff
v: v3
  • Loading branch information
Trent Piepho authored and Mauro Carvalho Chehab committed Oct 10, 2007
1 parent 1fbf5fa commit 86e0f83
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 106 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 16cf1d0c5d7b8970aca2ca426166833642ce0544
refs/heads/master: 05b2723387cb4086535e935ee07cca19086308fc
168 changes: 73 additions & 95 deletions trunk/drivers/media/video/cx88/cx88-alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Support for audio capture
* PCI function #1 of the cx2388x.
*
* (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
* (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
Expand Down Expand Up @@ -47,7 +48,6 @@
#define dprintk_core(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)


/****************************************************************************
Data type declarations - Can be moded to a header file later
****************************************************************************/
Expand All @@ -58,6 +58,7 @@
struct cx88_audio_dev {
struct cx88_core *core;
struct cx88_dmaqueue q;
u64 starttime;

/* pci i/o */
struct pci_dev *pci;
Expand All @@ -68,24 +69,20 @@ struct cx88_audio_dev {
struct snd_card *card;

spinlock_t reg_lock;
atomic_t count;

unsigned int dma_size;
unsigned int period_size;
unsigned int num_periods;

struct videobuf_dmabuf dma_risc;
struct videobuf_dmabuf dma_risc;

int mixer_volume[MIXER_ADDR_LAST+1][2];
int capture_source[MIXER_ADDR_LAST+1][2];

long int read_count;
long int read_offset;

struct cx88_buffer *buf;

long opened;
struct snd_pcm_substream *substream;
struct cx88_buffer *buf;

struct snd_pcm_substream *substream;
};
typedef struct cx88_audio_dev snd_cx88_card_t;

Expand Down Expand Up @@ -146,16 +143,13 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
cx_write(MO_AUDD_LNGTH, buf->bpl);

/* reset counter */
cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
atomic_set(&chip->count, 0);

dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, "
"%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
"byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
chip->num_periods, buf->bpl * chip->num_periods);

dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n",
chip->core->pci_irqmask,
chip->core->pci_irqmask | PCI_INT_AUDINT);

/* Enables corresponding bits at AUD_INT_STAT */
cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
Expand Down Expand Up @@ -198,7 +192,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
return 0;
}

#define MAX_IRQ_LOOP 10
#define MAX_IRQ_LOOP 50

/*
* BOARD Specific: IRQ dma bits
Expand All @@ -223,42 +217,32 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
{
struct cx88_core *core = chip->core;
u32 status, mask;
u32 count;

status = cx_read(MO_AUD_INTSTAT);
mask = cx_read(MO_AUD_INTMSK);
if (0 == (status & mask)) {
spin_unlock(&chip->reg_lock);
if (0 == (status & mask))
return;
}
cx_write(MO_AUD_INTSTAT, status);
if (debug > 1 || (status & mask & ~0xff))
cx88_print_irqbits(core->name, "irq aud",
cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
status, mask);
/* risc op code error */
if (status & AUD_INT_OPC_ERR) {
printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
cx_clear(MO_AUD_DMACNTRL, 0x11);
cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
}

if (status & AUD_INT_DN_SYNC) {
dprintk(1, "Downstream sync error\n");
cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
return;
}
/* risc1 downstream */
if (status & AUD_INT_DN_RISCI1) {
spin_lock(&chip->reg_lock);
count = cx_read(MO_AUDD_GPCNT);
spin_unlock(&chip->reg_lock);
if (chip->read_count == 0)
chip->read_count += chip->dma_size;
}

if (chip->read_count >= chip->period_size) {
dprintk(2, "Elapsing period\n");
atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
snd_pcm_period_elapsed(chip->substream);
}

dprintk(3,"Leaving audio IRQ handler...\n");

/* FIXME: Any other status should deserve a special handling? */
}

Expand All @@ -277,23 +261,20 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id)
(core->pci_irqmask | PCI_INT_AUDINT);
if (0 == status)
goto out;
dprintk( 3, "cx8801_irq\n" );
dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
dprintk( 3, " status: %d\n", status );
dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
loop, MAX_IRQ_LOOP, status);
handled = 1;
cx_write(MO_PCI_INTSTAT, status);

if (status & core->pci_irqmask)
cx88_core_irq(core, status);
if (status & PCI_INT_AUDINT) {
dprintk( 2, " ALSA IRQ handling\n" );
if (status & PCI_INT_AUDINT)
cx8801_aud_irq(chip);
}
};
}

if (MAX_IRQ_LOOP == loop) {
dprintk( 0, "clearing mask\n" );
dprintk(1,"%s/0: irq loop -- clearing mask\n",
printk(KERN_ERR
"%s/1: IRQ loop detected, disabling interrupts\n",
core->name);
cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
}
Expand All @@ -315,7 +296,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)

chip->dma_size = 0;

return 0;
return 0;
}

/****************************************************************************
Expand All @@ -325,6 +306,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
/*
* Digital hardware definition
*/
#define DEFAULT_FIFO_SIZE 4096
static struct snd_pcm_hardware snd_cx88_digital_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
Expand All @@ -337,19 +319,15 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = {
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = (2*2048),
.period_bytes_min = 2048,
.period_bytes_max = 2048,
.periods_min = 2,
.periods_max = 2,
/* Analog audio output will be full of clicks and pops if there
are not exactly four lines in the SRAM FIFO buffer. */
.period_bytes_min = DEFAULT_FIFO_SIZE/4,
.period_bytes_max = DEFAULT_FIFO_SIZE/4,
.periods_min = 1,
.periods_max = 1024,
.buffer_bytes_max = (1024*1024),
};

/*
* audio pcm capture runtime free
*/
static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
{
}
/*
* audio pcm capture open callback
*/
Expand All @@ -359,26 +337,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;

if (test_and_set_bit(0, &chip->opened))
return -EBUSY;

err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;

chip->substream = substream;

chip->read_count = 0;
chip->read_offset = 0;

runtime->private_free = snd_card_cx88_runtime_free;
runtime->hw = snd_cx88_digital_hw;

if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
bpl &= ~7; /* must be multiple of 8 */
runtime->hw.period_bytes_min = bpl;
runtime->hw.period_bytes_max = bpl;
}

return 0;
_error:
dprintk(1,"Error opening PCM!\n");
clear_bit(0, &chip->opened);
smp_mb__after_clear_bit();
return err;
}

Expand All @@ -387,11 +363,6 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
*/
static int snd_cx88_close(struct snd_pcm_substream *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);

clear_bit(0, &chip->opened);
smp_mb__after_clear_bit();

return 0;
}

Expand All @@ -403,54 +374,61 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct cx88_buffer *buf;
int ret;

if (substream->runtime->dma_area) {
dsp_buffer_free(chip);
substream->runtime->dma_area = NULL;
}


chip->period_size = params_period_bytes(hw_params);
chip->num_periods = params_periods(hw_params);
chip->dma_size = chip->period_size * params_periods(hw_params);

BUG_ON(!chip->dma_size);
BUG_ON(chip->num_periods & (chip->num_periods-1));

dprintk(1,"Setting buffer\n");

buf = kzalloc(sizeof(*buf),GFP_KERNEL);
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (NULL == buf)
return -ENOMEM;

buf->vb.memory = V4L2_MEMORY_MMAP;
buf->vb.field = V4L2_FIELD_NONE;
buf->vb.width = chip->period_size;
buf->bpl = chip->period_size;
buf->vb.height = chip->num_periods;
buf->vb.size = chip->dma_size;
buf->vb.field = V4L2_FIELD_NONE;

videobuf_dma_init(&buf->vb.dma);
videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE,
(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
if (ret < 0)
goto error;

videobuf_pci_dma_map(chip->pci,&buf->vb.dma);

ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma);
if (ret < 0)
goto error;

cx88_risc_databuffer(chip->pci, &buf->risc,
buf->vb.dma.sglist,
buf->vb.width, buf->vb.height);
ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist,
buf->vb.width, buf->vb.height, 1);
if (ret < 0)
goto error;

buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
/* Loop back to start of program */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);

buf->vb.state = STATE_PREPARED;

buf->bpl = chip->period_size;
chip->buf = buf;
chip->dma_risc = buf->vb.dma;

dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
substream->runtime->dma_area = chip->dma_risc.vmalloc;
return 0;

error:
kfree(buf);
return ret;
}

/*
Expand All @@ -477,7 +455,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream)
return 0;
}


/*
* trigger callback
*/
Expand All @@ -486,6 +463,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
int err;

/* Local interrupts are already disabled by ALSA */
spin_lock(&chip->reg_lock);

switch (cmd) {
Expand All @@ -512,17 +490,14 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
u16 count;

if (chip->read_count) {
chip->read_count -= snd_pcm_lib_period_bytes(substream);
chip->read_offset += snd_pcm_lib_period_bytes(substream);
if (chip->read_offset == chip->dma_size)
chip->read_offset = 0;
}

dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
return bytes_to_frames(runtime, chip->read_offset);
count = atomic_read(&chip->count);

// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
// count, new, count & (runtime->periods-1),
// runtime->period_size * (count & (runtime->periods-1)));
return runtime->period_size * (count & (runtime->periods-1));
}

/*
Expand Down Expand Up @@ -592,10 +567,13 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
int v;
u32 old_control;

/* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);

old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
v = 0x3f - (value->value.integer.value[0] & 0x3f);
cx_andor(AUD_VOL_CTL, 0x3f, v);

spin_unlock_irq(&chip->reg_lock);

return v != old_control;
Expand Down
Loading

0 comments on commit 86e0f83

Please sign in to comment.