summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
authorRicardo Cerqueira <devnull@localhost>2005-12-13 04:01:49 +0000
committerRicardo Cerqueira <devnull@localhost>2005-12-13 04:01:49 +0000
commit6635914a834de9bb84d044c5a3403ec8a39b61d2 (patch)
tree7f652cda083d901ed44cc778c9e3b12e6a01e229 /linux/drivers/media/video
parent227d01d09f86548134030d82e3c1cdfb1c7e2d93 (diff)
downloadmediapointer-dvb-s2-6635914a834de9bb84d044c5a3403ec8a39b61d2.tar.gz
mediapointer-dvb-s2-6635914a834de9bb84d044c5a3403ec8a39b61d2.tar.bz2
More cx88-alsa changes. Doesn't crash on removal anymore
From: Ricardo Cerqueira <v4l@cerqueira.org> - Bugfixes to allow the module to be removed without hard-locking the system Signed-off-by:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c402
1 files changed, 299 insertions, 103 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index ecc289433..b9f248c48 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-alsa.c,v 1.13 2005/12/10 11:15:54 mchehab Exp $
+ * $Id: cx88-alsa.c,v 1.14 2005/12/13 04:01:49 rmcc Exp $
*
* Support for audio capture
* PCI function #1 of the cx2388x.
@@ -41,6 +41,9 @@
#include "cx88-reg.h"
#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
@@ -84,11 +87,24 @@ struct cx88_audio_dev {
int mixer_volume[MIXER_ADDR_LAST+1][2];
int capture_source[MIXER_ADDR_LAST+1][2];
+ long int bufsize;
+ long int read_offset;
+
+ u32 __iomem *mmio;
long opened;
snd_pcm_substream_t *substream;
};
typedef struct cx88_audio_dev snd_cx88_card_t;
+typedef struct snd_card_cx88_pcm {
+ struct cx88_dev *dev;
+
+ spinlock_t lock;
+
+ snd_pcm_substream_t *substream;
+} snd_card_cx88_pcm_t;
+
+
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)
#define chip_t snd_cx88_card_t
#endif
@@ -105,6 +121,7 @@ static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
static snd_cx88_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
#endif
+static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
static unsigned int dummy;
@@ -140,10 +157,7 @@ int _cx88_start_audio_dma(snd_cx88_card_t *chip)
{
struct cx88_core *core=chip->core;
- /* setup fifo + format - out channel */
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25],
- chip->buf->bpl, chip->buf->risc.dma);
-
+ dprintk(1, "Starting audio DMA\n");
/* sets bpl size */
cx_write(MO_AUDD_LNGTH, chip->buf->bpl);
@@ -172,6 +186,7 @@ int _cx88_start_audio_dma(snd_cx88_card_t *chip)
int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
{
struct cx88_core *core=chip->core;
+ dprintk(1, "Stopping audio DMA\n");
/* stop dma */
cx_clear(MO_AUD_DMACNTRL, 0x11);
@@ -183,6 +198,9 @@ int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
#define MAX_IRQ_LOOP 10
+/*
+ * BOARD Specific: Threats timeouts
+ */
static void cx8801_timeout(unsigned long data)
{
snd_cx88_card_t *chip = (snd_cx88_card_t *)data;
@@ -197,19 +215,25 @@ static void cx8801_timeout(unsigned long data)
#endif
}
+/*
+ * BOARD Specific: IRQ dma bits
+ */
static char *cx88_aud_irqs[32] = {
"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
- "", /* reserved */
+ NULL, /* reserved */
"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
- "", /* reserved */
+ NULL, /* reserved */
"dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
- "", /* reserved */
+ NULL, /* reserved */
"dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
- "", /* reserved */
+ NULL, /* reserved */
"opc_err", "par_err", "rip_err", /* 16-18 */
"pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
};
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
static void cx8801_aud_irq(snd_cx88_card_t *chip)
{
struct cx88_core *core = chip->core;
@@ -236,15 +260,18 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
/* risc1 downstream */
if (status & 0x01) {
- spin_lock_irq(&chip->reg_lock);
+ spin_lock(&chip->reg_lock);
count = cx_read(MO_AUDD_GPCNT);
cx88_wakeup(core, &chip->q, count);
- spin_unlock_irq(&chip->reg_lock);
+ spin_unlock(&chip->reg_lock);
}
/* FIXME: Any other status should deserve a special handling? */
}
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
{
snd_cx88_card_t *chip = dev_id;
@@ -252,21 +279,28 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
u32 status;
int loop, handled = 0;
- for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
- if (0 == status)
- goto out;
- dprintk( 1, "cx8801_irq\n" );
- dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
- dprintk( 1, " status: %d\n", status );
- handled = 1;
- cx_write(MO_PCI_INTSTAT, status);
-
- if (status & core->pci_irqmask)
- cx88_core_irq(core,status);
- if (status & 0x02)
- cx8801_aud_irq(chip);
- };
+ for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+ status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+ if (0 == status)
+ goto out;
+ dprintk( 1, "cx8801_irq\n" );
+ dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+ dprintk( 1, " status: %d\n", status );
+ handled = 1;
+ cx_write(MO_PCI_INTSTAT, status);
+
+ if (status & core->pci_irqmask)
+ {
+ dprintk( 1, " passing to core\n" );
+ cx88_core_irq(core,status);
+ }
+ if (status & 0x02)
+ {
+ dprintk( 1, " ALSA IRQ handling\n" );
+ cx8801_aud_irq(chip);
+ }
+ };
+
if (MAX_IRQ_LOOP == loop) {
dprintk( 0, "clearing mask\n" );
dprintk(1,"%s/0: irq loop -- clearing mask\n",
@@ -312,6 +346,162 @@ static void snd_cx88_pci_error(bt87x_t *chip, unsigned int status)
#endif
/****************************************************************************
+ Videobuf setup code
+ ****************************************************************************/
+#if 0
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+ struct cx8800_fh *fh = q->priv_data;
+
+ *size = fh->fmt->depth*fh->width*fh->height >> 3;
+ if (0 == *count)
+ *count = 32;
+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;
+ return 0;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx8800_fh *fh = q->priv_data;
+ struct cx8800_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+ struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ int rc, init_buffer = 0;
+ unsigned int size;
+
+ BUG_ON(NULL == fh->fmt);
+ size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ return -EINVAL;
+
+ if (STATE_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = VBI_LINE_LENGTH;
+ buf->vb.height = VBI_LINE_COUNT;
+ buf->vb.size = size;
+ buf->vb.field = V4L2_FIELD_SEQ_TB;
+
+ if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+ goto fail;
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ buf->vb.dma.sglist,
+ 0, buf->vb.width * buf->vb.height,
+ buf->vb.width, 0,
+ buf->vb.height);
+ }
+ buf->vb.state = STATE_PREPARED;
+
+ dprintk_core(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+ buf, buf->vb.i,
+ fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+ (unsigned long)buf->risc.dma);
+
+ return 0;
+
+ fail:
+ cx88_free_buffer(dev->pci,buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx88_buffer *prev;
+ struct cx8800_fh *fh = vq->priv_data;
+ struct cx8800_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+ struct cx88_dmaqueue *q = &dev->vidq;
+
+ /* add jump to stopper */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+
+ if (!list_empty(&q->queued)) {
+ list_add_tail(&buf->vb.queue,&q->queued);
+ buf->vb.state = STATE_QUEUED;
+ dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+ buf, buf->vb.i);
+
+ } else if (list_empty(&q->active)) {
+ list_add_tail(&buf->vb.queue,&q->active);
+ start_video_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2,"[%p/%d] buffer_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else {
+ prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
+ if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.i);
+
+ } else {
+ list_add_tail(&buf->vb.queue,&q->queued);
+ buf->vb.state = STATE_QUEUED;
+ dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+ buf, buf->vb.i);
+ }
+ }
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_fh *fh = q->priv_data;
+
+ cx88_free_buffer(fh->dev->pci,buf);
+}
+
+static struct videobuf_queue_ops cx8800_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+static int dsp_buffer_init(snd_cx88_card_t *chip)
+{
+ int err;
+
+ BUG_ON(!chip->dmasound.bufsize);
+
+ /* allocate + initialize per filehandle data */
+ fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+ memset(fh,0,sizeof(*fh));
+ file->private_data = fh;
+ fh->dev = dev;
+
+ videobuf_queue_init(&fh->mpegq, &blackbird_qops,
+ dev->pci, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx88_buffer),
+ fh);
+ videobuf_dma_init(&chip->dmasound.dma);
+ err = videobuf_dma_init_kernel(&chip->dmasound.dma, PCI_DMA_FROMDEVICE,
+ (chip->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ if (0 != err)
+ return err;
+ return 0;
+}
+#endif
+/****************************************************************************
ALSA PCM Interface
****************************************************************************/
@@ -324,7 +514,10 @@ static snd_pcm_hardware_t snd_cx88_digital_hw = {
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = 0, /* set at runtime */
+
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 255 * 4092,
@@ -335,55 +528,27 @@ static snd_pcm_hardware_t snd_cx88_digital_hw = {
};
/*
- * Sets board to provide digital audio
+ * audio pcm capture runtime free
*/
-static int snd_cx88_set_digital_hw(snd_cx88_card_t *chip, snd_pcm_runtime_t *runtime)
-{
- static struct {
- int rate;
- unsigned int bit;
- } ratebits[] = {
- {8000, SNDRV_PCM_RATE_8000},
- {11025, SNDRV_PCM_RATE_11025},
- {16000, SNDRV_PCM_RATE_16000},
- {22050, SNDRV_PCM_RATE_22050},
- {32000, SNDRV_PCM_RATE_32000},
- {44100, SNDRV_PCM_RATE_44100},
- {48000, SNDRV_PCM_RATE_48000}
- };
- int i;
-#if 0
- chip->reg_control |= CTL_DA_IOM_DA;
-#endif
- runtime->hw = snd_cx88_digital_hw;
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- for (i = 0; i < ARRAY_SIZE(ratebits); ++i)
- if (chip->dig_rate == ratebits[i].rate) {
- runtime->hw.rates = ratebits[i].bit;
- break;
- }
- runtime->hw.rate_min = chip->dig_rate;
- runtime->hw.rate_max = chip->dig_rate;
- return 0;
-}
+static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+{
+ snd_pcm_hardware_t *pcm = runtime->private_data;
+ kfree(pcm);
+}
/*
- * audio open callback
+ * audio pcm capture open callback
*/
static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_cx88_pcm_t *pcm;
int err;
if (test_and_set_bit(0, &chip->opened))
return -EBUSY;
- err = snd_cx88_set_digital_hw(chip, runtime);
-
- if (err < 0)
- goto _error;
-
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
@@ -391,6 +556,19 @@ static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
chip->substream = substream;
return 0;
+ pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+ if (pcm == NULL) {
+ err=-ENOMEM;
+ goto _error;
+ }
+
+ spin_lock_init(&pcm->lock);
+
+ pcm->substream = substream;
+ runtime->private_data = pcm;
+ runtime->private_free = snd_card_cx88_runtime_free;
+ runtime->hw = snd_cx88_digital_hw;
+
_error:
clear_bit(0, &chip->opened);
smp_mb__after_clear_bit();
@@ -433,30 +611,17 @@ static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
static int snd_cx88_prepare(snd_pcm_substream_t *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-// snd_pcm_runtime_t *runtime = substream->runtime;
-// int decimation;
spin_lock_irq(&chip->reg_lock);
chip->dma_size = snd_pcm_lib_buffer_bytes(substream);
chip->period_size = snd_pcm_lib_period_bytes(substream);
-#if 0
- chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR);
- decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate;
- chip->reg_control |= decimation << CTL_DA_SDR_SHIFT;
- if (runtime->format == SNDRV_PCM_FORMAT_S8)
- chip->reg_control |= CTL_DA_SBR;
- snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
-
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
- outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME));
- outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE));
- ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM);
- ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode);
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1, ES_REG(ensoniq, DAC1_COUNT));
-#endif
+
+
+ /* setup fifo + format - out channel */
+ cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
+ chip->buf->bpl, chip->buf->risc.dma);
+
spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -467,16 +632,23 @@ static int snd_cx88_prepare(snd_pcm_substream_t *substream)
*/
static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
{
-// snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
-// return snd_cx88_start(chip);
+ err=_cx88_start_audio_dma(chip);
case SNDRV_PCM_TRIGGER_STOP:
-// return snd_cx88_stop(chip);
+ err=_cx88_stop_audio_dma(chip);
default:
- return -EINVAL;
+ err=-EINVAL;
}
+
+ spin_unlock(&chip->reg_lock);
+
+ return err;
}
/*
@@ -484,10 +656,10 @@ static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
*/
static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
{
-// snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-// snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
-// return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);
+ //return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);
}
/*
@@ -650,6 +822,7 @@ MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
static int snd_cx88_free(snd_cx88_card_t *chip)
{
+ dprintk(1,"cx88 free\n");
#if 0
if (chip->mmio) {
snd_bt87x_stop(chip);
@@ -659,16 +832,20 @@ static int snd_cx88_free(snd_cx88_card_t *chip)
iounmap(chip->mmio);
}
#endif
- if (chip->irq >= 0)
+ pci_disable_device(chip->pci);
+
+ if (chip->irq >= 0){
+ synchronize_irq(chip->irq);
free_irq(chip->irq, chip);
+ }
/* free memory */
- cx88_core_put(chip->core,chip->pci);
- pci_release_regions(chip->pci);
- pci_disable_device(chip->pci);
+ //pci_release_regions(chip->pci);
- kfree(chip);
+// btcx_riscmem_free(chip->pci,&chip->q.stopper);
+// cx88_core_put(chip->core,chip->pci);
+ //kfree(chip);
return 0;
}
@@ -678,6 +855,8 @@ static int snd_cx88_free(snd_cx88_card_t *chip)
static int snd_cx88_dev_free(snd_device_t *device)
{
snd_cx88_card_t *chip = device->device_data;
+
+ dprintk(1,"cx88 dev free\n");
return snd_cx88_free(chip);
}
@@ -702,6 +881,13 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
err = pci_enable_device(pci);
if (err < 0)
return err;
+ pci_set_master(pci);
+
+ if (!pci_dma_supported(pci,0xffffffff)) {
+ dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+ err = -EIO;
+ return err;
+ }
chip = kmalloc(sizeof(*chip),GFP_KERNEL);
if (NULL == chip) {
@@ -710,12 +896,6 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
}
memset(chip,0,sizeof(*chip));
- if (!pci_dma_supported(pci,0xffffffff)) {
- dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
- err = -EIO;
- kfree (chip);
- return err;
- }
/* pci init */
chip->card = card;
@@ -724,7 +904,12 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
spin_lock_init(&chip->reg_lock);
#if 0
- if ((err = pci_request_regions(pci, "CX88 audio")) < 0) {
+ if (!request_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0),
+ "CX88 audio")) {
+ err = -EBUSY;
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
+ "CX88 audio",pci_resource_start(pci,0));
kfree(chip);
pci_disable_device(pci);
return err;
@@ -732,7 +917,7 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
chip->mmio = ioremap_nocache(pci_resource_start(pci, 0),
pci_resource_len(pci, 0));
if (!chip->mmio) {
- snd_bt87x_free(chip);
+ kfree(chip);
snd_printk(KERN_ERR "cannot remap io memory\n");
return -ENOMEM;
}
@@ -745,6 +930,8 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
return err;
}
chip->core = core;
+
+
#if 1 /* Should be tested if it is wright */
chip->dig_rate=48000;
#endif
@@ -780,7 +967,7 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
pci_name(pci), chip->pci_rev, pci->irq,
chip->pci_lat,pci_resource_start(pci,0));
- pci_set_master(pci);
+ chip->irq = pci->irq;
synchronize_irq(chip->irq);
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
@@ -843,6 +1030,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
snd_card_free(card);
return (err);
}
+ snd_cx88_cards[devno] = card;
pci_set_drvdata(pci,card);
@@ -901,6 +1089,14 @@ static int cx88_audio_init(void)
*/
static void cx88_audio_fini(void)
{
+ int idx;
+
+/* printk(KERN_INFO "cx88 fini\n");
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ snd_card_free(snd_cx88_cards[idx]);
+ snd_cx88_cards[idx] = NULL;
+ }*/
+
pci_unregister_driver(&cx88_audio_pci_driver);
}