aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2004-10-30 00:55:25 +0200
committerJaroslav Kysela <perex@suse.cz>2004-10-30 00:55:25 +0200
commit654fd8c2403b3c96d6d108697ae30ae67496727b (patch)
tree0921c2531a090bc0231f8709fdf44c86f2e537ba /sound
parenteec2e6670c41f1aba7b02dde582951165a95966e (diff)
parent5f306baab24b1e8c587a5baa43de33d1ad19acdb (diff)
downloadhistory-654fd8c2403b3c96d6d108697ae30ae67496727b.tar.gz
Merge suse.cz:/home/perex/bk/linux-sound/linux-sound
into suse.cz:/home/perex/bk/linux-sound/work
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/core/info.c15
-rw-r--r--sound/core/init.c3
-rw-r--r--sound/core/seq/instr/ainstr_fm.c5
-rw-r--r--sound/core/seq/instr/ainstr_gf1.c5
-rw-r--r--sound/core/seq/instr/ainstr_iw.c5
-rw-r--r--sound/core/seq/instr/ainstr_simple.c5
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c2
-rw-r--r--sound/core/sound.c1
-rw-r--r--sound/isa/ad1848/ad1848_lib.c18
-rw-r--r--sound/isa/es1688/es1688_lib.c3
-rw-r--r--sound/pci/Kconfig5
-rw-r--r--sound/pci/au88x0/au88x0.c15
-rw-r--r--sound/pci/au88x0/au88x0.h6
-rw-r--r--sound/pci/au88x0/au88x0_core.c29
-rw-r--r--sound/pci/au88x0/au88x0_eq.c58
-rw-r--r--sound/pci/au88x0/au88x0_mixer.c4
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c4
-rw-r--r--sound/pci/bt87x.c149
-rw-r--r--sound/pci/emu10k1/emufx.c155
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c10
-rw-r--r--sound/usb/usx2y/usbusx2y.c25
-rw-r--r--sound/usb/usx2y/usbusx2y.h45
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c765
25 files changed, 760 insertions, 576 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 1e4511a7b6a2f2..ec85c5f9fa0815 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -70,7 +70,7 @@ source "sound/parisc/Kconfig"
endmenu
menu "Open Sound System"
- depends on SOUND!=n && (BROKEN || !(SPARC32 || SPARC64))
+ depends on SOUND!=n && (BROKEN || (!SPARC32 && !SPARC64))
config SOUND_PRIME
tristate "Open Sound System (DEPRECATED)"
diff --git a/sound/core/info.c b/sound/core/info.c
index db1e2575fdf3ec..76f7f5a74e5de3 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -20,7 +20,6 @@
*/
#include <sound/driver.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
@@ -959,18 +958,10 @@ static snd_info_entry_t *snd_info_version_entry = NULL;
static void snd_info_version_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
{
- static char *kernel_version = UTS_RELEASE;
-
snd_iprintf(buffer,
- "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
- "Compiled on " __DATE__ " for kernel %s"
-#ifdef CONFIG_SMP
- " (SMP)"
-#endif
-#ifdef MODVERSIONS
- " with versioned symbols"
-#endif
- ".\n", kernel_version);
+ "Advanced Linux Sound Architecture Driver Version "
+ CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
+ );
}
static int __init snd_info_version_init(void)
diff --git a/sound/core/init.c b/sound/core/init.c
index 2873a17bd34b82..2ffe74143d918a 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -37,7 +37,6 @@ struct snd_shutdown_f_ops {
struct snd_shutdown_f_ops *next;
};
-int snd_cards_count = 0;
unsigned int snd_cards_lock = 0; /* locked for registering/using */
snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED;
@@ -251,7 +250,6 @@ int snd_card_free(snd_card_t * card)
return -EINVAL;
write_lock(&snd_card_rwlock);
snd_cards[card->number] = NULL;
- snd_cards_count--;
write_unlock(&snd_card_rwlock);
#ifdef CONFIG_PM
@@ -441,7 +439,6 @@ int snd_card_register(snd_card_t * card)
if (card->id[0] == '\0')
choose_default_id(card);
snd_cards[card->number] = card;
- snd_cards_count++;
write_unlock(&snd_card_rwlock);
if ((err = snd_info_card_register(card)) < 0) {
snd_printd("unable to create card info\n");
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c
index 52a070b909182d..5c671e69884f9f 100644
--- a/sound/core/seq/instr/ainstr_fm.c
+++ b/sound/core/seq/instr/ainstr_fm.c
@@ -30,8 +30,6 @@ MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support.");
MODULE_LICENSE("GPL");
-char *snd_seq_fm_id = SNDRV_SEQ_INSTR_ID_OPL2_3;
-
static int snd_seq_fm_put(void *private_data, snd_seq_kinstr_t *instr,
char __user *instr_data, long len, int atomic, int cmd)
{
@@ -129,7 +127,7 @@ int snd_seq_fm_init(snd_seq_kinstr_ops_t *ops,
memset(ops, 0, sizeof(*ops));
// ops->private_data = private_data;
ops->add_len = sizeof(fm_instrument_t);
- ops->instr_type = snd_seq_fm_id;
+ ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3;
ops->put = snd_seq_fm_put;
ops->get = snd_seq_fm_get;
ops->get_size = snd_seq_fm_get_size;
@@ -155,5 +153,4 @@ static void __exit alsa_ainstr_fm_exit(void)
module_init(alsa_ainstr_fm_init)
module_exit(alsa_ainstr_fm_exit)
-EXPORT_SYMBOL(snd_seq_fm_id);
EXPORT_SYMBOL(snd_seq_fm_init);
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
index 6c21e52ca61ea9..0779c41ca03769 100644
--- a/sound/core/seq/instr/ainstr_gf1.c
+++ b/sound/core/seq/instr/ainstr_gf1.c
@@ -31,8 +31,6 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support.");
MODULE_LICENSE("GPL");
-char *snd_seq_gf1_id = SNDRV_SEQ_INSTR_ID_GUS_PATCH;
-
static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format)
{
unsigned int result = size;
@@ -331,7 +329,7 @@ int snd_seq_gf1_init(snd_gf1_ops_t *ops,
ops->private_data = private_data;
ops->kops.private_data = ops;
ops->kops.add_len = sizeof(gf1_instrument_t);
- ops->kops.instr_type = snd_seq_gf1_id;
+ ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH;
ops->kops.put = snd_seq_gf1_put;
ops->kops.get = snd_seq_gf1_get;
ops->kops.get_size = snd_seq_gf1_get_size;
@@ -357,5 +355,4 @@ static void __exit alsa_ainstr_gf1_exit(void)
module_init(alsa_ainstr_gf1_init)
module_exit(alsa_ainstr_gf1_exit)
-EXPORT_SYMBOL(snd_seq_gf1_id);
EXPORT_SYMBOL(snd_seq_gf1_init);
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
index 005171abe94dc9..39ff72b2aab367 100644
--- a/sound/core/seq/instr/ainstr_iw.c
+++ b/sound/core/seq/instr/ainstr_iw.c
@@ -31,8 +31,6 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
MODULE_LICENSE("GPL");
-char *snd_seq_iwffff_id = SNDRV_SEQ_INSTR_ID_INTERWAVE;
-
static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format)
{
unsigned int result = size;
@@ -595,7 +593,7 @@ int snd_seq_iwffff_init(snd_iwffff_ops_t *ops,
ops->private_data = private_data;
ops->kops.private_data = ops;
ops->kops.add_len = sizeof(iwffff_instrument_t);
- ops->kops.instr_type = snd_seq_iwffff_id;
+ ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE;
ops->kops.put = snd_seq_iwffff_put;
ops->kops.get = snd_seq_iwffff_get;
ops->kops.get_size = snd_seq_iwffff_get_size;
@@ -621,5 +619,4 @@ static void __exit alsa_ainstr_iw_exit(void)
module_init(alsa_ainstr_iw_init)
module_exit(alsa_ainstr_iw_exit)
-EXPORT_SYMBOL(snd_seq_iwffff_id);
EXPORT_SYMBOL(snd_seq_iwffff_init);
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c
index 8ae5d10e51c164..6183d21510345c 100644
--- a/sound/core/seq/instr/ainstr_simple.c
+++ b/sound/core/seq/instr/ainstr_simple.c
@@ -31,8 +31,6 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support.");
MODULE_LICENSE("GPL");
-char *snd_seq_simple_id = SNDRV_SEQ_INSTR_ID_SIMPLE;
-
static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format)
{
unsigned int result = size;
@@ -188,7 +186,7 @@ int snd_seq_simple_init(snd_simple_ops_t *ops,
ops->private_data = private_data;
ops->kops.private_data = ops;
ops->kops.add_len = sizeof(simple_instrument_t);
- ops->kops.instr_type = snd_seq_simple_id;
+ ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE;
ops->kops.put = snd_seq_simple_put;
ops->kops.get = snd_seq_simple_get;
ops->kops.get_size = snd_seq_simple_get_size;
@@ -214,5 +212,4 @@ static void __exit alsa_ainstr_simple_exit(void)
module_init(alsa_ainstr_simple_init)
module_exit(alsa_ainstr_simple_exit)
-EXPORT_SYMBOL(snd_seq_simple_id);
EXPORT_SYMBOL(snd_seq_simple_init);
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
index b17c1f8d1011e4..42ca9493fa600a 100644
--- a/sound/core/seq/oss/seq_oss_timer.c
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -149,7 +149,7 @@ send_timer_event(seq_oss_devinfo_t *dp, int type, int value)
ev.queue = dp->queue;
ev.data.queue.queue = dp->queue;
ev.data.queue.param.value = value;
- return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 0, 0);
+ return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0);
}
/*
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index dd7650dddc48a4..e32aa926f4ffcd 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -904,7 +904,7 @@ static int snd_seq_client_enqueue_event(client_t *client,
return -ENXIO; /* queue is not allocated */
/* allocate an event cell */
- err = snd_seq_event_dup(client->pool, event, &cell, !blocking && !atomic, file);
+ err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file);
if (err < 0)
return err;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index a9e477c2e72975..1fef4ed60a33b3 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -411,7 +411,6 @@ EXPORT_SYMBOL(snd_kmalloc_strdup);
EXPORT_SYMBOL(copy_to_user_fromio);
EXPORT_SYMBOL(copy_from_user_toio);
/* init.c */
-EXPORT_SYMBOL(snd_cards_count);
EXPORT_SYMBOL(snd_cards);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index d0a62f71b5d8c8..7510dfff482eb7 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -119,9 +119,8 @@ void snd_ad1848_out(ad1848_t *chip,
#endif
}
-void snd_ad1848_dout(ad1848_t *chip,
- unsigned char reg,
- unsigned char value)
+static void snd_ad1848_dout(ad1848_t *chip,
+ unsigned char reg, unsigned char value)
{
int timeout;
@@ -132,7 +131,7 @@ void snd_ad1848_dout(ad1848_t *chip,
mb();
}
-unsigned char snd_ad1848_in(ad1848_t *chip, unsigned char reg)
+static unsigned char snd_ad1848_in(ad1848_t *chip, unsigned char reg)
{
int timeout;
@@ -177,7 +176,7 @@ void snd_ad1848_debug(ad1848_t *chip)
* AD1848 detection / MCE routines
*/
-void snd_ad1848_mce_up(ad1848_t *chip)
+static void snd_ad1848_mce_up(ad1848_t *chip)
{
unsigned long flags;
int timeout;
@@ -198,7 +197,7 @@ void snd_ad1848_mce_up(ad1848_t *chip)
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-void snd_ad1848_mce_down(ad1848_t *chip)
+static void snd_ad1848_mce_down(ad1848_t *chip)
{
unsigned long flags;
int timeout;
@@ -584,7 +583,7 @@ static int snd_ad1848_capture_prepare(snd_pcm_substream_t * substream)
return 0;
}
-irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
ad1848_t *chip = dev_id;
@@ -1264,12 +1263,7 @@ int snd_ad1848_mixer(ad1848_t *chip)
return 0;
}
-EXPORT_SYMBOL(snd_ad1848_in);
EXPORT_SYMBOL(snd_ad1848_out);
-EXPORT_SYMBOL(snd_ad1848_dout);
-EXPORT_SYMBOL(snd_ad1848_mce_up);
-EXPORT_SYMBOL(snd_ad1848_mce_down);
-EXPORT_SYMBOL(snd_ad1848_interrupt);
EXPORT_SYMBOL(snd_ad1848_create);
EXPORT_SYMBOL(snd_ad1848_pcm);
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index c20bc7fc83d234..677a4d3133e398 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -479,7 +479,7 @@ static int snd_es1688_capture_trigger(snd_pcm_substream_t * substream,
return snd_es1688_trigger(chip, cmd, 0x0f);
}
-irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
es1688_t *chip = dev_id;
@@ -1042,7 +1042,6 @@ int snd_es1688_mixer(es1688_t *chip)
EXPORT_SYMBOL(snd_es1688_mixer_write);
EXPORT_SYMBOL(snd_es1688_mixer_read);
-EXPORT_SYMBOL(snd_es1688_interrupt);
EXPORT_SYMBOL(snd_es1688_create);
EXPORT_SYMBOL(snd_es1688_pcm);
EXPORT_SYMBOL(snd_es1688_mixer);
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 3248ed924ba7fd..d2b9b49e461d98 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -106,8 +106,9 @@ config SND_BT87X
depends on SND
select SND_PCM
help
- Say Y here to include support for recording audio from TV
- cards based on Brooktree Bt878/Bt879 chips.
+ If you want to record audio from TV cards based on
+ Brooktree Bt878/Bt879 chips, say Y here and read
+ <file:Documentation/sound/alsa/Bt87x.txt>.
To compile this driver as a module, choose M here: the module
will be called snd-bt87x.
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 611ee42eb844ce..7ce2e7631217e5 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -4,7 +4,7 @@
*
* This driver is the result of the OpenVortex Project from Savannah
* (savannah.nongnu.org/projects/openvortex). I would like to thank
- * the developers of OpenVortex, Jeff Muizelar and Kester Maddock, from
+ * the developers of OpenVortex, Jeff Muizelaar and Kester Maddock, from
* whom i got plenty of help, and their codebase was invaluable.
* Thanks to the ALSA developers, they helped a lot working out
* the ALSA part.
@@ -170,9 +170,8 @@ snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip)
if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0)
goto regions_out;
- chip->mmio =
- ioremap_nocache(pci_resource_start(pci, 0),
- pci_resource_len(pci, 0));
+ chip->mmio = ioremap_nocache(pci_resource_start(pci, 0),
+ pci_resource_len(pci, 0));
if (!chip->mmio) {
printk(KERN_ERR "MMIO area remap failed.\n");
err = -ENOMEM;
@@ -187,10 +186,9 @@ snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip)
goto core_out;
}
- if ((err =
- request_irq(pci->irq, vortex_interrupt,
- SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT,
- (void *)chip)) != 0) {
+ if ((err = request_irq(pci->irq, vortex_interrupt,
+ SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT,
+ chip)) != 0) {
printk(KERN_ERR "cannot grab irq\n");
goto irq_out;
}
@@ -214,7 +212,6 @@ snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip)
irq_out:
vortex_core_shutdown(chip);
core_out:
- //FIXME: the type of chip->mmio might need to be changed??
iounmap(chip->mmio);
ioremap_out:
pci_release_regions(chip->pci_dev);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index a300bfdabef250..d573d9c171b1e5 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -80,7 +80,8 @@
#define VORTEX_RESOURCE_LAST 0x00000005
/* Check for SDAC bit in "Extended audio ID" AC97 register */
-#define VORTEX_IS_QUAD(x) ((x->codec == NULL) ? 0 : (x->codec->ext_id&0x80))
+//#define VORTEX_IS_QUAD(x) (((x)->codec == NULL) ? 0 : ((x)->codec->ext_id&0x80))
+#define VORTEX_IS_QUAD(x) ((x)->isquad)
/* Check if chip has bug. */
#define IS_BAD_CHIP(x) (\
(x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX_2) || \
@@ -164,6 +165,8 @@ struct snd_vortex {
int xt_mode; /* 1: speakers, 0:headphones. */
#endif
+ int isquad; /* cache of extended ID codec flag. */
+
/* Gameport stuff. */
struct gameport *gameport;
@@ -208,6 +211,7 @@ static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma);
static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma);
static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma);
static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
+static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma);
#ifndef CHIP_AU8810
static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 684f639a20288c..3e4c3e0fb6f676 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -21,7 +21,7 @@
These functions are mainly the result of translations made
from the original disassembly of the au88x0 binary drivers,
written by Aureal before they went down.
- Many thanks to the Jeff Muizelar, Kester Maddock, and whoever
+ Many thanks to the Jeff Muizelaar, Kester Maddock, and whoever
contributed to the OpenVortex project.
The author of this file, put the few available pieces together
and translated the rest of the riddle (Mix, Src and connection stuff).
@@ -1223,6 +1223,33 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
return delta;
}
+
+static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
+ stream_t *dma = &vortex->dma_adb[adbdma];
+ int p, pp, i;
+
+ /* refresh hw page table */
+ for (i=0 ; i < 4 && i < dma->nr_periods; i++) {
+ /* p: audio buffer page index */
+ p = dma->period_virt + i;
+ if (p >= dma->nr_periods)
+ p -= dma->nr_periods;
+ /* pp: hardware DMA page index. */
+ pp = dma->period_real + i;
+ if (dma->nr_periods < 4) {
+ if (pp >= dma->nr_periods)
+ pp -= dma->nr_periods;
+ }
+ else {
+ if (pp >= 4)
+ pp -= 4;
+ }
+ hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+ /* Force write thru cache. */
+ hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (((adbdma << 2)+pp) << 2));
+ }
+}
+
static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
{
stream_t *dma = &vortex->dma_adb[adbdma];
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 9045a4bf193b75..53b47a42c7d805 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -45,6 +45,8 @@
#define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430)
#define VORTEX_EQ_CTRL (VORTEX_EQ_BASE + 0x440)
+#define VORTEX_BAND_COEFF_SIZE 0x30
+
/* CEqHw.s */
static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
{
@@ -52,10 +54,10 @@ static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
hwwrite(vortex->mmio, 0x2b3c8, level);
}
-static inline short sign_invert(short a)
+static inline u16 sign_invert(u16 a)
{
/* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */
- if (a == -32768)
+ if (a == (u16)-32768)
return 32767;
else
return -a;
@@ -71,13 +73,13 @@ static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[])
hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]);
if (eqhw->this08 == 0) {
- hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2] & 0xffff);
- hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3] & 0xffff);
- hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4] & 0xffff);
+ hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]);
+ hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]);
+ hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]);
} else {
- hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]) & 0xffff);
- hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]) & 0xffff);
- hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]) & 0xffff);
+ hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]));
+ hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]));
+ hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]));
}
i += 5;
}
@@ -93,13 +95,13 @@ static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[])
hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]);
if (eqhw->this08 == 0) {
- hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i] & 0xffff);
- hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i] & 0xffff);
- hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i] & 0xffff);
+ hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]);
+ hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]);
+ hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]);
} else {
- hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]) & 0xffff);
- hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]) & 0xffff);
- hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]) & 0xffff);
+ hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]));
+ hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]));
+ hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]));
}
i += 5;
}
@@ -176,8 +178,8 @@ static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
hwwrite(vortex->mmio, 0x2b3d4, a);
hwwrite(vortex->mmio, 0x2b3ec, b);
} else {
- hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a) & 0xffff);
- hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b) & 0xffff);
+ hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
+ hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
}
}
@@ -319,25 +321,27 @@ static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
#endif
/* EQ band levels settings */
-static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 a[])
+static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
- int ebx;
+ int i;
- for (ebx = 0; ebx < eqhw->this04; ebx++) {
- hwwrite(vortex->mmio, 0x2b024 + ebx * 0x30, a[ebx]);
+ /* set left peaks */
+ for (i = 0; i < eqhw->this04; i++) {
+ hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
}
- hwwrite(vortex->mmio, 0x2b3cc, a[eqhw->this04]);
- hwwrite(vortex->mmio, 0x2b3d8, a[eqhw->this04 + 1]);
+ hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
+ hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
- for (ebx = 0; ebx < eqhw->this04; ebx++) {
- hwwrite(vortex->mmio, 0x2b204 + ebx * 0x30,
- a[ebx + (eqhw->this04 + 2)]);
+ /* set right peaks */
+ for (i = 0; i < eqhw->this04; i++) {
+ hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
+ peaks[i + (eqhw->this04 + 2)]);
}
- hwwrite(vortex->mmio, 0x2b3e4, a[2 + (eqhw->this04 * 2)]);
- hwwrite(vortex->mmio, 0x2b3f0, a[3 + (eqhw->this04 * 2)]);
+ hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
+ hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
}
#if 0
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index 477b2d15ba5e74..95ed26ead5c516 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -26,5 +26,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
memset(&ac97, 0, sizeof(ac97));
// Intialize AC97 codec stuff.
ac97.private_data = vortex;
- return snd_ac97_mixer(pbus, &ac97, &vortex->codec);
+ err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
+ vortex->isquad = ((vortex->codec == NULL) ? 0 : (vortex->codec->ext_id&0x80));
+ return err;
}
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 8e6322158858d1..c9dfc32cc3ea05 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -313,8 +313,10 @@ static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
// do something to start the PCM engine
//printk(KERN_INFO "vortex: start %d\n", dma);
stream->fifo_enabled = 1;
- if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+ if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
+ vortex_adbdma_resetup(chip, dma);
vortex_adbdma_startfifo(chip, dma);
+ }
#ifndef CHIP_AU8810
else {
printk(KERN_INFO "vortex: wt start %d\n", dma);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 171699e87b70dc..e2fd248a0dcb37 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -45,6 +45,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
+static int load_all; /* allow to load the non-whitelisted cards */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Bt87x soundcard");
@@ -54,6 +55,8 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Bt87x soundcard");
module_param_array(digital_rate, int, NULL, 0444);
MODULE_PARM_DESC(digital_rate, "Digital input rate for Bt87x soundcard");
+module_param(load_all, bool, 0444);
+MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards");
#ifndef PCI_VENDOR_ID_BROOKTREE
@@ -173,7 +176,11 @@ struct snd_bt87x {
unsigned int lines;
u32 reg_control;
+ u32 interrupt_mask;
+
int current_line;
+
+ int pci_parity_errors;
};
enum { DEVICE_DIGITAL, DEVICE_ANALOG };
@@ -246,33 +253,53 @@ static void snd_bt87x_free_risc(bt87x_t *chip)
}
}
+static void snd_bt87x_pci_error(bt87x_t *chip, unsigned int status)
+{
+ u16 pci_status;
+
+ pci_read_config_word(chip->pci, PCI_STATUS, &pci_status);
+ pci_status &= PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY;
+ pci_write_config_word(chip->pci, PCI_STATUS, pci_status);
+ if (pci_status != PCI_STATUS_DETECTED_PARITY)
+ snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n",
+ status & ERROR_INTERRUPTS, pci_status);
+ else {
+ snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n");
+ /* error 'handling' similar to aic7xxx_pci.c: */
+ chip->pci_parity_errors++;
+ if (chip->pci_parity_errors > 20) {
+ snd_printk(KERN_ERR "Too many PCI parity errors observed.\n");
+ snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n");
+ snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n");
+ snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n");
+ chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR);
+ snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
+ }
+ }
+}
+
static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
bt87x_t *chip = dev_id;
- unsigned int status;
+ unsigned int status, irq_status;
status = snd_bt87x_readl(chip, REG_INT_STAT);
- if (!(status & MY_INTERRUPTS))
+ irq_status = status & chip->interrupt_mask;
+ if (!irq_status)
return IRQ_NONE;
- snd_bt87x_writel(chip, REG_INT_STAT, status & MY_INTERRUPTS);
+ snd_bt87x_writel(chip, REG_INT_STAT, irq_status);
- if (status & ERROR_INTERRUPTS) {
- if (status & (INT_FBUS | INT_FTRGT))
+ if (irq_status & ERROR_INTERRUPTS) {
+ if (irq_status & (INT_FBUS | INT_FTRGT))
snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status);
- if (status & INT_OCERR)
+ if (irq_status & INT_OCERR)
snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status);
- if (status & (INT_PPERR | INT_RIPERR | INT_PABORT)) {
- u16 pci_status;
- pci_read_config_word(chip->pci, PCI_STATUS, &pci_status);
- pci_write_config_word(chip->pci, PCI_STATUS, pci_status &
- (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
- PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
- PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
- snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n",
- status, pci_status);
- }
+ if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT))
+ snd_bt87x_pci_error(chip, irq_status);
}
- if ((status & INT_RISCI) && (chip->reg_control & CTL_ACAP_EN)) {
+ if ((irq_status & INT_RISCI) && (chip->reg_control & CTL_ACAP_EN)) {
int current_block, irq_block;
/* assume that exactly one line has been recorded */
@@ -458,7 +485,7 @@ static int snd_bt87x_start(bt87x_t *chip)
snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr);
snd_bt87x_writel(chip, REG_PACKET_LEN,
chip->line_bytes | (chip->lines << 16));
- snd_bt87x_writel(chip, REG_INT_MASK, MY_INTERRUPTS);
+ snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
spin_unlock(&chip->reg_lock);
return 0;
@@ -713,6 +740,7 @@ static int __devinit snd_bt87x_create(snd_card_t *card,
}
chip->reg_control = CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT);
+ chip->interrupt_mask = MY_INTERRUPTS;
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
snd_bt87x_writel(chip, REG_INT_MASK, 0);
snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
@@ -737,13 +765,73 @@ static int __devinit snd_bt87x_create(snd_card_t *card,
return 0;
}
+#define BT_DEVICE(chip, subvend, subdev, rate) \
+ { .vendor = PCI_VENDOR_ID_BROOKTREE, \
+ .device = PCI_DEVICE_ID_BROOKTREE_##chip, \
+ .subvendor = subvend, .subdevice = subdev, \
+ .driver_data = rate }
+
+/* driver_data is the default digital_rate value for that device */
+static struct pci_device_id snd_bt87x_ids[] = {
+ BT_DEVICE(878, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */
+ BT_DEVICE(879, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */
+ BT_DEVICE(878, 0x0070, 0xff01, 44100), /* Viewcast Osprey 200 */
+ { }
+};
+MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
+
+/* cards known not to have audio
+ * (DVB cards use the audio function to transfer MPEG data) */
+static struct {
+ unsigned short subvendor, subdevice;
+} blacklist[] __devinitdata = {
+ {0x0071, 0x0101}, /* Nebula Electronics DigiTV */
+ {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */
+ {0x1461, 0x0761}, /* AVermedia AverTV DVB-T */
+ {0x1461, 0x0771}, /* AVermedia DVB-T 771 */
+ {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */
+ {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */
+ {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
+};
+
+/* return the rate of the card, or a negative value if it's blacklisted */
+static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
+{
+ int i;
+ const struct pci_device_id *supported;
+
+ supported = pci_match_device(snd_bt87x_ids, pci);
+ if (supported)
+ return supported->driver_data;
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); ++i)
+ if (blacklist[i].subvendor == pci->subsystem_vendor &&
+ blacklist[i].subdevice == pci->subsystem_device) {
+ snd_printdd(KERN_INFO "card %#04x:%#04x has no audio\n",
+ pci->subsystem_vendor, pci->subsystem_device);
+ return -EBUSY;
+ }
+
+ snd_printk(KERN_INFO "unknown card %#04x:%#04x, using default rate 32000\n",
+ pci->subsystem_vendor, pci->subsystem_device);
+ snd_printk(KERN_DEBUG "please mail id, board name, and, "
+ "if it works, the correct digital_rate option to "
+ "<alsa-devel@lists.sf.net>\n");
+ return 32000; /* default rate */
+}
+
static int __devinit snd_bt87x_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
snd_card_t *card;
bt87x_t *chip;
- int err;
+ int err, rate;
+
+ rate = pci_id->driver_data;
+ if (! rate)
+ if ((rate = snd_bt87x_detect_card(pci)) <= 0)
+ return -ENODEV;
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -763,7 +851,7 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
if (digital_rate[dev] > 0)
chip->dig_rate = digital_rate[dev];
else
- chip->dig_rate = (int)pci_id->driver_data;
+ chip->dig_rate = rate;
err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital");
if (err < 0)
@@ -807,22 +895,13 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#define BT_DEVICE(chip, subvend, subdev, rate) \
- { .vendor = PCI_VENDOR_ID_BROOKTREE, \
- .device = PCI_DEVICE_ID_BROOKTREE_##chip, \
- .subvendor = subvend, .subdevice = subdev, \
- .driver_data = rate }
-
-/* driver_data is the default digital_rate value for that device */
-static struct pci_device_id snd_bt87x_ids[] = {
- BT_DEVICE(878, 0x0070, 0xff01, 44100), /* Osprey 200 */
-
- /* default entries for 32kHz and generic Bt87x cards */
- BT_DEVICE(878, PCI_ANY_ID, PCI_ANY_ID, 32000),
- BT_DEVICE(879, PCI_ANY_ID, PCI_ANY_ID, 32000),
+/* default entries for all Bt87x cards - it's not exported */
+/* driver_data is set to 0 to call detection */
+static struct pci_device_id snd_bt87x_default_ids[] = {
+ BT_DEVICE(878, PCI_ANY_ID, PCI_ANY_ID, 0),
+ BT_DEVICE(879, PCI_ANY_ID, PCI_ANY_ID, 0),
{ }
};
-MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
static struct pci_driver driver = {
.name = "Bt87x",
@@ -833,6 +912,8 @@ static struct pci_driver driver = {
static int __init alsa_card_bt87x_init(void)
{
+ if (load_all)
+ driver.id_table = snd_bt87x_default_ids;
return pci_module_init(&driver);
}
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index cc651b087e0aa7..00a7585b818d23 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -437,7 +437,7 @@ int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu,
}
int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu,
- snd_emu10k1_fx8010_irq_t *irq)
+ snd_emu10k1_fx8010_irq_t *irq)
{
snd_emu10k1_fx8010_irq_t *tmp;
unsigned long flags;
@@ -465,25 +465,35 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu,
* EMU10K1 effect manager
*************************************************************************/
-static void snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
- u32 op, u32 r, u32 a, u32 x, u32 y)
+static int snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
+ u32 op, u32 r, u32 a, u32 x, u32 y)
{
snd_assert(*ptr < 512, return);
set_bit(*ptr, icode->code_valid);
- icode->code[*ptr ][0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
- icode->code[(*ptr)++][1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
+ x = ((x & 0x3ff) << 10) | (y & 0x3ff);
+ y = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
+ a = *ptr++ * 2;
+ if (put_user(x, &icode->code[a + 0]) ||
+ put_user(y, &icode->code[a + 1]))
+ return -EFAULT;
+ return 0;
}
#define OP(icode, ptr, op, r, a, x, y) \
snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
-static void snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
- u32 op, u32 r, u32 a, u32 x, u32 y)
+static int snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
+ u32 op, u32 r, u32 a, u32 x, u32 y)
{
snd_assert(*ptr < 1024, return);
set_bit(*ptr, icode->code_valid);
- icode->code[*ptr ][0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
- icode->code[(*ptr)++][1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
+ x = ((x & 0x7ff) << 12) | (y & 0x7ff);
+ y = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
+ a = *ptr++ * 2;
+ if (put_user(x, &icode->code[a + 0]) ||
+ put_user(y, &icode->code[a + 1]))
+ return -EFAULT;
+ return 0;
}
#define A_OP(icode, ptr, op, r, a, x, y) \
@@ -501,83 +511,108 @@ unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc)
return snd_emu10k1_ptr_read(emu, pc, 0);
}
-static void snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
int gpr;
+ u32 val;
for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
if (!test_bit(gpr, icode->gpr_valid))
continue;
- snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, icode->gpr_map[gpr]);
+ if (get_user(val, &icode->gpr_map[gpr]))
+ return -EFAULT;
+ snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
}
+ return 0;
}
-static void snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
int gpr;
+ u32 val;
for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
set_bit(gpr, icode->gpr_valid);
- icode->gpr_map[gpr] = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
+ val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
+ if (put_user(val, &icode->gpr_map[gpr]))
+ return -EFAULT;
}
+ return 0;
}
-static void snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
int tram;
+ u32 addr, val;
for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
if (!test_bit(tram, icode->tram_valid))
continue;
- snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, icode->tram_data_map[tram]);
- if (!emu->audigy)
- snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram]);
- else {
- snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram] << 12);
- snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, icode->tram_addr_map[tram] >> 20);
+ if (get_user(val, icode->tram_data_map[tram]) ||
+ get_user(addr, icode->tram_addr_map[tram]))
+ return -EFAULT;
+ snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
+ if (!emu->audigy) {
+ snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
+ } else {
+ snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
+ snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
}
}
+ return 0;
}
-static void snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
int tram;
+ u32 val, addr;
memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
set_bit(tram, icode->tram_valid);
- icode->tram_data_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
- if (!emu->audigy)
- icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
- else {
- icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
- icode->tram_addr_map[tram] |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
+ val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
+ if (!emu->audigy) {
+ addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
+ } else {
+ addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
+ addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
}
+ if (put_user(val, &icode->tram_data_map[tram]) ||
+ put_user(addr, &icode->tram_addr_map[tram]))
+ return -EFAULT;
}
+ return 0;
}
-static void snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
- u32 pc;
+ u32 pc, lo, hi;
- for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) {
+ for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
if (!test_bit(pc, icode->code_valid))
continue;
- snd_emu10k1_efx_write(emu, pc * 2, icode->code[pc][0]);
- snd_emu10k1_efx_write(emu, pc * 2 + 1, icode->code[pc][1]);
+ if (get_user(lo, &icode->code[pc + 0]) ||
+ get_user(hi, &icode->code[pc + 1]))
+ return -EFAULT;
+ snd_emu10k1_efx_write(emu, pc + 0, lo);
+ snd_emu10k1_efx_write(emu, pc + 1, hi);
}
+ return 0;
}
-static void snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
u32 pc;
memset(icode->code_valid, 0, sizeof(icode->code_valid));
- for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) {
+ for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
set_bit(pc, icode->code_valid);
- icode->code[pc][0] = snd_emu10k1_efx_read(emu, pc * 2);
- icode->code[pc][1] = snd_emu10k1_efx_read(emu, pc * 2 + 1);
+ if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
+ return -EFAULT;
+ if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
+ return -EFAULT;
}
+ return 0;
}
static snd_emu10k1_fx8010_ctl_t *snd_emu10k1_look_for_ctl(emu10k1_t *emu, snd_ctl_elem_id_t *id)
@@ -647,7 +682,7 @@ static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl)
kfree(ctl);
}
-static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
unsigned int i, j;
emu10k1_fx8010_control_gpr_t __user *_gctl;
@@ -656,17 +691,20 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod
snd_kcontrol_new_t knew;
snd_kcontrol_t *kctl;
snd_ctl_elem_value_t *val;
+ int err = 0;
val = (snd_ctl_elem_value_t *)kmalloc(sizeof(*val), GFP_KERNEL);
if (!val)
- return;
+ return -ENOMEM;
for (i = 0, _gctl = icode->gpr_add_controls;
i < icode->gpr_add_control_count; i++, _gctl++) {
- if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
- break;
+ if (copy_from_user(&gctl, _gctl, sizeof(gctl))) {
+ err = -EFAULT;
+ goto __error;
+ }
snd_runtime_check(gctl.id.iface == SNDRV_CTL_ELEM_IFACE_MIXER ||
- gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, continue);
- snd_runtime_check(gctl.id.name[0] != '\0', continue);
+ gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error);
+ snd_runtime_check(gctl.id.name[0] != '\0', err = -EINVAL; goto __error);
ctl = snd_emu10k1_look_for_ctl(emu, &gctl.id);
memset(&knew, 0, sizeof(knew));
knew.iface = gctl.id.iface;
@@ -694,9 +732,9 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod
continue;
knew.private_value = (unsigned long)ctl;
memcpy(ctl, &nctl, sizeof(nctl));
- if (snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu)) < 0) {
+ if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
kfree(ctl);
- continue;
+ goto __error;
}
kctl->private_free = snd_emu10k1_ctl_private_free;
ctl->kcontrol = kctl;
@@ -711,10 +749,12 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod
}
snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
}
+ __error:
kfree(val);
+ return err;
}
-static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
{
unsigned int i;
snd_ctl_elem_id_t id;
@@ -724,13 +764,14 @@ static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod
for (i = 0, _id = icode->gpr_del_controls;
i < icode->gpr_del_control_count; i++, _id++) {
- snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, continue);
+ snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, return -EFAULT);
down_write(&card->controls_rwsem);
ctl = snd_emu10k1_look_for_ctl(emu, &id);
if (ctl)
snd_ctl_remove(card, ctl->kcontrol);
up_write(&card->controls_rwsem);
}
+ return 0;
}
static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
@@ -789,11 +830,12 @@ static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
else
snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
/* ok, do the main job */
- snd_emu10k1_del_controls(emu, icode);
- snd_emu10k1_gpr_poke(emu, icode);
- snd_emu10k1_tram_poke(emu, icode);
- snd_emu10k1_code_poke(emu, icode);
- snd_emu10k1_add_controls(emu, icode);
+ if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
+ (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
+ (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
+ (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
+ (err = snd_emu10k1_add_controls(emu, icode)) < 0)
+ goto __error;
/* start FX processor when the DSP code is updated */
if (emu->audigy)
snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
@@ -811,10 +853,13 @@ static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
down(&emu->fx8010.lock);
strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
/* ok, do the main job */
- snd_emu10k1_gpr_peek(emu, icode);
- snd_emu10k1_tram_peek(emu, icode);
- snd_emu10k1_code_peek(emu, icode);
- err = snd_emu10k1_list_controls(emu, icode);
+ err = snd_emu10k1_gpr_peek(emu, icode);
+ if (err >= 0)
+ err = snd_emu10k1_tram_peek(emu, icode);
+ if (err >= 0)
+ err = snd_emu10k1_code_peek(emu, icode);
+ if (err >= 0)
+ err = snd_emu10k1_list_controls(emu, icode);
up(&emu->fx8010.lock);
return err;
}
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index e6717f3e1bfc2c..97c9d45d7b792b 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -95,20 +95,14 @@ static unsigned int snd_us428ctls_poll(snd_hwdep_t *hw, struct file *file, poll_
{
unsigned int mask = 0;
usX2Ydev_t *us428 = (usX2Ydev_t*)hw->private_data;
- static unsigned LastN;
-
+ us428ctls_sharedmem_t *shm = us428->us428ctls_sharedmem;
if (us428->chip_status & USX2Y_STAT_CHIP_HUP)
return POLLHUP;
poll_wait(file, &us428->us428ctls_wait_queue_head, wait);
- down(&us428->open_mutex);
- if (us428->us428ctls_sharedmem
- && us428->us428ctls_sharedmem->CtlSnapShotLast != LastN) {
+ if (shm != NULL && shm->CtlSnapShotLast != shm->CtlSnapShotRed)
mask |= POLLIN;
- LastN = us428->us428ctls_sharedmem->CtlSnapShotLast;
- }
- up(&us428->open_mutex);
return mask;
}
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 82ecbf6025b05d..cca3d26b3c0688 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -1,6 +1,22 @@
/*
- * usbus428.c - ALSA USB US-428 Driver
+ * usbusy2y.c - ALSA USB US-428 Driver
*
+2004-10-26 Karsten Wiese
+ Version 0.8.6:
+ wake_up() process waiting in usX2Y_urbs_start() on error.
+
+2004-10-21 Karsten Wiese
+ Version 0.8.5:
+ nrpacks is runtime or compiletime configurable now with tested values from 1 to 4.
+
+2004-10-03 Karsten Wiese
+ Version 0.8.2:
+ Avoid any possible racing while in prepare callback.
+
+2004-09-30 Karsten Wiese
+ Version 0.8.0:
+ Simplified things and made ohci work again.
+
2004-09-20 Karsten Wiese
Version 0.7.3:
Use usb_kill_urb() instead of deprecated (kernel 2.6.9) usb_unlink_urb().
@@ -84,7 +100,7 @@
Version 0.0.2: midi works with snd-usb-midi, audio (only fullduplex now) with i.e. bristol.
The firmware has been sniffed from win2k us-428 driver 3.09.
- * Copyright (c) 2002 Karsten Wiese
+ * Copyright (c) 2002 - 2004 Karsten Wiese
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -119,7 +135,7 @@
MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
-MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.7.3");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.6");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
@@ -325,7 +341,8 @@ static snd_card_t* usX2Y_create_card(struct usb_device* device)
card->private_free = snd_usX2Y_card_private_free;
usX2Y(card)->chip.dev = device;
usX2Y(card)->chip.card = card;
- init_MUTEX (&usX2Y(card)->open_mutex);
+ init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
+ init_MUTEX (&usX2Y(card)->prepare_mutex);
INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
strcpy(card->driver, "USB "NAME_ALLCAPS"");
sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 71883dc170fb99..9f1dc0d849928b 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -3,15 +3,8 @@
#include "../usbaudio.h"
#include "usbus428ctldefs.h"
-#define NRURBS 2 /* */
-#define NRPACKS 1 /* FIXME: Currently only 1 works.
- usb-frames/ms per urb: 1 and 2 are supported.
- setting to 2 will PERHAPS make it easier for slow machines.
- Jitter will be higher though.
- On my PIII 500Mhz Laptop setting to 1 is the only way to go
- for PLAYING synths. i.e. Jack & Aeolus sound quit nicely
- at 4 periods 64 frames.
- */
+#define NRURBS 2
+
#define URBS_AsyncSeq 10
#define URB_DataLen_AsyncSeq 32
@@ -40,15 +33,43 @@ typedef struct {
snd_usX2Y_AsyncSeq_t AS04;
unsigned int rate,
format;
- int refframes;
int chip_status;
- struct semaphore open_mutex;
+ struct semaphore prepare_mutex;
us428ctls_sharedmem_t *us428ctls_sharedmem;
+ int wait_iso_frame;
wait_queue_head_t us428ctls_wait_queue_head;
- snd_usX2Y_substream_t *substream[4];
+ snd_usX2Y_substream_t *subs[4];
+ snd_usX2Y_substream_t * volatile prepare_subs;
+ wait_queue_head_t prepare_wait_queue;
} usX2Ydev_t;
+struct snd_usX2Y_substream {
+ usX2Ydev_t *usX2Y;
+ snd_pcm_substream_t *pcm_substream;
+
+ int endpoint;
+ unsigned int maxpacksize; /* max packet size in bytes */
+
+ atomic_t state;
+#define state_STOPPED 0
+#define state_STARTING1 1
+#define state_STARTING2 2
+#define state_STARTING3 3
+#define state_PREPARED 4
+#define state_PRERUNNING 6
+#define state_RUNNING 8
+
+ int hwptr; /* free frame position in the buffer (only for playback) */
+ int hwptr_done; /* processed frame position in the buffer */
+ int transfer_done; /* processed frames since last period update */
+
+ struct urb *urb[NRURBS]; /* data urb table */
+ struct urb *completed_urb;
+ char *tmpbuf; /* temporary buffer for playback */
+};
+
+
#define usX2Y(c) ((usX2Ydev_t*)(c)->private_data)
int usX2Y_audio_create(snd_card_t* card);
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index e32673e707915a..152bfa2ff39e91 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -1,10 +1,9 @@
/*
- * US-428 AUDIO
-
- * Copyright (c) 2002-2003 by Karsten Wiese
-
+ * US-X2Y AUDIO
+ * Copyright (c) 2002-2004 by Karsten Wiese
+ *
* based on
-
+ *
* (Tentative) USB Audio Driver for ALSA
*
* Main and PCM part
@@ -42,33 +41,30 @@
#include "usx2y.h"
#include "usbusx2y.h"
-
-struct snd_usX2Y_substream {
- usX2Ydev_t *usX2Y;
- snd_pcm_substream_t *pcm_substream;
-
- unsigned char endpoint;
- unsigned int datapipe; /* the data i/o pipe */
- unsigned int maxpacksize; /* max packet size in bytes */
-
- char prepared,
- running,
- stalled;
-
- int hwptr; /* free frame position in the buffer (only for playback) */
- int hwptr_done; /* processed frame position in the buffer */
- int transfer_done; /* processed frames since last period update */
-
- struct urb *urb[NRURBS]; /* data urb table */
- int next_urb_complete;
- struct urb *completed_urb;
- char *tmpbuf; /* temporary buffer for playback */
- volatile int submitted_urbs;
- wait_queue_head_t wait_queue;
-};
-
-
-
+#define USX2Y_NRPACKS 4 /* Default value used for nr of packs per urb.
+ 1 to 4 have been tested ok on uhci.
+ To use 3 on ohci, you'd need a patch:
+ look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
+ "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
+ .
+ 1, 2 and 4 work out of the box on ohci, if I recall correctly.
+ Bigger is safer operation,
+ smaller gives lower latencies.
+ */
+#define USX2Y_NRPACKS_VARIABLE y /* If your system works ok with this module's parameter
+ nrpacks set to 1, you might as well comment
+ this #define out, and thereby produce smaller, faster code.
+ You'd also set USX2Y_NRPACKS to 1 then.
+ */
+
+#ifdef USX2Y_NRPACKS_VARIABLE
+ static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
+ #define nr_of_packs() nrpacks
+ module_param(nrpacks, int, 0444);
+ MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
+#else
+ #define nr_of_packs() USX2Y_NRPACKS
+#endif
@@ -80,15 +76,15 @@ static int usX2Y_urb_capt_retire(snd_usX2Y_substream_t *subs)
int i, len, lens = 0, hwptr_done = subs->hwptr_done;
usX2Ydev_t *usX2Y = subs->usX2Y;
- for (i = 0; i < NRPACKS; i++) {
+ for (i = 0; i < nr_of_packs(); i++) {
cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
- snd_printdd("activ frame status %i\n", urb->iso_frame_desc[i].status);
+ snd_printk("activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
return urb->iso_frame_desc[i].status;
}
len = urb->iso_frame_desc[i].actual_length / usX2Y->stride;
if (! len) {
- snd_printk("0 == len ERROR!\n");
+ snd_printd("0 == len ERROR!\n");
continue;
}
@@ -134,7 +130,7 @@ static int usX2Y_urb_play_prepare(snd_usX2Y_substream_t *subs,
snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
count = 0;
- for (pack = 0; pack < NRPACKS; pack++) {
+ for (pack = 0; pack < nr_of_packs(); pack++) {
/* calculate the size of a packet */
counts = cap_urb->iso_frame_desc[pack].actual_length / usX2Y->stride;
count += counts;
@@ -142,28 +138,32 @@ static int usX2Y_urb_play_prepare(snd_usX2Y_substream_t *subs,
snd_printk("should not be here with counts=%i\n", counts);
return -EPIPE;
}
-
/* set up descriptor */
- urb->iso_frame_desc[pack].offset = pack ? urb->iso_frame_desc[pack - 1].offset + urb->iso_frame_desc[pack - 1].length : 0;
- urb->iso_frame_desc[pack].length = counts * usX2Y->stride;
+ urb->iso_frame_desc[pack].offset = pack ?
+ urb->iso_frame_desc[pack - 1].offset + urb->iso_frame_desc[pack - 1].length :
+ 0;
+ urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length;
}
- if (subs->hwptr + count > runtime->buffer_size) {
- /* err, the transferred area goes over buffer boundary.
- * copy the data to the temp buffer.
- */
- int len;
- len = runtime->buffer_size - subs->hwptr;
- urb->transfer_buffer = subs->tmpbuf;
- memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * usX2Y->stride, len * usX2Y->stride);
- memcpy(subs->tmpbuf + len * usX2Y->stride, runtime->dma_area, (count - len) * usX2Y->stride);
- subs->hwptr += count;
- subs->hwptr -= runtime->buffer_size;
- } else {
- /* set the buffer pointer */
- urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride;
- if ((subs->hwptr += count) >= runtime->buffer_size)
+ if (atomic_read(&subs->state) >= state_PRERUNNING)
+ if (subs->hwptr + count > runtime->buffer_size) {
+ /* err, the transferred area goes over buffer boundary.
+ * copy the data to the temp buffer.
+ */
+ int len;
+ len = runtime->buffer_size - subs->hwptr;
+ urb->transfer_buffer = subs->tmpbuf;
+ memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * usX2Y->stride, len * usX2Y->stride);
+ memcpy(subs->tmpbuf + len * usX2Y->stride, runtime->dma_area, (count - len) * usX2Y->stride);
+ subs->hwptr += count;
+ subs->hwptr -= runtime->buffer_size;
+ } else {
+ /* set the buffer pointer */
+ urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride;
+ if ((subs->hwptr += count) >= runtime->buffer_size)
subs->hwptr -= runtime->buffer_size;
- }
+ }
+ else
+ urb->transfer_buffer = subs->tmpbuf;
urb->transfer_buffer_length = count * usX2Y->stride;
return 0;
}
@@ -173,14 +173,10 @@ static int usX2Y_urb_play_prepare(snd_usX2Y_substream_t *subs,
*
* update the current position and call callback if a period is processed.
*/
-inline static int usX2Y_urb_play_retire(snd_usX2Y_substream_t *subs, struct urb *urb)
+static void usX2Y_urb_play_retire(snd_usX2Y_substream_t *subs, struct urb *urb)
{
snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
- int len = (urb->iso_frame_desc[0].actual_length
-#if NRPACKS > 1
- + urb->iso_frame_desc[1].actual_length
-#endif
- ) / subs->usX2Y->stride;
+ int len = urb->actual_length / subs->usX2Y->stride;
subs->transfer_done += len;
subs->hwptr_done += len;
@@ -190,224 +186,206 @@ inline static int usX2Y_urb_play_retire(snd_usX2Y_substream_t *subs, struct urb
subs->transfer_done -= runtime->period_size;
snd_pcm_period_elapsed(subs->pcm_substream);
}
- return 0;
}
-inline static int usX2Y_urb_submit(snd_usX2Y_substream_t *subs, struct urb *urb, int frame)
+static int usX2Y_urb_submit(snd_usX2Y_substream_t *subs, struct urb *urb, int frame)
{
int err;
if (!urb)
return -ENODEV;
- urb->start_frame = (frame + NRURBS*NRPACKS) & (1024 - 1);
+ urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks
urb->hcpriv = NULL;
urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- snd_printk("%i\n", err);
+ snd_printk("usb_submit_urb() returned %i\n", err);
return err;
- } else {
- subs->submitted_urbs++;
- if (subs->next_urb_complete < 0)
- subs->next_urb_complete = 0;
}
return 0;
}
-
-static inline int frame_distance(int from, int to)
+static inline int usX2Y_usbframe_complete(snd_usX2Y_substream_t *capsubs, snd_usX2Y_substream_t *playbacksubs, int frame)
{
- int distance = to - from;
- if (distance < -512)
- distance += 1024;
- else
- if (distance > 511)
- distance -= 1024;
- return distance;
-}
+ int err, state;
+ {
+ struct urb *urb = playbacksubs->completed_urb;
+ state = atomic_read(&playbacksubs->state);
+ if (NULL != urb) {
+ if (state == state_RUNNING)
+ usX2Y_urb_play_retire(playbacksubs, urb);
+ else
+ if (state >= state_PRERUNNING) {
+ atomic_inc(&playbacksubs->state);
+ }
+ } else {
+ switch (state) {
+ case state_STARTING1:
+ urb = playbacksubs->urb[0];
+ atomic_inc(&playbacksubs->state);
+ break;
+ case state_STARTING2:
+ urb = playbacksubs->urb[1];
+ atomic_inc(&playbacksubs->state);
+ break;
+ }
+ }
+ if (urb) {
+ if ((err = usX2Y_urb_play_prepare(playbacksubs, capsubs->completed_urb, urb)) ||
+ (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
+ return err;
+ }
+ }
-static void usX2Y_subs_set_next_urb_complete(snd_usX2Y_substream_t *subs)
-{
- int next_urb_complete = subs->next_urb_complete + 1;
- int distance;
- if (next_urb_complete >= NRURBS)
- next_urb_complete = 0;
- distance = frame_distance(subs->completed_urb->start_frame,
- subs->urb[next_urb_complete]->start_frame);
- if (1 == distance) {
- subs->next_urb_complete = next_urb_complete;
- } else {
- snd_printdd("distance %i not set_nuc %i %i %i \n", distance, subs->endpoint, next_urb_complete, subs->urb[next_urb_complete]->status);
- subs->next_urb_complete = -1;
+ playbacksubs->completed_urb = NULL;
+ }
+ state = atomic_read(&capsubs->state);
+ if (state >= state_PREPARED) {
+ if (state == state_RUNNING) {
+ if ((err = usX2Y_urb_capt_retire(capsubs)))
+ return err;
+ } else
+ if (state >= state_PRERUNNING) {
+ atomic_inc(&capsubs->state);
+ }
+ if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
+ return err;
}
+ capsubs->completed_urb = NULL;
+ return 0;
}
-static inline void usX2Y_usbframe_complete(snd_usX2Y_substream_t *capsubs, snd_usX2Y_substream_t *playbacksubs, int frame)
+static void usX2Y_clients_stop(usX2Ydev_t *usX2Y)
{
- {
- struct urb *urb;
- if ((urb = playbacksubs->completed_urb)) {
- if (playbacksubs->prepared)
- usX2Y_urb_play_retire(playbacksubs, urb);
- usX2Y_subs_set_next_urb_complete(playbacksubs);
+ int s, u;
+ for (s = 0; s < 4; s++) {
+ snd_usX2Y_substream_t *subs = usX2Y->subs[s];
+ if (subs) {
+ snd_printdd("%i %p state=%i\n", s, subs, atomic_read(&subs->state));
+ atomic_set(&subs->state, state_STOPPED);
}
- if (playbacksubs->running) {
- if (NULL == urb)
- urb = playbacksubs->urb[playbacksubs->next_urb_complete + 1];
- if (urb && 0 == usX2Y_urb_play_prepare(playbacksubs,
- capsubs->completed_urb,
- urb)) {
- if (usX2Y_urb_submit(playbacksubs, urb, frame) < 0)
- return;
- } else
- snd_pcm_stop(playbacksubs->pcm_substream, SNDRV_PCM_STATE_XRUN);
+ }
+ for (s = 0; s < 4; s++) {
+ snd_usX2Y_substream_t *subs = usX2Y->subs[s];
+ if (subs) {
+ if (atomic_read(&subs->state) >= state_PRERUNNING) {
+ snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
+ }
+ for (u = 0; u < NRURBS; u++) {
+ struct urb *urb = subs->urb[u];
+ if (NULL != urb)
+ snd_printdd("%i status=%i start_frame=%i\n", u, urb->status, urb->start_frame);
+ }
}
- playbacksubs->completed_urb = NULL;
}
- if (capsubs->running)
- usX2Y_urb_capt_retire(capsubs);
- usX2Y_subs_set_next_urb_complete(capsubs);
- if (capsubs->prepared)
- usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame);
- capsubs->completed_urb = NULL;
+ usX2Y->prepare_subs = NULL;
+ wake_up(&usX2Y->prepare_wait_queue);
}
-
-static void usX2Y_clients_stop(snd_usX2Y_substream_t *subs)
+static void usX2Y_error_urb_status(usX2Ydev_t *usX2Y, snd_usX2Y_substream_t *subs, struct urb *urb)
{
- usX2Ydev_t *usX2Y = subs->usX2Y;
- int i;
- for (i = 0; i < 4; i++) {
- snd_usX2Y_substream_t *substream = usX2Y->substream[i];
- if (substream && substream->running)
- snd_pcm_stop(substream->pcm_substream, SNDRV_PCM_STATE_XRUN);
- }
+ snd_printk("ep=%i stalled with status=%i\n", subs->endpoint, urb->status);
+ urb->status = 0;
+ usX2Y_clients_stop(usX2Y);
}
+static void usX2Y_error_sequence(usX2Ydev_t *usX2Y, snd_usX2Y_substream_t *subs, struct urb *urb)
+{
+ snd_printk("Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
+ "Most propably some urb of usb-frame %i is still missing.\n"
+ "Cause could be too long delays in usb-hcd interrupt handling.\n",
+ usb_get_current_frame_number(usX2Y->chip.dev),
+ subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
+ usX2Y_clients_stop(usX2Y);
+}
static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
{
snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
+ usX2Ydev_t *usX2Y = subs->usX2Y;
- subs->submitted_urbs--;
- if (urb->status) {
- snd_printk("ep=%i stalled with status=%i\n", subs->endpoint, urb->status);
- subs->stalled = 1;
- usX2Y_clients_stop(subs);
- urb->status = 0;
+ if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
+ snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", usb_get_current_frame_number(usX2Y->chip.dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame);
+ return;
+ }
+ if (unlikely(urb->status)) {
+ usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (urb == subs->urb[subs->next_urb_complete]) {
+ if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
subs->completed_urb = urb;
- } else {
- snd_printk("Sequence Error!(ep=%i;nuc=%i,frame=%i)\n",
- subs->endpoint, subs->next_urb_complete, urb->start_frame);
- subs->stalled = 1;
- usX2Y_clients_stop(subs);
+ else {
+ usX2Y_error_sequence(usX2Y, subs, urb);
return;
}
- if (waitqueue_active(&subs->wait_queue))
- wake_up(&subs->wait_queue);
{
- snd_usX2Y_substream_t *capsubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE],
- *playbacksubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
- if (capsubs->completed_urb &&
- (playbacksubs->completed_urb ||
- !playbacksubs->prepared ||
- (playbacksubs->prepared && (playbacksubs->next_urb_complete < 0 || // not started yet
- frame_distance(capsubs->completed_urb->start_frame,
- playbacksubs->urb[playbacksubs->next_urb_complete]->start_frame)
- > 0 || // other expected later
- playbacksubs->stalled))))
- usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame);
+ snd_usX2Y_substream_t *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE],
+ *playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
+ if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
+ (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
+ if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) {
+ if (nr_of_packs() <= urb->start_frame &&
+ urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
+ usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
+ else
+ usX2Y->wait_iso_frame += nr_of_packs();
+ } else {
+ snd_printdd("\n");
+ usX2Y_clients_stop(usX2Y);
+ }
+ }
}
}
-
-static int usX2Y_urbs_capt_start(snd_usX2Y_substream_t *subs)
+static void usX2Y_urbs_set_complete(usX2Ydev_t * usX2Y, void (*complete)(struct urb *, struct pt_regs *))
{
- int i, err;
-
- for (i = 0; i < NRURBS; i++) {
- unsigned long pack;
- struct urb *urb = subs->urb[i];
- urb->dev = subs->usX2Y->chip.dev;
- urb->transfer_flags = URB_ISO_ASAP;
- for (pack = 0; pack < NRPACKS; pack++) {
- urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
- urb->iso_frame_desc[pack].length = subs->maxpacksize;
- }
- urb->transfer_buffer_length = subs->maxpacksize * NRPACKS;
- if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
- return -EPIPE;
- } else {
- subs->submitted_urbs++;
- }
- urb->transfer_flags = 0;
+ int s, u;
+ for (s = 0; s < 4; s++) {
+ snd_usX2Y_substream_t *subs = usX2Y->subs[s];
+ if (NULL != subs)
+ for (u = 0; u < NRURBS; u++) {
+ struct urb * urb = subs->urb[u];
+ if (NULL != urb)
+ urb->complete = complete;
+ }
}
- subs->stalled = 0;
- subs->next_urb_complete = 0;
- subs->prepared = 1;
- return 0;
}
-/*
- * wait until all urbs are processed.
- */
-static int usX2Y_urbs_wait_clear(snd_usX2Y_substream_t *subs)
-{
- int timeout = HZ;
-
- do {
- if (0 == subs->submitted_urbs)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- snd_printdd("snd_usX2Y_urbs_wait_clear waiting\n");
- schedule_timeout(1);
- } while (--timeout > 0);
- if (subs->submitted_urbs)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", subs->submitted_urbs);
- return 0;
-}
-/*
- * return the current pcm pointer. just return the hwptr_done value.
- */
-static snd_pcm_uframes_t snd_usX2Y_pcm_pointer(snd_pcm_substream_t *substream)
+static void usX2Y_subs_startup_finish(usX2Ydev_t * usX2Y)
{
- snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
- return subs->hwptr_done;
+ usX2Y_urbs_set_complete(usX2Y, i_usX2Y_urb_complete);
+ usX2Y->prepare_subs = NULL;
}
-/*
- * start/stop substream
- */
-static int snd_usX2Y_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+
+static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs)
{
- snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
+ snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
+ usX2Ydev_t *usX2Y = subs->usX2Y;
+ snd_usX2Y_substream_t *prepare_subs = usX2Y->prepare_subs;
+ if (NULL != prepare_subs)
+ if (urb->start_frame == prepare_subs->urb[0]->start_frame) {
+ usX2Y_subs_startup_finish(usX2Y);
+ atomic_inc(&prepare_subs->state);
+ wake_up(&usX2Y->prepare_wait_queue);
+ }
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- snd_printdd("snd_usX2Y_pcm_trigger(START)\n");
- if (subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE]->stalled)
- return -EPIPE;
- else
- subs->running = 1;
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- snd_printdd("snd_usX2Y_pcm_trigger(STOP)\n");
- subs->running = 0;
- break;
- default:
- return -EINVAL;
- }
- return 0;
+ i_usX2Y_urb_complete(urb, regs);
}
+static void usX2Y_subs_prepare(snd_usX2Y_substream_t *subs)
+{
+ snd_printdd("usX2Y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n", subs, subs->endpoint, subs->urb[0], subs->urb[1]);
+ /* reset the pointer */
+ subs->hwptr = 0;
+ subs->hwptr_done = 0;
+ subs->transfer_done = 0;
+}
static void usX2Y_urb_release(struct urb** urb, int free_tb)
{
if (*urb) {
+ usb_kill_urb(*urb);
if (free_tb)
kfree((*urb)->transfer_buffer);
usb_free_urb(*urb);
@@ -415,97 +393,181 @@ static void usX2Y_urb_release(struct urb** urb, int free_tb)
}
}
/*
- * release a substream
+ * release a substreams urbs
*/
static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs)
{
int i;
- snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
- usX2Y_urbs_wait_clear(subs);
+ snd_printdd("usX2Y_urbs_release() %i\n", subs->endpoint);
for (i = 0; i < NRURBS; i++)
- usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK]);
+ usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]);
if (subs->tmpbuf) {
kfree(subs->tmpbuf);
subs->tmpbuf = NULL;
}
}
-
-static void usX2Y_substream_prepare(snd_usX2Y_substream_t *subs)
-{
- snd_printdd("usX2Y_substream_prepare() ep=%i urb0=%p urb1=%p\n", subs->endpoint, subs->urb[0], subs->urb[1]);
- /* reset the pointer */
- subs->hwptr = 0;
- subs->hwptr_done = 0;
- subs->transfer_done = 0;
-}
-
-
/*
* initialize a substream's urbs
*/
static int usX2Y_urbs_allocate(snd_usX2Y_substream_t *subs)
{
int i;
- int is_playback = subs == subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
+ unsigned int datapipe; /* the data i/o pipe */
+ int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
struct usb_device *dev = subs->usX2Y->chip.dev;
- snd_assert(!subs->prepared, return 0);
-
if (is_playback) { /* allocate a temporary buffer for playback */
- subs->datapipe = usb_sndisocpipe(dev, subs->endpoint);
+ datapipe = usb_sndisocpipe(dev, subs->endpoint);
subs->maxpacksize = dev->epmaxpacketout[subs->endpoint];
if (NULL == subs->tmpbuf) {
- subs->tmpbuf = kcalloc(NRPACKS, subs->maxpacksize, GFP_KERNEL);
+ subs->tmpbuf = kcalloc(nr_of_packs(), subs->maxpacksize, GFP_KERNEL);
if (NULL == subs->tmpbuf) {
snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
return -ENOMEM;
}
}
} else {
- subs->datapipe = usb_rcvisocpipe(dev, subs->endpoint);
+ datapipe = usb_rcvisocpipe(dev, subs->endpoint);
subs->maxpacksize = dev->epmaxpacketin[subs->endpoint];
}
/* allocate and initialize data urbs */
for (i = 0; i < NRURBS; i++) {
struct urb** purb = subs->urb + i;
- if (*purb)
+ if (*purb) {
+ usb_kill_urb(*purb);
continue;
- *purb = usb_alloc_urb(NRPACKS, GFP_KERNEL);
+ }
+ *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
if (NULL == *purb) {
usX2Y_urbs_release(subs);
return -ENOMEM;
}
if (!is_playback && !(*purb)->transfer_buffer) {
/* allocate a capture buffer per urb */
- (*purb)->transfer_buffer = kmalloc(subs->maxpacksize*NRPACKS, GFP_KERNEL);
+ (*purb)->transfer_buffer = kmalloc(subs->maxpacksize * nr_of_packs(), GFP_KERNEL);
if (NULL == (*purb)->transfer_buffer) {
usX2Y_urbs_release(subs);
return -ENOMEM;
}
}
(*purb)->dev = dev;
- (*purb)->pipe = subs->datapipe;
- (*purb)->number_of_packets = NRPACKS;
+ (*purb)->pipe = datapipe;
+ (*purb)->number_of_packets = nr_of_packs();
(*purb)->context = subs;
(*purb)->interval = 1;
- (*purb)->complete = snd_usb_complete_callback(i_usX2Y_urb_complete);
+ (*purb)->complete = i_usX2Y_subs_startup;
}
return 0;
}
-static void i_usX2Y_04Int(struct urb* urb, struct pt_regs *regs)
+static void usX2Y_subs_startup(snd_usX2Y_substream_t *subs)
{
- usX2Ydev_t* usX2Y = urb->context;
-
- if (urb->status) {
- snd_printk("snd_usX2Y_04Int() urb->status=%i\n", urb->status);
- return;
+ usX2Ydev_t *usX2Y = subs->usX2Y;
+ usX2Y->prepare_subs = subs;
+ subs->urb[0]->start_frame = -1;
+ wmb();
+ usX2Y_urbs_set_complete(usX2Y, i_usX2Y_subs_startup);
+}
+
+static int usX2Y_urbs_start(snd_usX2Y_substream_t *subs)
+{
+ int i, err;
+ usX2Ydev_t *usX2Y = subs->usX2Y;
+
+ if ((err = usX2Y_urbs_allocate(subs)) < 0)
+ return err;
+ subs->completed_urb = NULL;
+ for (i = 0; i < 4; i++) {
+ snd_usX2Y_substream_t *subs = usX2Y->subs[i];
+ if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
+ goto start;
}
- if (0 == --usX2Y->US04->len)
- wake_up(&usX2Y->In04WaitQueue);
+ usX2Y->wait_iso_frame = -1;
+ start:
+ {
+ usX2Y_subs_startup(subs);
+ for (i = 0; i < NRURBS; i++) {
+ struct urb *urb = subs->urb[i];
+ if (usb_pipein(urb->pipe)) {
+ unsigned long pack;
+ if (0 == i)
+ atomic_set(&subs->state, state_STARTING3);
+ urb->dev = usX2Y->chip.dev;
+ urb->transfer_flags = URB_ISO_ASAP;
+ for (pack = 0; pack < nr_of_packs(); pack++) {
+ urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
+ urb->iso_frame_desc[pack].length = subs->maxpacksize;
+ }
+ urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
+ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+ err = -EPIPE;
+ goto cleanup;
+ } else {
+ if (0 > usX2Y->wait_iso_frame)
+ usX2Y->wait_iso_frame = urb->start_frame;
+ }
+ urb->transfer_flags = 0;
+ } else {
+ atomic_set(&subs->state, state_STARTING1);
+ break;
+ }
+ }
+ err = 0;
+ wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
+ if (atomic_read(&subs->state) != state_PREPARED) {
+ err = -EPIPE;
+ }
+
+ cleanup:
+ if (err) {
+ usX2Y_subs_startup_finish(usX2Y);
+ usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
+ }
+ }
+ return err;
+}
+
+/*
+ * return the current pcm pointer. just return the hwptr_done value.
+ */
+static snd_pcm_uframes_t snd_usX2Y_pcm_pointer(snd_pcm_substream_t *substream)
+{
+ snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
+ return subs->hwptr_done;
+}
+/*
+ * start/stop substream
+ */
+static int snd_usX2Y_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+ snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ snd_printdd("snd_usX2Y_pcm_trigger(START)\n");
+ if (atomic_read(&subs->state) == state_PREPARED &&
+ atomic_read(&subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= state_PREPARED) {
+ atomic_set(&subs->state, state_PRERUNNING);
+ } else {
+ snd_printdd("\n");
+ return -EPIPE;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ snd_printdd("snd_usX2Y_pcm_trigger(STOP)\n");
+ if (atomic_read(&subs->state) >= state_PRERUNNING)
+ atomic_set(&subs->state, state_PREPARED);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
+
+
/*
* allocate a buffer, setup samplerate
*
@@ -592,76 +654,74 @@ static struct s_c2 SetRate48000[] =
};
#define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000)
+static void i_usX2Y_04Int(struct urb* urb, struct pt_regs *regs)
+{
+ usX2Ydev_t* usX2Y = urb->context;
+
+ if (urb->status) {
+ snd_printk("snd_usX2Y_04Int() urb->status=%i\n", urb->status);
+ }
+ if (0 == --usX2Y->US04->len)
+ wake_up(&usX2Y->In04WaitQueue);
+}
+
static int usX2Y_rate_set(usX2Ydev_t *usX2Y, int rate)
{
int err = 0, i;
snd_usX2Y_urbSeq_t *us = NULL;
int *usbdata = NULL;
- DECLARE_WAITQUEUE(wait, current);
struct s_c2 *ra = rate == 48000 ? SetRate48000 : SetRate44100;
if (usX2Y->rate != rate) {
- do {
- us = kmalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
- if (NULL == us) {
- err = -ENOMEM;
- break;
- }
- memset(us, 0, sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS);
- usbdata = kmalloc(sizeof(int)*NOOF_SETRATE_URBS, GFP_KERNEL);
- if (NULL == usbdata) {
+ us = kmalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
+ if (NULL == us) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ memset(us, 0, sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS);
+ usbdata = kmalloc(sizeof(int)*NOOF_SETRATE_URBS, GFP_KERNEL);
+ if (NULL == usbdata) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
+ if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
err = -ENOMEM;
- break;
+ goto cleanup;
}
- for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
- if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
- err = -ENOMEM;
- break;
- }
- ((char*)(usbdata + i))[0] = ra[i].c1;
- ((char*)(usbdata + i))[1] = ra[i].c2;
- usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),
- usbdata + i, 2, i_usX2Y_04Int, usX2Y);
+ ((char*)(usbdata + i))[0] = ra[i].c1;
+ ((char*)(usbdata + i))[1] = ra[i].c2;
+ usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),
+ usbdata + i, 2, i_usX2Y_04Int, usX2Y);
#ifdef OLD_USB
- us->urb[i]->transfer_flags = USB_QUEUE_BULK;
+ us->urb[i]->transfer_flags = USB_QUEUE_BULK;
#endif
- }
- if (err)
- break;
-
- add_wait_queue(&usX2Y->In04WaitQueue, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- us->submitted = 0;
- us->len = NOOF_SETRATE_URBS;
- usX2Y->US04 = us;
-
- do {
- signed long timeout = schedule_timeout(HZ/2);
-
- if (signal_pending(current)) {
- err = -ERESTARTSYS;
- break;
- }
- if (0 == timeout) {
- err = -ENODEV;
- break;
- }
- usX2Y->rate = rate;
- usX2Y->refframes = rate == 48000 ? 47 : 44;
- } while (0);
-
- remove_wait_queue(&usX2Y->In04WaitQueue, &wait);
- } while (0);
-
+ }
+ us->submitted = 0;
+ us->len = NOOF_SETRATE_URBS;
+ usX2Y->US04 = us;
+ wait_event_timeout(usX2Y->In04WaitQueue, 0 == us->len, HZ);
+ usX2Y->US04 = NULL;
+ if (us->len)
+ err = -ENODEV;
+ cleanup:
if (us) {
us->submitted = 2*NOOF_SETRATE_URBS;
for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
- usb_kill_urb(us->urb[i]);
- usb_free_urb(us->urb[i]);
+ struct urb *urb = us->urb[i];
+ if (urb->status) {
+ if (!err)
+ err = -ENODEV;
+ usb_kill_urb(urb);
+ }
+ usb_free_urb(urb);
}
usX2Y->US04 = NULL;
kfree(usbdata);
kfree(us);
+ if (!err) {
+ usX2Y->rate = rate;
+ }
}
}
@@ -745,27 +805,28 @@ static int snd_usX2Y_pcm_hw_free(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
+ down(&subs->usX2Y->prepare_mutex);
snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
- snd_usX2Y_substream_t *cap_subs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE];
- subs->prepared = 0;
+ snd_usX2Y_substream_t *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
+ atomic_set(&subs->state, state_STOPPED);
usX2Y_urbs_release(subs);
if (!cap_subs->pcm_substream ||
!cap_subs->pcm_substream->runtime ||
!cap_subs->pcm_substream->runtime->status ||
cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
- cap_subs->prepared = 0;
+ atomic_set(&cap_subs->state, state_STOPPED);
usX2Y_urbs_release(cap_subs);
}
} else {
- snd_usX2Y_substream_t *playback_subs = subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
- if (!playback_subs->prepared) {
- subs->prepared = 0;
+ snd_usX2Y_substream_t *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
+ if (atomic_read(&playback_subs->state) < state_PREPARED) {
+ atomic_set(&subs->state, state_STOPPED);
usX2Y_urbs_release(subs);
}
}
-
+ up(&subs->usX2Y->prepare_mutex);
return snd_pcm_lib_free_pages(substream);
}
/*
@@ -777,71 +838,32 @@ static int snd_usX2Y_pcm_prepare(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
- snd_usX2Y_substream_t *capsubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE];
+ usX2Ydev_t *usX2Y = subs->usX2Y;
+ snd_usX2Y_substream_t *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
int err = 0;
snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
+ down(&usX2Y->prepare_mutex);
+ usX2Y_subs_prepare(subs);
// Start hardware streams
// SyncStream first....
- if (! capsubs->prepared) {
- if (subs->usX2Y->format != runtime->format)
- if ((err = usX2Y_format_set(subs->usX2Y, runtime->format)) < 0)
- return err;
- if (subs->usX2Y->rate != runtime->rate)
- if ((err = usX2Y_rate_set(subs->usX2Y, runtime->rate)) < 0)
- return err;
- snd_printdd("starting capture pipe for playpipe\n");
- usX2Y_urbs_allocate(capsubs);
- capsubs->completed_urb = NULL;
- {
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&capsubs->wait_queue, &wait);
- if (0 <= (err = usX2Y_urbs_capt_start(capsubs))) {
- signed long timeout;
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(HZ/4);
- if (signal_pending(current))
- err = -ERESTARTSYS;
- else {
- snd_printdd("%li\n", HZ/4 - timeout);
- if (0 == timeout)
- err = -EPIPE;
- }
- }
- remove_wait_queue(&capsubs->wait_queue, &wait);
- if (0 > err)
- return err;
- }
+ if (atomic_read(&capsubs->state) < state_PREPARED) {
+ if (usX2Y->format != runtime->format)
+ if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
+ goto up_prepare_mutex;
+ if (usX2Y->rate != runtime->rate)
+ if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
+ goto up_prepare_mutex;
+ snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe");
+ if (0 > (err = usX2Y_urbs_start(capsubs)))
+ goto up_prepare_mutex;
}
- if (subs != capsubs) {
- int u;
- if (!subs->prepared) {
- if ((err = usX2Y_urbs_allocate(subs)) < 0)
- return err;
- subs->prepared = 1;
- }
- while (subs->submitted_urbs)
- for (u = 0; u < NRURBS; u++) {
- snd_printdd("%i\n", subs->urb[u]->status);
- while(subs->urb[u]->status || NULL != subs->urb[u]->hcpriv) {
- signed long timeout;
- snd_printdd("ep=%i waiting for urb=%p status=%i hcpriv=%p\n",
- subs->endpoint, subs->urb[u],
- subs->urb[u]->status, subs->urb[u]->hcpriv);
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(HZ/10);
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
- }
- }
- subs->completed_urb = NULL;
- subs->next_urb_complete = -1;
- subs->stalled = 0;
- }
+ if (subs != capsubs && atomic_read(&subs->state) < state_PREPARED)
+ err = usX2Y_urbs_start(subs);
- usX2Y_substream_prepare(subs);
+ up_prepare_mutex:
+ up(&usX2Y->prepare_mutex);
return err;
}
@@ -933,7 +955,7 @@ static int usX2Y_audio_stream_new(snd_card_t *card, int playback_endpoint, int c
snd_pcm_t *pcm;
int err, i;
snd_usX2Y_substream_t **usX2Y_substream =
- usX2Y(card)->substream + 2 * usX2Y(card)->chip.pcm_devs;
+ usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs;
for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
@@ -942,7 +964,6 @@ static int usX2Y_audio_stream_new(snd_card_t *card, int playback_endpoint, int c
snd_printk(KERN_ERR "cannot malloc\n");
return -ENOMEM;
}
- init_waitqueue_head(&usX2Y_substream[i]->wait_queue);
usX2Y_substream[i]->usX2Y = usX2Y(card);
}