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,7 +110,7 @@ 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,7 +176,7 @@ 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,10 +455,17 @@ 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;
case SNDRV_PCM_TRIGGER_SUSPEND:
do_start = 0; break;
default:
return -EINVAL;
}
what = 0;
s = substream;
do {
if (s == chip->playback_substream) {
what |= CS4231_PLAYBACK_ENABLE;
......@@ -467,7 +477,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
s = s->link_next;
} while (s != substream);
spin_lock(&chip->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_START) {
if (do_start) {
chip->image[CS4231_IFACE_CTRL] |= what;
if (chip->trigger)
chip->trigger(chip, what, 1);
......@@ -478,12 +488,6 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
}
snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
spin_unlock(&chip->reg_lock);
break;
}
default:
result = -EINVAL;
break;
}
#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,6 +530,9 @@ 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);
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,11 +1210,19 @@ 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:
{
case SNDRV_PCM_TRIGGER_SUSPEND:
do_start = 0; break;
default:
return -EINVAL;
}
what = whati = capture_flag = 0;
s = substream;
do {
......@@ -1228,10 +1236,14 @@ static int snd_ali_trigger(snd_pcm_substream_t *substream,
whati |= 1 << (evoice->number & 0x1f);
what |= 1 << (evoice->number & 0x1f);
}
if (cmd == SNDRV_PCM_TRIGGER_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)
......@@ -1240,29 +1252,22 @@ static int snd_ali_trigger(snd_pcm_substream_t *substream,
s = s->link_next;
} while (s != substream);
spin_lock(&codec->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
if (! do_start) {
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) {
if (do_start) {
val |= whati;
} else {
val &= ~whati;
}
outl(val, ALI_REG(codec, ALI_AINTEN));
if (cmd == SNDRV_PCM_TRIGGER_START) {
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);
break;
}
default:
return -EINVAL;
}
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,
......
This diff is collapsed.
......@@ -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);
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) {
/* 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;
} 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
down (&chip->spos_mutex);
snd_assert (sample_rate != 0, return -ENXIO);
snd_assert (cpcm->pcm_channel != NULL);
down (&chip->spos_mutex);
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,9 +628,9 @@ 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;
......@@ -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,22 +589,57 @@ 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;
unsigned int tmp1, tmp2;
unsigned int phiIncr;
unsigned int correctionPerGOF, correctionPerSec;
snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,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;
{
src_task_scb_t src_task_scb = {
0x0028,0x00c8,
0x5555,0x0000,
0x0000,0x0000,
src_buffer_addr,1,
0x0028,0x00c8,
correctionPerGOF,correctionPerSec,
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
0x0000,src_delay_buffer_addr,
0x0,
0x80,(src_delay_buffer_addr + (24 * 4)),
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,
0x04000000,
phiIncr,
{
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
......@@ -625,6 +663,7 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
dest,ins->s16_up,parent_scb,
scb_child_type);
}
return scb;
}
......@@ -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,6 +1216,7 @@ 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 (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;
......@@ -1183,11 +1224,13 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
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,29 +934,31 @@ 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) {
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);
}
......@@ -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,16 +1039,12 @@ 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);
}
}
err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
if (err < 0) {
snd_magic_kfree(umidi);
......@@ -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;
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) < 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;
}
buf, val_len, HZ / 10) >= 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),
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);
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