Commit fe6a9c21 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-sound.bkbits.net/linux-sound

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 807b9692 42628d82
...@@ -611,6 +611,8 @@ Module parameters ...@@ -611,6 +611,8 @@ Module parameters
* Digigram VX442 * Digigram VX442
omni - Omni I/O support for MidiMan M-Audio Delta44/66 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 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 is not used with all Envy24 based cards (for example in the MidiMan Delta
......
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/
...@@ -460,7 +460,7 @@ static inline int ac97_is_modem(ac97_t * ac97) ...@@ -460,7 +460,7 @@ static inline int ac97_is_modem(ac97_t * ac97)
} }
static inline int ac97_is_rev22(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) static inline int ac97_can_amap(ac97_t * ac97)
{ {
......
...@@ -187,7 +187,8 @@ ...@@ -187,7 +187,8 @@
#define CS8427_VER8427A 0x71 #define CS8427_VER8427A 0x71
int snd_cs8427_detect(snd_i2c_bus_t *bus, unsigned char addr); 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); 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_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); int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg);
......
...@@ -428,7 +428,7 @@ struct _snd_pcm_str { ...@@ -428,7 +428,7 @@ struct _snd_pcm_str {
snd_info_entry_t *proc_root; snd_info_entry_t *proc_root;
snd_info_entry_t *proc_info_entry; snd_info_entry_t *proc_info_entry;
#ifdef CONFIG_SND_DEBUG #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; snd_info_entry_t *proc_xrun_debug_entry;
#endif #endif
}; };
......
/* include/version.h. Generated by configure. */ /* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "1.0.3" #define CONFIG_SND_VERSION "1.0.4rc2"
#define CONFIG_SND_DATE " (Mon Mar 01 10:12:14 2004 UTC)" #define CONFIG_SND_DATE " (Tue Mar 30 08:19:30 2004 UTC)"
...@@ -88,8 +88,18 @@ struct ioctl32_mapper timer_mappers[] = { ...@@ -88,8 +88,18 @@ struct ioctl32_mapper timer_mappers[] = {
{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) }, { SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS), MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) }, { 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_START),
MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP), MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE), MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
#endif
{ 0 }, { 0 },
}; };
...@@ -403,7 +403,7 @@ static void snd_pcm_xrun_debug_write(snd_info_entry_t *entry, snd_info_buffer_t ...@@ -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; snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
char line[64]; char line[64];
if (!snd_info_get_line(buffer, line, sizeof(line))) 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 #endif
......
...@@ -167,6 +167,7 @@ static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream, ...@@ -167,6 +167,7 @@ static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream,
substream->pcm->card->number, substream->pcm->card->number,
substream->pcm->device, substream->pcm->device,
substream->stream ? 'c' : 'p'); substream->stream ? 'c' : 'p');
if (substream->pstr->xrun_debug > 1)
dump_stack(); dump_stack();
} }
#endif #endif
...@@ -194,8 +195,11 @@ static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream ...@@ -194,8 +195,11 @@ static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream
if (delta > 0) { if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_DEBUG #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); 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 #endif
return 0; return 0;
} }
...@@ -232,8 +236,11 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream) ...@@ -232,8 +236,11 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
if (delta > 0) { if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_DEBUG #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); 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 #endif
return 0; return 0;
} }
......
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
*/ */
/* Greatest common divisor */ /* 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) { if (a < b) {
r = a; r = a;
a = b; a = b;
...@@ -49,7 +49,7 @@ static int gcd(int a, int b) ...@@ -49,7 +49,7 @@ static int gcd(int a, int b)
void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream) 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; snd_pcm_runtime_t *runtime = substream->runtime;
mult = 1000000000; mult = 1000000000;
...@@ -67,7 +67,11 @@ void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream) ...@@ -67,7 +67,11 @@ void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
mult /= 2; mult /= 2;
rate /= 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; runtime->timer_resolution = mult * fsize / rate;
} }
......
...@@ -50,6 +50,7 @@ typedef struct { ...@@ -50,6 +50,7 @@ typedef struct {
typedef struct { typedef struct {
unsigned char regmap[0x14]; /* map of first 1 + 13 registers */ unsigned char regmap[0x14]; /* map of first 1 + 13 registers */
unsigned int rate; unsigned int rate;
unsigned int reset_timeout;
cs8427_stream_t playback; cs8427_stream_t playback;
cs8427_stream_t capture; cs8427_stream_t capture;
} cs8427_t; } cs8427_t;
...@@ -163,6 +164,7 @@ static void snd_cs8427_free(snd_i2c_device_t *device) ...@@ -163,6 +164,7 @@ static void snd_cs8427_free(snd_i2c_device_t *device)
int snd_cs8427_create(snd_i2c_bus_t *bus, int snd_cs8427_create(snd_i2c_bus_t *bus,
unsigned char addr, unsigned char addr,
unsigned int reset_timeout,
snd_i2c_device_t **r_cs8427) snd_i2c_device_t **r_cs8427)
{ {
static unsigned char initvals1[] = { static unsigned char initvals1[] = {
...@@ -256,6 +258,9 @@ int snd_cs8427_create(snd_i2c_bus_t *bus, ...@@ -256,6 +258,9 @@ int snd_cs8427_create(snd_i2c_bus_t *bus,
snd_i2c_unlock(bus); snd_i2c_unlock(bus);
/* turn on run bit and rock'n'roll */ /* turn on run bit and rock'n'roll */
if (reset_timeout < 1)
reset_timeout = 1;
chip->reset_timeout = reset_timeout;
snd_cs8427_reset(device); snd_cs8427_reset(device);
#if 0 // it's nice for read tests #if 0 // it's nice for read tests
...@@ -301,7 +306,7 @@ void snd_cs8427_reset(snd_i2c_device_t *cs8427) ...@@ -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]); snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]);
udelay(200); udelay(200);
snd_i2c_unlock(cs8427->bus); snd_i2c_unlock(cs8427->bus);
end_time = jiffies + HZ / 2; end_time = jiffies + chip->reset_timeout;
while (time_after_eq(end_time, jiffies)) { while (time_after_eq(end_time, jiffies)) {
snd_i2c_lock(cs8427->bus); snd_i2c_lock(cs8427->bus);
data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS); data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS);
...@@ -309,7 +314,7 @@ void snd_cs8427_reset(snd_i2c_device_t *cs8427) ...@@ -309,7 +314,7 @@ void snd_cs8427_reset(snd_i2c_device_t *cs8427)
if (!(data & CS8427_UNLOCK)) if (!(data & CS8427_UNLOCK))
break; break;
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100); schedule_timeout(1);
} }
snd_i2c_lock(cs8427->bus); snd_i2c_lock(cs8427->bus);
chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK; chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
......
...@@ -396,11 +396,14 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho ...@@ -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; ac97->spec.ad18xx.pcmreg[codec] = new;
spin_unlock(&ac97->reg_lock); spin_unlock(&ac97->reg_lock);
/* select single codec */ /* 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 */ /* update PCM bits */
ac97->bus->write(ac97, AC97_PCM, new); ac97->bus->write(ac97, AC97_PCM, new);
/* select all codecs */ /* 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 } else
spin_unlock(&ac97->reg_lock); spin_unlock(&ac97->reg_lock);
up(&ac97->spec.ad18xx.mutex); up(&ac97->spec.ad18xx.mutex);
...@@ -2032,11 +2035,12 @@ void snd_ac97_resume(ac97_t *ac97) ...@@ -2032,11 +2035,12 @@ void snd_ac97_resume(ac97_t *ac97)
if (! ac97->spec.ad18xx.id[codec]) if (! ac97->spec.ad18xx.id[codec])
continue; continue;
/* select single codec */ /* 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]); ac97->bus->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);
} }
/* select all codecs */ /* 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 */ /* restore ac97 status */
...@@ -2055,12 +2059,13 @@ void snd_ac97_resume(ac97_t *ac97) ...@@ -2055,12 +2059,13 @@ void snd_ac97_resume(ac97_t *ac97)
if (! ac97->spec.ad18xx.id[codec]) if (! ac97->spec.ad18xx.id[codec])
continue; continue;
/* select single codec */ /* 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 */ /* update PCM bits */
ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]); ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);
} }
/* select all codecs */ /* select all codecs */
ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
continue; continue;
} else if (i == AC97_AD_TEST || } else if (i == AC97_AD_TEST ||
i == AC97_AD_CODEC_CFG || i == AC97_AD_CODEC_CFG ||
......
...@@ -562,8 +562,11 @@ int patch_conexant(ac97_t * ac97) ...@@ -562,8 +562,11 @@ int patch_conexant(ac97_t * ac97)
*/ */
int patch_ad1819(ac97_t * ac97) int patch_ad1819(ac97_t * ac97)
{ {
unsigned short scfg;
// patch for Analog Devices // 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; return 0;
} }
...@@ -572,7 +575,7 @@ static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned sh ...@@ -572,7 +575,7 @@ static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned sh
unsigned short val; unsigned short val;
// test for unchained codec // 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 */ snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000); /* ID0C, ID1C, SDIE = off */
val = snd_ac97_read(ac97, AC97_VENDOR_ID2); val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340) if ((val & 0xff40) != 0x5340)
...@@ -588,7 +591,7 @@ static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bi ...@@ -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 }; static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
unsigned short val; 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 snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004); // SDIE
val = snd_ac97_read(ac97, AC97_VENDOR_ID2); val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340) if ((val & 0xff40) != 0x5340)
...@@ -611,7 +614,8 @@ static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, in ...@@ -611,7 +614,8 @@ static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, in
if (cidx1 < 0 && cidx2 < 0) if (cidx1 < 0 && cidx2 < 0)
return; return;
// test for chained codecs // 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 snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002); // ID1C
ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002; ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002;
if (cidx1 >= 0) { if (cidx1 >= 0) {
...@@ -634,10 +638,13 @@ int patch_ad1881(ac97_t * ac97) ...@@ -634,10 +638,13 @@ int patch_ad1881(ac97_t * ac97)
// patch for Analog Devices // patch for Analog Devices
unsigned short codecs[3]; unsigned short codecs[3];
unsigned short val;
int idx, num; int idx, num;
init_MUTEX(&ac97->spec.ad18xx.mutex); 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[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14)); codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13)); codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
...@@ -659,7 +666,7 @@ int patch_ad1881(ac97_t * ac97) ...@@ -659,7 +666,7 @@ int patch_ad1881(ac97_t * ac97)
__end: __end:
/* select all codecs */ /* 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 */ /* check if only one codec is present */
for (idx = num = 0; idx < 3; idx++) for (idx = num = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) if (ac97->spec.ad18xx.id[idx])
...@@ -1003,6 +1010,7 @@ int patch_ad1985(ac97_t * ac97) ...@@ -1003,6 +1010,7 @@ int patch_ad1985(ac97_t * ac97)
{ {
unsigned short misc; unsigned short misc;
patch_ad1881(ac97);
ac97->build_ops = &patch_ad1985_build_ops; ac97->build_ops = &patch_ad1985_build_ops;
misc = snd_ac97_read(ac97, AC97_AD_MISC); misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* switch front/surround line-out/hp-out */ /* switch front/surround line-out/hp-out */
......
...@@ -89,7 +89,7 @@ static unsigned char rate_reg_tables[2][4][9] = { ...@@ -89,7 +89,7 @@ static unsigned char rate_reg_tables[2][4][9] = {
0xff, /* slot 6 */ 0xff, /* slot 6 */
AC97_PCM_LFE_DAC_RATE, /* slot 7 */ AC97_PCM_LFE_DAC_RATE, /* slot 7 */
AC97_PCM_LFE_DAC_RATE, /* slot 8 */ 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 10 */
AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ AC97_PCM_FRONT_DAC_RATE, /* slot 11 */
}, },
...@@ -140,7 +140,7 @@ static unsigned char rate_reg_tables[2][4][9] = { ...@@ -140,7 +140,7 @@ static unsigned char rate_reg_tables[2][4][9] = {
0xff, /* slot 6 */ 0xff, /* slot 6 */
AC97_PCM_LFE_DAC_RATE, /* slot 7 */ AC97_PCM_LFE_DAC_RATE, /* slot 7 */
AC97_PCM_LFE_DAC_RATE, /* slot 8 */ 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 10 */
AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ AC97_PCM_FRONT_DAC_RATE, /* slot 11 */
} }
......
...@@ -241,12 +241,13 @@ static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buff ...@@ -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++) for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) { if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */ /* 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_ac97_proc_read_main(ac97, buffer, idx);
snd_iprintf(buffer, "\n\n"); snd_iprintf(buffer, "\n\n");
} }
/* select all codecs */ /* 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); up(&ac97->spec.ad18xx.mutex);
snd_iprintf(buffer, "\nAD18XX configuration\n"); snd_iprintf(buffer, "\nAD18XX configuration\n");
...@@ -285,11 +286,12 @@ static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, ...@@ -285,11 +286,12 @@ static void snd_ac97_proc_regs_read(snd_info_entry_t *entry,
for (idx = 0; idx < 3; idx++) for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) { if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */ /* 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); snd_ac97_proc_regs_read_main(ac97, buffer, idx);
} }
/* select all codecs */ /* 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); up(&ac97->spec.ad18xx.mutex);
} else { } else {
snd_ac97_proc_regs_read_main(ac97, buffer, 0); snd_ac97_proc_regs_read_main(ac97, buffer, 0);
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#ifndef __SOUND_AU88X0_H #ifndef __SOUND_AU88X0_H
#define __SOUND_AU88X0_H #define __SOUND_AU88X0_H
#ifdef __KERNEL__
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -29,22 +28,6 @@ ...@@ -29,22 +28,6 @@
#include <sound/hwdep.h> #include <sound/hwdep.h>
#include <sound/ac97_codec.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 #ifndef CHIP_AU8820
#include "au88x0_eq.h" #include "au88x0_eq.h"
#include "au88x0_a3d.h" #include "au88x0_a3d.h"
......
...@@ -51,7 +51,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ ...@@ -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 enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
static int thinkpad[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(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard."); 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."); ...@@ -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_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
MODULE_PARM(mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM(mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); 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[] = { static struct pci_device_id snd_cs46xx_ids[] = {
{ 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4280 */ { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4280 */
...@@ -219,7 +219,7 @@ module_exit(alsa_card_cs46xx_exit) ...@@ -219,7 +219,7 @@ module_exit(alsa_card_cs46xx_exit)
#ifndef MODULE #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) static int __init alsa_card_cs46xx_setup(char *str)
{ {
...@@ -229,7 +229,10 @@ static int __init alsa_card_cs46xx_setup(char *str) ...@@ -229,7 +229,10 @@ static int __init alsa_card_cs46xx_setup(char *str)
return 0; return 0;
(void)(get_option(&str,&enable[nr_dev]) == 2 && (void)(get_option(&str,&enable[nr_dev]) == 2 &&
get_option(&str,&index[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++; nr_dev++;
return 1; return 1;
} }
......
...@@ -90,6 +90,7 @@ static unsigned char ap_cs8427_codec_select(ice1712_t *ice) ...@@ -90,6 +90,7 @@ static unsigned char ap_cs8427_codec_select(ice1712_t *ice)
tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427; tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427;
break; break;
case ICE1712_SUBDEVICE_AUDIOPHILE: case ICE1712_SUBDEVICE_AUDIOPHILE:
case ICE1712_SUBDEVICE_DELTA410:
tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC; tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL; tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
break; break;
...@@ -112,6 +113,7 @@ static void ap_cs8427_codec_deassert(ice1712_t *ice, unsigned char tmp) ...@@ -112,6 +113,7 @@ static void ap_cs8427_codec_deassert(ice1712_t *ice, unsigned char tmp)
tmp |= ICE1712_DELTA_1010LT_CS_NONE; tmp |= ICE1712_DELTA_1010LT_CS_NONE;
break; break;
case ICE1712_SUBDEVICE_AUDIOPHILE: case ICE1712_SUBDEVICE_AUDIOPHILE:
case ICE1712_SUBDEVICE_DELTA410:
tmp |= ICE1712_DELTA_AP_CS_DIGITAL; tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
break; break;
case ICE1712_SUBDEVICE_VX442: case ICE1712_SUBDEVICE_VX442:
......
...@@ -82,6 +82,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ ...@@ -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 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 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 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(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard."); MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
...@@ -95,6 +96,9 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); ...@@ -95,6 +96,9 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
MODULE_PARM(omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM(omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support."); MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support.");
MODULE_PARM_SYNTAX(omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); 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 #ifndef PCI_VENDOR_ID_ICE
#define PCI_VENDOR_ID_ICE 0x1412 #define PCI_VENDOR_ID_ICE 0x1412
...@@ -386,7 +390,9 @@ int __devinit snd_ice1712_init_cs8427(ice1712_t *ice, int addr) ...@@ -386,7 +390,9 @@ int __devinit snd_ice1712_init_cs8427(ice1712_t *ice, int addr)
{ {
int err; 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"); snd_printk("CS8427 initialization failed\n");
return err; return err;
} }
...@@ -1505,10 +1511,10 @@ static void snd_ice1712_mixer_free_ac97(ac97_t *ac97) ...@@ -1505,10 +1511,10 @@ static void snd_ice1712_mixer_free_ac97(ac97_t *ac97)
static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice) static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
{ {
int err; int err;
ac97_t ac97;
ac97_bus_t bus, *pbus;
if (ice_has_con_ac97(ice)) { if (ice_has_con_ac97(ice)) {
ac97_bus_t bus, *pbus;
ac97_t ac97;
memset(&bus, 0, sizeof(bus)); memset(&bus, 0, sizeof(bus));
bus.write = snd_ice1712_ac97_write; bus.write = snd_ice1712_ac97_write;
bus.read = snd_ice1712_ac97_read; bus.read = snd_ice1712_ac97_read;
...@@ -1527,8 +1533,6 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice) ...@@ -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)) { if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
ac97_bus_t bus, *pbus;
ac97_t ac97;
memset(&bus, 0, sizeof(bus)); memset(&bus, 0, sizeof(bus));
bus.write = snd_ice1712_pro_ac97_write; bus.write = snd_ice1712_pro_ac97_write;
bus.read = snd_ice1712_pro_ac97_read; bus.read = snd_ice1712_pro_ac97_read;
...@@ -2404,6 +2408,7 @@ static int snd_ice1712_dev_free(snd_device_t *device) ...@@ -2404,6 +2408,7 @@ static int snd_ice1712_dev_free(snd_device_t *device)
static int __devinit snd_ice1712_create(snd_card_t * card, static int __devinit snd_ice1712_create(snd_card_t * card,
struct pci_dev *pci, struct pci_dev *pci,
int omni, int omni,
int cs8427_timeout,
ice1712_t ** r_ice1712) ice1712_t ** r_ice1712)
{ {
ice1712_t *ice; ice1712_t *ice;
...@@ -2428,6 +2433,11 @@ static int __devinit snd_ice1712_create(snd_card_t * card, ...@@ -2428,6 +2433,11 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
if (ice == NULL) if (ice == NULL)
return -ENOMEM; return -ENOMEM;
ice->omni = omni ? 1 : 0; 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); spin_lock_init(&ice->reg_lock);
init_MUTEX(&ice->gpio_mutex); init_MUTEX(&ice->gpio_mutex);
init_MUTEX(&ice->open_mutex); init_MUTEX(&ice->open_mutex);
...@@ -2547,7 +2557,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, ...@@ -2547,7 +2557,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
strcpy(card->driver, "ICE1712"); strcpy(card->driver, "ICE1712");
strcpy(card->shortname, "ICEnsemble 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); snd_card_free(card);
return err; return err;
} }
......
...@@ -346,6 +346,7 @@ struct _snd_ice1712 { ...@@ -346,6 +346,7 @@ struct _snd_ice1712 {
snd_i2c_bus_t *i2c; /* I2C bus */ snd_i2c_bus_t *i2c; /* I2C bus */
snd_i2c_device_t *cs8404; /* CS8404A I2C device */ snd_i2c_device_t *cs8404; /* CS8404A I2C device */
snd_i2c_device_t *cs8427; /* CS8427 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 */ snd_i2c_device_t *i2cdevs[2]; /* additional i2c devices */
struct ice1712_gpio { struct ice1712_gpio {
......
...@@ -96,7 +96,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); ...@@ -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_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); 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 #ifdef SUPPORT_JOYSTICK
MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard."); 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 ...@@ -824,19 +824,16 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs
spin_lock(&chip->reg_lock); spin_lock(&chip->reg_lock);
status = igetdword(chip, chip->int_sta_reg); status = igetdword(chip, chip->int_sta_reg);
if ((status & chip->int_sta_mask) == 0) { if ((status & chip->int_sta_mask) == 0) {
static int err_count = 10;
if (status) { if (status) {
/* ack */ /* ack */
iputdword(chip, chip->int_sta_reg, status); 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) if (chip->device_type != DEVICE_NFORCE)
status ^= igetdword(chip, chip->int_sta_reg); status = 0;
} }
spin_unlock(&chip->reg_lock); 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); return IRQ_RETVAL(status);
} }
...@@ -1689,6 +1686,12 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { ...@@ -1689,6 +1686,12 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = {
}; };
static struct ac97_quirk ac97_quirks[] __devinitdata = { static struct ac97_quirk ac97_quirks[] __devinitdata = {
{
.vendor = 0x0e11,
.device = 0x00b8,
.name = "Compaq Evo D510C",
.type = AC97_TUNE_HP_ONLY
},
{ {
.vendor = 0x1014, .vendor = 0x1014,
.device = 0x1f00, .device = 0x1f00,
...@@ -2739,6 +2742,7 @@ static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci, ...@@ -2739,6 +2742,7 @@ static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci,
pci_read_config_word(pci, 0xe6, &val); pci_read_config_word(pci, 0xe6, &val);
#ifdef SUPPORT_JOYSTICK #ifdef SUPPORT_JOYSTICK
val &= ~0x100;
if (joystick[dev]) { if (joystick[dev]) {
if (! request_region(ich_gameport.io, 8, "ICH gameport")) { if (! request_region(ich_gameport.io, 8, "ICH gameport")) {
printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n", ich_gameport.io); 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, ...@@ -2751,6 +2755,7 @@ static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci,
} }
#endif #endif
#ifdef SUPPORT_MIDI #ifdef SUPPORT_MIDI
val &= ~0x20;
if (mpu_port[dev] > 0) { if (mpu_port[dev] > 0) {
if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) {
u8 b; u8 b;
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <pcmcia/ciscode.h> #include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include "pdaudiocf.h" #include "pdaudiocf.h"
#define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
/* /*
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/info.h> #include <sound/info.h>
#include "pdaudiocf.h" #include "pdaudiocf.h"
#define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
/* /*
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <sound/core.h> #include <sound/core.h>
#include "pdaudiocf.h" #include "pdaudiocf.h"
#define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
/* /*
......
...@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL"); ...@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static int enable = 1; /* static int enable = 1; */
#ifdef PMAC_SUPPORT_PCM_BEEP #ifdef PMAC_SUPPORT_PCM_BEEP
static int enable_beep = 1; static int enable_beep = 1;
#endif #endif
...@@ -47,9 +47,9 @@ MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); ...@@ -47,9 +47,9 @@ MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
MODULE_PARM(id, "s"); MODULE_PARM(id, "s");
MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip."); MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
MODULE_PARM(enable, "i"); /* MODULE_PARM(enable, "i");
MODULE_PARM_DESC(enable, "Enable this soundchip."); MODULE_PARM_DESC(enable, "Enable this soundchip.");
MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */
#ifdef PMAC_SUPPORT_PCM_BEEP #ifdef PMAC_SUPPORT_PCM_BEEP
MODULE_PARM(enable_beep, "i"); MODULE_PARM(enable_beep, "i");
MODULE_PARM_DESC(enable_beep, "Enable beep using PCM."); MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
...@@ -183,6 +183,8 @@ module_exit(alsa_card_pmac_exit) ...@@ -183,6 +183,8 @@ module_exit(alsa_card_pmac_exit)
static int __init alsa_card_pmac_setup(char *str) static int __init alsa_card_pmac_setup(char *str)
{ {
int __attribute__ ((__unused__)) enable = 1;
(void)(get_option(&str,&enable) == 2 && (void)(get_option(&str,&enable) == 2 &&
get_option(&str,&index) == 2 && get_option(&str,&index) == 2 &&
get_id(&str,&id) == 2 get_id(&str,&id) == 2
......
...@@ -104,6 +104,7 @@ MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC); ...@@ -104,6 +104,7 @@ MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
*/ */
#define MAX_PACKS 10 #define MAX_PACKS 10
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
#define MAX_URBS 5 /* max. 20ms long packets */ #define MAX_URBS 5 /* max. 20ms long packets */
#define SYNC_URBS 2 /* always two urbs for sync */ #define SYNC_URBS 2 /* always two urbs for sync */
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
...@@ -161,8 +162,8 @@ struct snd_usb_substream { ...@@ -161,8 +162,8 @@ struct snd_usb_substream {
unsigned int datapipe; /* the data i/o pipe */ unsigned int datapipe; /* the data i/o pipe */
unsigned int syncpipe; /* 1 - async out or adaptive in */ unsigned int syncpipe; /* 1 - async out or adaptive in */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ 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 freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */ 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 freqmax; /* maximum sampling rate, used for buffer management */
unsigned int phase; /* phase accumulator */ unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */ unsigned int maxpacksize; /* max packet size in bytes */
...@@ -184,7 +185,7 @@ struct snd_usb_substream { ...@@ -184,7 +185,7 @@ struct snd_usb_substream {
unsigned int nurbs; /* # urbs */ unsigned int nurbs; /* # urbs */
snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */
snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync 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 */ char *tmpbuf; /* temporary buffer for playback */
u64 formats; /* format bitmasks (all or'ed) */ u64 formats; /* format bitmasks (all or'ed) */
...@@ -218,17 +219,38 @@ static snd_usb_audio_t *usb_chip[SNDRV_CARDS]; ...@@ -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) * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
* this will overflow at approx 2MSPS * 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. * fill the length and offset of each urb descriptor.
* the fixed 10.14 frequency is passed through the pipe. * 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, ...@@ -243,14 +265,40 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs,
urb->number_of_packets = ctx->packets; urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */ 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].length = 3;
urb->iso_frame_desc[i].offset = offs; 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[0] = subs->freqn;
cp[1] = subs->freqn >> 8; cp[1] = subs->freqn >> 8;
cp[2] = subs->freqn >> 16; cp[2] = subs->freqn >> 16;
cp[3] = subs->freqn >> 24;
} }
urb->interval = 1;
return 0; return 0;
} }
...@@ -301,7 +349,6 @@ static int prepare_capture_urb(snd_usb_substream_t *subs, ...@@ -301,7 +349,6 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
spin_unlock_irqrestore(&subs->lock, flags); spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer = ctx->buf; urb->transfer_buffer = ctx->buf;
urb->transfer_buffer_length = offs; urb->transfer_buffer_length = offs;
urb->interval = 1;
#if 0 // for check #if 0 // for check
if (! urb->bandwidth) { if (! urb->bandwidth) {
int bustime; int bustime;
...@@ -372,7 +419,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs, ...@@ -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. * 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, ...@@ -386,16 +433,37 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs,
urb->number_of_packets = ctx->packets; urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */ 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].length = 3;
urb->iso_frame_desc[i].offset = offs; urb->iso_frame_desc[i].offset = offs;
} }
urb->interval = 1;
return 0; 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. * retrieve the current 10.14 frequency from pipe, and set it.
* the value is referred in prepare_playback_urb(). * the value is referred in prepare_playback_urb().
...@@ -410,11 +478,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, ...@@ -410,11 +478,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
unsigned long flags; unsigned long flags;
found = 0; 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 || if (urb->iso_frame_desc[i].status ||
urb->iso_frame_desc[i].actual_length < 3) urb->iso_frame_desc[i].actual_length < 3)
continue; continue;
f = combine_triple(cp); f = combine_triple(cp) << 2;
#if 0 #if 0
if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { 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", snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n",
...@@ -434,6 +502,37 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, ...@@ -434,6 +502,37 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
return 0; return 0;
} }
/*
* 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 * prepare urb for playback data pipe
* *
...@@ -464,8 +563,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, ...@@ -464,8 +563,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
if (subs->fill_max) if (subs->fill_max)
counts = subs->maxframesize; /* fixed */ counts = subs->maxframesize; /* fixed */
else { else {
subs->phase = (subs->phase & 0x3fff) + subs->freqm; subs->phase = (subs->phase & 0xffff) + subs->freqm;
counts = subs->phase >> 14; counts = subs->phase >> 16;
if (counts > subs->maxframesize) if (counts > subs->maxframesize)
counts = subs->maxframesize; counts = subs->maxframesize;
} }
...@@ -515,7 +614,6 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, ...@@ -515,7 +614,6 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
spin_unlock_irqrestore(&subs->lock, flags); spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride; urb->transfer_buffer_length = offs * stride;
ctx->transfer = offs; ctx->transfer = offs;
urb->interval = 1;
return 0; return 0;
} }
...@@ -565,6 +663,21 @@ static struct snd_urb_ops audio_urb_ops[2] = { ...@@ -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 * complete callback from data urb
*/ */
...@@ -822,15 +935,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -822,15 +935,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
{ {
unsigned int maxsize, n, i; unsigned int maxsize, n, i;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; 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 */ /* calculate the frequency in 16.16 format */
subs->freqn = subs->freqm = get_usb_rate(rate); 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->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
subs->phase = 0; subs->phase = 0;
/* calculate the max. size of packet */ /* 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) { if (subs->maxpacksize && maxsize > subs->maxpacksize) {
//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
// maxsize, subs->maxpacksize); // maxsize, subs->maxpacksize);
...@@ -842,9 +959,14 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -842,9 +959,14 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
else else
subs->curpacksize = maxsize; 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 */ /* allocate a temporary buffer for playback */
if (is_playback) { if (is_playback) {
subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL); subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
if (! subs->tmpbuf) { if (! subs->tmpbuf) {
snd_printk(KERN_ERR "cannot malloc tmpbuf\n"); snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
return -ENOMEM; return -ENOMEM;
...@@ -855,16 +977,16 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -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; total_packs = (period_bytes + maxsize - 1) / maxsize;
if (total_packs < 2 * MIN_PACKS_URB) if (total_packs < 2 * MIN_PACKS_URB)
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) { if (subs->nurbs > MAX_URBS) {
/* too much... */ /* too much... */
subs->nurbs = MAX_URBS; subs->nurbs = MAX_URBS;
total_packs = MAX_URBS * nrpacks; total_packs = MAX_URBS * urb_packs;
} }
n = total_packs; n = total_packs;
for (i = 0; i < subs->nurbs; i++) { for (i = 0; i < subs->nurbs; i++) {
npacks[i] = n > nrpacks ? nrpacks : n; npacks[i] = n > urb_packs ? urb_packs : n;
n -= nrpacks; n -= urb_packs;
} }
if (subs->nurbs <= 1) { if (subs->nurbs <= 1) {
/* too little - we need at least two packets /* 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 ...@@ -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->pipe = subs->datapipe;
u->urb->transfer_flags = URB_ISO_ASAP; u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->number_of_packets = u->packets; u->urb->number_of_packets = u->packets;
u->urb->interval = 1;
u->urb->context = u; u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_urb); 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 ...@@ -929,12 +1052,16 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
release_substream_urbs(subs, 0); release_substream_urbs(subs, 0);
return -ENOMEM; return -ENOMEM;
} }
u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 3; u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
u->urb->transfer_buffer_length = nrpacks * 3; u->urb->transfer_buffer_length = nrpacks * 4;
u->urb->dev = subs->dev; u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe; u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP; u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->number_of_packets = u->packets; 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->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); 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) ...@@ -1099,7 +1226,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
/* set interface */ /* set interface */
if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) { 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", snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
dev->devnum, fmt->iface, fmt->altsetting); dev->devnum, fmt->iface, fmt->altsetting);
return -EIO; return -EIO;
...@@ -1116,7 +1243,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) ...@@ -1116,7 +1243,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
else else
subs->datapipe = usb_rcvisocpipe(dev, ep); subs->datapipe = usb_rcvisocpipe(dev, ep);
subs->syncpipe = subs->syncinterval = 0; subs->syncpipe = subs->syncinterval = 0;
subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; subs->maxpacksize = fmt->maxpacksize;
subs->fill_max = 0; subs->fill_max = 0;
/* we need a sync pipe in async OUT or adaptive IN mode */ /* 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 ...@@ -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, "%d ", subs->dataurb[i].packets);
snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, "]\n");
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
snd_iprintf(buffer, " Momentary freq = %d.%d Hz\n", snd_iprintf(buffer, " Momentary freq = %u Hz\n",
(subs->freqm * 125) >> 11, snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
(subs->freqm >> 10) * 625 ? get_full_speed_hz(subs->freqm)
+ (((subs->freqm & ((1 << 10) - 1)) * 625) >> 10) : get_high_speed_hz(subs->freqm));
- 10 * ((subs->freqm * 125) >> 11));
} else { } else {
snd_iprintf(buffer, " Status: Stop\n"); snd_iprintf(buffer, " Status: Stop\n");
} }
...@@ -1890,7 +2016,10 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat ...@@ -1890,7 +2016,10 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->stream = as; subs->stream = as;
subs->direction = stream; subs->direction = stream;
subs->dev = as->chip->dev; subs->dev = as->chip->dev;
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
subs->ops = audio_urb_ops[stream]; 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, snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
SNDRV_DMA_TYPE_CONTINUOUS, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), snd_dma_continuous_data(GFP_KERNEL),
...@@ -2351,6 +2480,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) ...@@ -2351,6 +2480,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
fp->altset_idx = i; fp->altset_idx = i;
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
/* FIXME: decode wMaxPacketSize of high bandwith endpoints */
fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
fp->attributes = csep[3]; fp->attributes = csep[3];
...@@ -2405,7 +2535,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) ...@@ -2405,7 +2535,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
return err; return err;
} }
/* try to set the interface... */ /* 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_pitch(chip->dev, iface_no, alts, fp);
init_usb_sample_rate(chip->dev, iface_no, alts, fp, fp->rate_max); 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 ...@@ -2422,7 +2552,6 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver
int idx; int idx;
snd_usb_stream_t *as; snd_usb_stream_t *as;
snd_usb_substream_t *subs; snd_usb_substream_t *subs;
struct list_head *p;
as = list_entry(head, snd_usb_stream_t, list); as = list_entry(head, snd_usb_stream_t, list);
for (idx = 0; idx < 2; idx++) { for (idx = 0; idx < 2; idx++) {
...@@ -2431,11 +2560,6 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver ...@@ -2431,11 +2560,6 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver
return; return;
release_substream_urbs(subs, 1); release_substream_urbs(subs, 1);
subs->interface = -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, ...@@ -2587,14 +2711,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip,
struct usb_interface *iface, struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk) 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 probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
int err; int err;
for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { 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; continue;
iface = get_iface(config, quirk->ifnum);
if (quirk->ifnum != probed_ifnum && if (quirk->ifnum != probed_ifnum &&
usb_interface_claimed(iface)) usb_interface_claimed(iface))
continue; continue;
...@@ -2706,9 +2829,6 @@ static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) ...@@ -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) 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); snd_magic_kfree(chip);
return 0; return 0;
} }
...@@ -2723,10 +2843,11 @@ static int snd_usb_audio_dev_free(snd_device_t *device) ...@@ -2723,10 +2843,11 @@ static int snd_usb_audio_dev_free(snd_device_t *device)
/* /*
* create a chip instance and set its names. * 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, const snd_usb_audio_quirk_t *quirk,
snd_usb_audio_t **rchip) snd_usb_audio_t **rchip)
{ {
snd_card_t *card;
snd_usb_audio_t *chip; snd_usb_audio_t *chip;
int err, len; int err, len;
char component[14]; char component[14];
...@@ -2735,10 +2856,26 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, ...@@ -2735,10 +2856,26 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
}; };
*rchip = NULL; *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); chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
if (! chip) if (! chip) {
snd_card_free(card);
return -ENOMEM; return -ENOMEM;
}
chip->index = idx;
chip->dev = dev; chip->dev = dev;
chip->card = card; chip->card = card;
INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->pcm_list);
...@@ -2746,6 +2883,7 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, ...@@ -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) { if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_usb_audio_free(chip); snd_usb_audio_free(chip);
snd_card_free(card);
return err; return err;
} }
...@@ -2788,6 +2926,10 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, ...@@ -2788,6 +2926,10 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
if (len < sizeof(card->longname)) if (len < sizeof(card->longname))
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); 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_usb_audio_create_proc(chip);
snd_card_set_dev(card, &dev->dev); snd_card_set_dev(card, &dev->dev);
...@@ -2814,7 +2956,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -2814,7 +2956,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
struct usb_host_config *config = dev->actconfig; struct usb_host_config *config = dev->actconfig;
const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info;
int i, err; int i, err;
snd_card_t *card;
snd_usb_audio_t *chip; snd_usb_audio_t *chip;
struct usb_host_interface *alts; struct usb_host_interface *alts;
int ifnum; int ifnum;
...@@ -2842,11 +2983,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -2842,11 +2983,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
down(&register_mutex); down(&register_mutex);
for (i = 0; i < SNDRV_CARDS; i++) { for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) { if (usb_chip[i] && usb_chip[i]->dev == dev) {
chip = usb_chip[i]; if (usb_chip[i]->shutdown) {
if (chip->shutdown) {
snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n"); snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
goto __error; goto __error;
} }
chip = usb_chip[i];
break; break;
} }
} }
...@@ -2863,17 +3004,9 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -2863,17 +3004,9 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
if (enable[i] && ! usb_chip[i] && if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == dev->descriptor.idVendor) && (vid[i] == -1 || vid[i] == dev->descriptor.idVendor) &&
(pid[i] == -1 || pid[i] == dev->descriptor.idProduct)) { (pid[i] == -1 || pid[i] == dev->descriptor.idProduct)) {
card = snd_card_new(index[i], id[i], THIS_MODULE, 0); if (snd_usb_audio_create(dev, i, quirk, &chip) < 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);
goto __error; goto __error;
} }
chip->index = i;
usb_chip[i] = chip;
break; break;
} }
if (! chip) { if (! chip) {
...@@ -2899,16 +3032,17 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -2899,16 +3032,17 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
/* we are allowed to call snd_card_register() many times */ /* we are allowed to call snd_card_register() many times */
if (snd_card_register(chip->card) < 0) { if (snd_card_register(chip->card) < 0) {
if (! chip->num_interfaces)
snd_card_free(chip->card);
goto __error; goto __error;
} }
usb_chip[chip->index] = chip;
chip->num_interfaces++; chip->num_interfaces++;
up(&register_mutex); up(&register_mutex);
return chip; return chip;
__error: __error:
if (chip && !chip->num_interfaces)
snd_card_free(chip->card);
up(&register_mutex); up(&register_mutex);
__err_val: __err_val:
return NULL; return NULL;
...@@ -2942,6 +3076,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) ...@@ -2942,6 +3076,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_for_each(p, &chip->midi_list) { list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p, &usb_audio_driver); snd_usbmidi_disconnect(p, &usb_audio_driver);
} }
usb_chip[chip->index] = NULL;
up(&register_mutex); up(&register_mutex);
snd_card_free_in_thread(card); snd_card_free_in_thread(card);
} else { } else {
......
...@@ -207,7 +207,6 @@ void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); ...@@ -207,7 +207,6 @@ void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
* (conditional for compatibility with the older API) * (conditional for compatibility with the older API)
*/ */
#ifndef get_iface_desc #ifndef get_iface_desc
#define get_iface(cfg, num) ((cfg)->interface[(num)])
#define get_iface_desc(iface) (&(iface)->desc) #define get_iface_desc(iface) (&(iface)->desc)
#define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc) #define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc)
#define get_ep_desc(ep) (&(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); ...@@ -222,4 +221,8 @@ void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
#define snd_usb_complete_callback(x) (x) #define snd_usb_complete_callback(x) (x)
#endif #endif
#ifndef snd_usb_get_speed
#define snd_usb_get_speed(dev) ((dev)->speed)
#endif
#endif /* __USBAUDIO_H */ #endif /* __USBAUDIO_H */
...@@ -714,7 +714,6 @@ void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver) ...@@ -714,7 +714,6 @@ void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver)
if (ep->in && ep->in->urb) if (ep->in && ep->in->urb)
usb_unlink_urb(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) static void snd_usbmidi_rawmidi_free(snd_rawmidi_t* rmidi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment