summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-30 16:35:48 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-30 16:35:48 -0800
commitfe6a9c2179b19c03fbaba00df4e441a07197d3c2 (patch)
treef2d9857effa45114e13d4bfda227e48a1bfbec5b
parent807b969250fca26cb08ea65275f4728101a0f0a2 (diff)
parent42628d8267e54d5328b07e72afdecf1be4b8b662 (diff)
Merge http://linux-sound.bkbits.net/linux-sound
into ppc970.osdl.org:/home/torvalds/v2.6/linux
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt2
-rw-r--r--Documentation/sound/alsa/Procfile.txt185
-rw-r--r--include/sound/ac97_codec.h2
-rw-r--r--include/sound/cs8427.h3
-rw-r--r--include/sound/pcm.h2
-rw-r--r--include/sound/version.h4
-rw-r--r--sound/core/ioctl32/timer32.c10
-rw-r--r--sound/core/pcm.c2
-rw-r--r--sound/core/pcm_lib.c13
-rw-r--r--sound/core/pcm_timer.c12
-rw-r--r--sound/i2c/cs8427.c9
-rw-r--r--sound/pci/ac97/ac97_codec.c17
-rw-r--r--sound/pci/ac97/ac97_patch.c18
-rw-r--r--sound/pci/ac97/ac97_pcm.c4
-rw-r--r--sound/pci/ac97/ac97_proc.c10
-rw-r--r--sound/pci/au88x0/au88x0.h17
-rw-r--r--sound/pci/cs46xx/cs46xx.c11
-rw-r--r--sound/pci/ice1712/delta.c2
-rw-r--r--sound/pci/ice1712/ice1712.c22
-rw-r--r--sound/pci/ice1712/ice1712.h1
-rw-r--r--sound/pci/intel8x0.c21
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c1
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_core.c1
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_irq.c1
-rw-r--r--sound/ppc/powermac.c10
-rw-r--r--sound/usb/usbaudio.c271
-rw-r--r--sound/usb/usbaudio.h5
-rw-r--r--sound/usb/usbmidi.c1
28 files changed, 513 insertions, 144 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 7ace9d04cb3c..0badcacd9dc0 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -611,6 +611,8 @@ Module parameters
* Digigram VX442
omni - Omni I/O support for MidiMan M-Audio Delta44/66
+ cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
+ in msec resolution, default value is 500 (0.5 sec)
Module supports up to 8 cards and autoprobe. Note: The consumer part
is not used with all Envy24 based cards (for example in the MidiMan Delta
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
new file mode 100644
index 000000000000..d686ea3c39eb
--- /dev/null
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -0,0 +1,185 @@
+ Proc Files of ALSA Drivers
+ ==========================
+ Takashi Iwai <tiwai@suse.de>
+
+General
+-------
+
+ALSA has its own proc tree, /proc/asound. Many useful information are
+found in this tree. When you encounter a problem and need debugging,
+check the files listed in the following sections.
+
+Each card has its subtree cardX, where X is from 0 to 7. The
+card-specific files are stored in the card* subdirectories.
+
+
+Global Information
+------------------
+
+cards
+ Shows the list of currently configured ALSA drivers,
+ index, the id string, short and long descriptions.
+
+version
+ Shows the version string and compile date.
+
+modules
+ Lists the module of each card
+
+devices
+ Lists the ALSA native device mappings.
+
+meminfo
+ Shows the status of allocated pages via ALSA drivers.
+ Appears only when CONFIG_SND_DEBUG=y.
+
+hwdep
+ Lists the currently available hwdep devices in format of
+ <card>-<device>: <name>
+
+pcm
+ Lists the currently available PCM devices in format of
+ <card>-<device>: <id>: <name> : <sub-streams>
+
+timer
+ Lists the currently available timer devices
+
+
+oss/devices
+ Lists the OSS device mappings.
+
+oss/sndstat
+ Provides the output compatible with /dev/sndstat.
+ You can symlink this to /dev/sndstat.
+
+
+Card Specific Files
+-------------------
+
+The card-specific files are found in /proc/asound/card* directories.
+Some drivers (e.g. cmipci) have their own proc entries for the
+register dump, etc (e.g. /proc/asound/card*/cmipci shows the register
+dump). These files would be really helpful for debugging.
+
+When PCM devices are available on this card, you can see directories
+like pcm0p or pcm1c. They hold the PCM information for each PCM
+stream. The number after 'pcm' is the PCM device number from 0, and
+the last 'p' or 'c' means playback or capture direction. The files in
+this subtree is described later.
+
+The status of MIDI I/O is found in midi* files. It shows the device
+name and the received/transmitted bytes through the MIDI device.
+
+When the card is equipped with AC97 codecs, there are codec97#*
+subdirectories (desribed later).
+
+When the OSS mixer emulation is enabled (and the module is loaded),
+oss_mixer file appears here, too. This shows the current mapping of
+OSS mixer elements to the ALSA control elements. You can change the
+mapping by writing to this device. Read OSS-Emulation.txt for
+details.
+
+
+PCM Proc Files
+--------------
+
+card*/pcm*/info
+ The general information of this PCM device: card #, device #,
+ substreams, etc.
+
+card*/pcm*/xrun_debug
+ This file appears when CONFIG_SND_DEBUG=y.
+ This shows the status of xrun (= buffer overrun/xrun) debug of
+ ALSA PCM middle layer, as an integer from 0 to 2. The value
+ can be changed by writing to this file, such as
+
+ # cat 2 > /proc/asound/card0/pcm0p/xrun_debug
+
+ When this value is greater than 0, the driver will show the
+ messages to kernel log when an xrun is detected. The debug
+ message is shown also when the invalid H/W pointer is detected
+ at the update of periods (usually called from the interrupt
+ handler).
+
+ When this value is greater than 1, the driver will show the
+ stack trace additionally. This may help the debugging.
+
+card*/pcm*/sub*/info
+ The general information of this PCM sub-stream.
+
+card*/pcm*/sub*/status
+ The current status of this PCM sub-stream, elapsed time,
+ H/W position, etc.
+
+card*/pcm*/sub*/hw_params
+ The hardware parameters set for this sub-stream.
+
+card*/pcm*/sub*/sw_params
+ The soft parameters set for this sub-stream.
+
+card*/pcm*/sub*/prealloc
+ The buffer pre-allocation information.
+
+
+AC97 Codec Information
+----------------------
+
+card*/codec97#*/ac97#?-?
+ Shows the general information of this AC97 codec chip, such as
+ name, capabilities, set up.
+
+card*/codec97#0/ac97#?-?+regs
+ Shows the AC97 register dump. Useful for debugging.
+
+
+Sequencer Information
+---------------------
+
+seq/drivers
+ Lists the currently available ALSA sequencer drivers.
+
+seq/clients
+ Shows the list of currently available sequencer clinets and
+ ports. The connection status and the running status are shown
+ in this file, too.
+
+seq/queues
+ Lists the currently allocated/running sequener queues.
+
+seq/timer
+ Lists the currently allocated/running sequencer timers.
+
+seq/oss
+ Lists the OSS-compatible sequencer stuffs.
+
+
+Help For Debugging?
+-------------------
+
+When the problem is related with PCM, first try to turn on xrun_debug
+mode. This will give you the kernel messages when and where xrun
+happened.
+
+If it's really a bug, report it with the following information
+
+ - the name of the driver/card, show in /proc/asound/cards
+ - the reigster dump, if available (e.g. card*/cmipci)
+
+when it's a PCM problem,
+
+ - set-up of PCM, shown in hw_parms, sw_params, and status in the PCM
+ sub-stream directory
+
+when it's a mixer problem,
+
+ - AC97 proc files, codec97#*/* files
+
+for USB audio/midi,
+
+ - output of lsusb -v
+ - stream* files in card directory
+
+
+The ALSA bug-tracking system is found at:
+
+ https://bugtrack.alsa-project.org/alsa-bug/
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 0113fbebcf92..2be436ea7a21 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -460,7 +460,7 @@ static inline int ac97_is_modem(ac97_t * ac97)
}
static inline int ac97_is_rev22(ac97_t * ac97)
{
- return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
+ return (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_22;
}
static inline int ac97_can_amap(ac97_t * ac97)
{
diff --git a/include/sound/cs8427.h b/include/sound/cs8427.h
index f6c9e5f34317..229dba000d62 100644
--- a/include/sound/cs8427.h
+++ b/include/sound/cs8427.h
@@ -187,7 +187,8 @@
#define CS8427_VER8427A 0x71
int snd_cs8427_detect(snd_i2c_bus_t *bus, unsigned char addr);
-int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr, snd_i2c_device_t **r_cs8427);
+int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr,
+ unsigned int reset_timeout, snd_i2c_device_t **r_cs8427);
void snd_cs8427_reset(snd_i2c_device_t *cs8427);
int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned char val);
int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg);
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 44f5d84a8365..17d8b22090df 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -428,7 +428,7 @@ struct _snd_pcm_str {
snd_info_entry_t *proc_root;
snd_info_entry_t *proc_info_entry;
#ifdef CONFIG_SND_DEBUG
- unsigned int xrun_debug: 1;
+ unsigned int xrun_debug; /* 0 = disabled, 1 = verbose, 2 = stacktrace */
snd_info_entry_t *proc_xrun_debug_entry;
#endif
};
diff --git a/include/sound/version.h b/include/sound/version.h
index 1be7e7287c97..fac198497aae 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated by configure. */
-#define CONFIG_SND_VERSION "1.0.3"
-#define CONFIG_SND_DATE " (Mon Mar 01 10:12:14 2004 UTC)"
+#define CONFIG_SND_VERSION "1.0.4rc2"
+#define CONFIG_SND_DATE " (Tue Mar 30 08:19:30 2004 UTC)"
diff --git a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
index 24030026c988..ce49daa5866f 100644
--- a/sound/core/ioctl32/timer32.c
+++ b/sound/core/ioctl32/timer32.c
@@ -88,8 +88,18 @@ struct ioctl32_mapper timer_mappers[] = {
{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) },
+#if 0
+ /* ** FIXME **
+ * The following four entries are disabled because they conflict
+ * with the TCOC* definitions.
+ * Unfortunately, the current ioctl32 wrapper uses a single
+ * hash table for all devices. Once when the wrapper is fixed
+ * with the table based on devices, they'll be back again.
+ */
MAP_COMPAT(SNDRV_TIMER_IOCTL_START),
MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
+ MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
+#endif
{ 0 },
};
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 670a604ec17f..4f879747d1db 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -403,7 +403,7 @@ static void snd_pcm_xrun_debug_write(snd_info_entry_t *entry, snd_info_buffer_t
snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
char line[64];
if (!snd_info_get_line(buffer, line, sizeof(line)))
- pstr->xrun_debug = !!simple_strtoul(line, NULL, 10);
+ pstr->xrun_debug = simple_strtoul(line, NULL, 10);
}
#endif
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index fa7e73931f4d..49ab38418282 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -167,7 +167,8 @@ static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream,
substream->pcm->card->number,
substream->pcm->device,
substream->stream ? 'c' : 'p');
- dump_stack();
+ if (substream->pstr->xrun_debug > 1)
+ dump_stack();
}
#endif
return -EPIPE;
@@ -194,8 +195,11 @@ static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream
if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_DEBUG
- if (runtime->periods > 1)
+ if (runtime->periods > 1 && substream->pstr->xrun_debug) {
snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
+ if (substream->pstr->xrun_debug > 1)
+ dump_stack();
+ }
#endif
return 0;
}
@@ -232,8 +236,11 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_DEBUG
- if (runtime->periods > 2)
+ if (runtime->periods > 2 && substream->pstr->xrun_debug) {
snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
+ if (substream->pstr->xrun_debug > 1)
+ dump_stack();
+ }
#endif
return 0;
}
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index cf801a7e80a9..40121971ef15 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -32,9 +32,9 @@
*/
/* Greatest common divisor */
-static int gcd(int a, int b)
+static unsigned long gcd(unsigned long a, unsigned long b)
{
- int r;
+ unsigned long r;
if (a < b) {
r = a;
a = b;
@@ -49,7 +49,7 @@ static int gcd(int a, int b)
void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
{
- unsigned int rate, mult, fsize, l;
+ unsigned long rate, mult, fsize, l;
snd_pcm_runtime_t *runtime = substream->runtime;
mult = 1000000000;
@@ -67,7 +67,11 @@ void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
mult /= 2;
rate /= 2;
}
- snd_assert(rate != 0, return);
+ if (rate == 0) {
+ snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
+ runtime->timer_resolution = -1;
+ return;
+ }
runtime->timer_resolution = mult * fsize / rate;
}
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index 498a3c40f2c9..c8f148ea2ee9 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -50,6 +50,7 @@ typedef struct {
typedef struct {
unsigned char regmap[0x14]; /* map of first 1 + 13 registers */
unsigned int rate;
+ unsigned int reset_timeout;
cs8427_stream_t playback;
cs8427_stream_t capture;
} cs8427_t;
@@ -163,6 +164,7 @@ static void snd_cs8427_free(snd_i2c_device_t *device)
int snd_cs8427_create(snd_i2c_bus_t *bus,
unsigned char addr,
+ unsigned int reset_timeout,
snd_i2c_device_t **r_cs8427)
{
static unsigned char initvals1[] = {
@@ -256,6 +258,9 @@ int snd_cs8427_create(snd_i2c_bus_t *bus,
snd_i2c_unlock(bus);
/* turn on run bit and rock'n'roll */
+ if (reset_timeout < 1)
+ reset_timeout = 1;
+ chip->reset_timeout = reset_timeout;
snd_cs8427_reset(device);
#if 0 // it's nice for read tests
@@ -301,7 +306,7 @@ void snd_cs8427_reset(snd_i2c_device_t *cs8427)
snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]);
udelay(200);
snd_i2c_unlock(cs8427->bus);
- end_time = jiffies + HZ / 2;
+ end_time = jiffies + chip->reset_timeout;
while (time_after_eq(end_time, jiffies)) {
snd_i2c_lock(cs8427->bus);
data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS);
@@ -309,7 +314,7 @@ void snd_cs8427_reset(snd_i2c_device_t *cs8427)
if (!(data & CS8427_UNLOCK))
break;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/100);
+ schedule_timeout(1);
}
snd_i2c_lock(cs8427->bus);
chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 6f94c782458c..4044d0816c71 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -396,11 +396,14 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho
ac97->spec.ad18xx.pcmreg[codec] = new;
spin_unlock(&ac97->reg_lock);
/* select single codec */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+ ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
+ (ac97->regs[AC97_AD_SERIAL_CFG] & ~0x7000) |
+ ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
/* update PCM bits */
ac97->bus->write(ac97, AC97_PCM, new);
/* select all codecs */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
+ ac97->regs[AC97_AD_SERIAL_CFG] | 0x7000);
} else
spin_unlock(&ac97->reg_lock);
up(&ac97->spec.ad18xx.mutex);
@@ -2032,11 +2035,12 @@ __reset_ready:
if (! ac97->spec.ad18xx.id[codec])
continue;
/* select single codec */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
ac97->bus->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);
}
/* select all codecs */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
}
/* restore ac97 status */
@@ -2055,12 +2059,13 @@ __reset_ready:
if (! ac97->spec.ad18xx.id[codec])
continue;
/* select single codec */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
/* update PCM bits */
ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);
}
/* select all codecs */
- ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
continue;
} else if (i == AC97_AD_TEST ||
i == AC97_AD_CODEC_CFG ||
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index cd01cace01c6..1baa82ef51af 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -562,8 +562,11 @@ int patch_conexant(ac97_t * ac97)
*/
int patch_ad1819(ac97_t * ac97)
{
+ unsigned short scfg;
+
// patch for Analog Devices
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
+ scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
+ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */
return 0;
}
@@ -572,7 +575,7 @@ static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned sh
unsigned short val;
// test for unchained codec
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, mask);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000); /* ID0C, ID1C, SDIE = off */
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
@@ -588,7 +591,7 @@ static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bi
static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
unsigned short val;
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, cfg_bits[idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004); // SDIE
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
@@ -611,7 +614,8 @@ static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, in
if (cidx1 < 0 && cidx2 < 0)
return;
// test for chained codecs
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[unchained_idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002); // ID1C
ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002;
if (cidx1 >= 0) {
@@ -634,10 +638,13 @@ int patch_ad1881(ac97_t * ac97)
// patch for Analog Devices
unsigned short codecs[3];
+ unsigned short val;
int idx, num;
init_MUTEX(&ac97->spec.ad18xx.mutex);
+ val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
+ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val);
codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
@@ -659,7 +666,7 @@ int patch_ad1881(ac97_t * ac97)
__end:
/* select all codecs */
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
/* check if only one codec is present */
for (idx = num = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx])
@@ -1003,6 +1010,7 @@ int patch_ad1985(ac97_t * ac97)
{
unsigned short misc;
+ patch_ad1881(ac97);
ac97->build_ops = &patch_ad1985_build_ops;
misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* switch front/surround line-out/hp-out */
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index 7725fffba28c..f87194ddcf34 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -89,7 +89,7 @@ static unsigned char rate_reg_tables[2][4][9] = {
0xff, /* slot 6 */
AC97_PCM_LFE_DAC_RATE, /* slot 7 */
AC97_PCM_LFE_DAC_RATE, /* slot 8 */
- AC97_PCM_FRONT_DAC_RATE, /* slot 9 */
+ 0xff, /* slot 9 */
AC97_PCM_FRONT_DAC_RATE, /* slot 10 */
AC97_PCM_FRONT_DAC_RATE, /* slot 11 */
},
@@ -140,7 +140,7 @@ static unsigned char rate_reg_tables[2][4][9] = {
0xff, /* slot 6 */
AC97_PCM_LFE_DAC_RATE, /* slot 7 */
AC97_PCM_LFE_DAC_RATE, /* slot 8 */
- AC97_PCM_FRONT_DAC_RATE, /* slot 9 */
+ 0xff, /* slot 9 */
AC97_PCM_FRONT_DAC_RATE, /* slot 10 */
AC97_PCM_FRONT_DAC_RATE, /* slot 11 */
}
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 9bad06371eca..2080463799a2 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -241,12 +241,13 @@ static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buff
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
snd_ac97_proc_read_main(ac97, buffer, idx);
snd_iprintf(buffer, "\n\n");
}
/* select all codecs */
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
up(&ac97->spec.ad18xx.mutex);
snd_iprintf(buffer, "\nAD18XX configuration\n");
@@ -285,11 +286,12 @@ static void snd_ac97_proc_regs_read(snd_info_entry_t *entry,
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
snd_ac97_proc_regs_read_main(ac97, buffer, idx);
}
/* select all codecs */
- snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
up(&ac97->spec.ad18xx.mutex);
} else {
snd_ac97_proc_regs_read_main(ac97, buffer, 0);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index fff8c0284715..2ab68cfb6148 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -17,7 +17,6 @@
#ifndef __SOUND_AU88X0_H
#define __SOUND_AU88X0_H
-#ifdef __KERNEL__
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -29,22 +28,6 @@
#include <sound/hwdep.h>
#include <sound/ac97_codec.h>
-
-#ifndef PCI_VENDOR_ID_AUREAL
-#define PCI_VENDOR_ID_AUREAL 0x12eb
-#endif
-#ifndef PCI_DEVICE_ID_AUREAL_VORTEX
-#define PCI_DEVICE_ID_AUREAL_VORTEX 0x0001
-#endif
-#ifndef PCI_DEVICE_ID_AUREAL_VORTEX2
-#define PCI_DEVICE_ID_AUREAL_VORTEX2 0x0002
-#endif
-#ifndef PCI_DEVICE_ID_AUREAL_ADVANTAGE
-#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003
-#endif
-
-#endif
-
#ifndef CHIP_AU8820
#include "au88x0_eq.h"
#include "au88x0_a3d.h"
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 3a0ab29bb31f..52673bd3b560 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -51,7 +51,7 @@ 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 external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard.");
@@ -70,7 +70,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control.");
MODULE_PARM_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
MODULE_PARM(mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
-MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
+MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
static struct pci_device_id snd_cs46xx_ids[] = {
{ 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4280 */
@@ -219,7 +219,7 @@ module_exit(alsa_card_cs46xx_exit)
#ifndef MODULE
-/* format is: snd-cs46xx=enable,index,id */
+/* format is: snd-cs46xx=enable,index,id,mmap_valid,external_amp,thinkpad */
static int __init alsa_card_cs46xx_setup(char *str)
{
@@ -229,7 +229,10 @@ static int __init alsa_card_cs46xx_setup(char *str)
return 0;
(void)(get_option(&str,&enable[nr_dev]) == 2 &&
get_option(&str,&index[nr_dev]) == 2 &&
- get_id(&str,&id[nr_dev]) == 2);
+ get_id(&str,&id[nr_dev]) == 2 &&
+ get_option(&str,&mmap_valid[nr_dev]) == 2 &&
+ get_option(&str,&external_amp[nr_dev]) == 2 &&
+ get_option(&str,&thinkpad[nr_dev]) == 2);
nr_dev++;
return 1;
}
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 860f3fbb0e1b..a5ba80c48e87 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -90,6 +90,7 @@ static unsigned char ap_cs8427_codec_select(ice1712_t *ice)
tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427;
break;
case ICE1712_SUBDEVICE_AUDIOPHILE:
+ case ICE1712_SUBDEVICE_DELTA410:
tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
break;
@@ -112,6 +113,7 @@ static void ap_cs8427_codec_deassert(ice1712_t *ice, unsigned char tmp)
tmp |= ICE1712_DELTA_1010LT_CS_NONE;
break;
case ICE1712_SUBDEVICE_AUDIOPHILE:
+ case ICE1712_SUBDEVICE_DELTA410:
tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
break;
case ICE1712_SUBDEVICE_VX442:
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 00a2cfd4d339..5e4455aa3f3a 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -82,6 +82,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 omni[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0}; /* Delta44 & 66 Omni I/O support */
+static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transciever reset timeout value in msec */
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
@@ -95,6 +96,9 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
MODULE_PARM(omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support.");
MODULE_PARM_SYNTAX(omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
+MODULE_PARM(cs8427_timeout, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution.");
+MODULE_PARM_SYNTAX(cs8427_timeout, SNDRV_ENABLED ", allows:{{1,1000}},default=500,skill:advanced");
#ifndef PCI_VENDOR_ID_ICE
#define PCI_VENDOR_ID_ICE 0x1412
@@ -386,7 +390,9 @@ int __devinit snd_ice1712_init_cs8427(ice1712_t *ice, int addr)
{
int err;
- if ((err = snd_cs8427_create(ice->i2c, addr, &ice->cs8427)) < 0) {
+ if ((err = snd_cs8427_create(ice->i2c, addr,
+ (ice->cs8427_timeout * HZ) / 1000,
+ &ice->cs8427)) < 0) {
snd_printk("CS8427 initialization failed\n");
return err;
}
@@ -1505,10 +1511,10 @@ static void snd_ice1712_mixer_free_ac97(ac97_t *ac97)
static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
{
int err;
+ ac97_t ac97;
+ ac97_bus_t bus, *pbus;
if (ice_has_con_ac97(ice)) {
- ac97_bus_t bus, *pbus;
- ac97_t ac97;
memset(&bus, 0, sizeof(bus));
bus.write = snd_ice1712_ac97_write;
bus.read = snd_ice1712_ac97_read;
@@ -1527,8 +1533,6 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
}
if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
- ac97_bus_t bus, *pbus;
- ac97_t ac97;
memset(&bus, 0, sizeof(bus));
bus.write = snd_ice1712_pro_ac97_write;
bus.read = snd_ice1712_pro_ac97_read;
@@ -2404,6 +2408,7 @@ static int snd_ice1712_dev_free(snd_device_t *device)
static int __devinit snd_ice1712_create(snd_card_t * card,
struct pci_dev *pci,
int omni,
+ int cs8427_timeout,
ice1712_t ** r_ice1712)
{
ice1712_t *ice;
@@ -2428,6 +2433,11 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
if (ice == NULL)
return -ENOMEM;
ice->omni = omni ? 1 : 0;
+ if (cs8427_timeout < 1)
+ cs8427_timeout = 1;
+ else if (cs8427_timeout > 1000)
+ cs8427_timeout = 1000;
+ ice->cs8427_timeout = cs8427_timeout;
spin_lock_init(&ice->reg_lock);
init_MUTEX(&ice->gpio_mutex);
init_MUTEX(&ice->open_mutex);
@@ -2547,7 +2557,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
strcpy(card->driver, "ICE1712");
strcpy(card->shortname, "ICEnsemble ICE1712");
- if ((err = snd_ice1712_create(card, pci, omni[dev], &ice)) < 0) {
+ if ((err = snd_ice1712_create(card, pci, omni[dev], cs8427_timeout[dev], &ice)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 6496e0e9a065..8b4bc08a534e 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -346,6 +346,7 @@ struct _snd_ice1712 {
snd_i2c_bus_t *i2c; /* I2C bus */
snd_i2c_device_t *cs8404; /* CS8404A I2C device */
snd_i2c_device_t *cs8427; /* CS8427 I2C device */
+ unsigned int cs8427_timeout; /* CS8427 reset timeout in HZ/100 */
snd_i2c_device_t *i2cdevs[2]; /* additional i2c devices */
struct ice1712_gpio {
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index a4476c5cfecd..e03f67fed1bb 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -96,7 +96,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
-MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,3}},dialog:list,default:-1");
+MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1");
#ifdef SUPPORT_JOYSTICK
MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard.");
@@ -824,19 +824,16 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs
spin_lock(&chip->reg_lock);
status = igetdword(chip, chip->int_sta_reg);
if ((status & chip->int_sta_mask) == 0) {
- static int err_count = 10;
if (status) {
/* ack */
iputdword(chip, chip->int_sta_reg, status);
+ /* some Nforce[2] boards have problems when
+ IRQ_NONE is returned here.
+ */
if (chip->device_type != DEVICE_NFORCE)
- status ^= igetdword(chip, chip->int_sta_reg);
+ status = 0;
}
spin_unlock(&chip->reg_lock);
- if (chip->device_type != DEVICE_NFORCE && status && err_count) {
- err_count--;
- snd_printd("intel8x0: unknown IRQ bits 0x%x (sta_mask=0x%x)\n",
- status, chip->int_sta_mask);
- }
return IRQ_RETVAL(status);
}
@@ -1690,6 +1687,12 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = {
static struct ac97_quirk ac97_quirks[] __devinitdata = {
{
+ .vendor = 0x0e11,
+ .device = 0x00b8,
+ .name = "Compaq Evo D510C",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
.vendor = 0x1014,
.device = 0x1f00,
.name = "MS-9128",
@@ -2739,6 +2742,7 @@ static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci,
pci_read_config_word(pci, 0xe6, &val);
#ifdef SUPPORT_JOYSTICK
+ val &= ~0x100;
if (joystick[dev]) {
if (! request_region(ich_gameport.io, 8, "ICH gameport")) {
printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n", ich_gameport.io);
@@ -2751,6 +2755,7 @@ static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci,
}
#endif
#ifdef SUPPORT_MIDI
+ val &= ~0x20;
if (mpu_port[dev] > 0) {
if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) {
u8 b;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 473acab55feb..f0efe445dfca 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -25,7 +25,6 @@
#include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h>
#include "pdaudiocf.h"
-#define SNDRV_GET_ID
#include <sound/initval.h>
/*
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index 97a57a09b8c0..d8f721eef5fb 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -23,7 +23,6 @@
#include <sound/core.h>
#include <sound/info.h>
#include "pdaudiocf.h"
-#define SNDRV_GET_ID
#include <sound/initval.h>
/*
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index 789bca01a9dd..bc019ea27291 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -21,7 +21,6 @@
#include <sound/driver.h>
#include <sound/core.h>
#include "pdaudiocf.h"
-#define SNDRV_GET_ID
#include <sound/initval.h>
/*
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index aac82c0644a7..c46e69edc713 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
-static int enable = 1;
+/* static int enable = 1; */
#ifdef PMAC_SUPPORT_PCM_BEEP
static int enable_beep = 1;
#endif
@@ -47,9 +47,9 @@ MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
MODULE_PARM(id, "s");
MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "i");
-MODULE_PARM_DESC(enable, "Enable this soundchip.");
-MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+/* MODULE_PARM(enable, "i");
+ MODULE_PARM_DESC(enable, "Enable this soundchip.");
+ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */
#ifdef PMAC_SUPPORT_PCM_BEEP
MODULE_PARM(enable_beep, "i");
MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
@@ -183,6 +183,8 @@ module_exit(alsa_card_pmac_exit)
static int __init alsa_card_pmac_setup(char *str)
{
+ int __attribute__ ((__unused__)) enable = 1;
+
(void)(get_option(&str,&enable) == 2 &&
get_option(&str,&index) == 2 &&
get_id(&str,&id) == 2
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 4969b5118c29..1a7ab1bd0782 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -104,6 +104,7 @@ MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
*/
#define MAX_PACKS 10
+#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
#define MAX_URBS 5 /* max. 20ms long packets */
#define SYNC_URBS 2 /* always two urbs for sync */
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
@@ -161,8 +162,8 @@ struct snd_usb_substream {
unsigned int datapipe; /* the data i/o pipe */
unsigned int syncpipe; /* 1 - async out or adaptive in */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
- unsigned int freqn; /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
- unsigned int freqm; /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
+ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
unsigned int freqmax; /* maximum sampling rate, used for buffer management */
unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */
@@ -184,7 +185,7 @@ struct snd_usb_substream {
unsigned int nurbs; /* # urbs */
snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */
snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */
- char syncbuf[SYNC_URBS * MAX_PACKS * 3]; /* sync buffer; it's so small - let's get static */
+ char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */
char *tmpbuf; /* temporary buffer for playback */
u64 formats; /* format bitmasks (all or'ed) */
@@ -218,17 +219,38 @@ static snd_usb_audio_t *usb_chip[SNDRV_CARDS];
/*
- * convert a sampling rate into USB format (fs/1000 in Q10.14)
- * this will overflow at approx 2MSPS
+ * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
+ * this will overflow at approx 524 kHz
*/
-inline static unsigned get_usb_rate(unsigned int rate)
+inline static unsigned get_usb_full_speed_rate(unsigned int rate)
{
- return ((rate << 11) + 62) / 125;
+ return ((rate << 13) + 62) / 125;
+}
+
+/*
+ * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
+ * this will overflow at approx 4 MHz
+ */
+inline static unsigned get_usb_high_speed_rate(unsigned int rate)
+{
+ return ((rate << 10) + 62) / 125;
+}
+
+/* convert our full speed USB rate into sampling rate in Hz */
+inline static unsigned get_full_speed_hz(unsigned int usb_rate)
+{
+ return (usb_rate * 125 + (1 << 12)) >> 13;
+}
+
+/* convert our high speed USB rate into sampling rate in Hz */
+inline static unsigned get_high_speed_hz(unsigned int usb_rate)
+{
+ return (usb_rate * 125 + (1 << 9)) >> 10;
}
/*
- * prepare urb for capture sync pipe
+ * prepare urb for full speed capture sync pipe
*
* fill the length and offset of each urb descriptor.
* the fixed 10.14 frequency is passed through the pipe.
@@ -243,14 +265,40 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs,
urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3, cp += 3) {
+ for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
urb->iso_frame_desc[i].length = 3;
urb->iso_frame_desc[i].offset = offs;
+ cp[0] = subs->freqn >> 2;
+ cp[1] = subs->freqn >> 10;
+ cp[2] = subs->freqn >> 18;
+ }
+ return 0;
+}
+
+/*
+ * prepare urb for high speed capture sync pipe
+ *
+ * fill the length and offset of each urb descriptor.
+ * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ */
+static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,
+ snd_pcm_runtime_t *runtime,
+ struct urb *urb)
+{
+ unsigned char *cp = urb->transfer_buffer;
+ snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+ int i, offs;
+
+ urb->number_of_packets = ctx->packets;
+ urb->dev = ctx->subs->dev; /* we need to set this at each time */
+ for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
+ urb->iso_frame_desc[i].length = 4;
+ urb->iso_frame_desc[i].offset = offs;
cp[0] = subs->freqn;
cp[1] = subs->freqn >> 8;
cp[2] = subs->freqn >> 16;
+ cp[3] = subs->freqn >> 24;
}
- urb->interval = 1;
return 0;
}
@@ -301,7 +349,6 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer = ctx->buf;
urb->transfer_buffer_length = offs;
- urb->interval = 1;
#if 0 // for check
if (! urb->bandwidth) {
int bustime;
@@ -372,7 +419,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
/*
- * prepare urb for playback sync pipe
+ * prepare urb for full speed playback sync pipe
*
* set up the offset and length to receive the current frequency.
*/
@@ -386,16 +433,37 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs,
urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3) {
+ for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
urb->iso_frame_desc[i].length = 3;
urb->iso_frame_desc[i].offset = offs;
}
- urb->interval = 1;
return 0;
}
/*
- * process after playback sync complete
+ * prepare urb for high speed playback sync pipe
+ *
+ * set up the offset and length to receive the current frequency.
+ */
+
+static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,
+ snd_pcm_runtime_t *runtime,
+ struct urb *urb)
+{
+ int i, offs;
+ snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+ urb->number_of_packets = ctx->packets;
+ urb->dev = ctx->subs->dev; /* we need to set this at each time */
+ for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
+ urb->iso_frame_desc[i].length = 4;
+ urb->iso_frame_desc[i].offset = offs;
+ }
+ return 0;
+}
+
+/*
+ * process after full speed playback sync complete
*
* retrieve the current 10.14 frequency from pipe, and set it.
* the value is referred in prepare_playback_urb().
@@ -410,11 +478,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
unsigned long flags;
found = 0;
- for (i = 0; i < urb->number_of_packets; i++, cp += 3) {
+ for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
if (urb->iso_frame_desc[i].status ||
urb->iso_frame_desc[i].actual_length < 3)
continue;
- f = combine_triple(cp);
+ f = combine_triple(cp) << 2;
#if 0
if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) {
snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n",
@@ -435,6 +503,37 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
}
/*
+ * process after high speed playback sync complete
+ *
+ * retrieve the current 12.13 frequency from pipe, and set it.
+ * the value is referred in prepare_playback_urb().
+ */
+static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
+ snd_pcm_runtime_t *runtime,
+ struct urb *urb)
+{
+ int i;
+ unsigned int found;
+ unsigned char *cp = urb->transfer_buffer;
+ unsigned long flags;
+
+ found = 0;
+ for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
+ if (urb->iso_frame_desc[i].status ||
+ urb->iso_frame_desc[i].actual_length < 4)
+ continue;
+ found = combine_quad(cp) & 0x0fffffff;
+ }
+ if (found) {
+ spin_lock_irqsave(&subs->lock, flags);
+ subs->freqm = found;
+ spin_unlock_irqrestore(&subs->lock, flags);
+ }
+
+ return 0;
+}
+
+/*
* prepare urb for playback data pipe
*
* we copy the data directly from the pcm buffer.
@@ -464,8 +563,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
if (subs->fill_max)
counts = subs->maxframesize; /* fixed */
else {
- subs->phase = (subs->phase & 0x3fff) + subs->freqm;
- counts = subs->phase >> 14;
+ subs->phase = (subs->phase & 0xffff) + subs->freqm;
+ counts = subs->phase >> 16;
if (counts > subs->maxframesize)
counts = subs->maxframesize;
}
@@ -515,7 +614,6 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride;
ctx->transfer = offs;
- urb->interval = 1;
return 0;
}
@@ -565,6 +663,21 @@ static struct snd_urb_ops audio_urb_ops[2] = {
},
};
+static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
+ {
+ .prepare = prepare_playback_urb,
+ .retire = retire_playback_urb,
+ .prepare_sync = prepare_playback_sync_urb_hs,
+ .retire_sync = retire_playback_sync_urb_hs,
+ },
+ {
+ .prepare = prepare_capture_urb,
+ .retire = retire_capture_urb,
+ .prepare_sync = prepare_capture_sync_urb_hs,
+ .retire_sync = retire_capture_sync_urb,
+ },
+};
+
/*
* complete callback from data urb
*/
@@ -822,15 +935,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
{
unsigned int maxsize, n, i;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned int npacks[MAX_URBS], total_packs;
+ unsigned int npacks[MAX_URBS], urb_packs, total_packs;
- /* calculate the frequency in 10.14 format */
- subs->freqn = subs->freqm = get_usb_rate(rate);
+ /* calculate the frequency in 16.16 format */
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+ subs->freqn = get_usb_full_speed_rate(rate);
+ else
+ subs->freqn = get_usb_high_speed_rate(rate);
+ subs->freqm = subs->freqn;
subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
subs->phase = 0;
/* calculate the max. size of packet */
- maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14;
+ maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16;
if (subs->maxpacksize && maxsize > subs->maxpacksize) {
//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
// maxsize, subs->maxpacksize);
@@ -842,9 +959,14 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
else
subs->curpacksize = maxsize;
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+ urb_packs = nrpacks;
+ else
+ urb_packs = nrpacks * 8;
+
/* allocate a temporary buffer for playback */
if (is_playback) {
- subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL);
+ subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
if (! subs->tmpbuf) {
snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
return -ENOMEM;
@@ -855,16 +977,16 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
total_packs = (period_bytes + maxsize - 1) / maxsize;
if (total_packs < 2 * MIN_PACKS_URB)
total_packs = 2 * MIN_PACKS_URB;
- subs->nurbs = (total_packs + nrpacks - 1) / nrpacks;
+ subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
if (subs->nurbs > MAX_URBS) {
/* too much... */
subs->nurbs = MAX_URBS;
- total_packs = MAX_URBS * nrpacks;
+ total_packs = MAX_URBS * urb_packs;
}
n = total_packs;
for (i = 0; i < subs->nurbs; i++) {
- npacks[i] = n > nrpacks ? nrpacks : n;
- n -= nrpacks;
+ npacks[i] = n > urb_packs ? urb_packs : n;
+ n -= urb_packs;
}
if (subs->nurbs <= 1) {
/* too little - we need at least two packets
@@ -913,6 +1035,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
u->urb->pipe = subs->datapipe;
u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->number_of_packets = u->packets;
+ u->urb->interval = 1;
u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
}
@@ -929,12 +1052,16 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
release_substream_urbs(subs, 0);
return -ENOMEM;
}
- u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 3;
- u->urb->transfer_buffer_length = nrpacks * 3;
+ u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
+ u->urb->transfer_buffer_length = nrpacks * 4;
u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->number_of_packets = u->packets;
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ u->urb->interval = 8;
+ else
+ u->urb->interval = 1;
u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb);
}
@@ -1099,7 +1226,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
/* set interface */
if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) {
- if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) {
+ if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
dev->devnum, fmt->iface, fmt->altsetting);
return -EIO;
@@ -1116,7 +1243,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
else
subs->datapipe = usb_rcvisocpipe(dev, ep);
subs->syncpipe = subs->syncinterval = 0;
- subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
+ subs->maxpacksize = fmt->maxpacksize;
subs->fill_max = 0;
/* we need a sync pipe in async OUT or adaptive IN mode */
@@ -1836,11 +1963,10 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe
snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
snd_iprintf(buffer, "]\n");
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
- snd_iprintf(buffer, " Momentary freq = %d.%d Hz\n",
- (subs->freqm * 125) >> 11,
- (subs->freqm >> 10) * 625
- + (((subs->freqm & ((1 << 10) - 1)) * 625) >> 10)
- - 10 * ((subs->freqm * 125) >> 11));
+ snd_iprintf(buffer, " Momentary freq = %u Hz\n",
+ snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+ ? get_full_speed_hz(subs->freqm)
+ : get_high_speed_hz(subs->freqm));
} else {
snd_iprintf(buffer, " Status: Stop\n");
}
@@ -1890,7 +2016,10 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->stream = as;
subs->direction = stream;
subs->dev = as->chip->dev;
- subs->ops = audio_urb_ops[stream];
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+ subs->ops = audio_urb_ops[stream];
+ else
+ subs->ops = audio_urb_ops_high_speed[stream];
snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
@@ -2351,6 +2480,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
fp->altset_idx = i;
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+ /* FIXME: decode wMaxPacketSize of high bandwith endpoints */
fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
fp->attributes = csep[3];
@@ -2405,7 +2535,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
return err;
}
/* try to set the interface... */
- usb_set_interface(chip->dev, iface_no, i);
+ usb_set_interface(chip->dev, iface_no, altno);
init_usb_pitch(chip->dev, iface_no, alts, fp);
init_usb_sample_rate(chip->dev, iface_no, alts, fp, fp->rate_max);
}
@@ -2422,7 +2552,6 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver
int idx;
snd_usb_stream_t *as;
snd_usb_substream_t *subs;
- struct list_head *p;
as = list_entry(head, snd_usb_stream_t, list);
for (idx = 0; idx < 2; idx++) {
@@ -2431,11 +2560,6 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver
return;
release_substream_urbs(subs, 1);
subs->interface = -1;
- /* release interfaces */
- list_for_each(p, &subs->fmt_list) {
- struct audioformat *fp = list_entry(p, struct audioformat, list);
- usb_driver_release_interface(driver, usb_ifnum_to_if(subs->dev, fp->iface));
- }
}
}
@@ -2587,14 +2711,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip,
struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk)
{
- struct usb_host_config *config = chip->dev->actconfig;
int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
int err;
for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
- if (quirk->ifnum >= get_cfg_desc(config)->bNumInterfaces)
+ iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
+ if (!iface)
continue;
- iface = get_iface(config, quirk->ifnum);
if (quirk->ifnum != probed_ifnum &&
usb_interface_claimed(iface))
continue;
@@ -2706,9 +2829,6 @@ static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
static int snd_usb_audio_free(snd_usb_audio_t *chip)
{
- down(&register_mutex);
- usb_chip[chip->index] = NULL;
- up(&register_mutex);
snd_magic_kfree(chip);
return 0;
}
@@ -2723,10 +2843,11 @@ static int snd_usb_audio_dev_free(snd_device_t *device)
/*
* create a chip instance and set its names.
*/
-static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
+static int snd_usb_audio_create(struct usb_device *dev, int idx,
const snd_usb_audio_quirk_t *quirk,
snd_usb_audio_t **rchip)
{
+ snd_card_t *card;
snd_usb_audio_t *chip;
int err, len;
char component[14];
@@ -2735,10 +2856,26 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
};
*rchip = NULL;
+
+ if (snd_usb_get_speed(dev) != USB_SPEED_FULL &&
+ snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+ snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
+ return -ENXIO;
+ }
+
+ card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0);
+ if (card == NULL) {
+ snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+ return -ENOMEM;
+ }
+
chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
- if (! chip)
+ if (! chip) {
+ snd_card_free(card);
return -ENOMEM;
+ }
+ chip->index = idx;
chip->dev = dev;
chip->card = card;
INIT_LIST_HEAD(&chip->pcm_list);
@@ -2746,6 +2883,7 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_usb_audio_free(chip);
+ snd_card_free(card);
return err;
}
@@ -2788,6 +2926,10 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
if (len < sizeof(card->longname))
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
+ strlcat(card->longname,
+ snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed",
+ sizeof(card->longname));
+
snd_usb_audio_create_proc(chip);
snd_card_set_dev(card, &dev->dev);
@@ -2814,7 +2956,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
struct usb_host_config *config = dev->actconfig;
const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info;
int i, err;
- snd_card_t *card;
snd_usb_audio_t *chip;
struct usb_host_interface *alts;
int ifnum;
@@ -2842,11 +2983,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
down(&register_mutex);
for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) {
- chip = usb_chip[i];
- if (chip->shutdown) {
+ if (usb_chip[i]->shutdown) {
snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
goto __error;
}
+ chip = usb_chip[i];
break;
}
}
@@ -2863,17 +3004,9 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == dev->descriptor.idVendor) &&
(pid[i] == -1 || pid[i] == dev->descriptor.idProduct)) {
- card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
- if (card == NULL) {
- snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
- goto __error;
- }
- if (snd_usb_audio_create(card, dev, quirk, &chip) < 0) {
- snd_card_free(card);
+ if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
goto __error;
}
- chip->index = i;
- usb_chip[i] = chip;
break;
}
if (! chip) {
@@ -2899,16 +3032,17 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
/* we are allowed to call snd_card_register() many times */
if (snd_card_register(chip->card) < 0) {
- if (! chip->num_interfaces)
- snd_card_free(chip->card);
goto __error;
}
+ usb_chip[chip->index] = chip;
chip->num_interfaces++;
up(&register_mutex);
return chip;
__error:
+ if (chip && !chip->num_interfaces)
+ snd_card_free(chip->card);
up(&register_mutex);
__err_val:
return NULL;
@@ -2942,6 +3076,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p, &usb_audio_driver);
}
+ usb_chip[chip->index] = NULL;
up(&register_mutex);
snd_card_free_in_thread(card);
} else {
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index d26075663cc4..064194c9f36a 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -207,7 +207,6 @@ void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
* (conditional for compatibility with the older API)
*/
#ifndef get_iface_desc
-#define get_iface(cfg, num) ((cfg)->interface[(num)])
#define get_iface_desc(iface) (&(iface)->desc)
#define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc)
#define get_ep_desc(ep) (&(ep)->desc)
@@ -222,4 +221,8 @@ void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
#define snd_usb_complete_callback(x) (x)
#endif
+#ifndef snd_usb_get_speed
+#define snd_usb_get_speed(dev) ((dev)->speed)
+#endif
+
#endif /* __USBAUDIO_H */
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index ec81e2733be1..a2f1b5621475 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -714,7 +714,6 @@ void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver)
if (ep->in && ep->in->urb)
usb_unlink_urb(ep->in->urb);
}
- usb_driver_release_interface(driver, umidi->iface);
}
static void snd_usbmidi_rawmidi_free(snd_rawmidi_t* rmidi)