Commit 86b40124 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - CS46xx
    - volume bug fixes and phase reversal fix
    - AC3 stuff...
    - SPDIF input fix
  - init.c
    - used workqueue for the disconnection job
  - CMIPCI
    - S/PDIF output / PLL updates
  - ICE1712
    - fixed reversed volume for AK4524 and AK4528 codecs
    - added support for Hoontech STA DSP24 Media 7.1
  - USB audio
    - various mixer fixes
    - quirks for Edirol PCR-30/50 keyboards and Midiman hardware
parent 3a404fb6
......@@ -1663,6 +1663,8 @@ typedef struct _snd_cs46xx_pcm_t {
snd_pcm_substream_t *substream;
pcm_channel_descriptor_t * pcm_channel;
int pcm_channel_id; /* Fron Rear, Center Lfe ... */
} cs46xx_pcm_t;
typedef struct {
......
......@@ -140,7 +140,6 @@ typedef struct _pcm_channel_descriptor_t {
dsp_scb_descriptor_t * pcm_reader_scb;
dsp_scb_descriptor_t * src_scb;
dsp_scb_descriptor_t * mixer_scb;
int pcm_channel_id;
void * private_data;
} pcm_channel_descriptor_t;
......
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc6"
#define CONFIG_SND_DATE " (Thu Dec 05 10:04:08 2002 UTC)"
#define CONFIG_SND_DATE " (Wed Dec 11 11:08:10 2002 UTC)"
......@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/ctype.h>
#include <linux/smp_lock.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
......@@ -152,13 +152,13 @@ int snd_card_disconnect(snd_card_t * card)
struct file_operations *f_ops, *old_f_ops;
int err;
write_lock(&card->files_lock);
spin_lock(&card->files_lock);
if (card->shutdown) {
write_unlock(&card->files_lock);
spin_unlock(&card->files_lock);
return 0;
}
card->shutdown = 1;
write_unlock(&card->files_lock);
spin_unlock(&card->files_lock);
/* phase 1: disable fops (user space) operations for ALSA API */
write_lock(&snd_card_rwlock);
......@@ -181,7 +181,9 @@ int snd_card_disconnect(snd_card_t * card)
f_ops = &s_f_ops->f_ops;
memset(f_ops, 0, sizeof(*f_ops));
#ifndef LINUX_2_2
f_ops->owner = file->f_op->owner;
#endif
f_ops->release = file->f_op->release;
f_ops->poll = snd_disconnect_poll;
......@@ -220,6 +222,10 @@ int snd_card_disconnect(snd_card_t * card)
* snd_card_free: frees given soundcard structure
* @card: soundcard structure
*
* This function releases the soundcard structure and the all assigned
* devices automatically. That is, you don't have to release the devices
* by yourself.
*
* Returns - zero. Frees all associated devices and frees the control
* interface associated to given soundcard.
*/
......@@ -283,22 +289,11 @@ int snd_card_free(snd_card_t * card)
return 0;
}
static int snd_card_free_thread(void * __card)
static void snd_card_free_thread(void * __card)
{
snd_card_t *card = __card;
struct module * module;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
lock_kernel();
#endif
daemonize();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
reparent_to_init();
#endif
strcpy(current->comm, "snd-free");
if (!try_inc_mod_count(module = card->module)) {
snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
module = NULL;
......@@ -310,31 +305,33 @@ static int snd_card_free_thread(void * __card)
if (module)
__MOD_DEC_USE_COUNT(module);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
unlock_kernel();
#endif
return 0;
}
/**
* snd_card_free_in_thread: call snd_card_free() in thread
* @card: soundcard structure
*
* This function schedules the call of #snd_card_free function in a
* work queue. When all devices are released (non-busy), the work
* is woken up and calls #snd_card_free.
*
* When a card can be disconnected at any time by hotplug service,
* this function should be used in disconnect (or detach) callback
* instead of calling #snd_card_free directly.
*
* Returns - zero otherwise a negative error code if the start of thread failed.
*/
int snd_card_free_in_thread(snd_card_t * card)
{
int pid;
DECLARE_WORK(works, snd_card_free_thread, card);
if (card->files == NULL) {
snd_card_free(card);
return 0;
}
pid = kernel_thread(snd_card_free_thread, card, 0);
if (pid >= 0)
if (schedule_work(&works))
return 0;
snd_printk(KERN_ERR "kernel_thread failed in snd_card_free_in_thread for card %i\n", card->number);
/* try to free the structure immediately */
snd_card_free(card);
......@@ -395,6 +392,17 @@ static void choose_default_id(snd_card_t * card)
}
}
/**
* snd_card_register: register the soundcard
* @card: soundcard structure
*
* This function registers all the devices assigned to the soundcard.
* Until calling this, the ALSA control interface is blocked from the
* external accesses. Thus, you should call this function at the end
* of the initialization of the card.
*
* Returns - zero otherwise a negative error code if the registrain failed.
*/
int snd_card_register(snd_card_t * card)
{
int err;
......@@ -509,6 +517,17 @@ int __exit snd_card_info_done(void)
return 0;
}
/**
* snd_component_add: add a component string
* @card: soundcard structure
* @component: the component id string
*
* This function adds the component id string to the supported list.
* The component can be referred from the alsa-lib.
*
* Returns - zero otherwise a negative error code.
*/
int snd_component_add(snd_card_t *card, const char *component)
{
char *ptr;
......@@ -529,6 +548,17 @@ int snd_component_add(snd_card_t *card, const char *component)
return 0;
}
/**
* snd_card_file_add: add the file to the file list of the card
* @card: soundcard structure
* @file: file pointer
*
* This function adds the file to the file linked-list of the card.
* This linked-list is used to keep tracking the connection state,
* and to avoid the release of busy resources by hotplug.
*
* Returns zero or a negative error code.
*/
int snd_card_file_add(snd_card_t *card, struct file *file)
{
struct snd_monitor_file *mfile;
......@@ -550,6 +580,19 @@ int snd_card_file_add(snd_card_t *card, struct file *file)
return 0;
}
/**
* snd_card_file_remove: remove the file from the file list
* @card: soundcard structure
* @file: file pointer
*
* This function removes the file formerly added to the card via
* #snd_card_file_add function.
* If all files are removed and the release of the card is
* scheduled, it will wake up the the thread to call #snd_card_free
* (see #snd_card_free_in_thread function).
*
* Returns zero or a negative error code.
*/
int snd_card_file_remove(snd_card_t *card, struct file *file)
{
struct snd_monitor_file *mfile, *pfile = NULL;
......@@ -580,7 +623,12 @@ int snd_card_file_remove(snd_card_t *card, struct file *file)
}
#ifdef CONFIG_PM
/* the power lock must be active before call */
/**
* snd_power_wait: wait until the power-state is changed.
* @card: soundcard structure
*
* Note: the power lock must be active before call.
*/
void snd_power_wait(snd_card_t *card)
{
wait_queue_t wait;
......
......@@ -110,8 +110,8 @@ int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream)
snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
} else
#endif
snd_runtime_check(pos <= runtime->buffer_size, return 0);
snd_runtime_check(pos < runtime->buffer_size, return 0);
pos -= pos % runtime->min_align;
new_hw_ptr = runtime->hw_ptr_base + pos;
......@@ -176,8 +176,8 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
} else
#endif
snd_runtime_check(pos <= runtime->buffer_size, return 0);
snd_runtime_check(pos < runtime->buffer_size, return 0);
pos -= pos % runtime->min_align;
new_hw_ptr = runtime->hw_ptr_base + pos;
......
......@@ -283,6 +283,8 @@ static int snd_seq_device_dev_disconnect(snd_device_t *device)
return -ENOENT;
free_device(dev, ops);
unlock_driver(ops);
return 0;
}
......
......@@ -445,6 +445,9 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
int result = 0;
unsigned int what;
snd_pcm_substream_t *s;
int do_start;
#if 0
printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
......@@ -452,38 +455,39 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
do_start = 1; break;
case SNDRV_PCM_TRIGGER_STOP:
{
unsigned int what = 0;
snd_pcm_substream_t *s = substream;
do {
if (s == chip->playback_substream) {
what |= CS4231_PLAYBACK_ENABLE;
snd_pcm_trigger_done(s, substream);
} else if (s == chip->capture_substream) {
what |= CS4231_RECORD_ENABLE;
snd_pcm_trigger_done(s, substream);
}
s = s->link_next;
} while (s != substream);
spin_lock(&chip->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_START) {
chip->image[CS4231_IFACE_CTRL] |= what;
if (chip->trigger)
chip->trigger(chip, what, 1);
} else {
chip->image[CS4231_IFACE_CTRL] &= ~what;
if (chip->trigger)
chip->trigger(chip, what, 0);
}
snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
spin_unlock(&chip->reg_lock);
break;
}
case SNDRV_PCM_TRIGGER_SUSPEND:
do_start = 0; break;
default:
result = -EINVAL;
break;
return -EINVAL;
}
what = 0;
s = substream;
do {
if (s == chip->playback_substream) {
what |= CS4231_PLAYBACK_ENABLE;
snd_pcm_trigger_done(s, substream);
} else if (s == chip->capture_substream) {
what |= CS4231_RECORD_ENABLE;
snd_pcm_trigger_done(s, substream);
}
s = s->link_next;
} while (s != substream);
spin_lock(&chip->reg_lock);
if (do_start) {
chip->image[CS4231_IFACE_CTRL] |= what;
if (chip->trigger)
chip->trigger(chip, what, 1);
} else {
chip->image[CS4231_IFACE_CTRL] &= ~what;
if (chip->trigger)
chip->trigger(chip, what, 0);
}
snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
spin_unlock(&chip->reg_lock);
#if 0
snd_cs4231_debug(chip);
#endif
......@@ -1188,7 +1192,9 @@ int snd_cs4231_probe(cs4231_t *chip)
static snd_pcm_hardware_t snd_cs4231_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
......@@ -1207,7 +1213,9 @@ static snd_pcm_hardware_t snd_cs4231_playback =
static snd_pcm_hardware_t snd_cs4231_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
......
......@@ -444,8 +444,7 @@ static int snd_es18xx_playback_hw_params(snd_pcm_substream_t * substream,
if (snd_pcm_format_width(params_format(hw_params)) == 16)
shift++;
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
if ((chip->caps & ES18XX_DUPLEX_MONO) &&
(chip->capture_a_substream) &&
params_channels(hw_params) != 1) {
......@@ -453,10 +452,8 @@ static int snd_es18xx_playback_hw_params(snd_pcm_substream_t * substream,
return -EBUSY;
}
chip->dma2_shift = shift;
break;
case 1:
} else {
chip->dma1_shift = shift;
break;
}
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
......@@ -495,19 +492,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
snd_pcm_substream_t * substream,
int cmd)
{
if (cmd == SNDRV_PCM_TRIGGER_START) {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (chip->active & DAC2)
return 0;
chip->active |= DAC2;
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
if (!(chip->active & DAC2))
return 0;
chip->active &= ~DAC2;
} else {
return -EINVAL;
}
if (cmd == SNDRV_PCM_TRIGGER_START) {
/* Start DMA */
if (chip->dma2 >= 4)
snd_es18xx_mixer_write(chip, 0x78, 0xb3);
......@@ -523,8 +513,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
/* Enable PCM output */
snd_es18xx_dsp_command(chip, 0xD1);
#endif
}
else {
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!(chip->active & DAC2))
return 0;
chip->active &= ~DAC2;
/* Stop DMA */
snd_es18xx_mixer_write(chip, 0x78, 0x00);
#ifdef AVOID_POPS
......@@ -536,7 +530,10 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
/* Disable PCM output */
snd_es18xx_dsp_command(chip, 0xD3);
#endif
}
break;
default:
return -EINVAL;
}
return 0;
}
......@@ -608,24 +605,27 @@ static int snd_es18xx_capture_trigger(snd_pcm_substream_t *substream,
{
es18xx_t *chip = snd_pcm_substream_chip(substream);
if (cmd == SNDRV_PCM_TRIGGER_START) {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (chip->active & ADC1)
return 0;
chip->active |= ADC1;
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
/* Start DMA */
snd_es18xx_write(chip, 0xB8, 0x0f);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!(chip->active & ADC1))
return 0;
chip->active &= ~ADC1;
} else {
/* Stop DMA */
snd_es18xx_write(chip, 0xB8, 0x00);
break;
default:
return -EINVAL;
}
if (cmd == SNDRV_PCM_TRIGGER_START)
/* Start DMA */
snd_es18xx_write(chip, 0xB8, 0x0f);
else
/* Stop DMA */
snd_es18xx_write(chip, 0xB8, 0x00);
return 0;
}
......@@ -670,19 +670,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
snd_pcm_substream_t *substream,
int cmd)
{
if (cmd == SNDRV_PCM_TRIGGER_START) {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (chip->active & DAC1)
return 0;
chip->active |= DAC1;
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
if (!(chip->active & DAC1))
return 0;
chip->active &= ~DAC1;
} else {
return -EINVAL;
}
if (cmd == SNDRV_PCM_TRIGGER_START) {
/* Start DMA */
snd_es18xx_write(chip, 0xB8, 0x05);
#ifdef AVOID_POPS
......@@ -691,8 +684,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
/* Enable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD1);
#endif
}
else {
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!(chip->active & DAC1))
return 0;
chip->active &= ~DAC1;
/* Stop DMA */
snd_es18xx_write(chip, 0xB8, 0x00);
#ifdef AVOID_POPS
......@@ -701,33 +698,31 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
/* Disable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD3);
#endif
}
break;
default:
return -EINVAL;
}
return 0;
}
static int snd_es18xx_playback_prepare(snd_pcm_substream_t *substream)
{
es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
return snd_es18xx_playback1_prepare(chip, substream);
case 1:
else
return snd_es18xx_playback2_prepare(chip, substream);
}
return -EINVAL;
}
static int snd_es18xx_playback_trigger(snd_pcm_substream_t *substream,
int cmd)
{
es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
return snd_es18xx_playback1_trigger(chip, substream, cmd);
case 1:
else
return snd_es18xx_playback2_trigger(chip, substream, cmd);
}
return -EINVAL;
}
static void snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -798,19 +793,17 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(snd_pcm_substream_t * subst
es18xx_t *chip = snd_pcm_substream_chip(substream);
int pos;
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
if (!(chip->active & DAC2))
return 0;
pos = chip->dma2_size - snd_dma_residue(chip->dma2);
return pos >> chip->dma2_shift;
case 1:
} else {
if (!(chip->active & DAC1))
return 0;
pos = chip->dma1_size - snd_dma_residue(chip->dma1);
return pos >> chip->dma1_shift;
}
return 0;
}
static snd_pcm_uframes_t snd_es18xx_capture_pointer(snd_pcm_substream_t * substream)
......@@ -827,6 +820,7 @@ static snd_pcm_uframes_t snd_es18xx_capture_pointer(snd_pcm_substream_t * substr
static snd_pcm_hardware_t snd_es18xx_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
......@@ -846,6 +840,7 @@ static snd_pcm_hardware_t snd_es18xx_playback =
static snd_pcm_hardware_t snd_es18xx_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
......@@ -867,20 +862,17 @@ static int snd_es18xx_playback_open(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
if ((chip->caps & ES18XX_DUPLEX_MONO) &&
chip->capture_a_substream &&
chip->capture_a_substream->runtime->channels != 1)
return -EAGAIN;
chip->playback_a_substream = substream;
break;
case 1:
} else if (substream->number <= 1) {
if (chip->capture_a_substream)
return -EAGAIN;
chip->playback_b_substream = substream;
break;
default:
} else {
snd_BUG();
return -EINVAL;
}
......@@ -912,17 +904,10 @@ static int snd_es18xx_playback_close(snd_pcm_substream_t * substream)
{
es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) {
case 0:
if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
chip->playback_a_substream = NULL;
break;
case 1:
else
chip->playback_b_substream = NULL;
break;
default:
snd_BUG();
return -EINVAL;
}
snd_pcm_lib_free_pages(substream);
return 0;
......@@ -1544,6 +1529,9 @@ static int __init snd_es18xx_probe(es18xx_t *chip)
snd_printd("[0x%lx] ESS%x chip found\n", chip->port, chip->version);
if (chip->dma1 == chip->dma2)
chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
return snd_es18xx_initialize(chip);
}
......@@ -1600,6 +1588,8 @@ int __init snd_es18xx_pcm(es18xx_t *chip, int device, snd_pcm_t ** rpcm)
pcm->info_flags = 0;
if (chip->caps & ES18XX_DUPLEX_SAME)
pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
if (! (chip->caps & ES18XX_PCM2))
pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
sprintf(pcm->name, "ESS AudioDrive ES%x", chip->version);
chip->pcm = pcm;
......@@ -1709,7 +1699,7 @@ static int snd_es18xx_free(es18xx_t *chip)
disable_dma(chip->dma1);
free_dma(chip->dma1);
}
if (chip->dma2 >= 0) {
if (chip->dma2 >= 0 && chip->dma1 != chip->dma2) {
disable_dma(chip->dma2);
free_dma(chip->dma2);
}
......@@ -1773,7 +1763,7 @@ static int __init snd_es18xx_new_device(snd_card_t * card,
}
chip->dma1 = dma1;
if (request_dma(dma2, "ES18xx DMA 2")) {
if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
snd_es18xx_free(chip);
printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
return -EBUSY;
......@@ -2181,10 +2171,16 @@ static int __init snd_audiodrive_probe(int dev)
#endif
sprintf(card->driver, "ES%x", chip->version);
sprintf(card->shortname, "ESS AudioDrive ES%x", chip->version);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma1 %d, dma2 %d",
card->shortname,
chip->port,
xirq, xdma1, xdma2);
if (xdma1 != xdma2)
sprintf(card->longname, "%s at 0x%lx, irq %d, dma1 %d, dma2 %d",
card->shortname,
chip->port,
xirq, xdma1, xdma2);
else
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
card->shortname,
chip->port,
xirq, xdma1);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
......
......@@ -666,7 +666,7 @@ static int __init alsa_card_sb16_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
int __attribute__ ((__unused__)) pnp = INT_MAX;
int __attribute__ ((__unused__)) csp = INT_MAX;
int __attribute__ ((__unused__)) xcsp = INT_MAX;
if (nr_dev >= SNDRV_CARDS)
return 0;
......@@ -683,7 +683,7 @@ static int __init alsa_card_sb16_setup(char *str)
get_option(&str,&mic_agc[nr_dev]) == 2
#ifdef CONFIG_SND_SB16_CSP
&&
get_option(&str,&csp[nr_dev]) == 2
get_option(&str,&xcsp) == 2
#endif
#ifdef SNDRV_SBAWE_EMU8000
&&
......@@ -697,7 +697,7 @@ static int __init alsa_card_sb16_setup(char *str)
#endif
#ifdef CONFIG_SND_SB16_CSP
if (csp != INT_MAX)
csp[nr_dev] = csp;
csp[nr_dev] = xcsp;
#endif
nr_dev++;
return 1;
......
......@@ -1210,59 +1210,64 @@ static int snd_ali_trigger(snd_pcm_substream_t *substream,
unsigned int what, whati, capture_flag;
snd_ali_voice_t *pvoice = NULL, *evoice = NULL;
unsigned int val;
int do_start;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
do_start = 1; break;
case SNDRV_PCM_TRIGGER_STOP:
{
what = whati = capture_flag = 0;
s = substream;
do {
if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) {
pvoice = (snd_ali_voice_t *) s->runtime->private_data;
evoice = pvoice->extra;
what |= 1 << (pvoice->number & 0x1f);
if (evoice == NULL) {
whati |= 1 << (pvoice->number & 0x1f);
} else {
whati |= 1 << (evoice->number & 0x1f);
what |= 1 << (evoice->number & 0x1f);
}
if (cmd == SNDRV_PCM_TRIGGER_START) {
pvoice->running = 1;
if (evoice != NULL)
evoice->running = 1;
}
snd_pcm_trigger_done(s, substream);
if (pvoice->mode)
capture_flag = 1;
case SNDRV_PCM_TRIGGER_SUSPEND:
do_start = 0; break;
default:
return -EINVAL;
}
what = whati = capture_flag = 0;
s = substream;
do {
if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) {
pvoice = (snd_ali_voice_t *) s->runtime->private_data;
evoice = pvoice->extra;
what |= 1 << (pvoice->number & 0x1f);
if (evoice == NULL) {
whati |= 1 << (pvoice->number & 0x1f);
} else {
whati |= 1 << (evoice->number & 0x1f);
what |= 1 << (evoice->number & 0x1f);
}
s = s->link_next;
} while (s != substream);
spin_lock(&codec->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
outl(what, ALI_REG(codec, ALI_STOP));
pvoice->running = 0;
if (evoice != NULL)
evoice->running = 0;
}
val = inl(ALI_REG(codec, ALI_AINTEN));
if (cmd == SNDRV_PCM_TRIGGER_START) {
val |= whati;
} else {
val &= ~whati;
}
outl(val, ALI_REG(codec, ALI_AINTEN));
if (cmd == SNDRV_PCM_TRIGGER_START) {
outl(what, ALI_REG(codec, ALI_START));
if (do_start) {
pvoice->running = 1;
if (evoice != NULL)
evoice->running = 1;
} else {
pvoice->running = 0;
if (evoice != NULL)
evoice->running = 0;
}
snd_pcm_trigger_done(s, substream);
if (pvoice->mode)
capture_flag = 1;
}
snd_ali_printk("trigger: what=%xh whati=%xh\n",what,whati);
spin_unlock(&codec->reg_lock);
break;
s = s->link_next;
} while (s != substream);
spin_lock(&codec->reg_lock);
if (! do_start) {
outl(what, ALI_REG(codec, ALI_STOP));
}
default:
return -EINVAL;
val = inl(ALI_REG(codec, ALI_AINTEN));
if (do_start) {
val |= whati;
} else {
val &= ~whati;
}
outl(val, ALI_REG(codec, ALI_AINTEN));
if (do_start) {
outl(what, ALI_REG(codec, ALI_START));
}
snd_ali_printk("trigger: what=%xh whati=%xh\n",what,whati);
spin_unlock(&codec->reg_lock);
return 0;
}
......@@ -1544,7 +1549,9 @@ static snd_pcm_hardware_t snd_ali_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
......@@ -1568,7 +1575,9 @@ static snd_pcm_hardware_t snd_ali_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
......
......@@ -17,8 +17,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Does not work. Warning may block system in capture mode */
/* #define USE_VAR48KRATE */
/* Define this if you want soft ac3 encoding - it's still buggy.. */
/* #define DO_SOFT_AC3 */
/* #define USE_AES_IEC958 */
#define DO_SOFT_AC3
#define USE_AES_IEC958
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/pci.h>
......@@ -151,9 +161,15 @@ MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0}
#define CM_REG_INT_STATUS 0x10
#define CM_INTR 0x80000000
#define CM_VCO 0x08000000 /* Voice Control? CMI8738 */
#define CM_MCBINT 0x04000000 /* Master Control Block abort cond.? */
#define CM_UARTINT 0x00010000
#define CM_LTDMAINT 0x00008000
#define CM_HTDMAINT 0x00004000
#define CM_XDO46 0x00000080 /* Modell 033? Direct programming EEPROM (read data register) */
#define CM_LHBTOG 0x00000040 /* High/Low status from DMA ctrl register */
#define CM_LEG_HDMA 0x00000020 /* Legacy is in High DMA channel */
#define CM_LEG_STEREO 0x00000010 /* Legacy is in Stereo mode */
#define CM_CH1BUSY 0x00000008
#define CM_CH0BUSY 0x00000004
#define CM_CHINT1 0x00000002
......@@ -218,6 +234,11 @@ MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0}
#define CM_REG_SB16_DATA 0x22
#define CM_REG_SB16_ADDR 0x23
#define CM_REFFREQ_XIN (315*1000*1000)/22 /* 14.31818 Mhz reference clock frequency pin XIN */
#define CM_ADCMULT_XIN 512 /* Guessed (487 best for 44.1kHz, not for 88/176kHz) */
#define CM_TOLERANCE_RATE 0.001 /* Tolerance sample rate pitch (1000ppm) */
#define CM_MAXIMUM_RATE 80000000 /* Note more than 80MHz */
#define CM_REG_MIXER1 0x24
#define CM_FMMUTE 0x80 /* mute FM */
#define CM_FMMUTE_SHIFT 7
......@@ -263,6 +284,39 @@ MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0}
#define CM_DMAUTO 0x01
#define CM_REG_AC97 0x28 /* hmmm.. do we have ac97 link? */
/*
* For CMI-8338 (0x28 - 0x2b) .. is this valid for CMI-8738
* or identical with AC97 codec?
*/
#define CM_REG_EXTERN_CODEC CM_REG_AC97
/*
* MPU401 pci port index address 0x40 - 0x4f (CMI-8738 spec ver. 0.6)
*/
#define CM_REG_MPU_PCI 0x40
/*
* FM pci port index address 0x50 - 0x5f (CMI-8738 spec ver. 0.6)
*/
#define CM_REG_FM_PCI 0x50
/*
* for CMI-8338 .. this is not valid for CMI-8738.
*/
#define CM_REG_EXTENT_IND 0xf0
#define CM_VPHONE_MASK 0xe0 /* Phone volume control (0-3) << 5 */
#define CM_VPHONE_SHIFT 5
#define CM_VPHOM 0x10 /* Phone mute control */
#define CM_VSPKM 0x08 /* Speaker mute control, default high */
#define CM_RLOOPREN 0x04 /* Rec. R-channel enable */
#define CM_RLOOPLEN 0x02 /* Rec. L-channel enable */
/*
* CMI-8338 spec ver 0.5 (this is not valid for CMI-8738):
* the 8 registers 0xf8 - 0xff are used for programming m/n counter by the PLL
* unit (readonly?).
*/
#define CM_REG_PLL 0xf8
/*
* extended registers
......@@ -330,12 +384,6 @@ MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0}
#endif
/*
* define this if you want soft ac3 encoding - it's still buggy..
*/
/* #define DO_SOFT_AC3 */
/*
* driver data
*/
......@@ -401,6 +449,9 @@ struct snd_stru_cmipci {
unsigned int dig_status;
unsigned int dig_pcm_status;
#ifdef USE_AES_IEC958
snd_ctl_elem_value_t *spdif_channel;
#endif
snd_kcontrol_t *spdif_pcm_ctl;
snd_pcm_hardware_t *hw_info[3]; /* for playbacks */
......@@ -515,12 +566,86 @@ static unsigned int snd_cmipci_rate_freq(unsigned int rate)
return 0;
}
#ifdef USE_VAR48KRATE
/*
* Determine PLL values for frequency setup, maybe the CMI8338 (CMI8738???)
* does it this way .. maybe not. Never get any information from C-Media about
* that <werner@suse.de>.
*/
static int snd_cmipci_pll_rmn(unsigned int rate, unsigned int adcmult, int *r, int *m, int *n)
{
unsigned int delta, tolerance;
int xm, xn, xr;
for (*r = 0; rate < CM_MAXIMUM_RATE/adcmult; *r += (1<<5))
rate <<= 1;
*n = -1;
if (*r > 0xff)
goto out;
tolerance = rate*CM_TOLERANCE_RATE;
for (xn = (1+2); xn < (0x1f+2); xn++) {
for (xm = (1+2); xm < (0xff+2); xm++) {
xr = ((CM_REFFREQ_XIN/adcmult) * xm) / xn;
if (xr < rate)
delta = rate - xr;
else
delta = xr - rate;
/*
* If we found one, remember this,
* and try to find a closer one
*/
if (delta < tolerance) {
tolerance = delta;
*m = xm - 2;
*n = xn - 2;
}
}
}
out:
return (*n > -1);
}
/*
* Program pll register bits, I assume that the 8 registers 0xf8 upto 0xff
* are mapped onto the 8 ADC/DAC sampling frequency which can be choosen
* at the register CM_REG_FUNCTRL1 (0x04).
* Problem: other ways are also possible (any information about that?)
*/
static void snd_cmipci_set_pll(cmipci_t *cm, unsigned int rate, unsigned int slot)
{
unsigned int reg = CM_REG_PLL + slot;
/*
* Guess that this programs at reg. 0x04 the pos 15:13/12:10
* for DSFC/ASFC (000 upto 111).
*/
/* FIXME: Init (Do we've to set an other register first before programming?) */
/* FIXME: Is this correct? Or shouldn't the m/n/r values be used for that? */
snd_cmipci_write_b(cm, reg, rate>>8);
snd_cmipci_write_b(cm, reg, rate&0xff);
/* FIXME: Setup (Do we've to set an other register first to enable this?) */
}
#endif /* USE_VAR48KRATE */
static int snd_cmipci_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
static void snd_cmipci_ch_reset(cmipci_t *cm, int ch)
{
int reset = CM_RST_CH0 << (cm->channel[ch].ch);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset);
udelay(10);
}
static int snd_cmipci_hw_free(snd_pcm_substream_t * substream)
{
return snd_pcm_lib_free_pages(substream);
......@@ -699,7 +824,7 @@ static int snd_cmipci_pcm_trigger(cmipci_t *cm, cmipci_pcm_t *rec,
/* reset */
cm->ctrl &= ~chen;
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
cm->ctrl |= pause;
......@@ -784,8 +909,10 @@ static snd_pcm_uframes_t snd_cmipci_capture_pointer(snd_pcm_substream_t *substre
* write the raw subframe via 32bit data mode.
*/
# ifndef USE_AES_IEC958
/* find parity for bit 4~30 */
static unsigned parity(unsigned int data)
static unsigned int parity(unsigned int data)
{
unsigned int parity = 0;
int counter = 4;
......@@ -835,6 +962,187 @@ inline static u32 convert_ac3_32bit(cmipci_t *cm, u32 val)
return data;
}
# else /* if USE_AES_IEC958 */
/*
* The bitstream handling
*/
typedef struct iec958_stru_bitstream {
u32 *data; /* Holds the current position */
u32 left; /* Bits left in current 32bit frame */
u32 word; /* The 32bit frame of the current position */
u32 bits; /* All bits together */
int err; /* Error condition */
} iec958_bitstream_t ;
static iec958_bitstream_t bs;
/* Initialize ptr on the buffer */
static void iec958_init_bitstream(u8 *buf, u32 size)
{
bs.data = (u32 *)buf; /* Set initial position */
bs.word = *bs.data; /* The first 32bit frame */
bs.left = 32; /* has exactly 32bits */
bs.bits = size;
bs.err = 0;
}
/* Remove ptr on the buffer */
static void iec958_clear_bitstream(void)
{
bs.data = NULL;
bs.left = 0;
bs.err = 0;
}
/* Get bits from bitstream (max 32) */
static inline u32 iec958_getbits(u32 bits)
{
u32 res;
if (bs.bits < bits) {
bits = bs.bits;
bs.err = 1;
}
if (bits > 32) {
bits = 32;
bs.err = 1;
}
bs.bits -= bits;
# ifdef WORDS_BIGENDIAN
if (bits < bs.left) { /* Within 32bit frame */
res = (bs.word << (32 - bs.left)) >> (32 - bits);
bs.left -= bits;
goto out;
} /* We may cross the frame boundary */
res = (bs.word << (32 - bs.left)) >> (32 - bs.left);
bits -= bs.left;
bs.word = *(++bs.data); /* Next 32bit frame */
if (bits) /* Add remaining bits, if any */
res = (res << bits) | (bs.word >> (32 - bits));
# else /* not WORDS_BIGENDIAN */
if (bits < bs.left) { /* Within 32bit frame */
res = (bs.word << (32 - bits)) >> (32 - bits);
bs.word >>= bits;
bs.left -= bits;
goto out;
} /* We may cross the frame boundary */
res = bs.word;
bits -= bs.left;
bs.word = *(++bs.data); /* Next 32bit frame */
if (bits) { /* Add remaining bits, if any */
res = res | (((bs.word << (32 - bits)) >> (32 - bits)) << bits);
bs.word >>= bits;
}
# endif /* not WORDS_BIGENDIAN */
bs.left = (32 - bits);
out:
return res;
}
static inline u32 iec958_bits_avail(void)
{
return bs.bits;
}
static inline int iec958_error(void)
{
return bs.err;
}
/*
* Determine parity for time slots 4 upto 30
* to be sure that bit 4 upt 31 will carry
* an even number of ones and zeros.
*/
static u32 iec958_parity(u32 data)
{
u32 parity = 0;
int counter = 4;
data >>= 4; /* start from bit 4 */
while (counter++ <= 30) {
if (data & 0x00000001)
parity++;
data >>= 1;
}
return (parity & 0x00000001);
}
/*
* Compose 32bit iec958 subframe, two sub frames
* build one frame with two channels.
*
* bit 0-3 = preamble
* 4-7 = AUX (=0)
* 8-27 = data (12-27 for 16bit, 8-27 for 20bit, and 24bit without AUX)
* 28 = validity (0 for valid data, else 'in error')
* 29 = user data (0)
* 30 = channel status (24 bytes for 192 frames)
* 31 = parity
*/
static inline u32 iec958_subframe(cmipci_t *cm, snd_ctl_elem_value_t * ucontrol)
{
u32 data;
u32 byte = cm->spdif_counter >> 4;
u32 mask = 1 << ((cm->spdif_counter >> 1) - (byte << 3));
u8 * status = ucontrol->value.iec958.status;
if (status[2] & IEC958_AES2_PRO_SBITS_24) {
/* Does this work for LE systems ??? */
if (status[2] & IEC958_AES2_PRO_WORDLEN_24_20) {
data = iec958_getbits(24);
data <<= 4;
} else {
data = iec958_getbits(20);
data <<= 8;
}
} else {
if (status[2] & IEC958_AES2_PRO_WORDLEN_24_20) {
/* Does this work for LE systems ??? */
data = iec958_getbits(20);
data <<= 8;
} else {
data = iec958_getbits(16);
data <<= 12;
}
}
/*
* Set one of the 192 bits of the channel status (AES3 and higher)
*/
if (status[byte] & mask)
data |= 0x40000000;
if (iec958_parity(data)) /* parity bit 4-30 */
data |= 0x80000000;
/* Preamble */
if (!cm->spdif_counter)
data |= 0x03; /* Block start, 'Z' */
else if (cm->spdif_counter % 2)
data |= 0x05; /* odd sub frame, 'Y' */
else
data |= 0x09; /* even sub frame, 'X' */
/*
* sub frame counter: 2 sub frame are one audio frame
* and 192 frames are one block
*/
cm->spdif_counter = (++cm->spdif_counter) % 384;
return data;
}
# endif /* if USE_AES_IEC958 */
static int snd_cmipci_ac3_copy(snd_pcm_substream_t *subs, int channel,
snd_pcm_uframes_t pos, void *src,
......@@ -842,9 +1150,15 @@ static int snd_cmipci_ac3_copy(snd_pcm_substream_t *subs, int channel,
{
cmipci_t *cm = snd_pcm_substream_chip(subs);
u32 *dst;
u16 *srcp = src, val;
snd_pcm_uframes_t offset;
snd_pcm_runtime_t *runtime = subs->runtime;
#ifndef USE_AES_IEC958
u16 *srcp = src, val;
#else
char buf[1920]; /* bits can be divided by 20, 24, 16 */
size_t bytes = frames_to_bytes(runtime, count);
#endif
if (!cm->channel[CM_CH_PLAY].ac3_shift) {
if (copy_from_user(runtime->dma_area +
......@@ -860,14 +1174,34 @@ static int snd_cmipci_ac3_copy(snd_pcm_substream_t *subs, int channel,
/* frame = 16bit stereo */
offset = (pos << 1) % (cm->channel[CM_CH_PLAY].dma_size << 2);
dst = (u32*)(runtime->dma_area + offset);
# ifndef USE_AES_IEC958
count /= 2;
while (count-- > 0) {
get_user(val, srcp);
srcp++;
*dst++ = convert_ac3_32bit(cm, val);
}
# else
while (bytes) {
size_t c = bytes;
if (c > sizeof(buf))
c = sizeof(buf);
if (copy_from_user(buf, src, c))
return -EFAULT;
bytes -= c;
src += c;
iec958_init_bitstream(buf, c*8);
while (iec958_bits_avail()) {
*(dst++) = iec958_subframe(cm, cm->spdif_channel);
if (iec958_error())
return -EINVAL;
}
iec958_clear_bitstream();
}
# endif
return 0;
}
......@@ -879,7 +1213,10 @@ static int snd_cmipci_ac3_silence(snd_pcm_substream_t *subs, int channel,
u32 *dst;
snd_pcm_uframes_t offset;
snd_pcm_runtime_t *runtime = subs->runtime;
# ifdef USE_AES_IEC958
char buf[1920]; /* bits can be divided by 20, 24, 16 */
size_t bytes = frames_to_bytes(runtime, count);
# endif
if (! cm->channel[CM_CH_PLAY].ac3_shift)
return snd_pcm_format_set_silence(runtime->format,
runtime->dma_area + frames_to_bytes(runtime, pos), count);
......@@ -887,12 +1224,31 @@ static int snd_cmipci_ac3_silence(snd_pcm_substream_t *subs, int channel,
/* frame = 16bit stereo */
offset = (pos << 1) % (cm->channel[CM_CH_PLAY].dma_size << 2);
dst = (u32*)(subs->runtime->dma_area + offset);
# ifndef USE_AES_IEC958
count /= 2;
while (count-- > 0) {
*dst++ = convert_ac3_32bit(cm, 0);
}
# else
while (bytes) {
size_t c = bytes;
if (c > sizeof(buf))
c = sizeof(buf);
/* Q: Does this function know about 24bit silence? */
if (snd_pcm_format_set_silence(runtime->format, buf, bytes_to_frames(runtime, c)))
return -EINVAL;
iec958_init_bitstream(buf, c*8);
while (iec958_bits_avail()) {
*(dst++) = iec958_subframe(cm, cm->spdif_channel);
if (iec958_error())
return -EINVAL;
}
iec958_clear_bitstream();
}
# endif
return 0;
}
#endif /* DO_SOFT_AC3 */
......@@ -996,6 +1352,9 @@ static int snd_cmipci_spdif_stream_get(snd_kcontrol_t *kcontrol,
spin_lock_irqsave(&chip->reg_lock, flags);
for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] = (chip->dig_pcm_status >> (i * 8)) & 0xff;
#ifdef USE_AES_IEC958
ucontrol = chip->spdif_channel;
#endif
spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
......@@ -1014,6 +1373,9 @@ static int snd_cmipci_spdif_stream_put(snd_kcontrol_t *kcontrol,
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
change = val != chip->dig_pcm_status;
chip->dig_pcm_status = val;
#ifdef USE_AES_IEC958
chip->spdif_channel = ucontrol;
#endif
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
......@@ -1128,9 +1490,11 @@ static void setup_ac3(cmipci_t *cm, snd_pcm_substream_t *subs, int do_ac3, int r
if (cm->can_ac3_hw) {
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);
} else {
#ifdef DO_SOFT_AC3
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);
#endif /* DO_SOFT_AC3 */
}
}
}
......@@ -1248,7 +1612,7 @@ static int snd_cmipci_capture_spdif_hw_free(snd_pcm_substream_t *subs)
static void snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
cmipci_t *cm = snd_magic_cast(cmipci_t, dev_id, return);
unsigned int status;
unsigned int status, mask = 0;
/* fastpath out, to ease interrupt sharing */
status = snd_cmipci_read(cm, CM_REG_INT_STATUS);
......@@ -1257,14 +1621,12 @@ static void snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* acknowledge interrupt */
spin_lock(&cm->reg_lock);
if (status & CM_CHINT0) {
snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, CM_CH0_INT_EN);
snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, CM_CH0_INT_EN);
}
if (status & CM_CHINT1) {
snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, CM_CH1_INT_EN);
snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, CM_CH1_INT_EN);
}
if (status & CM_CHINT0)
mask |= CM_CH0_INT_EN;
if (status & CM_CHINT1)
mask |= CM_CH1_INT_EN;
snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask);
snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask);
spin_unlock(&cm->reg_lock);
if (cm->rmidi && (status & CM_UARTINT))
......@@ -1419,6 +1781,7 @@ static void close_device_check(cmipci_t *cm, int mode)
down(&cm->open_mutex);
if (cm->opened[ch] == mode) {
snd_cmipci_ch_reset(cm, ch);
cm->channel[ch].running = 0;
cm->channel[ch].substream = NULL;
cm->opened[ch] = 0;
......@@ -2144,9 +2507,8 @@ static snd_cmipci_switch_args_t cmipci_switch_arg_##sname = { \
DEFINE_SWITCH_ARG(sname, xreg, xmask, xmask, xis_byte, xac3)
#if 0 /* these will be controlled in pcm device */
DEFINE_BIT_SWITCH_ARG(spdif_in, CM_REG_FUNCTRL1, CM_SPDF_1, 0);
DEFINE_BIT_SWITCH_ARG(spdif_0, CM_REG_FUNCTRL1, CM_SPDF_0, 0);
DEFINE_BIT_SWITCH_ARG(spdo_48k, CM_REG_MISC_CTRL, CM_SPDF_AC97|CM_SPDIF48K, 0);
DEFINE_BIT_SWITCH_ARG(spdif_in, CM_REG_FUNCTRL1, CM_SPDF_1, 0, 0);
DEFINE_BIT_SWITCH_ARG(spdif_out, CM_REG_FUNCTRL1, CM_SPDF_0, 0, 0);
#endif
DEFINE_BIT_SWITCH_ARG(spdif_in_sel1, CM_REG_CHFORMAT, CM_SPDIF_SELECT1, 0, 0);
DEFINE_BIT_SWITCH_ARG(spdif_in_sel2, CM_REG_MISC_CTRL, CM_SPDIF_SELECT2, 0, 0);
......@@ -2156,6 +2518,7 @@ DEFINE_BIT_SWITCH_ARG(spdi_valid, CM_REG_MISC, CM_SPDVALID, 1, 0);
DEFINE_BIT_SWITCH_ARG(spdif_copyright, CM_REG_LEGACY_CTRL, CM_SPDCOPYRHT, 0, 0);
DEFINE_BIT_SWITCH_ARG(spdif_dac_out, CM_REG_LEGACY_CTRL, CM_DAC2SPDO, 0, 1);
DEFINE_SWITCH_ARG(spdo_5v, CM_REG_MISC_CTRL, CM_SPDO5V, 0, 0, 0); /* inverse: 0 = 5V */
// DEFINE_BIT_SWITCH_ARG(spdo_48k, CM_REG_MISC_CTRL, CM_SPDF_AC97|CM_SPDIF48K, 0, 1);
DEFINE_BIT_SWITCH_ARG(spdif_loop, CM_REG_FUNCTRL1, CM_SPDFLOOP, 0, 1);
DEFINE_BIT_SWITCH_ARG(spdi_monitor, CM_REG_MIXER1, CM_CDPLAY, 1, 0);
/* DEFINE_BIT_SWITCH_ARG(spdi_phase, CM_REG_CHFORMAT, CM_SPDIF_INVERSE, 0, 0); */
......@@ -2228,8 +2591,7 @@ static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = {
static snd_kcontrol_new_t snd_cmipci_8738_mixer_switches[] __devinitdata = {
#if 0 /* controlled in pcm device */
DEFINE_MIXER_SWITCH("IEC958 In Record", spdif_in),
DEFINE_MIXER_SWITCH("IEC958 Out", spdif_0),
DEFINE_MIXER_SWITCH("IEC958 Out 48KHz", spdo_48k),
DEFINE_MIXER_SWITCH("IEC958 Out", spdif_out),
DEFINE_MIXER_SWITCH("IEC958 Out To DAC", spdo2dac),
#endif
// DEFINE_MIXER_SWITCH("IEC958 Output Switch", spdif_enable),
......@@ -2242,6 +2604,7 @@ static snd_kcontrol_new_t snd_cmipci_8738_mixer_switches[] __devinitdata = {
DEFINE_MIXER_SWITCH("IEC958 In Valid", spdi_valid),
DEFINE_MIXER_SWITCH("IEC958 Copyright", spdif_copyright),
DEFINE_MIXER_SWITCH("IEC958 5V", spdo_5v),
// DEFINE_MIXER_SWITCH("IEC958 In/Out 48KHz", spdo_48k),
DEFINE_MIXER_SWITCH("IEC958 Loop", spdif_loop),
DEFINE_MIXER_SWITCH("IEC958 In Monitor", spdi_monitor),
};
......@@ -2475,6 +2838,8 @@ static int snd_cmipci_free(cmipci_t *cm)
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN);
snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT);
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
snd_cmipci_ch_reset(cm, CM_CH_CAPT);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, 0); /* disable channels */
snd_cmipci_write(cm, CM_REG_FUNCTRL1, 0);
......@@ -2547,7 +2912,6 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
pci_set_master(cm->pci);
/*
* check chip version, max channels and capabilities
*/
......@@ -2568,6 +2932,8 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
/* initialize codec registers */
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
snd_cmipci_ch_reset(cm, CM_CH_CAPT);
snd_cmipci_write(cm, CM_REG_FUNCTRL0, 0); /* disable channels */
snd_cmipci_write(cm, CM_REG_FUNCTRL1, 0);
......@@ -2578,6 +2944,30 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
#else
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC);
#endif
/* Set Bus Master Request */
snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_BREQ);
/* Assume TX and compatible chip set (Autodetection required for VX chip sets) */
switch (pci->device) {
struct list_head *pos;
int txvx;
case PCI_DEVICE_ID_CMEDIA_CM8738:
case PCI_DEVICE_ID_CMEDIA_CM8738B:
txvx = 1;
list_for_each(pos, &(pci->global_list)) {
struct pci_dev * cur = list_entry(pos, struct pci_dev, global_list);
if (cur->vendor != 0x8086) /* PCI_VENDOR_ID_INTEL */
continue;
if (cur->device != 0x7030) /* PCI_DEVICE_ID_INTEL_82437VX */
continue;
txvx = 0;
}
if (txvx)
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_TXVX);
break;
default:
break;
}
/* set MPU address */
switch (iomidi) {
......@@ -2663,6 +3053,15 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
snd_cmipci_free(cm);
return err;
}
#ifdef USE_VAR48KRATE
for (val = 0; val < RATES; val++)
snd_cmipci_set_pll(cm, rates[val], val);
/*
* (Re-)Enable external switch spdo_48k
*/
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97);
#endif /* USE_VAR48KRATE */
*rcmipci = cm;
return 0;
......
......@@ -735,12 +735,14 @@ static int snd_cs4281_trigger(snd_pcm_substream_t *substream, int cmd)
dma->valFCR &= ~BA0_FCR_FEN;
break;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR & ~BA0_DMR_DMA);
dma->valDMR |= BA0_DMR_DMA;
dma->valDCR &= ~BA0_DCR_MSK;
dma->valFCR |= BA0_FCR_FEN;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
dma->valDMR &= ~(BA0_DMR_DMA|BA0_DMR_POLL);
dma->valDCR |= BA0_DCR_MSK;
dma->valFCR &= ~BA0_FCR_FEN;
......@@ -900,6 +902,7 @@ static snd_pcm_hardware_t snd_cs4281_playback =
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
......@@ -925,6 +928,7 @@ static snd_pcm_hardware_t snd_cs4281_capture =
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
......
......@@ -849,7 +849,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_
cpcm->hw_io = ptr;
cpcm->hw_ready -= bytes;
cpcm->sw_io += bytes;
if (cpcm->sw_io > cpcm->sw_bufsize)
if (cpcm->sw_io >= cpcm->sw_bufsize)
cpcm->sw_io -= cpcm->sw_bufsize;
snd_cs46xx_playback_transfer(substream, 0);
return cpcm->sw_io >> cpcm->shift;
......@@ -874,7 +874,7 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t
chip->capt.hw_io = ptr;
chip->capt.hw_ready += bytes;
chip->capt.sw_io += bytes;
if (chip->capt.sw_io > chip->capt.sw_bufsize)
if (chip->capt.sw_io >= chip->capt.sw_bufsize)
chip->capt.sw_io -= chip->capt.sw_bufsize;
snd_cs46xx_capture_transfer(substream, 0);
return chip->capt.sw_io >> chip->capt.shift;
......@@ -952,7 +952,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* magic value to unmute PCM stream playback volume */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address +
SCBVolumeCtrl) << 2, 0x80007fff);
SCBVolumeCtrl) << 2, 0x80008000);
if (cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
......@@ -1032,32 +1032,27 @@ static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream,
static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
int sample_rate)
{
/* if this is the only PCMReaderSCB child under current
SrcTask then there no need to re-create pcm-channel */
if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
cpcm->pcm_channel->sample_rate != sample_rate &&
/* never set a 0 khz sample rate */
sample_rate) {
/* sample rate not set or we can reuse
the same SRC*/
cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate);
/* If PCMReaderSCB and SrcTaskSCB not created yet ... */
if ( cpcm->pcm_channel == NULL) {
cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate,
cpcm, cpcm->hw_addr,cpcm->pcm_channel_id);
if (cpcm->pcm_channel == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
return -ENOMEM;
}
cpcm->pcm_channel->sample_rate = sample_rate;
}
/* if there is more then 1 PCMReaderSCB child's under current
SrcTask then we must recreate channel */
if (cpcm->pcm_channel->sample_rate != sample_rate &&
cpcm->pcm_channel->src_scb->ref_count != 1 &&
/* never set a 0 khz sample rate */
sample_rate) {
} else
/* if sample rate is changed */
if (cpcm->pcm_channel->sample_rate != sample_rate) {
int unlinked = cpcm->pcm_channel->unlinked;
cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm,
cpcm->hw_addr,
cpcm->pcm_channel->pcm_channel_id)) == NULL) {
cpcm->pcm_channel_id)) == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
return -ENXIO;
return -ENOMEM;
}
if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
......@@ -1082,15 +1077,21 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
snd_assert (sample_rate != 0, return -ENXIO);
down (&chip->spos_mutex);
snd_assert (cpcm->pcm_channel != NULL);
if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
up (&chip->spos_mutex);
return -ENXIO;
}
snd_assert (cpcm->pcm_channel != NULL);
if (!cpcm->pcm_channel) {
up (&chip->spos_mutex);
return -ENXIO;
}
if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
up (&chip->spos_mutex);
return -EINVAL;
......@@ -1108,11 +1109,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
substream->ops = &snd_cs46xx_playback_ops;
} else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
substream->ops = &snd_cs46xx_playback_rear_ops;
} else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
substream->ops = &snd_cs46xx_playback_iec958_ops;
} else {
snd_assert(0);
......@@ -1135,11 +1136,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
substream->ops = &snd_cs46xx_playback_indirect_ops;
} else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
substream->ops = &snd_cs46xx_playback_indirect_rear_ops;
} else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
} else {
snd_assert(0);
......@@ -1165,6 +1166,10 @@ static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream)
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
/* if play_back open fails, then this function
is called and cpcm can actually be NULL here */
if (!cpcm) return -ENXIO;
if (runtime->dma_area != cpcm->hw_area)
snd_pcm_lib_free_pages(substream);
......@@ -1482,15 +1487,8 @@ static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pc
cpcm->substream = substream;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex);
cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr,pcm_channel_id);
if (cpcm->pcm_channel == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
snd_magic_kfree(cpcm);
up (&chip->spos_mutex);
return -ENOMEM;
}
cpcm->pcm_channel = NULL;
cpcm->pcm_channel_id = pcm_channel_id;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes);
......@@ -1583,6 +1581,9 @@ static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream)
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
/* when playback_open fails, then cpcm can be NULL */
if (!cpcm) return -ENXIO;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex);
if (cpcm->pcm_channel) {
......@@ -1887,8 +1888,8 @@ static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left;
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_left;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_right;
return 0;
}
......@@ -1913,8 +1914,8 @@ static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_right;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_left;
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_left;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_right;
return 0;
}
......@@ -1923,8 +1924,8 @@ static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
int change = 0;
if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] ||
chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[1]) {
if (chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[0] ||
chip->dsp_spos_instance->spdif_input_volume_right!= ucontrol->value.integer.value[1]) {
cs46xx_dsp_set_iec958_volume (chip,
ucontrol->value.integer.value[0],
ucontrol->value.integer.value[1]);
......@@ -2206,6 +2207,7 @@ static int snd_cs46xx_spdif_stream_put(snd_kcontrol_t * kcontrol,
#endif /* CONFIG_SND_CS46XX_NEW_DSP */
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
static int snd_cs46xx_egpio_select_info(snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo)
......@@ -3331,8 +3333,8 @@ int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip)
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* set the attenuation to 0dB */
snd_cs46xx_poke(chip, (MASTERMIX_SCB_ADDR + 0xE) << 2, 0x80008000);
snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000);
/* snd_cs46xx_poke(chip, (MASTERMIX_SCB_ADDR + 0xE) << 2, 0x80008000);
snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000); */
/*
* Initialize cs46xx SPDIF controller
......
......@@ -152,6 +152,7 @@ dsp_scb_descriptor_t * cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * s
dsp_scb_descriptor_t * parent_scb,
int scb_child_type);
dsp_scb_descriptor_t * cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
int sample_rate,
u16 src_buffer_addr,
u16 src_delay_buffer_addr,u32 dest,
dsp_scb_descriptor_t * parent_scb,
......@@ -202,8 +203,6 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
int pcm_channel_id);
void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,
pcm_channel_descriptor_t * pcm_channel);
void cs46xx_dsp_set_src_sample_rate(cs46xx_t * chip,dsp_scb_descriptor_t * src,
u32 rate);
int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
......
......@@ -615,7 +615,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
col = 0;
for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x30; i += sizeof(u32),col ++) {
for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x40; i += sizeof(u32),col ++) {
if (col == 4) {
snd_iprintf(buffer,"\n");
col = 0;
......@@ -628,14 +628,14 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
snd_iprintf(buffer,"%08X ",readl(dst + i));
}
snd_iprintf(buffer,"\n\n");
snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
col = 0;
for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x40; i += sizeof(u32),col ++) {
for (i = 0x2580 ; i < 0x2580 + 0x40 ; i += sizeof(u32),col ++) {
if (col == 4) {
snd_iprintf(buffer,"\n");
col = 0;
}
if (col == 0) {
snd_iprintf(buffer, "%04X ",i);
}
......@@ -646,7 +646,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
col = 0;
for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x40; i += sizeof(u32),col ++) {
for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30; i += sizeof(u32),col ++) {
if (col == 4) {
snd_iprintf(buffer,"\n");
col = 0;
......@@ -705,7 +705,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
snd_iprintf(buffer,"%08X ",readl(dst + i));
}
#if 0
snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
col = 0;
for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
......@@ -720,7 +720,22 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
snd_iprintf(buffer,"%08X ",readl(dst + i));
}
#endif
snd_iprintf(buffer,"\nSPDIFI_IP_OUTPUT_BUFFER1: \n");
col = 0;
for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80; i += sizeof(u32),col ++) {
if (col == 4) {
snd_iprintf(buffer,"\n");
col = 0;
}
if (col == 0) {
snd_iprintf(buffer, "%04X ",i);
}
snd_iprintf(buffer,"%08X ",readl(dst + i));
}
snd_iprintf(buffer,"\n");
}
......@@ -1356,6 +1371,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip)
/* SPDIF input sampel rate converter */
src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
48000,
SRC_OUTPUT_BUF1,
SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
master_mix_scb,
......@@ -1597,11 +1613,14 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
cs46xx_src_link(chip,ins->spdif_in_src);
/* unmute SRC volume */
cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
spin_unlock_irq(&chip->reg_lock);
/* set SPDIF input sample rate and unmute
NOTE: only 48khz support for SPDIF input this time */
cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000);
/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
/* monitor state */
ins->spdif_status_in = 1;
......
......@@ -197,7 +197,7 @@ static inline u8 _wrap_all_bits (u8 val) {
((val & 0x10) >> 1) |
((val & 0x20) >> 3) |
((val & 0x40) >> 5) |
((val & 0x80) >> 6);
((val & 0x80) >> 7);
return wrapped;
......
......@@ -576,8 +576,11 @@ cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * scb_name,
return scb;
}
#define GOF_PER_SEC 200
dsp_scb_descriptor_t *
cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
int rate,
u16 src_buffer_addr,
u16 src_delay_buffer_addr,u32 dest,
dsp_scb_descriptor_t * parent_scb,
......@@ -586,45 +589,81 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * scb;
src_task_scb_t src_task_scb = {
0x0028,0x00c8,
0x5555,0x0000,
0x0000,0x0000,
src_buffer_addr,1,
0x0028,0x00c8,
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
0x0000,src_delay_buffer_addr,
0x0,
0x80,(src_delay_buffer_addr + (24 * 4)),
0,0, /* next_scb, sub_list_ptr */
0,0, /* entry, this_spb */
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
src_buffer_addr << 0x10,
0x04000000,
{
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
}
};
unsigned int tmp1, tmp2;
unsigned int phiIncr;
unsigned int correctionPerGOF, correctionPerSec;
if (ins->s16_up == NULL) {
ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
SYMBOL_CODE);
if (ins->s16_up == NULL) {
snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
return NULL;
}
}
snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
/* clear buffers */
_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
/*
* Compute the values used to drive the actual sample rate conversion.
* The following formulas are being computed, using inline assembly
* since we need to use 64 bit arithmetic to compute the values:
*
* phiIncr = floor((Fs,in * 2^26) / Fs,out)
* correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
* GOF_PER_SEC)
* ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
* GOF_PER_SEC * correctionPerGOF
*
* i.e.
*
* phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
* correctionPerGOF:correctionPerSec =
* dividend:remainder(ulOther / GOF_PER_SEC)
*/
tmp1 = rate << 16;
phiIncr = tmp1 / 48000;
tmp1 -= phiIncr * 48000;
tmp1 <<= 10;
phiIncr <<= 10;
tmp2 = tmp1 / 48000;
phiIncr += tmp2;
tmp1 -= tmp2 * 48000;
correctionPerGOF = tmp1 / GOF_PER_SEC;
tmp1 -= correctionPerGOF * GOF_PER_SEC;
correctionPerSec = tmp1;
scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
dest,ins->s16_up,parent_scb,
scb_child_type);
{
src_task_scb_t src_task_scb = {
0x0028,0x00c8,
0x5555,0x0000,
0x0000,0x0000,
src_buffer_addr,1,
correctionPerGOF,correctionPerSec,
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
0x0000,src_delay_buffer_addr,
0x0,
0x080,(src_delay_buffer_addr + (24 * 4)),
0,0, /* next_scb, sub_list_ptr */
0,0, /* entry, this_spb */
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
src_buffer_addr << 0x10,
phiIncr,
{
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
}
};
if (ins->s16_up == NULL) {
ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
SYMBOL_CODE);
if (ins->s16_up == NULL) {
snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
return NULL;
}
}
/* clear buffers */
_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
dest,ins->s16_up,parent_scb,
scb_child_type);
}
return scb;
}
......@@ -796,7 +835,7 @@ cs46xx_dsp_create_pcm_serial_input_scb(cs46xx_t * chip,char * scb_name,u32 dest,
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
0,
0,input_scb->address,
0,input_scb->address,
{
0x8000,0x8000,
0x8000,0x8000
......@@ -1007,7 +1046,7 @@ dsp_scb_descriptor_t * cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char *
/* C */ snoop_buffer_address << 0x10,
/* D */ 0,
/* E */ { 0x8000,0x8000,
/* F */ 0xffff,0xffff
/* F */ 0xffff,0xffff
}
};
......@@ -1093,6 +1132,8 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
dsp_scb_descriptor_t * src_parent_scb = NULL;
/*dsp_scb_descriptor_t * pcm_parent_scb;*/
char scb_name[DSP_MAX_SCB_NAME];
int i,pcm_index = -1, insert_point, src_index = -1;
......@@ -1116,13 +1157,14 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
case DSP_IEC958_CHANNEL:
snd_assert (ins->asynch_tx_scb != NULL, return NULL);
mixer_scb = ins->asynch_tx_scb;
#if 0
if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
snd_printdd ("IEC958 opened in AC3 mode\n");
/*src_scb = ins->asynch_tx_scb;
ins->asynch_tx_scb->ref_count ++;*/
/* if sample rate is set to 48khz we pass
the Sample Rate Converted (which could
alter the raw data stream ...) */
if (sample_rate == 48000) {
snd_printdd ("IEC958 pass through\n");
src_parent_scb = ins->asynch_tx_scb;
}
#endif
break;
default:
snd_assert (0);
......@@ -1158,8 +1200,6 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
}
if (src_scb == NULL) {
dsp_scb_descriptor_t * src_parent_scb;
if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
return NULL;
......@@ -1176,18 +1216,21 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
snd_assert (src_index != -1,return NULL);
/* we need to create a new SRC SCB */
if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
src_parent_scb = mixer_scb;
insert_point = SCB_ON_PARENT_SUBLIST_SCB;
} else {
src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
insert_point = SCB_ON_PARENT_NEXT_SCB;
}
if (src_parent_scb == NULL) {
if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
src_parent_scb = mixer_scb;
insert_point = SCB_ON_PARENT_SUBLIST_SCB;
} else {
src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
insert_point = SCB_ON_PARENT_NEXT_SCB;
}
} else insert_point = SCB_ON_PARENT_NEXT_SCB;
snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
sample_rate,
src_output_buffer_addr[src_index],
src_delay_buffer_addr[src_index],
/* 0x400 - 0x600 source SCBs */
......@@ -1200,7 +1243,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
return NULL;
}
cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
ins->nsrc_scb ++;
}
......@@ -1226,6 +1269,19 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
return NULL;
}
if (pcm_channel_id == DSP_IEC958_CHANNEL && sample_rate == 48000) {
snd_assert (ins->spdif_pcm_input_scb == NULL);
/* a hack to make the skip the SRC and pass the stream
directly to the SPDIF task */
ins->spdif_pcm_input_scb =
cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_PCM",
PCMSERIALINII_SCB_ADDR,
pcm_scb,
ins->asynch_tx_scb,
SCB_ON_PARENT_SUBLIST_SCB);
}
spin_lock_irqsave(&chip->reg_lock, flags);
ins->pcm_channels[pcm_index].sample_rate = sample_rate;
ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
......@@ -1236,7 +1292,6 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
ins->pcm_channels[pcm_index].active = 1;
ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
ins->pcm_channels[pcm_index].pcm_channel_id = pcm_channel_id;
ins->npcm_channels ++;
spin_unlock_irqrestore(&chip->reg_lock, flags);
......@@ -1416,59 +1471,6 @@ int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
return 0;
}
#define GOF_PER_SEC 200
void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u32 rate)
{
unsigned long flags;
unsigned int tmp1, tmp2;
unsigned int phiIncr;
unsigned int correctionPerGOF, correctionPerSec;
snd_printdd( "dsp_spos: setting SRC rate to %u\n",rate);
/*
* Compute the values used to drive the actual sample rate conversion.
* The following formulas are being computed, using inline assembly
* since we need to use 64 bit arithmetic to compute the values:
*
* phiIncr = floor((Fs,in * 2^26) / Fs,out)
* correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
* GOF_PER_SEC)
* ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
* GOF_PER_SEC * correctionPerGOF
*
* i.e.
*
* phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
* correctionPerGOF:correctionPerSec =
* dividend:remainder(ulOther / GOF_PER_SEC)
*/
tmp1 = rate << 16;
phiIncr = tmp1 / 48000;
tmp1 -= phiIncr * 48000;
tmp1 <<= 10;
phiIncr <<= 10;
tmp2 = tmp1 / 48000;
phiIncr += tmp2;
tmp1 -= tmp2 * 48000;
correctionPerGOF = tmp1 / GOF_PER_SEC;
tmp1 -= correctionPerGOF * GOF_PER_SEC;
correctionPerSec = tmp1;
/*
* Fill in the SampleRateConverter control block.
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
u16 addr,char * scb_name)
{
......@@ -1655,10 +1657,19 @@ int cs46xx_iec958_post_close (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
/* deallocate stuff */
if (ins->spdif_pcm_input_scb != NULL) {
cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
ins->spdif_pcm_input_scb = NULL;
}
cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
ins->asynch_tx_scb = NULL;
/* clear buffer to prevent any undesired noise */
_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
/* restore state */
if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
cs46xx_dsp_enable_spdif_out (chip);
}
......
......@@ -199,7 +199,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
.name = "EMU10K1/Audigy",
.name = "EMU10K1_Audigy",
.id_table = snd_emu10k1_ids,
.probe = snd_card_emu10k1_probe,
.remove = __devexit_p(snd_card_emu10k1_remove),
......
......@@ -217,9 +217,11 @@ void __devinit snd_ice1712_ak4524_init(ice1712_t *ice)
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
#define AK_GET_ADDR(val) ((val) & 0xff)
#define AK_GET_SHIFT(val) (((val) >> 16) & 0xff)
#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f)
#define AK_GET_INVERT(val) (((val) >> 23) & 1)
#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
#define AK_INVERT (1<<23)
static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
......@@ -237,8 +239,11 @@ static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_
ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
ucontrol->value.integer.value[0] = mask - ice->ak4524.images[chip][addr];
unsigned char val = ice->ak4524.images[chip][addr];
ucontrol->value.integer.value[0] = invert ? mask - val : val;
return 0;
}
......@@ -247,9 +252,14 @@ static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_
ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char nval = mask - (ucontrol->value.integer.value[0] % (mask+1));
int change = ice->ak4524.images[chip][addr] != nval;
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
int change;
if (invert)
nval = mask - nval;
change = ice->ak4524.images[chip][addr] != nval;
if (change)
snd_ice1712_ak4524_write(ice, chip, addr, nval);
return change;
......@@ -353,7 +363,7 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice)
break;
case SND_AK4529: {
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
ctl.private_value = AK_COMPOSE(0, val, 0, 255);
ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
break;
}
}
......
......@@ -218,6 +218,11 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
"Hoontech SoundTrack Audio DSP24",
snd_ice1712_hoontech_init,
},
{
ICE1712_SUBDEVICE_STDSP24_MEDIA7_1,
"Hoontech STA DSP24 Media 7.1",
snd_ice1712_hoontech_init,
},
{ } /* terminator */
};
......@@ -27,6 +27,7 @@
#define HOONTECH_DEVICE_DESC "{Hoontech SoundTrack DSP 24},"
#define ICE1712_SUBDEVICE_STDSP24 0x12141217 /* Hoontech SoundTrack Audio DSP 24 */
#define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */
extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
......
......@@ -23,9 +23,38 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* ToDo: full duplex (32, 32/8, 32Pro)
* ****************************************************************************
*
* Note #1 "Sek'd models" ................................... martin 2002-12-07
*
* Identical soundcards by Sek'd were labeled:
* RME Digi 32 = Sek'd Prodif 32
* RME Digi 32 Pro = Sek'd Prodif 96
* RME Digi 32/8 = Sek'd Prodif Gold
*
* ****************************************************************************
*
* Note #2 "full duplex mode" ............................... martin 2002-12-07
*
* Full duplex doesn't work. All cards (32, 32/8, 32Pro) are working identical
* in this mode. Rec data and play data are using the same buffer therefore. At
* first you have got the playing bits in the buffer and then (after playing
* them) they were overwitten by the captured sound of the CS8412/14. Both
* modes (play/record) are running harmonically hand in hand in the same buffer
* and you have only one start bit plus one interrupt bit to control this
* paired action.
* This is opposite to the latter rme96 where playing and capturing is totally
* separated and so their full duplex mode is supported by alsa (using two
* start bits and two interrupts for two different buffers).
* But due to the wrong sequence of playing and capturing ALSA shows no solved
* full duplex support for the rme32 at the moment. That's bad, but I'm not
* able to solve it. Are you motivated enough to solve this problem now? Your
* patch would be welcome!
*
* ****************************************************************************
*/
#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
......@@ -80,29 +109,29 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
#define RME32_IO_RESET_POS 0x20100
/* Write control register bits */
#define RME32_WCR_START (1 << 0)
#define RME32_WCR_MONO (1 << 1) /* 0: stereo, 1: mono
#define RME32_WCR_START (1 << 0) /* startbit */
#define RME32_WCR_MONO (1 << 1) /* 0=stereo, 1=mono
Setting the whole card to mono
don't seems to be very useful.
doesn't seem to be very useful.
A software-solution can handle
full-duplex with one direction in
stereo and the other way in mono.
So, the hardware should work all
the time in stereo! */
#define RME32_WCR_MODE24 (1 << 2)
#define RME32_WCR_SEL (1 << 3)
#define RME32_WCR_FREQ_0 (1 << 4)
#define RME32_WCR_MODE24 (1 << 2) /* 0=16bit, 1=32bit */
#define RME32_WCR_SEL (1 << 3) /* 0=input on output, 1=normal playback/capture */
#define RME32_WCR_FREQ_0 (1 << 4) /* frequency (play) */
#define RME32_WCR_FREQ_1 (1 << 5)
#define RME32_WCR_INP_0 (1 << 6)
#define RME32_WCR_INP_0 (1 << 6) /* input switch */
#define RME32_WCR_INP_1 (1 << 7)
#define RME32_WCR_RESET (1 << 8)
#define RME32_WCR_MUTE (1 << 9)
#define RME32_WCR_PRO (1 << 10)
#define RME32_WCR_DS_BM (1 << 11) /* only PRO/Adat-Version */
#define RME32_WCR_ADAT (1 << 12) /* only Adat-Version */
#define RME32_WCR_AUTOSYNC (1 << 13)
#define RME32_WCR_PD (1 << 14) /* only PRO-Version */
#define RME32_WCR_EMP (1 << 15) /* only PRO-Version */
#define RME32_WCR_RESET (1 << 8) /* Reset address */
#define RME32_WCR_MUTE (1 << 9) /* digital mute for output */
#define RME32_WCR_PRO (1 << 10) /* 1=professional, 0=consumer */
#define RME32_WCR_DS_BM (1 << 11) /* 1=DoubleSpeed (only PRO-Version); 1=BlockMode (only Adat-Version) */
#define RME32_WCR_ADAT (1 << 12) /* Adat Mode (only Adat-Version) */
#define RME32_WCR_AUTOSYNC (1 << 13) /* AutoSync */
#define RME32_WCR_PD (1 << 14) /* DAC Reset (only PRO-Version) */
#define RME32_WCR_EMP (1 << 15) /* 1=Emphasis on (only PRO-Version) */
#define RME32_WCR_BITPOS_FREQ_0 4
#define RME32_WCR_BITPOS_FREQ_1 5
......@@ -111,13 +140,13 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
/* Read control register bits */
#define RME32_RCR_AUDIO_ADDR_MASK 0x10001
#define RME32_RCR_LOCK (1 << 23)
#define RME32_RCR_ERF (1 << 26)
#define RME32_RCR_FREQ_0 (1 << 27)
#define RME32_RCR_LOCK (1 << 23) /* 1=locked, 0=not locked */
#define RME32_RCR_ERF (1 << 26) /* 1=Error, 0=no Error */
#define RME32_RCR_FREQ_0 (1 << 27) /* CS841x frequency (record) */
#define RME32_RCR_FREQ_1 (1 << 28)
#define RME32_RCR_FREQ_2 (1 << 29)
#define RME32_RCR_KMODE (1 << 30)
#define RME32_RCR_IRQ (1 << 31)
#define RME32_RCR_KMODE (1 << 30) /* card mode: 1=PLL, 0=quartz */
#define RME32_RCR_IRQ (1 << 31) /* interrupt */
#define RME32_RCR_BITPOS_F0 27
#define RME32_RCR_BITPOS_F1 28
......@@ -153,12 +182,12 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
#ifndef PCI_DEVICE_ID_DIGI32
# define PCI_DEVICE_ID_DIGI32 0x9896
#endif
#ifndef PCI_DEVICE_ID_DIGI32_8
# define PCI_DEVICE_ID_DIGI32_8 0x9898
#endif
#ifndef PCI_DEVICE_ID_DIGI32_PRO
# define PCI_DEVICE_ID_DIGI32_PRO 0x9897
#endif
#ifndef PCI_DEVICE_ID_DIGI32_8
# define PCI_DEVICE_ID_DIGI32_8 0x9898
#endif
typedef struct snd_rme32 {
spinlock_t lock;
......@@ -314,10 +343,13 @@ static snd_pcm_hardware_t snd_rme32_playback_spdif_info = {
static snd_pcm_hardware_t snd_rme32_capture_spdif_info = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE),
.rates = (SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000),
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000),
.rate_min = 32000,
.rate_max = 48000,
.channels_min = 2,
......
......@@ -5,7 +5,7 @@ menu "ALSA USB devices"
config SND_USB_AUDIO
tristate "USB Audio/MIDI driver"
depends on SND
depends on SND && USB
help
Say 'Y' or 'M' to include support for USB audio and USB MIDI devices.
......
......@@ -172,7 +172,8 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_MIDI_YAMAHA, data is NULL */
/* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
/* for QUIRK_MIDI_MIDIMAN, data points to a snd_usb_midi_endpoint_info
* structure (out_cables and in_cables only) */
/* for QUIRK_ROLAND_UA100, data is NULL */
......
......@@ -172,7 +172,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
/*
* Processes the data read from the device.
*/
static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
static void snd_usbmidi_in_urb_complete(struct urb* urb)
{
snd_usb_midi_in_endpoint_t* ep = snd_magic_cast(snd_usb_midi_in_endpoint_t, urb->context, return);
......@@ -197,7 +197,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
/*
* Converts the data read from a Midiman device to standard USB MIDI packets.
*/
static void snd_usbmidi_in_midiman_complete(struct urb* urb, struct pt_regs *regs)
static void snd_usbmidi_in_midiman_complete(struct urb* urb)
{
if (urb->status == 0) {
uint8_t* buffer = (uint8_t*)urb->transfer_buffer;
......@@ -223,10 +223,10 @@ static void snd_usbmidi_in_midiman_complete(struct urb* urb, struct pt_regs *reg
}
}
}
snd_usbmidi_in_urb_complete(urb, regs);
snd_usbmidi_in_urb_complete(urb);
}
static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
static void snd_usbmidi_out_urb_complete(struct urb* urb)
{
snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, urb->context, return);
......@@ -892,7 +892,8 @@ static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi,
/*
* Creates the endpoints and their ports for Midiman devices.
*/
static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports)
static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoint)
{
snd_usb_midi_endpoint_info_t ep_info;
struct usb_interface* intf;
......@@ -906,7 +907,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports
return -ENOENT;
hostif = intf->altsetting;
intfd = get_iface_desc(hostif);
if (intfd->bNumEndpoints < (ports > 1 ? 5 : 3)) {
if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) {
snd_printdd(KERN_ERR "not enough endpoints\n");
return -ENOENT;
}
......@@ -923,7 +924,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports
snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
return -ENXIO;
}
if (ports > 1) {
if (endpoint->out_cables > 0x0001) {
epd = get_endpoint(hostif, 4);
if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
......@@ -933,31 +934,33 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports
}
ep_info.epnum = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = 0x5555 & ((1 << ports) - 1);
ep_info.out_cables = endpoint->out_cables & 0x5555;
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
return err;
ep_info.epnum = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.in_cables = (1 << ports) - 1;
ep_info.in_cables = endpoint->in_cables;
err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
return err;
umidi->endpoints[0].in->urb->complete = snd_usbmidi_in_midiman_complete;
if (ports > 1) {
if (endpoint->out_cables > 0x0001) {
ep_info.epnum = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = 0xaaaa & ((1 << ports) - 1);
ep_info.out_cables = endpoint->out_cables & 0xaaaa;
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);
if (err < 0)
return err;
}
for (cable = 0; cable < ports; ++cable) {
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable,
&umidi->endpoints[cable & 1].out->ports[cable].substream);
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable,
&umidi->endpoints[0].in->ports[cable].substream);
for (cable = 0; cable < 0x10; ++cable) {
if (endpoint->out_cables & (1 << cable))
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable,
&umidi->endpoints[cable & 1].out->ports[cable].substream);
if (endpoint->in_cables & (1 << cable))
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable,
&umidi->endpoints[0].in->ports[cable].substream);
}
return 0;
}
......@@ -1020,6 +1023,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
break;
case QUIRK_MIDI_MIDIMAN:
memcpy(&endpoints[0], quirk->data,
sizeof(snd_usb_midi_endpoint_info_t));
err = 0;
break;
default:
......@@ -1034,15 +1039,11 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
}
/* create rawmidi device */
if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN) {
in_ports = out_ports = (int)quirk->data;
} else {
out_ports = 0;
in_ports = 0;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
}
out_ports = 0;
in_ports = 0;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
}
err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
if (err < 0) {
......@@ -1052,7 +1053,7 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
/* create endpoint/port structures */
if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN)
err = snd_usbmidi_create_endpoints_midiman(umidi, (int)quirk->data);
err = snd_usbmidi_create_endpoints_midiman(umidi, &endpoints[0]);
else
err = snd_usbmidi_create_endpoints(umidi, endpoints);
if (err < 0) {
......
......@@ -81,8 +81,7 @@ struct usb_mixer_elem_info {
int channels;
int val_type;
int min, max, res;
unsigned int initialized: 1,
hack_hole1: 1; /* -256 value is missing */
unsigned int initialized: 1;
};
......@@ -281,17 +280,20 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
{
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
if (usb_control_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, cval->ctrlif | (cval->id << 8),
buf, val_len, HZ) < 0) {
snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, idx = 0x%x, val = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type);
return -EINVAL;
while (timeout-- > 0) {
if (usb_control_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, cval->ctrlif | (cval->id << 8),
buf, val_len, HZ / 10) >= 0) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
}
}
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, idx = 0x%x, val = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type);
return -EINVAL;
}
static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value)
......@@ -313,15 +315,19 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
{
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
return usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, cval->ctrlif | (cval->id << 8),
buf, val_len, HZ);
while (timeout -- > 0)
if (usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, cval->ctrlif | (cval->id << 8),
buf, val_len, HZ / 10) >= 0)
return 0;
return -EINVAL;
}
static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value)
......
......@@ -475,6 +475,20 @@
}
}
},
{
USB_DEVICE(0x0582, 0x0033),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "PCR",
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0007
}
}
},
/* Midiman/M-Audio devices */
{
......@@ -484,7 +498,10 @@
.product_name = "MidiSport 2x2",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 2
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0003,
.in_cables = 0x0003
}
}
},
{
......@@ -494,7 +511,10 @@
.product_name = "MidiSport 1x1",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
},
{
......@@ -504,7 +524,10 @@
.product_name = "Keystation",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
},
{
......@@ -514,7 +537,10 @@
.product_name = "MidiSport 4x4",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 4
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x000f,
.in_cables = 0x000f
}
}
},
{
......@@ -524,7 +550,23 @@
.product_name = "MidiSport 8x8",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 9
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x01ff,
.in_cables = 0x01ff
}
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1041),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "MidiSport 2x4",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x000f,
.in_cables = 0x0003
}
}
},
{
......@@ -534,7 +576,10 @@
.product_name = "Quattro",
.ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
},
{
......@@ -544,7 +589,10 @@
.product_name = "AudioPhile",
.ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment