diff options
Diffstat (limited to 'sound/pci/emu10k1/p16v.c')
| -rw-r--r-- | sound/pci/emu10k1/p16v.c | 204 |
1 files changed, 87 insertions, 117 deletions
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 1099f102b365..b74128e61254 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -149,42 +149,19 @@ static const struct snd_pcm_hardware snd_p16v_capture_hw = { .fifo_size = 0, }; -static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime) -{ - struct snd_emu10k1_pcm *epcm = runtime->private_data; - - kfree(epcm); -} - /* open_playback callback */ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - struct snd_emu10k1_voice *channel = &(emu->p16v_voices[channel_id]); - struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int err; - epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ - - if (epcm == NULL) - return -ENOMEM; - epcm->emu = emu; - epcm->substream = substream; /* dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ - runtime->private_data = epcm; - runtime->private_free = snd_p16v_pcm_free_substream; runtime->hw = snd_p16v_playback_hw; - channel->emu = emu; - channel->number = channel_id; - - channel->use=1; #if 0 /* debug */ dev_dbg(emu->card->dev, "p16v: open channel_id=%d, channel=%p, use=0x%x\n", @@ -193,56 +170,28 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea channel_id, chip, channel); #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ - channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = 'P'; - runtime->sync.id32[2] = 16; - runtime->sync.id32[3] = 'V'; - return 0; } + /* open_capture callback */ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream, int channel_id) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - struct snd_emu10k1_voice *channel = &(emu->p16v_capture_voice); - struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int err; - epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ - - if (epcm == NULL) - return -ENOMEM; - epcm->emu = emu; - epcm->substream = substream; /* dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ - runtime->private_data = epcm; - runtime->private_free = snd_p16v_pcm_free_substream; runtime->hw = snd_p16v_capture_hw; - channel->emu = emu; - channel->number = channel_id; - - channel->use=1; -#if 0 /* debug */ - dev_dbg(emu->card->dev, - "p16v: open channel_id=%d, channel=%p, use=0x%x\n", - channel_id, channel, channel->use); - dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", - channel_id, chip, channel); -#endif /* debug */ - /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ - channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; @@ -252,22 +201,12 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream /* close callback */ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - //struct snd_pcm_runtime *runtime = substream->runtime; - //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0; - /* FIXME: maybe zero others */ return 0; } /* close callback */ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - //struct snd_pcm_runtime *runtime = substream->runtime; - //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_capture_voice.use = 0; - /* FIXME: maybe zero others */ return 0; } @@ -282,13 +221,24 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream) return snd_p16v_pcm_open_capture_channel(substream, 0); } +static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) { + static const unsigned char id[4] = { 'P', '1', '6', 'V' }; + snd_pcm_set_sync_per_card(substream, arg, id, 4); + return 0; + } + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); + u32 *table_base = (u32 *)(emu->p16v_buffer->area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; u32 tmp; @@ -306,23 +256,28 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) runtime->dma_addr, runtime->dma_area, table_base); dev_dbg(emu->card->dev, "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", - emu->p16v_buffer.addr, emu->p16v_buffer.area, - emu->p16v_buffer.bytes); + emu->p16v_buffer->addr, emu->p16v_buffer->area, + emu->p16v_buffer->bytes); #endif /* debug */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); + tmp &= ~(A_SPDIF_RATE_MASK | A_EHC_SRC48_MASK); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_44100 | A_EHC_SRC48_44); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_96000 | A_EHC_SRC48_96); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_192000 | A_EHC_SRC48_192); break; case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_48000 | A_EHC_SRC48_BYPASS); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ @@ -331,15 +286,15 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) table_base[(i*2)+1]=period_size_bytes<<16; } - snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel)); + snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer->addr+(8*16*channel)); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); - snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); - snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); + snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_END_ADDRESS, channel, 0); + snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_POINTER, channel, 0); return 0; } @@ -350,7 +305,6 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - u32 tmp; /* dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, " @@ -360,24 +314,23 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); */ - tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_44100); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_96000); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_192000); break; case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_48000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); + snd_emu10k1_ptr20_write(emu, CAPTURE_FIFO_POINTER, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); @@ -389,24 +342,56 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) static void snd_p16v_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); enable = inl(emu->port + INTE2) | intrenb; outl(enable, emu->port + INTE2); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int disable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); disable = inl(emu->port + INTE2) & (~intrenb); outl(disable, emu->port + INTE2); - spin_unlock_irqrestore(&emu->emu_lock, flags); +} + +static void snd_p16v_interrupt(struct snd_emu10k1 *emu) +{ + unsigned int status; + + while ((status = inl(emu->port + IPR2)) != 0) { + u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ + + /* dev_dbg(emu->card->dev, "p16v status=0x%x\n", status); */ + if (status & mask) { + struct snd_pcm_substream *substream = + emu->pcm_p16v->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime && runtime->private_data) { + snd_pcm_period_elapsed(substream); + } else { + dev_err(emu->card->dev, + "p16v: status: 0x%08x, mask=0x%08x\n", + status, mask); + } + } + if (status & 0x110000) { + struct snd_pcm_substream *substream = + emu->pcm_p16v->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + /* dev_info(emu->card->dev, "capture int found\n"); */ + if (runtime && runtime->private_data) { + /* dev_info(emu->card->dev, "capture period_elapsed\n"); */ + snd_pcm_period_elapsed(substream); + } + } + outl(status, emu->port + IPR2); /* ack all */ + } } /* trigger_playback callback */ @@ -415,7 +400,6 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; - struct snd_emu10k1_pcm *epcm; int channel; int result = 0; struct snd_pcm_substream *s; @@ -437,10 +421,9 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, s->stream != SNDRV_PCM_STREAM_PLAYBACK) continue; runtime = s->runtime; - epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */ - epcm->running = running; + runtime->private_data = (void *)(ptrdiff_t)running; basic |= (0x1<<channel); inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); snd_pcm_trigger_done(s, substream); @@ -469,7 +452,6 @@ static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream, { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_emu10k1_pcm *epcm = runtime->private_data; int channel = 0; int result = 0; u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; @@ -478,13 +460,13 @@ static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: snd_p16v_intr_enable(emu, inte); snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); - epcm->running = 1; + runtime->private_data = (void *)1; break; case SNDRV_PCM_TRIGGER_STOP: snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); snd_p16v_intr_disable(emu, inte); //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); - epcm->running = 0; + runtime->private_data = NULL; break; default: result = -EINVAL; @@ -499,10 +481,10 @@ snd_p16v_pcm_pointer_playback(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_emu10k1_pcm *epcm = runtime->private_data; snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; int channel = substream->pcm->device - emu->p16v_device_offset; - if (!epcm->running) + + if (!runtime->private_data) return 0; ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); @@ -524,11 +506,10 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_emu10k1_pcm *epcm = runtime->private_data; snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; int channel = 0; - if (!epcm->running) + if (!runtime->private_data) return 0; ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); @@ -552,6 +533,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) static const struct snd_pcm_ops snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, .close = snd_p16v_pcm_close_playback, + .ioctl = snd_p16v_pcm_ioctl_playback, .prepare = snd_p16v_pcm_prepare_playback, .trigger = snd_p16v_pcm_trigger_playback, .pointer = snd_p16v_pcm_pointer_playback, @@ -565,20 +547,6 @@ static const struct snd_pcm_ops snd_p16v_capture_ops = { .pointer = snd_p16v_pcm_pointer_capture, }; - -int snd_p16v_free(struct snd_emu10k1 *chip) -{ - // release the data - if (chip->p16v_buffer.area) { - snd_dma_free_pages(&chip->p16v_buffer); - /* - dev_dbg(chip->card->dev, "period lables free: %p\n", - &chip->p16v_buffer); - */ - } - return 0; -} - int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; @@ -589,7 +557,8 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; - if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) + err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -600,8 +569,9 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "p16v"); + strscpy(pcm->name, "p16v"); emu->pcm_p16v = pcm; + emu->p16v_interrupt = snd_p16v_interrupt; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -808,8 +778,8 @@ int snd_p16v_mixer(struct snd_emu10k1 *emu) struct snd_card *card = emu->card; for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], - emu))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], emu)); + if (err < 0) return err; } return 0; |
