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 { ...@@ -1663,6 +1663,8 @@ typedef struct _snd_cs46xx_pcm_t {
snd_pcm_substream_t *substream; snd_pcm_substream_t *substream;
pcm_channel_descriptor_t * pcm_channel; pcm_channel_descriptor_t * pcm_channel;
int pcm_channel_id; /* Fron Rear, Center Lfe ... */
} cs46xx_pcm_t; } cs46xx_pcm_t;
typedef struct { typedef struct {
......
...@@ -140,7 +140,6 @@ typedef struct _pcm_channel_descriptor_t { ...@@ -140,7 +140,6 @@ typedef struct _pcm_channel_descriptor_t {
dsp_scb_descriptor_t * pcm_reader_scb; dsp_scb_descriptor_t * pcm_reader_scb;
dsp_scb_descriptor_t * src_scb; dsp_scb_descriptor_t * src_scb;
dsp_scb_descriptor_t * mixer_scb; dsp_scb_descriptor_t * mixer_scb;
int pcm_channel_id;
void * private_data; void * private_data;
} pcm_channel_descriptor_t; } pcm_channel_descriptor_t;
......
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc6" #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 @@ ...@@ -26,7 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/smp_lock.h> #include <linux/workqueue.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include <sound/info.h> #include <sound/info.h>
...@@ -152,13 +152,13 @@ int snd_card_disconnect(snd_card_t * card) ...@@ -152,13 +152,13 @@ int snd_card_disconnect(snd_card_t * card)
struct file_operations *f_ops, *old_f_ops; struct file_operations *f_ops, *old_f_ops;
int err; int err;
write_lock(&card->files_lock); spin_lock(&card->files_lock);
if (card->shutdown) { if (card->shutdown) {
write_unlock(&card->files_lock); spin_unlock(&card->files_lock);
return 0; return 0;
} }
card->shutdown = 1; card->shutdown = 1;
write_unlock(&card->files_lock); spin_unlock(&card->files_lock);
/* phase 1: disable fops (user space) operations for ALSA API */ /* phase 1: disable fops (user space) operations for ALSA API */
write_lock(&snd_card_rwlock); write_lock(&snd_card_rwlock);
...@@ -181,7 +181,9 @@ int snd_card_disconnect(snd_card_t * card) ...@@ -181,7 +181,9 @@ int snd_card_disconnect(snd_card_t * card)
f_ops = &s_f_ops->f_ops; f_ops = &s_f_ops->f_ops;
memset(f_ops, 0, sizeof(*f_ops)); memset(f_ops, 0, sizeof(*f_ops));
#ifndef LINUX_2_2
f_ops->owner = file->f_op->owner; f_ops->owner = file->f_op->owner;
#endif
f_ops->release = file->f_op->release; f_ops->release = file->f_op->release;
f_ops->poll = snd_disconnect_poll; f_ops->poll = snd_disconnect_poll;
...@@ -220,6 +222,10 @@ int snd_card_disconnect(snd_card_t * card) ...@@ -220,6 +222,10 @@ int snd_card_disconnect(snd_card_t * card)
* snd_card_free: frees given soundcard structure * snd_card_free: frees given soundcard structure
* @card: 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 * Returns - zero. Frees all associated devices and frees the control
* interface associated to given soundcard. * interface associated to given soundcard.
*/ */
...@@ -283,22 +289,11 @@ int snd_card_free(snd_card_t * card) ...@@ -283,22 +289,11 @@ int snd_card_free(snd_card_t * card)
return 0; return 0;
} }
static int snd_card_free_thread(void * __card) static void snd_card_free_thread(void * __card)
{ {
snd_card_t *card = __card; snd_card_t *card = __card;
struct module * module; 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)) { 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); snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
module = NULL; module = NULL;
...@@ -310,31 +305,33 @@ static int snd_card_free_thread(void * __card) ...@@ -310,31 +305,33 @@ static int snd_card_free_thread(void * __card)
if (module) if (module)
__MOD_DEC_USE_COUNT(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 * snd_card_free_in_thread: call snd_card_free() in thread
* @card: soundcard structure * @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. * Returns - zero otherwise a negative error code if the start of thread failed.
*/ */
int snd_card_free_in_thread(snd_card_t * card) int snd_card_free_in_thread(snd_card_t * card)
{ {
int pid; DECLARE_WORK(works, snd_card_free_thread, card);
if (card->files == NULL) { if (card->files == NULL) {
snd_card_free(card); snd_card_free(card);
return 0; return 0;
} }
pid = kernel_thread(snd_card_free_thread, card, 0); if (schedule_work(&works))
if (pid >= 0)
return 0; return 0;
snd_printk(KERN_ERR "kernel_thread failed in snd_card_free_in_thread for card %i\n", card->number); 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 */ /* try to free the structure immediately */
snd_card_free(card); snd_card_free(card);
...@@ -395,6 +392,17 @@ static void choose_default_id(snd_card_t * 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 snd_card_register(snd_card_t * card)
{ {
int err; int err;
...@@ -509,6 +517,17 @@ int __exit snd_card_info_done(void) ...@@ -509,6 +517,17 @@ int __exit snd_card_info_done(void)
return 0; 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) int snd_component_add(snd_card_t *card, const char *component)
{ {
char *ptr; char *ptr;
...@@ -529,6 +548,17 @@ int snd_component_add(snd_card_t *card, const char *component) ...@@ -529,6 +548,17 @@ int snd_component_add(snd_card_t *card, const char *component)
return 0; 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) int snd_card_file_add(snd_card_t *card, struct file *file)
{ {
struct snd_monitor_file *mfile; struct snd_monitor_file *mfile;
...@@ -550,6 +580,19 @@ int snd_card_file_add(snd_card_t *card, struct file *file) ...@@ -550,6 +580,19 @@ int snd_card_file_add(snd_card_t *card, struct file *file)
return 0; 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) int snd_card_file_remove(snd_card_t *card, struct file *file)
{ {
struct snd_monitor_file *mfile, *pfile = NULL; struct snd_monitor_file *mfile, *pfile = NULL;
...@@ -580,7 +623,12 @@ int snd_card_file_remove(snd_card_t *card, struct file *file) ...@@ -580,7 +623,12 @@ int snd_card_file_remove(snd_card_t *card, struct file *file)
} }
#ifdef CONFIG_PM #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) void snd_power_wait(snd_card_t *card)
{ {
wait_queue_t wait; wait_queue_t wait;
......
...@@ -110,8 +110,8 @@ int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) ...@@ -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); 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 } else
#endif #endif
snd_runtime_check(pos <= runtime->buffer_size, return 0); snd_runtime_check(pos < runtime->buffer_size, return 0);
pos -= pos % runtime->min_align; pos -= pos % runtime->min_align;
new_hw_ptr = runtime->hw_ptr_base + pos; new_hw_ptr = runtime->hw_ptr_base + pos;
...@@ -176,8 +176,8 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream) ...@@ -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); 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 } else
#endif #endif
snd_runtime_check(pos <= runtime->buffer_size, return 0); snd_runtime_check(pos < runtime->buffer_size, return 0);
pos -= pos % runtime->min_align; pos -= pos % runtime->min_align;
new_hw_ptr = runtime->hw_ptr_base + pos; new_hw_ptr = runtime->hw_ptr_base + pos;
......
...@@ -283,6 +283,8 @@ static int snd_seq_device_dev_disconnect(snd_device_t *device) ...@@ -283,6 +283,8 @@ static int snd_seq_device_dev_disconnect(snd_device_t *device)
return -ENOENT; return -ENOENT;
free_device(dev, ops); free_device(dev, ops);
unlock_driver(ops);
return 0; return 0;
} }
......
...@@ -445,6 +445,9 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, ...@@ -445,6 +445,9 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
int result = 0; int result = 0;
unsigned int what;
snd_pcm_substream_t *s;
int do_start;
#if 0 #if 0
printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS))); 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, ...@@ -452,38 +455,39 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
do_start = 1; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
{ case SNDRV_PCM_TRIGGER_SUSPEND:
unsigned int what = 0; do_start = 0; break;
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;
}
default: default:
result = -EINVAL; return -EINVAL;
break; }
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 #if 0
snd_cs4231_debug(chip); snd_cs4231_debug(chip);
#endif #endif
...@@ -1188,7 +1192,9 @@ int snd_cs4231_probe(cs4231_t *chip) ...@@ -1188,7 +1192,9 @@ int snd_cs4231_probe(cs4231_t *chip)
static snd_pcm_hardware_t snd_cs4231_playback = static snd_pcm_hardware_t snd_cs4231_playback =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .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 | .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), SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
...@@ -1207,7 +1213,9 @@ static snd_pcm_hardware_t snd_cs4231_playback = ...@@ -1207,7 +1213,9 @@ static snd_pcm_hardware_t snd_cs4231_playback =
static snd_pcm_hardware_t snd_cs4231_capture = static snd_pcm_hardware_t snd_cs4231_capture =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .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 | .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), SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .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, ...@@ -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) if (snd_pcm_format_width(params_format(hw_params)) == 16)
shift++; shift++;
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
case 0:
if ((chip->caps & ES18XX_DUPLEX_MONO) && if ((chip->caps & ES18XX_DUPLEX_MONO) &&
(chip->capture_a_substream) && (chip->capture_a_substream) &&
params_channels(hw_params) != 1) { params_channels(hw_params) != 1) {
...@@ -453,10 +452,8 @@ static int snd_es18xx_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -453,10 +452,8 @@ static int snd_es18xx_playback_hw_params(snd_pcm_substream_t * substream,
return -EBUSY; return -EBUSY;
} }
chip->dma2_shift = shift; chip->dma2_shift = shift;
break; } else {
case 1:
chip->dma1_shift = shift; chip->dma1_shift = shift;
break;
} }
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err; return err;
...@@ -495,19 +492,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip, ...@@ -495,19 +492,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
snd_pcm_substream_t * substream, snd_pcm_substream_t * substream,
int cmd) int cmd)
{ {
if (cmd == SNDRV_PCM_TRIGGER_START) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (chip->active & DAC2) if (chip->active & DAC2)
return 0; return 0;
chip->active |= DAC2; 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 */ /* Start DMA */
if (chip->dma2 >= 4) if (chip->dma2 >= 4)
snd_es18xx_mixer_write(chip, 0x78, 0xb3); snd_es18xx_mixer_write(chip, 0x78, 0xb3);
...@@ -523,8 +513,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip, ...@@ -523,8 +513,12 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
/* Enable PCM output */ /* Enable PCM output */
snd_es18xx_dsp_command(chip, 0xD1); snd_es18xx_dsp_command(chip, 0xD1);
#endif #endif
} break;
else { case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!(chip->active & DAC2))
return 0;
chip->active &= ~DAC2;
/* Stop DMA */ /* Stop DMA */
snd_es18xx_mixer_write(chip, 0x78, 0x00); snd_es18xx_mixer_write(chip, 0x78, 0x00);
#ifdef AVOID_POPS #ifdef AVOID_POPS
...@@ -536,7 +530,10 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip, ...@@ -536,7 +530,10 @@ static int snd_es18xx_playback1_trigger(es18xx_t *chip,
/* Disable PCM output */ /* Disable PCM output */
snd_es18xx_dsp_command(chip, 0xD3); snd_es18xx_dsp_command(chip, 0xD3);
#endif #endif
} break;
default:
return -EINVAL;
}
return 0; return 0;
} }
...@@ -608,24 +605,27 @@ static int snd_es18xx_capture_trigger(snd_pcm_substream_t *substream, ...@@ -608,24 +605,27 @@ static int snd_es18xx_capture_trigger(snd_pcm_substream_t *substream,
{ {
es18xx_t *chip = snd_pcm_substream_chip(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) if (chip->active & ADC1)
return 0; return 0;
chip->active |= ADC1; 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)) if (!(chip->active & ADC1))
return 0; return 0;
chip->active &= ~ADC1; chip->active &= ~ADC1;
} else { /* Stop DMA */
snd_es18xx_write(chip, 0xB8, 0x00);
break;
default:
return -EINVAL; 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; return 0;
} }
...@@ -670,19 +670,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip, ...@@ -670,19 +670,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
snd_pcm_substream_t *substream, snd_pcm_substream_t *substream,
int cmd) int cmd)
{ {
if (cmd == SNDRV_PCM_TRIGGER_START) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (chip->active & DAC1) if (chip->active & DAC1)
return 0; return 0;
chip->active |= DAC1; 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 */ /* Start DMA */
snd_es18xx_write(chip, 0xB8, 0x05); snd_es18xx_write(chip, 0xB8, 0x05);
#ifdef AVOID_POPS #ifdef AVOID_POPS
...@@ -691,8 +684,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip, ...@@ -691,8 +684,12 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
/* Enable Audio 1 */ /* Enable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD1); snd_es18xx_dsp_command(chip, 0xD1);
#endif #endif
} break;
else { case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!(chip->active & DAC1))
return 0;
chip->active &= ~DAC1;
/* Stop DMA */ /* Stop DMA */
snd_es18xx_write(chip, 0xB8, 0x00); snd_es18xx_write(chip, 0xB8, 0x00);
#ifdef AVOID_POPS #ifdef AVOID_POPS
...@@ -701,33 +698,31 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip, ...@@ -701,33 +698,31 @@ static int snd_es18xx_playback2_trigger(es18xx_t *chip,
/* Disable Audio 1 */ /* Disable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD3); snd_es18xx_dsp_command(chip, 0xD3);
#endif #endif
} break;
default:
return -EINVAL;
}
return 0; return 0;
} }
static int snd_es18xx_playback_prepare(snd_pcm_substream_t *substream) static int snd_es18xx_playback_prepare(snd_pcm_substream_t *substream)
{ {
es18xx_t *chip = snd_pcm_substream_chip(substream); es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
case 0:
return snd_es18xx_playback1_prepare(chip, substream); return snd_es18xx_playback1_prepare(chip, substream);
case 1: else
return snd_es18xx_playback2_prepare(chip, substream); return snd_es18xx_playback2_prepare(chip, substream);
}
return -EINVAL;
} }
static int snd_es18xx_playback_trigger(snd_pcm_substream_t *substream, static int snd_es18xx_playback_trigger(snd_pcm_substream_t *substream,
int cmd) int cmd)
{ {
es18xx_t *chip = snd_pcm_substream_chip(substream); es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
case 0:
return snd_es18xx_playback1_trigger(chip, substream, cmd); return snd_es18xx_playback1_trigger(chip, substream, cmd);
case 1: else
return snd_es18xx_playback2_trigger(chip, substream, cmd); return snd_es18xx_playback2_trigger(chip, substream, cmd);
}
return -EINVAL;
} }
static void snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 ...@@ -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); es18xx_t *chip = snd_pcm_substream_chip(substream);
int pos; int pos;
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
case 0:
if (!(chip->active & DAC2)) if (!(chip->active & DAC2))
return 0; return 0;
pos = chip->dma2_size - snd_dma_residue(chip->dma2); pos = chip->dma2_size - snd_dma_residue(chip->dma2);
return pos >> chip->dma2_shift; return pos >> chip->dma2_shift;
case 1: } else {
if (!(chip->active & DAC1)) if (!(chip->active & DAC1))
return 0; return 0;
pos = chip->dma1_size - snd_dma_residue(chip->dma1); pos = chip->dma1_size - snd_dma_residue(chip->dma1);
return pos >> chip->dma1_shift; return pos >> chip->dma1_shift;
} }
return 0;
} }
static snd_pcm_uframes_t snd_es18xx_capture_pointer(snd_pcm_substream_t * substream) 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 ...@@ -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 = static snd_pcm_hardware_t snd_es18xx_playback =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
...@@ -846,6 +840,7 @@ static snd_pcm_hardware_t snd_es18xx_playback = ...@@ -846,6 +840,7 @@ static snd_pcm_hardware_t snd_es18xx_playback =
static snd_pcm_hardware_t snd_es18xx_capture = static snd_pcm_hardware_t snd_es18xx_capture =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), 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) ...@@ -867,20 +862,17 @@ static int snd_es18xx_playback_open(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
es18xx_t *chip = snd_pcm_substream_chip(substream); es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
case 0:
if ((chip->caps & ES18XX_DUPLEX_MONO) && if ((chip->caps & ES18XX_DUPLEX_MONO) &&
chip->capture_a_substream && chip->capture_a_substream &&
chip->capture_a_substream->runtime->channels != 1) chip->capture_a_substream->runtime->channels != 1)
return -EAGAIN; return -EAGAIN;
chip->playback_a_substream = substream; chip->playback_a_substream = substream;
break; } else if (substream->number <= 1) {
case 1:
if (chip->capture_a_substream) if (chip->capture_a_substream)
return -EAGAIN; return -EAGAIN;
chip->playback_b_substream = substream; chip->playback_b_substream = substream;
break; } else {
default:
snd_BUG(); snd_BUG();
return -EINVAL; return -EINVAL;
} }
...@@ -912,17 +904,10 @@ static int snd_es18xx_playback_close(snd_pcm_substream_t * substream) ...@@ -912,17 +904,10 @@ static int snd_es18xx_playback_close(snd_pcm_substream_t * substream)
{ {
es18xx_t *chip = snd_pcm_substream_chip(substream); es18xx_t *chip = snd_pcm_substream_chip(substream);
switch (substream->number) { if (substream->number == 0 && (chip->caps & ES18XX_PCM2))
case 0:
chip->playback_a_substream = NULL; chip->playback_a_substream = NULL;
break; else
case 1:
chip->playback_b_substream = NULL; chip->playback_b_substream = NULL;
break;
default:
snd_BUG();
return -EINVAL;
}
snd_pcm_lib_free_pages(substream); snd_pcm_lib_free_pages(substream);
return 0; return 0;
...@@ -1544,6 +1529,9 @@ static int __init snd_es18xx_probe(es18xx_t *chip) ...@@ -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); 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); return snd_es18xx_initialize(chip);
} }
...@@ -1600,6 +1588,8 @@ int __init snd_es18xx_pcm(es18xx_t *chip, int device, snd_pcm_t ** rpcm) ...@@ -1600,6 +1588,8 @@ int __init snd_es18xx_pcm(es18xx_t *chip, int device, snd_pcm_t ** rpcm)
pcm->info_flags = 0; pcm->info_flags = 0;
if (chip->caps & ES18XX_DUPLEX_SAME) if (chip->caps & ES18XX_DUPLEX_SAME)
pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX; 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); sprintf(pcm->name, "ESS AudioDrive ES%x", chip->version);
chip->pcm = pcm; chip->pcm = pcm;
...@@ -1709,7 +1699,7 @@ static int snd_es18xx_free(es18xx_t *chip) ...@@ -1709,7 +1699,7 @@ static int snd_es18xx_free(es18xx_t *chip)
disable_dma(chip->dma1); disable_dma(chip->dma1);
free_dma(chip->dma1); free_dma(chip->dma1);
} }
if (chip->dma2 >= 0) { if (chip->dma2 >= 0 && chip->dma1 != chip->dma2) {
disable_dma(chip->dma2); disable_dma(chip->dma2);
free_dma(chip->dma2); free_dma(chip->dma2);
} }
...@@ -1773,7 +1763,7 @@ static int __init snd_es18xx_new_device(snd_card_t * card, ...@@ -1773,7 +1763,7 @@ static int __init snd_es18xx_new_device(snd_card_t * card,
} }
chip->dma1 = dma1; chip->dma1 = dma1;
if (request_dma(dma2, "ES18xx DMA 2")) { if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
snd_es18xx_free(chip); snd_es18xx_free(chip);
printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
return -EBUSY; return -EBUSY;
...@@ -2181,10 +2171,16 @@ static int __init snd_audiodrive_probe(int dev) ...@@ -2181,10 +2171,16 @@ static int __init snd_audiodrive_probe(int dev)
#endif #endif
sprintf(card->driver, "ES%x", chip->version); sprintf(card->driver, "ES%x", chip->version);
sprintf(card->shortname, "ESS AudioDrive 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", if (xdma1 != xdma2)
card->shortname, sprintf(card->longname, "%s at 0x%lx, irq %d, dma1 %d, dma2 %d",
chip->port, card->shortname,
xirq, xdma1, xdma2); 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) { if ((err = snd_card_register(card)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
......
...@@ -666,7 +666,7 @@ static int __init alsa_card_sb16_setup(char *str) ...@@ -666,7 +666,7 @@ static int __init alsa_card_sb16_setup(char *str)
{ {
static unsigned __initdata nr_dev = 0; static unsigned __initdata nr_dev = 0;
int __attribute__ ((__unused__)) pnp = INT_MAX; int __attribute__ ((__unused__)) pnp = INT_MAX;
int __attribute__ ((__unused__)) csp = INT_MAX; int __attribute__ ((__unused__)) xcsp = INT_MAX;
if (nr_dev >= SNDRV_CARDS) if (nr_dev >= SNDRV_CARDS)
return 0; return 0;
...@@ -683,7 +683,7 @@ static int __init alsa_card_sb16_setup(char *str) ...@@ -683,7 +683,7 @@ static int __init alsa_card_sb16_setup(char *str)
get_option(&str,&mic_agc[nr_dev]) == 2 get_option(&str,&mic_agc[nr_dev]) == 2
#ifdef CONFIG_SND_SB16_CSP #ifdef CONFIG_SND_SB16_CSP
&& &&
get_option(&str,&csp[nr_dev]) == 2 get_option(&str,&xcsp) == 2
#endif #endif
#ifdef SNDRV_SBAWE_EMU8000 #ifdef SNDRV_SBAWE_EMU8000
&& &&
...@@ -697,7 +697,7 @@ static int __init alsa_card_sb16_setup(char *str) ...@@ -697,7 +697,7 @@ static int __init alsa_card_sb16_setup(char *str)
#endif #endif
#ifdef CONFIG_SND_SB16_CSP #ifdef CONFIG_SND_SB16_CSP
if (csp != INT_MAX) if (csp != INT_MAX)
csp[nr_dev] = csp; csp[nr_dev] = xcsp;
#endif #endif
nr_dev++; nr_dev++;
return 1; return 1;
......
...@@ -1210,59 +1210,64 @@ static int snd_ali_trigger(snd_pcm_substream_t *substream, ...@@ -1210,59 +1210,64 @@ static int snd_ali_trigger(snd_pcm_substream_t *substream,
unsigned int what, whati, capture_flag; unsigned int what, whati, capture_flag;
snd_ali_voice_t *pvoice = NULL, *evoice = NULL; snd_ali_voice_t *pvoice = NULL, *evoice = NULL;
unsigned int val; unsigned int val;
int do_start;
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
do_start = 1; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
{ case SNDRV_PCM_TRIGGER_SUSPEND:
what = whati = capture_flag = 0; do_start = 0; break;
s = substream; default:
do { return -EINVAL;
if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) { }
pvoice = (snd_ali_voice_t *) s->runtime->private_data;
evoice = pvoice->extra; what = whati = capture_flag = 0;
what |= 1 << (pvoice->number & 0x1f); s = substream;
if (evoice == NULL) { do {
whati |= 1 << (pvoice->number & 0x1f); if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) {
} else { pvoice = (snd_ali_voice_t *) s->runtime->private_data;
whati |= 1 << (evoice->number & 0x1f); evoice = pvoice->extra;
what |= 1 << (evoice->number & 0x1f); what |= 1 << (pvoice->number & 0x1f);
} if (evoice == NULL) {
if (cmd == SNDRV_PCM_TRIGGER_START) { whati |= 1 << (pvoice->number & 0x1f);
pvoice->running = 1; } else {
if (evoice != NULL) whati |= 1 << (evoice->number & 0x1f);
evoice->running = 1; what |= 1 << (evoice->number & 0x1f);
}
snd_pcm_trigger_done(s, substream);
if (pvoice->mode)
capture_flag = 1;
} }
s = s->link_next; if (do_start) {
} while (s != substream); pvoice->running = 1;
spin_lock(&codec->reg_lock); if (evoice != NULL)
if (cmd == SNDRV_PCM_TRIGGER_STOP) { evoice->running = 1;
outl(what, ALI_REG(codec, ALI_STOP)); } else {
pvoice->running = 0; pvoice->running = 0;
if (evoice != NULL) if (evoice != NULL)
evoice->running = 0; evoice->running = 0;
} }
val = inl(ALI_REG(codec, ALI_AINTEN)); snd_pcm_trigger_done(s, substream);
if (cmd == SNDRV_PCM_TRIGGER_START) { if (pvoice->mode)
val |= whati; capture_flag = 1;
} else {
val &= ~whati;
}
outl(val, ALI_REG(codec, ALI_AINTEN));
if (cmd == SNDRV_PCM_TRIGGER_START) {
outl(what, ALI_REG(codec, ALI_START));
} }
snd_ali_printk("trigger: what=%xh whati=%xh\n",what,whati); s = s->link_next;
spin_unlock(&codec->reg_lock); } while (s != substream);
break; spin_lock(&codec->reg_lock);
if (! do_start) {
outl(what, ALI_REG(codec, ALI_STOP));
} }
default: val = inl(ALI_REG(codec, ALI_AINTEN));
return -EINVAL; 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; return 0;
} }
...@@ -1544,7 +1549,9 @@ static snd_pcm_hardware_t snd_ali_playback = ...@@ -1544,7 +1549,9 @@ static snd_pcm_hardware_t snd_ali_playback =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | 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 | .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
...@@ -1568,7 +1575,9 @@ static snd_pcm_hardware_t snd_ali_capture = ...@@ -1568,7 +1575,9 @@ static snd_pcm_hardware_t snd_ali_capture =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | 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 | .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .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) ...@@ -735,12 +735,14 @@ static int snd_cs4281_trigger(snd_pcm_substream_t *substream, int cmd)
dma->valFCR &= ~BA0_FCR_FEN; dma->valFCR &= ~BA0_FCR_FEN;
break; break;
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR & ~BA0_DMR_DMA); snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR & ~BA0_DMR_DMA);
dma->valDMR |= BA0_DMR_DMA; dma->valDMR |= BA0_DMR_DMA;
dma->valDCR &= ~BA0_DCR_MSK; dma->valDCR &= ~BA0_DCR_MSK;
dma->valFCR |= BA0_FCR_FEN; dma->valFCR |= BA0_FCR_FEN;
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
dma->valDMR &= ~(BA0_DMR_DMA|BA0_DMR_POLL); dma->valDMR &= ~(BA0_DMR_DMA|BA0_DMR_POLL);
dma->valDCR |= BA0_DCR_MSK; dma->valDCR |= BA0_DCR_MSK;
dma->valFCR &= ~BA0_FCR_FEN; dma->valFCR &= ~BA0_FCR_FEN;
...@@ -900,6 +902,7 @@ static snd_pcm_hardware_t snd_cs4281_playback = ...@@ -900,6 +902,7 @@ static snd_pcm_hardware_t snd_cs4281_playback =
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
...@@ -925,6 +928,7 @@ static snd_pcm_hardware_t snd_cs4281_capture = ...@@ -925,6 +928,7 @@ static snd_pcm_hardware_t snd_cs4281_capture =
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | 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_ ...@@ -849,7 +849,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_
cpcm->hw_io = ptr; cpcm->hw_io = ptr;
cpcm->hw_ready -= bytes; cpcm->hw_ready -= bytes;
cpcm->sw_io += 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; cpcm->sw_io -= cpcm->sw_bufsize;
snd_cs46xx_playback_transfer(substream, 0); snd_cs46xx_playback_transfer(substream, 0);
return cpcm->sw_io >> cpcm->shift; return cpcm->sw_io >> cpcm->shift;
...@@ -874,7 +874,7 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t ...@@ -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_io = ptr;
chip->capt.hw_ready += bytes; chip->capt.hw_ready += bytes;
chip->capt.sw_io += 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; chip->capt.sw_io -= chip->capt.sw_bufsize;
snd_cs46xx_capture_transfer(substream, 0); snd_cs46xx_capture_transfer(substream, 0);
return chip->capt.sw_io >> chip->capt.shift; return chip->capt.sw_io >> chip->capt.shift;
...@@ -952,7 +952,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, ...@@ -952,7 +952,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
/* magic value to unmute PCM stream playback volume */ /* magic value to unmute PCM stream playback volume */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address +
SCBVolumeCtrl) << 2, 0x80007fff); SCBVolumeCtrl) << 2, 0x80008000);
if (cpcm->pcm_channel->unlinked) if (cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel); cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
...@@ -1032,32 +1032,27 @@ static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream, ...@@ -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, static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
int sample_rate) int sample_rate)
{ {
/* if this is the only PCMReaderSCB child under current
SrcTask then there no need to re-create pcm-channel */ /* If PCMReaderSCB and SrcTaskSCB not created yet ... */
if ( cpcm->pcm_channel->src_scb->ref_count == 1 && if ( cpcm->pcm_channel == NULL) {
cpcm->pcm_channel->sample_rate != sample_rate && cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate,
/* never set a 0 khz sample rate */ cpcm, cpcm->hw_addr,cpcm->pcm_channel_id);
sample_rate) { if (cpcm->pcm_channel == NULL) {
/* sample rate not set or we can reuse snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
the same SRC*/ return -ENOMEM;
cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate); }
cpcm->pcm_channel->sample_rate = sample_rate; cpcm->pcm_channel->sample_rate = sample_rate;
} } else
/* if sample rate is changed */
/* if there is more then 1 PCMReaderSCB child's under current if (cpcm->pcm_channel->sample_rate != sample_rate) {
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) {
int unlinked = cpcm->pcm_channel->unlinked; int unlinked = cpcm->pcm_channel->unlinked;
cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm,
cpcm->hw_addr, 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"); 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); 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, ...@@ -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); cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
snd_assert (sample_rate != 0, return -ENXIO);
down (&chip->spos_mutex); down (&chip->spos_mutex);
snd_assert (cpcm->pcm_channel != NULL);
if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) { if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
up (&chip->spos_mutex); up (&chip->spos_mutex);
return -ENXIO; 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)) { if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
up (&chip->spos_mutex); up (&chip->spos_mutex);
return -EINVAL; return -EINVAL;
...@@ -1108,11 +1109,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -1108,11 +1109,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
#ifdef CONFIG_SND_CS46XX_NEW_DSP #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; 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; 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; substream->ops = &snd_cs46xx_playback_iec958_ops;
} else { } else {
snd_assert(0); snd_assert(0);
...@@ -1135,11 +1136,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -1135,11 +1136,11 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
} }
#ifdef CONFIG_SND_CS46XX_NEW_DSP #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; 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; 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; substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
} else { } else {
snd_assert(0); snd_assert(0);
...@@ -1165,6 +1166,10 @@ static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream) ...@@ -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); 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) if (runtime->dma_area != cpcm->hw_area)
snd_pcm_lib_free_pages(substream); snd_pcm_lib_free_pages(substream);
...@@ -1482,15 +1487,8 @@ static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pc ...@@ -1482,15 +1487,8 @@ static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pc
cpcm->substream = substream; cpcm->substream = substream;
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex); down (&chip->spos_mutex);
cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr,pcm_channel_id); cpcm->pcm_channel = NULL;
cpcm->pcm_channel_id = 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;
}
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes); &hw_constraints_period_sizes);
...@@ -1583,6 +1581,9 @@ static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream) ...@@ -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); 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 #ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex); down (&chip->spos_mutex);
if (cpcm->pcm_channel) { if (cpcm->pcm_channel) {
...@@ -1887,8 +1888,8 @@ static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ ...@@ -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); cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right; ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_left;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left; ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_right;
return 0; return 0;
} }
...@@ -1913,8 +1914,8 @@ static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_val ...@@ -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); cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = 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] = chip->dsp_spos_instance->spdif_input_volume_left; ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_right;
return 0; return 0;
} }
...@@ -1923,8 +1924,8 @@ static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_val ...@@ -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); cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
int change = 0; int change = 0;
if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] || if (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!= ucontrol->value.integer.value[1]) {
cs46xx_dsp_set_iec958_volume (chip, cs46xx_dsp_set_iec958_volume (chip,
ucontrol->value.integer.value[0], ucontrol->value.integer.value[0],
ucontrol->value.integer.value[1]); ucontrol->value.integer.value[1]);
...@@ -2206,6 +2207,7 @@ static int snd_cs46xx_spdif_stream_put(snd_kcontrol_t * kcontrol, ...@@ -2206,6 +2207,7 @@ static int snd_cs46xx_spdif_stream_put(snd_kcontrol_t * kcontrol,
#endif /* CONFIG_SND_CS46XX_NEW_DSP */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
static int snd_cs46xx_egpio_select_info(snd_kcontrol_t *kcontrol, static int snd_cs46xx_egpio_select_info(snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo) snd_ctl_elem_info_t *uinfo)
...@@ -3331,8 +3333,8 @@ int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip) ...@@ -3331,8 +3333,8 @@ int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip)
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
/* set the attenuation to 0dB */ /* set the attenuation to 0dB */
snd_cs46xx_poke(chip, (MASTERMIX_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); snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000); */
/* /*
* Initialize cs46xx SPDIF controller * Initialize cs46xx SPDIF controller
......
...@@ -152,6 +152,7 @@ dsp_scb_descriptor_t * cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * s ...@@ -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, dsp_scb_descriptor_t * parent_scb,
int scb_child_type); int scb_child_type);
dsp_scb_descriptor_t * cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name, 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_buffer_addr,
u16 src_delay_buffer_addr,u32 dest, u16 src_delay_buffer_addr,u32 dest,
dsp_scb_descriptor_t * parent_scb, dsp_scb_descriptor_t * parent_scb,
...@@ -202,8 +203,6 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa ...@@ -202,8 +203,6 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
int pcm_channel_id); int pcm_channel_id);
void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip, void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,
pcm_channel_descriptor_t * pcm_channel); 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_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
int cs46xx_dsp_pcm_link (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, 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_ ...@@ -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"); snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
col = 0; 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) { if (col == 4) {
snd_iprintf(buffer,"\n"); snd_iprintf(buffer,"\n");
col = 0; col = 0;
...@@ -628,14 +628,14 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_ ...@@ -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,"%08X ",readl(dst + i));
} }
snd_iprintf(buffer,"\n\n"); snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
col = 0; 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) { if (col == 4) {
snd_iprintf(buffer,"\n"); snd_iprintf(buffer,"\n");
col = 0; col = 0;
} }
if (col == 0) { if (col == 0) {
snd_iprintf(buffer, "%04X ",i); snd_iprintf(buffer, "%04X ",i);
} }
...@@ -646,7 +646,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_ ...@@ -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"); snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
col = 0; 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) { if (col == 4) {
snd_iprintf(buffer,"\n"); snd_iprintf(buffer,"\n");
col = 0; col = 0;
...@@ -705,7 +705,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_ ...@@ -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)); snd_iprintf(buffer,"%08X ",readl(dst + i));
} }
#if 0
snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n"); snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
col = 0; col = 0;
for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) { 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_ ...@@ -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)); 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"); snd_iprintf(buffer,"\n");
} }
...@@ -1356,6 +1371,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip) ...@@ -1356,6 +1371,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip)
/* SPDIF input sampel rate converter */ /* SPDIF input sampel rate converter */
src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI", src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
48000,
SRC_OUTPUT_BUF1, SRC_OUTPUT_BUF1,
SRC_DELAY_BUF1,SRCTASK_SCB_ADDR, SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
master_mix_scb, master_mix_scb,
...@@ -1597,11 +1613,14 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip) ...@@ -1597,11 +1613,14 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0); cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
cs46xx_src_link(chip,ins->spdif_in_src); 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); spin_unlock_irq(&chip->reg_lock);
/* set SPDIF input sample rate and unmute /* set SPDIF input sample rate and unmute
NOTE: only 48khz support for SPDIF input this time */ 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 */ /* monitor state */
ins->spdif_status_in = 1; ins->spdif_status_in = 1;
......
...@@ -197,7 +197,7 @@ static inline u8 _wrap_all_bits (u8 val) { ...@@ -197,7 +197,7 @@ static inline u8 _wrap_all_bits (u8 val) {
((val & 0x10) >> 1) | ((val & 0x10) >> 1) |
((val & 0x20) >> 3) | ((val & 0x20) >> 3) |
((val & 0x40) >> 5) | ((val & 0x40) >> 5) |
((val & 0x80) >> 6); ((val & 0x80) >> 7);
return wrapped; return wrapped;
......
This diff is collapsed.
...@@ -199,7 +199,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) ...@@ -199,7 +199,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
} }
static struct pci_driver driver = { static struct pci_driver driver = {
.name = "EMU10K1/Audigy", .name = "EMU10K1_Audigy",
.id_table = snd_emu10k1_ids, .id_table = snd_emu10k1_ids,
.probe = snd_card_emu10k1_probe, .probe = snd_card_emu10k1_probe,
.remove = __devexit_p(snd_card_emu10k1_remove), .remove = __devexit_p(snd_card_emu10k1_remove),
......
...@@ -217,9 +217,11 @@ void __devinit snd_ice1712_ak4524_init(ice1712_t *ice) ...@@ -217,9 +217,11 @@ void __devinit snd_ice1712_ak4524_init(ice1712_t *ice)
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff) #define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
#define AK_GET_ADDR(val) ((val) & 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_GET_MASK(val) (((val) >> 24) & 0xff)
#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) #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) 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_ ...@@ -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); ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(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 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; return 0;
} }
...@@ -247,9 +252,14 @@ static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_ ...@@ -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); ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(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 int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char nval = mask - (ucontrol->value.integer.value[0] % (mask+1)); unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
int change = ice->ak4524.images[chip][addr] != nval; int change;
if (invert)
nval = mask - nval;
change = ice->ak4524.images[chip][addr] != nval;
if (change) if (change)
snd_ice1712_ak4524_write(ice, chip, addr, nval); snd_ice1712_ak4524_write(ice, chip, addr, nval);
return change; return change;
...@@ -353,7 +363,7 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice) ...@@ -353,7 +363,7 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice)
break; break;
case SND_AK4529: { case SND_AK4529: {
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */ 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; break;
} }
} }
......
...@@ -218,6 +218,11 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { ...@@ -218,6 +218,11 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
"Hoontech SoundTrack Audio DSP24", "Hoontech SoundTrack Audio DSP24",
snd_ice1712_hoontech_init, snd_ice1712_hoontech_init,
}, },
{
ICE1712_SUBDEVICE_STDSP24_MEDIA7_1,
"Hoontech STA DSP24 Media 7.1",
snd_ice1712_hoontech_init,
},
{ } /* terminator */ { } /* terminator */
}; };
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define HOONTECH_DEVICE_DESC "{Hoontech SoundTrack DSP 24}," #define HOONTECH_DEVICE_DESC "{Hoontech SoundTrack DSP 24},"
#define ICE1712_SUBDEVICE_STDSP24 0x12141217 /* Hoontech SoundTrack Audio 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[]; extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
......
...@@ -23,9 +23,38 @@ ...@@ -23,9 +23,38 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 <sound/driver.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -80,29 +109,29 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); ...@@ -80,29 +109,29 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
#define RME32_IO_RESET_POS 0x20100 #define RME32_IO_RESET_POS 0x20100
/* Write control register bits */ /* Write control register bits */
#define RME32_WCR_START (1 << 0) #define RME32_WCR_START (1 << 0) /* startbit */
#define RME32_WCR_MONO (1 << 1) /* 0: stereo, 1: mono #define RME32_WCR_MONO (1 << 1) /* 0=stereo, 1=mono
Setting the whole card to 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 A software-solution can handle
full-duplex with one direction in full-duplex with one direction in
stereo and the other way in mono. stereo and the other way in mono.
So, the hardware should work all So, the hardware should work all
the time in stereo! */ the time in stereo! */
#define RME32_WCR_MODE24 (1 << 2) #define RME32_WCR_MODE24 (1 << 2) /* 0=16bit, 1=32bit */
#define RME32_WCR_SEL (1 << 3) #define RME32_WCR_SEL (1 << 3) /* 0=input on output, 1=normal playback/capture */
#define RME32_WCR_FREQ_0 (1 << 4) #define RME32_WCR_FREQ_0 (1 << 4) /* frequency (play) */
#define RME32_WCR_FREQ_1 (1 << 5) #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_INP_1 (1 << 7)
#define RME32_WCR_RESET (1 << 8) #define RME32_WCR_RESET (1 << 8) /* Reset address */
#define RME32_WCR_MUTE (1 << 9) #define RME32_WCR_MUTE (1 << 9) /* digital mute for output */
#define RME32_WCR_PRO (1 << 10) #define RME32_WCR_PRO (1 << 10) /* 1=professional, 0=consumer */
#define RME32_WCR_DS_BM (1 << 11) /* only PRO/Adat-Version */ #define RME32_WCR_DS_BM (1 << 11) /* 1=DoubleSpeed (only PRO-Version); 1=BlockMode (only Adat-Version) */
#define RME32_WCR_ADAT (1 << 12) /* only Adat-Version */ #define RME32_WCR_ADAT (1 << 12) /* Adat Mode (only Adat-Version) */
#define RME32_WCR_AUTOSYNC (1 << 13) #define RME32_WCR_AUTOSYNC (1 << 13) /* AutoSync */
#define RME32_WCR_PD (1 << 14) /* only PRO-Version */ #define RME32_WCR_PD (1 << 14) /* DAC Reset (only PRO-Version) */
#define RME32_WCR_EMP (1 << 15) /* 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_0 4
#define RME32_WCR_BITPOS_FREQ_1 5 #define RME32_WCR_BITPOS_FREQ_1 5
...@@ -111,13 +140,13 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); ...@@ -111,13 +140,13 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
/* Read control register bits */ /* Read control register bits */
#define RME32_RCR_AUDIO_ADDR_MASK 0x10001 #define RME32_RCR_AUDIO_ADDR_MASK 0x10001
#define RME32_RCR_LOCK (1 << 23) #define RME32_RCR_LOCK (1 << 23) /* 1=locked, 0=not locked */
#define RME32_RCR_ERF (1 << 26) #define RME32_RCR_ERF (1 << 26) /* 1=Error, 0=no Error */
#define RME32_RCR_FREQ_0 (1 << 27) #define RME32_RCR_FREQ_0 (1 << 27) /* CS841x frequency (record) */
#define RME32_RCR_FREQ_1 (1 << 28) #define RME32_RCR_FREQ_1 (1 << 28)
#define RME32_RCR_FREQ_2 (1 << 29) #define RME32_RCR_FREQ_2 (1 << 29)
#define RME32_RCR_KMODE (1 << 30) #define RME32_RCR_KMODE (1 << 30) /* card mode: 1=PLL, 0=quartz */
#define RME32_RCR_IRQ (1 << 31) #define RME32_RCR_IRQ (1 << 31) /* interrupt */
#define RME32_RCR_BITPOS_F0 27 #define RME32_RCR_BITPOS_F0 27
#define RME32_RCR_BITPOS_F1 28 #define RME32_RCR_BITPOS_F1 28
...@@ -153,12 +182,12 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); ...@@ -153,12 +182,12 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
#ifndef PCI_DEVICE_ID_DIGI32 #ifndef PCI_DEVICE_ID_DIGI32
# define PCI_DEVICE_ID_DIGI32 0x9896 # define PCI_DEVICE_ID_DIGI32 0x9896
#endif #endif
#ifndef PCI_DEVICE_ID_DIGI32_8
# define PCI_DEVICE_ID_DIGI32_8 0x9898
#endif
#ifndef PCI_DEVICE_ID_DIGI32_PRO #ifndef PCI_DEVICE_ID_DIGI32_PRO
# define PCI_DEVICE_ID_DIGI32_PRO 0x9897 # define PCI_DEVICE_ID_DIGI32_PRO 0x9897
#endif #endif
#ifndef PCI_DEVICE_ID_DIGI32_8
# define PCI_DEVICE_ID_DIGI32_8 0x9898
#endif
typedef struct snd_rme32 { typedef struct snd_rme32 {
spinlock_t lock; spinlock_t lock;
...@@ -314,10 +343,13 @@ static snd_pcm_hardware_t snd_rme32_playback_spdif_info = { ...@@ -314,10 +343,13 @@ static snd_pcm_hardware_t snd_rme32_playback_spdif_info = {
static snd_pcm_hardware_t snd_rme32_capture_spdif_info = { static snd_pcm_hardware_t snd_rme32_capture_spdif_info = {
.info = (SNDRV_PCM_INFO_MMAP | .info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), SNDRV_PCM_INFO_INTERLEAVED |
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE),
.rates = (SNDRV_PCM_RATE_32000 | .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_min = 32000,
.rate_max = 48000, .rate_max = 48000,
.channels_min = 2, .channels_min = 2,
......
...@@ -5,7 +5,7 @@ menu "ALSA USB devices" ...@@ -5,7 +5,7 @@ menu "ALSA USB devices"
config SND_USB_AUDIO config SND_USB_AUDIO
tristate "USB Audio/MIDI driver" tristate "USB Audio/MIDI driver"
depends on SND depends on SND && USB
help help
Say 'Y' or 'M' to include support for USB audio and USB MIDI devices. Say 'Y' or 'M' to include support for USB audio and USB MIDI devices.
......
...@@ -172,7 +172,8 @@ struct snd_usb_midi_endpoint_info { ...@@ -172,7 +172,8 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_MIDI_YAMAHA, data is NULL */ /* 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 */ /* for QUIRK_ROLAND_UA100, data is NULL */
......
...@@ -172,7 +172,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep, ...@@ -172,7 +172,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
/* /*
* Processes the data read from the device. * 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); 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) ...@@ -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. * 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) { if (urb->status == 0) {
uint8_t* buffer = (uint8_t*)urb->transfer_buffer; 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 ...@@ -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); 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, ...@@ -892,7 +892,8 @@ static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi,
/* /*
* Creates the endpoints and their ports for Midiman devices. * 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; snd_usb_midi_endpoint_info_t ep_info;
struct usb_interface* intf; struct usb_interface* intf;
...@@ -906,7 +907,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports ...@@ -906,7 +907,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports
return -ENOENT; return -ENOENT;
hostif = intf->altsetting; hostif = intf->altsetting;
intfd = get_iface_desc(hostif); 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"); snd_printdd(KERN_ERR "not enough endpoints\n");
return -ENOENT; return -ENOENT;
} }
...@@ -923,7 +924,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports ...@@ -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"); snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
return -ENXIO; return -ENXIO;
} }
if (ports > 1) { if (endpoint->out_cables > 0x0001) {
epd = get_endpoint(hostif, 4); epd = get_endpoint(hostif, 4);
if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { (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 ...@@ -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.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]); err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0) if (err < 0)
return err; return err;
ep_info.epnum = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; 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]); err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0) if (err < 0)
return err; return err;
umidi->endpoints[0].in->urb->complete = snd_usbmidi_in_midiman_complete; 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.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]); err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);
if (err < 0) if (err < 0)
return err; return err;
} }
for (cable = 0; cable < ports; ++cable) { for (cable = 0; cable < 0x10; ++cable) {
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable, if (endpoint->out_cables & (1 << cable))
&umidi->endpoints[cable & 1].out->ports[cable].substream); snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable,
snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable, &umidi->endpoints[cable & 1].out->ports[cable].substream);
&umidi->endpoints[0].in->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; return 0;
} }
...@@ -1020,6 +1023,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, ...@@ -1020,6 +1023,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]); err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
break; break;
case QUIRK_MIDI_MIDIMAN: case QUIRK_MIDI_MIDIMAN:
memcpy(&endpoints[0], quirk->data,
sizeof(snd_usb_midi_endpoint_info_t));
err = 0; err = 0;
break; break;
default: default:
...@@ -1034,15 +1039,11 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, ...@@ -1034,15 +1039,11 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
} }
/* create rawmidi device */ /* create rawmidi device */
if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN) { out_ports = 0;
in_ports = out_ports = (int)quirk->data; in_ports = 0;
} else { for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
out_ports = 0; out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
in_ports = 0; in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
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); err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
if (err < 0) { if (err < 0) {
...@@ -1052,7 +1053,7 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, ...@@ -1052,7 +1053,7 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
/* create endpoint/port structures */ /* create endpoint/port structures */
if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN) 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 else
err = snd_usbmidi_create_endpoints(umidi, endpoints); err = snd_usbmidi_create_endpoints(umidi, endpoints);
if (err < 0) { if (err < 0) {
......
...@@ -81,8 +81,7 @@ struct usb_mixer_elem_info { ...@@ -81,8 +81,7 @@ struct usb_mixer_elem_info {
int channels; int channels;
int val_type; int val_type;
int min, max, res; int min, max, res;
unsigned int initialized: 1, unsigned int initialized: 1;
hack_hole1: 1; /* -256 value is missing */
}; };
...@@ -281,17 +280,20 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i ...@@ -281,17 +280,20 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
{ {
unsigned char buf[2]; unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; 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), while (timeout-- > 0) {
request, if (usb_control_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, request,
validx, cval->ctrlif | (cval->id << 8), USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
buf, val_len, HZ) < 0) { validx, cval->ctrlif | (cval->id << 8),
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); buf, val_len, HZ / 10) >= 0) {
return -EINVAL; *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)); 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 0; return -EINVAL;
} }
static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value) 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 ...@@ -313,15 +315,19 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
{ {
unsigned char buf[2]; unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
value_set = convert_bytes_value(cval, value_set); value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff; buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff; buf[1] = (value_set >> 8) & 0xff;
return usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0), while (timeout -- > 0)
request, if (usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, request,
validx, cval->ctrlif | (cval->id << 8), USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
buf, val_len, HZ); 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) static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value)
......
...@@ -475,6 +475,20 @@ ...@@ -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 */ /* Midiman/M-Audio devices */
{ {
...@@ -484,7 +498,10 @@ ...@@ -484,7 +498,10 @@
.product_name = "MidiSport 2x2", .product_name = "MidiSport 2x2",
.ifnum = QUIRK_ANY_INTERFACE, .ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -494,7 +511,10 @@
.product_name = "MidiSport 1x1", .product_name = "MidiSport 1x1",
.ifnum = QUIRK_ANY_INTERFACE, .ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -504,7 +524,10 @@
.product_name = "Keystation", .product_name = "Keystation",
.ifnum = QUIRK_ANY_INTERFACE, .ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -514,7 +537,10 @@
.product_name = "MidiSport 4x4", .product_name = "MidiSport 4x4",
.ifnum = QUIRK_ANY_INTERFACE, .ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -524,7 +550,23 @@
.product_name = "MidiSport 8x8", .product_name = "MidiSport 8x8",
.ifnum = QUIRK_ANY_INTERFACE, .ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -534,7 +576,10 @@
.product_name = "Quattro", .product_name = "Quattro",
.ifnum = 9, .ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN, .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 @@ ...@@ -544,7 +589,10 @@
.product_name = "AudioPhile", .product_name = "AudioPhile",
.ifnum = 9, .ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN, .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