Commit 164882b8 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - added AZT3328 driver
  - added Terratec Aureon support to ICE1724 driver
  - fixed possible PCI posting problems
    - ENS1370, ENS1371, FM801, ICE1712, ICE1724, VIA82xx
  - AC'97 code
    - added new IDs
    - fixed typo in S/PDIF code
    - C-Media related fixes
  - USB driver
    - added nrpacks module option
    - added hack for AudioTrak Optoplay
    - removed OLD_USB stuff
parent cb4acf11
......@@ -187,6 +187,13 @@ Module parameters
Module supports up to 8 cards, PnP and autoprobe.
Module snd-azt3328
------------------
Module for soundcards based on Aztech AZF3328 PCI chip.
Module supports up to 8 cards.
Module snd-cmi8330
------------------
......
......@@ -2906,7 +2906,8 @@ struct _snd_pcm_runtime {
</para>
<para>
This callback may be called multiple times, too.
This function is always called before the close callback is called.
Also, the callback may be called multiple times, too.
Keep track whether the resource was already released.
</para>
</section>
......@@ -3007,14 +3008,16 @@ struct _snd_pcm_runtime {
</para>
<para>
When the pcm supports the suspend/resume operation,
When the pcm supports the suspend/resume operation
(i.e. <constant>SNDRV_PCM_INFO_RESUME</constant> flag is set),
<constant>SUSPEND</constant> and <constant>RESUME</constant>
commands must be handled, too. Obviously it does suspend and
resume of the pcm substream. Usually, the
<constant>SUSPEND</constant> is identical with
<constant>STOP</constant> command and the
<constant>RESUME</constant> is identical with
<constant>START</constant> command.
commands must be handled, too.
These commands are issued when the power-management status is
changed. Obviously, the <constant>SUSPEND</constant> and
<constant>RESUME</constant>
do suspend and resume of the pcm substream, and usually, they
are identical with <constant>STOP</constant> and
<constant>START</constant> commands, respectively.
</para>
<para>
......@@ -3331,9 +3334,96 @@ struct _snd_pcm_runtime {
</para>
<para>
There are many different constraints. You can even define your
own constraint rules. I won't explain the details here, rather I
would like to say, <quote>Luke, use the source.</quote>
There are many different constraints.
Look in <filename>sound/asound.h</filename> for a complete list.
You can even define your own constraint rules.
For example, let's suppose my_chip can manage a substream of 1 channel
if and only if the format is S16_LE, otherwise it supports any format
specified in the <type>snd_pcm_hardware_t</type> stucture (or in any
other constraint_list). You can build a rule like this:
<example>
<title>Example of Hardware Constraints for Channels</title>
<programlisting>
<![CDATA[
static int hw_rule_format_by_channels(snd_pcm_hw_params_t *params,
snd_pcm_hw_rule_t *rule)
{
snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
snd_mask_t *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_t fmt;
snd_mask_any(&fmt); // Init the struct
if (c->min < 2) {
fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
return snd_mask_refine(f, &fmt);
}
return 0;
}
]]>
</programlisting>
</example>
</para>
<para>
Then you need to call this function to add your rule:
<informalexample>
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-1);
]]>
</programlisting>
</informalexample>
</para>
<para>
The rule function is called when an application sets the number of
channels. But an application can set the format before the number of
channels. Thus you also need to define the inverse rule:
<example>
<title>Example of Hardware Constraints for Channels</title>
<programlisting>
<![CDATA[
static int hw_rule_channels_by_format(snd_pcm_hw_params_t *params,
snd_pcm_hw_rule_t *rule)
{
snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
snd_mask_t *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_interval_t ch;
snd_interval_any(&ch);
if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
ch.min = ch.max = 1;
ch.integer = 1;
return snd_interval_refine(c, &ch);
}
return 0;
}
]]>
</programlisting>
</example>
</para>
<para>
...and in the open callback:
<informalexample>
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-1);
]]>
</programlisting>
</informalexample>
</para>
<para>
I won't explain more details here, rather I
would like to say, <quote>Luke, use the source.</quote>
</para>
</section>
......@@ -5756,6 +5846,10 @@ struct _snd_pcm_runtime {
Kevin Conder reformatted the original plain-text to the
DocBook format.
</para>
<para>
Giuliano Pochini corrected typos and contributed the example codes
in the hardware constraints section.
</para>
</chapter>
......
......@@ -37,11 +37,13 @@ struct snd_ak4xxx_ops {
void (*set_rate_val)(akm4xxx_t *ak, unsigned int rate);
};
#define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */
struct snd_akm4xxx {
snd_card_t *card;
unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
unsigned int num_dacs; /* AK4524 or AK4528 DACs */
unsigned char images[AK4XXX_MAX_CHIPS][16]; /* saved register image */
unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image for IPGA (AK4528) */
unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */
void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */
......@@ -58,4 +60,9 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state);
void snd_akm4xxx_init(akm4xxx_t *ak);
int snd_akm4xxx_build_controls(akm4xxx_t *ak);
#define snd_akm4xxx_get(ak,chip,reg) (ak)->images[(chip) * 16 + (reg)]
#define snd_akm4xxx_set(ak,chip,reg,val) ((ak)->images[(chip) * 16 + (reg)] = (val))
#define snd_akm4xxx_get_ipga(ak,chip,reg) (ak)->ipga_gain[chip][(reg)-4]
#define snd_akm4xxx_set_ipga(ak,chip,reg,val) ((ak)->ipga_gain[chip][(reg)-4] = (val))
#endif /* __SOUND_AK4XXX_ADDA_H */
......@@ -25,6 +25,7 @@
#include <linux/sched.h> /* wake_up() */
#include <asm/semaphore.h> /* struct semaphore */
#include <linux/rwsem.h> /* struct rw_semaphore */
#include <linux/workqueue.h> /* struct workqueue_struct */
/* Typedef's */
typedef struct timespec snd_timestamp_t;
......@@ -158,6 +159,7 @@ struct _snd_card {
spinlock_t files_lock; /* lock the files for this card */
int shutdown; /* this card is going down */
wait_queue_head_t shutdown_sleep;
struct work_struct free_workq; /* for free in workqueue */
#ifdef CONFIG_PM
int (*set_power_state) (snd_card_t *card, unsigned int state);
......
/* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.4"
#define CONFIG_SND_DATE " (Sat May 31 13:37:06 2003 UTC)"
#define CONFIG_SND_DATE " (Fri Jun 06 09:23:03 2003 UTC)"
......@@ -45,6 +45,7 @@ obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AZT3328) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
......
......@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/ctype.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
......@@ -50,6 +49,8 @@ static void snd_card_id_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer
snd_iprintf(buffer, "%s\n", entry->card->id);
}
static void snd_card_free_thread(void * __card);
/**
* snd_card_new - create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
......@@ -115,6 +116,7 @@ snd_card_t *snd_card_new(int idx, const char *xid,
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
init_waitqueue_head(&card->shutdown_sleep);
INIT_WORK(&card->free_workq, snd_card_free_thread, card);
#ifdef CONFIG_PM
init_MUTEX(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
......@@ -327,16 +329,15 @@ static void snd_card_free_thread(void * __card)
*/
int snd_card_free_in_thread(snd_card_t * card)
{
DECLARE_WORK(works, snd_card_free_thread, card);
if (card->files == NULL) {
snd_card_free(card);
return 0;
}
if (schedule_work(&works))
if (schedule_work(&card->free_workq))
return 0;
snd_printk(KERN_ERR "kernel_thread failed in snd_card_free_in_thread for card %i\n", card->number);
snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
/* try to free the structure immediately */
snd_card_free(card);
return -EFAULT;
......@@ -354,6 +355,10 @@ static void choose_default_id(snd_card_t * card)
id++;
}
id = card->id;
while (*spos != '\0' && !isalnum(*spos))
spos++;
if (isdigit(*spos))
*id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D';
while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
if (isalnum(*spos))
*id++ = *spos;
......@@ -362,6 +367,9 @@ static void choose_default_id(snd_card_t * card)
*id = '\0';
id = card->id;
if (*id == '\0')
strcpy(id, "default");
while (1) {
if (loops-- == 0) {
......@@ -421,7 +429,7 @@ int snd_card_register(snd_card_t * card)
write_unlock(&snd_card_rwlock);
return 0;
}
if (!card->id[0])
if (card->id[0] == '\0')
choose_default_id(card);
snd_cards[card->number] = card;
snd_cards_count++;
......
......@@ -862,7 +862,7 @@ static struct action_ops snd_pcm_action_pause = {
static int snd_pcm_pause(snd_pcm_substream_t *substream, int push)
{
return snd_pcm_action(&snd_pcm_action_pause, substream, 0);
return snd_pcm_action(&snd_pcm_action_pause, substream, push);
}
#ifdef CONFIG_PM
......
......@@ -43,6 +43,7 @@ obj-$(call sequencer,$(CONFIG_SND_MTPAV)) += $(RAWMIDI_OBJS)
obj-$(call sequencer,$(CONFIG_SND_MPU401)) += $(RAWMIDI_OBJS)
obj-$(call sequencer,$(CONFIG_SND_ALS100)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(call sequencer,$(CONFIG_SND_DT019X)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
......
......@@ -19,6 +19,7 @@ sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_
# Toplevel Module Dependency
obj-$(call sequencer,$(CONFIG_SND_ALS100)) += snd-ainstr-fm.o
obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += snd-ainstr-fm.o
obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += snd-ainstr-fm.o
obj-$(call sequencer,$(CONFIG_SND_DT019X)) += snd-ainstr-fm.o
obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += snd-ainstr-fm.o
obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += snd-ainstr-fm.o
......
......@@ -10,6 +10,7 @@ snd-mpu401-uart-objs := mpu401_uart.o
obj-$(CONFIG_SND_MPU401) += snd-mpu401.o snd-mpu401-uart.o
obj-$(CONFIG_SND_ALS100) += snd-mpu401-uart.o
obj-$(CONFIG_SND_AZT2320) += snd-mpu401-uart.o
obj-$(CONFIG_SND_AZT3328) += snd-mpu401-uart.o
obj-$(CONFIG_SND_DT019X) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ES18XX) += snd-mpu401-uart.o
obj-$(CONFIG_SND_OPL3SA2) += snd-mpu401-uart.o
......
......@@ -17,6 +17,7 @@ endif
# Toplevel Module Dependency
obj-$(CONFIG_SND_ALS100) += $(OPL3_OBJS)
obj-$(CONFIG_SND_AZT2320) += $(OPL3_OBJS)
obj-$(CONFIG_SND_AZT3328) += $(OPL3_OBJS)
obj-$(CONFIG_SND_DT019X) += $(OPL3_OBJS)
obj-$(CONFIG_SND_ES18XX) += $(OPL3_OBJS)
obj-$(CONFIG_SND_OPL3SA2) += $(OPL3_OBJS)
......
......@@ -42,12 +42,12 @@ void snd_akm4xxx_write(akm4xxx_t *ak, int chip, unsigned char reg, unsigned char
/* save the data */
if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
if ((reg != 0x04 && reg != 0x05) || (reg & 0x80) == 0)
ak->images[chip][reg] = val;
snd_akm4xxx_set(ak, chip, reg, val);
else
ak->ipga_gain[chip][reg-4] = val;
snd_akm4xxx_set_ipga(ak, chip, reg, val);
} else {
/* AK4529, or else */
ak->images[chip][reg] = val;
snd_akm4xxx_set(ak, chip, reg, val);
}
ak->ops.unlock(ak, chip);
}
......@@ -72,12 +72,12 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state)
continue;
/* DAC volumes */
for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
snd_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]);
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
if (ak->type == SND_AK4528)
continue;
/* IPGA */
for (reg = 0x04; reg < 0x06; reg++)
snd_akm4xxx_write(ak, chip, reg, ak->ipga_gain[chip][reg-4]);
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg));
}
break;
case SND_AK4529:
......@@ -89,7 +89,7 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state)
return;
for (reg = 0x00; reg < 0x0a; reg++)
if (reg != 0x01)
snd_akm4xxx_write(ak, 0, reg, ak->images[0][reg]);
snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg));
break;
case SND_AK4381:
for (chip = 0; chip < ak->num_dacs/2; chip++) {
......@@ -97,7 +97,7 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state)
if (state)
continue;
for (reg = 0x01; reg < 0x05; reg++)
snd_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]);
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
}
break;
}
......@@ -240,7 +240,7 @@ static int snd_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
int addr = AK_GET_ADDR(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char val = ak->images[chip][addr];
unsigned char val = snd_akm4xxx_get(ak, chip, addr);
ucontrol->value.integer.value[0] = invert ? mask - val : val;
return 0;
......@@ -258,7 +258,7 @@ static int snd_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
if (invert)
nval = mask - nval;
change = ak->images[chip][addr] != nval;
change = snd_akm4xxx_get(ak, chip, addr) != nval;
if (change)
snd_akm4xxx_write(ak, chip, addr, nval);
return change;
......@@ -278,7 +278,7 @@ static int snd_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_valu
akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
ucontrol->value.integer.value[0] = ak->ipga_gain[chip][addr-4] & 0x7f;
ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
return 0;
}
......@@ -288,7 +288,7 @@ static int snd_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_valu
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
int change = ak->ipga_gain[chip][addr] != nval;
int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval;
if (change)
snd_akm4xxx_write(ak, chip, addr, nval);
return change;
......@@ -314,7 +314,7 @@ static int snd_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int shift = AK_GET_SHIFT(kcontrol->private_value);
ucontrol->value.enumerated.item[0] = (ak->images[chip][addr] >> shift) & 3;
ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
return 0;
}
......@@ -327,8 +327,8 @@ static int snd_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
int change;
nval = (nval << shift) | (ak->images[chip][addr] & ~(3 << shift));
change = ak->images[chip][addr] != nval;
nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
change = snd_akm4xxx_get(ak, chip, addr) != nval;
if (change)
snd_akm4xxx_write(ak, chip, addr, nval);
return change;
......
......@@ -9,6 +9,12 @@ config SND_ALI5451
help
Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
config SND_AZT3328
tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
depends on SND && EXPERIMENTAL
help
Say 'Y' or 'M' to include support for Aztech AZF3328 (PCI168) soundcards.
config SND_CS46XX
tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
depends on SND && SOUND_GAMEPORT
......@@ -181,7 +187,7 @@ config SND_VX222
tristate "Digigram VX222"
depends on SND
help
Say 'Y' or 'M' to include support for Digigram VX222 soundcards
Say 'Y' or 'M' to include support for Digigram VX222 soundcards.
endmenu
......@@ -4,6 +4,7 @@
#
snd-als4000-objs := als4000.o
snd-azt3328-objs := azt3328.o
snd-cmipci-objs := cmipci.o
snd-cs4281-objs := cs4281.o
snd-ens1370-objs := ens1370.o
......@@ -33,5 +34,6 @@ obj-$(CONFIG_SND_RME32) += snd-rme32.o
obj-$(CONFIG_SND_RME96) += snd-rme96.o
obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o
obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/
......@@ -103,6 +103,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1881, NULL },
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1980, NULL },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL },
......@@ -112,6 +113,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x414c4730, 0xffffffff, "ALC101", NULL, NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL },
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL },
......@@ -122,6 +124,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x43525948, 0xfffffff8, "CS4201", NULL, NULL },
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif, NULL },
{ 0x43525960, 0xfffffff8, "CS4291", NULL, NULL },
{ 0x43525970, 0xfffffff8, "CS4202", NULL, NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
{ 0x44543031, 0xfffffff0, "DT0398", NULL, NULL },
......@@ -130,10 +133,13 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x48525300, 0xffffff00, "HMP9701", NULL, NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL, NULL },
{ 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A?
{ 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL },
{ 0x49434551, 0xffffffff, "VT1616", NULL, NULL },
{ 0x49434552, 0xffffffff, "VT1616i", NULL, NULL }, // VT1616 compatible (chipset integrated)
{ 0x49544520, 0xffffffff, "IT2226E", NULL, NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
{ 0x53494c20, 0xffffffe0, "Si3036/8", NULL, NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
......@@ -159,6 +165,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721, NULL },
{ 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744, NULL },
{ 0x83847650, 0xffffffff, "STAC9750/51", NULL, NULL }, // patch?
{ 0x83847652, 0xffffffff, "STAC9752/53", NULL, NULL }, // patch?
{ 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756, NULL },
{ 0x83847666, 0xffffffff, "STAC9766/67", NULL, NULL }, // patch?
{ 0, 0, NULL, NULL, NULL }
......@@ -183,7 +190,7 @@ static const char *snd_ac97_stereo_enhancements[] =
/* 14 */ "Binaura 3D Audio Enhancement",
/* 15 */ "ESS Technology Stereo Enhancement",
/* 16 */ "Harman International VMAx",
/* 17 */ "Nvidea 3D Stereo Enhancement",
/* 17 */ "Nvidea/IC Ensemble/KS Waves 3D Stereo Enhancement",
/* 18 */ "Philips Incredible Sound",
/* 19 */ "Texas Instruments 3D Stereo Enhancement",
/* 20 */ "VLSI Technology 3D Stereo Enhancement",
......@@ -1672,18 +1679,18 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
ac97->spec.ad18xx.pcmreg[2] = 0x9f1f;
}
} else {
unsigned int pcm_ctrls = 2;
/* FIXME: C-Media chips have no PCM volume!! */
if (/*ac97->id == 0x434d4941 ||*/
ac97->id == 0x434d4942 ||
ac97->id == 0x434d4961)
goto no_pcm;
for (idx = 0; idx < 2; idx++)
pcm_ctrls = 1;
for (idx = 0; idx < pcm_ctrls; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pcm[idx], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);
no_pcm:
/* build Capture controls */
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_capture[idx], ac97))) < 0)
......@@ -2074,6 +2081,10 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
ac97->card = card;
spin_lock_init(&ac97->reg_lock);
if (ac97->pci) {
pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor);
pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device);
}
if (ac97->reset) {
ac97->reset(ac97);
goto __access_ok;
......@@ -2713,7 +2724,7 @@ static int set_spdif_rate(ac97_t *ac97, unsigned short rate)
}
spin_lock(&ac97->reg_lock);
old = ac97->regs[reg] & ~mask;
old = ac97->regs[reg] & mask;
spin_unlock(&ac97->reg_lock);
if (old != bits) {
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
......
This diff is collapsed.
#ifndef __SOUND_AZF3328_H
#define __SOUND_AZF3328_H
/* type argument to use for the I/O functions */
#define WORD_VALUE 0x1000
#define DWORD_VALUE 0x2000
#define BYTE_VALUE 0x4000
/*** main I/O area port indices ***/
/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
/* the driver initialisation suggests a layout of 3 main areas:
* from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe DirectX
* timer ???). and probably another area from 0x60 to 0x6f
* (IRQ management, power management etc. ???). */
/* playback area */
#define IDX_IO_PLAY_FLAGS 0x00
/* able to reactivate output after output muting due to 8/16bit
* output change, just like 0x0002.
* 0x0001 is the only bit that's able to start the DMA counter */
#define DMA_RESUME 0x0001 /* paused if cleared ? */
/* 0x0002 *temporarily* set during DMA stopping. hmm
* both 0x0002 and 0x0004 set in playback setup. */
/* able to reactivate output after output muting due to 8/16bit
* output change, just like 0x0001. */
#define DMA_PLAY_SOMETHING1 0x0002 /* \ alternated (toggled) */
/* 0x0004: NOT able to reactivate output */
#define DMA_PLAY_SOMETHING2 0x0004 /* / bits */
#define SOMETHING_ALMOST_ALWAYS_SET 0x0008 /* ???; can be modified */
#define DMA_EPILOGUE_SOMETHING 0x0010
#define DMA_SOMETHING_ELSE 0x0020 /* ??? */
#define SOMETHING_UNMODIFIABLE 0xffc0 /* unused ? not modifiable */
#define IDX_IO_PLAY_IRQMASK 0x02
/* write back to flags in case flags are set, in order to ACK IRQ in handler
* (bit 1 of port 0x64 indicates interrupt for one of these three types)
* sometimes in this case it just writes 0xffff to globally ACK all IRQs
* settings written are not reflected when reading back, though.
* seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows ? */
#define IRQ_PLAY_SOMETHING 0x0001 /* something & ACK */
#define IRQ_FINISHED_PLAYBUF_1 0x0002 /* 1st dmabuf finished & ACK */
#define IRQ_FINISHED_PLAYBUF_2 0x0004 /* 2nd dmabuf finished & ACK */
#define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */
#define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */
#define IRQMASK_UNMODIFIABLE 0xffe0 /* unused ? not modifiable */
#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area */
#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area */
#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area */
#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area */
#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position */
#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area */
#define IDX_IO_PLAY_SOUNDFORMAT 0x16
/* all unspecified bits can't be modified */
#define SOUNDFORMAT_FREQUENCY_MASK 0x000f
/* all _SUSPECTED_ values are not used by Windows drivers, so we don't
* have any hard facts, only rough measurements */
#define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c
#define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a
#define SOUNDFORMAT_FREQ_5510 0x0d
#define SOUNDFORMAT_FREQ_6620 0x0b
#define SOUNDFORMAT_FREQ_8000 0x00 /* also 0x0e ? */
#define SOUNDFORMAT_FREQ_9600 0x08
#define SOUNDFORMAT_FREQ_SUSPECTED_12000 0x09
#define SOUNDFORMAT_FREQ_11025 0x01 /* also 0x0f ? */
#define SOUNDFORMAT_FREQ_16000 0x02
#define SOUNDFORMAT_FREQ_22050 0x03
#define SOUNDFORMAT_FREQ_32000 0x04
#define SOUNDFORMAT_FREQ_44100 0x05
#define SOUNDFORMAT_FREQ_48000 0x06
#define SOUNDFORMAT_FREQ_SUSPECTED_64000 0x07
#define SOUNDFORMAT_FLAG_16BIT 0x0010
#define SOUNDFORMAT_FLAG_2CHANNELS 0x0020
/* recording area (see also: playback bit flag definitions) */
#define IDX_IO_REC_FLAGS 0x20 /* ?? */
#define IDX_IO_REC_IRQMASK 0x22 /* ?? */
#define IRQ_REC_SOMETHING 0x0001 /* something & ACK */
#define IRQ_FINISHED_RECBUF_1 0x0002 /* 1st dmabuf finished & ACK */
#define IRQ_FINISHED_RECBUF_2 0x0004 /* 2nd dmabuf finished & ACK */
/* hmm, maybe these are just the corresponding *recording* flags ?
* but OTOH they are most likely at port 0x22 instead */
#define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */
#define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */
#define IDX_IO_REC_DMA_START_1 0x24
#define IDX_IO_REC_DMA_START_2 0x28
#define IDX_IO_REC_DMA_LEN_1 0x2c
#define IDX_IO_REC_DMA_LEN_2 0x2e
#define IDX_IO_REC_DMA_CURRPOS 0x30
#define IDX_IO_REC_DMA_CURROFS 0x34
#define IDX_IO_REC_SOUNDFORMAT 0x36
/* some third area ? (after playback and recording) */
#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init */
/* general */
#define IDX_IO_60H 0x60 /* writing 0xffff returns 0xffff */
#define IDX_IO_62H 0x62 /* writing to WORD 0x0062 can hang the box ! --> responsible for IRQ management as a whole ?? */
#define IDX_IO_IRQ63H 0x63 /* FIXME !! */
#define IO_IRQ63H_SOMETHING 0x04 /* being set in IRQ handler in case port 0x00 had 0x0020 set upon IRQ handler */
#define IDX_IO_IRQSTATUS 0x64
#define IRQ_PLAYBACK 0x0001
#define IRQ_RECORDING 0x0002
#define IRQ_MPU401 0x0010
#define IRQ_SOMEIRQ 0x0020 /* ???? */
#define IRQ_WHO_KNOWS_UNUSED 0x00e0 /* probably unused */
#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */
#define IDX_IO_SOME_VALUE 0x68 /* this is always set to 0x3ff, and writable; maybe some buffer limit, but I couldn't find out more */
#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback !!! maybe power management ?? */
#define IDX_IO_6CH 0x6C /* this WORD can have all its bits activated ? */
#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */
/* further I/O indices not saved/restored, so probably not used */
/*** I/O 2 area port indices ***/
/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
#define IDX_IO2_LEGACY_ADDR 0x04
#define LEGACY_SOMETHING 0x01 /* OPL3 ?? */
#define LEGACY_JOY 0x08
/*** mixer I/O area port indices ***/
/* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
* generally spoken: AC97 register index = AZF3328 mixer reg index + 2
* (in other words: AZF3328 NOT fully AC97 compliant) */
#define MIXER_VOLUME_RIGHT_MASK 0x001f
#define MIXER_VOLUME_LEFT_MASK 0x1f00
#define MIXER_MUTE_MASK 0x8000
#define IDX_MIXER_RESET 0x00 /* does NOT seem to have AC97 ID bits */
#define IDX_MIXER_PLAY_MASTER 0x02
#define IDX_MIXER_MODEMOUT 0x04
#define IDX_MIXER_BASSTREBLE 0x06
#define MIXER_BASSTREBLE_TREBLE_VOLUME_MASK 0x000e
#define MIXER_BASSTREBLE_BASS_VOLUME_MASK 0x0e00
#define IDX_MIXER_PCBEEP 0x08
#define IDX_MIXER_MODEMIN 0x0a
#define IDX_MIXER_MIC 0x0c
#define MIXER_MIC_MICGAIN_20DB_ENHANCEMENT_MASK 0x0040
#define IDX_MIXER_LINEIN 0x0e
#define IDX_MIXER_CDAUDIO 0x10
#define IDX_MIXER_VIDEO 0x12
#define IDX_MIXER_AUX 0x14
#define IDX_MIXER_WAVEOUT 0x16
#define IDX_MIXER_FMSYNTH 0x18
#define IDX_MIXER_REC_SELECT 0x1a
#define MIXER_REC_SELECT_MIC 0x00
#define MIXER_REC_SELECT_CD 0x01
#define MIXER_REC_SELECT_VIDEO 0x02
#define MIXER_REC_SELECT_AUX 0x03
#define MIXER_REC_SELECT_LINEIN 0x04
#define MIXER_REC_SELECT_MIXSTEREO 0x05
#define MIXER_REC_SELECT_MIXMONO 0x06
#define MIXER_REC_SELECT_MONOIN 0x07
#define IDX_MIXER_REC_VOLUME 0x1c
#define IDX_MIXER_ADVCTL1 0x1e
/* unlisted bits are unmodifiable */
#define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e
#define MIXER_ADVCTL1_HIFI3D_MASK 0x0300
#define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg ! */
/* unlisted bits are unmodifiable */
#define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass ? mutes WaveOut at LineOut */
#define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select ? */
#define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source ? */
#define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable ? */
#define MIXER_ADVCTL2_BIT15 0x8000 /* unknown */
#define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown ??? */
/* driver internal flags */
#define SET_CHAN_LEFT 1
#define SET_CHAN_RIGHT 2
#endif /* __SOUND_AZF3328_H */
......@@ -1634,8 +1634,10 @@ static int __devinit snd_ensoniq_1370_mixer(ensoniq_t * ensoniq)
/* try reset AK4531 */
outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC));
inw(ES_REG(ensoniq, 1370_CODEC));
udelay(100);
outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC));
inw(ES_REG(ensoniq, 1370_CODEC));
udelay(100);
memset(&ak4531, 0, sizeof(ak4531));
......@@ -1975,6 +1977,7 @@ static int __devinit snd_ensoniq_create(snd_card_t * card,
}
/* AC'97 warm reset to start the bitclk */
outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL));
inl(ES_REG(ensoniq, CONTROL));
udelay(20);
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
/* Init the sample rate converter */
......
......@@ -959,6 +959,7 @@ static int __devinit snd_fm801_create(snd_card_t * card,
/* codec cold reset + AC'97 warm reset */
outw((1<<5)|(1<<6), FM801_REG(chip, CODEC_CTRL));
inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
udelay(100);
outw(0, FM801_REG(chip, CODEC_CTRL));
......
......@@ -4,7 +4,7 @@
#
snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o ak4xxx.o
snd-ice1724-objs := ice1724.o amp.o revo.o ak4xxx.o
snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o ak4xxx.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o
......
......@@ -97,17 +97,6 @@ static void snd_ice1712_akm4xxx_write(akm4xxx_t *ak, int chip,
udelay(1);
}
/* save the data */
if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
ak->images[chip][addr] = data;
else
ak->ipga_gain[chip][addr-4] = data;
} else {
/* AK4529, or else */
ak->images[chip][addr] = data;
}
if (priv->cs_mask == priv->cs_addr) {
if (priv->cif) {
/* assert a cs pulse to trigger */
......
This diff is collapsed.
#ifndef __SOUND_AUREON_H
#define __SOUND_AUREON_H
/*
* ALSA driver for VIA VT1724 (Envy24HT)
*
* Lowlevel functions for Terratec Aureon cards
*
* Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define AUREON_DEVICE_DESC "{Terratec,Aureon 5.1 Sky},"\
"{Terratec,Aureon 7.1 Space},"
#define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */
#define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */
extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
/* GPIO bits */
#define AUREON_CS8415_CS (1 << 23)
#define AUREON_CS8415_CDTO (1 << 22)
#define AUREON_WM_RESET (1 << 20)
#define AUREON_WM_CLK (1 << 19)
#define AUREON_WM_DATA (1 << 18)
#define AUREON_WM_RW (1 << 17)
#define AUREON_AC97_RESET (1 << 16)
#define AUREON_DIGITAL_SEL1 (1 << 15)
#define AUREON_HP_SEL (1 << 14)
#define AUREON_WM_CS (1 << 12)
#endif /* __SOUND_AUREON_H */
......@@ -298,11 +298,13 @@ static snd_kcontrol_new_t snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
static void snd_ice1712_set_gpio_dir(ice1712_t *ice, unsigned int data)
{
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, data);
inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
}
static void snd_ice1712_set_gpio_mask(ice1712_t *ice, unsigned int data)
{
snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data);
inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
}
static unsigned int snd_ice1712_get_gpio_data(ice1712_t *ice)
......@@ -313,6 +315,7 @@ static unsigned int snd_ice1712_get_gpio_data(ice1712_t *ice)
static void snd_ice1712_set_gpio_data(ice1712_t *ice, unsigned int val)
{
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, val);
inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
}
......
......@@ -42,6 +42,7 @@
/* lowlevel routines */
#include "amp.h"
#include "revo.h"
#include "aureon.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)");
......@@ -50,6 +51,7 @@ MODULE_CLASSES("{sound}");
MODULE_DEVICES("{"
REVO_DEVICE_DESC
AMP_AUDIO2000_DEVICE_DESC
AUREON_DEVICE_DESC
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
"{ICEnsemble,Generic Envy24HT}}");
......@@ -172,6 +174,7 @@ static unsigned short snd_vt1724_ac97_read(ac97_t *ac97, unsigned short reg)
static void snd_vt1724_set_gpio_dir(ice1712_t *ice, unsigned int data)
{
outl(data, ICEREG1724(ice, GPIO_DIRECTION));
inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */
}
/* set the gpio mask (0 = writable) */
......@@ -179,12 +182,14 @@ static void snd_vt1724_set_gpio_mask(ice1712_t *ice, unsigned int data)
{
outw(data, ICEREG1724(ice, GPIO_WRITE_MASK));
outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22));
inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
}
static void snd_vt1724_set_gpio_data(ice1712_t *ice, unsigned int data)
{
outw(data, ICEREG1724(ice, GPIO_DATA));
outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22));
inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */
}
static unsigned int snd_vt1724_get_gpio_data(ice1712_t *ice)
......@@ -415,14 +420,16 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force
val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
if (val != old) {
outb(val, ICEMT1724(ice, I2S_FORMAT));
/* FIXME: is this revo only? */
/* assert PRST# to converters; MT05 bit 7 */
outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
spin_unlock_irqrestore(&ice->reg_lock, flags);
mdelay(5);
spin_lock_irqsave(&ice->reg_lock, flags);
/* deassert PRST# */
outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_REVOLUTION71) {
/* FIXME: is this revo only? */
/* assert PRST# to converters; MT05 bit 7 */
outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
spin_unlock_irqrestore(&ice->reg_lock, flags);
mdelay(5);
spin_lock_irqsave(&ice->reg_lock, flags);
/* deassert PRST# */
outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
}
}
}
spin_unlock_irqrestore(&ice->reg_lock, flags);
......@@ -1549,6 +1556,7 @@ static struct snd_ice1712_card_info no_matched __devinitdata;
static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_revo_cards,
snd_vt1724_amp_cards,
snd_vt1724_aureon_cards,
0,
};
......@@ -1572,6 +1580,7 @@ static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice)
{
int dev = 0xa0; /* EEPROM device address */
unsigned int i, size;
struct snd_ice1712_card_info **tbl, *c;
if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) == 0) {
snd_printk("ICE1724 has not detected EEPROM\n");
......@@ -1581,6 +1590,23 @@ static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice)
(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) |
(snd_vt1724_read_i2c(ice, dev, 0x02) << 16) |
(snd_vt1724_read_i2c(ice, dev, 0x03) << 24);
/* if the EEPROM is given by the driver, use it */
for (tbl = card_tables; *tbl; tbl++) {
for (c = *tbl; c->subvendor; c++) {
if (c->subvendor == ice->eeprom.subvendor) {
if (! c->eeprom_size || ! c->eeprom_data)
goto found;
snd_printdd("using the defined eeprom..\n");
ice->eeprom.version = 2;
ice->eeprom.size = c->eeprom_size + 6;
memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
goto read_skipped;
}
}
}
found:
ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04);
if (ice->eeprom.size < 6)
ice->eeprom.size = 32;
......@@ -1597,6 +1623,7 @@ static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice)
for (i = 0; i < size; i++)
ice->eeprom.data[i] = snd_vt1724_read_i2c(ice, dev, i + 6);
read_skipped:
ice->eeprom.gpiomask = eeprom_triple(ice, ICE_EEP2_GPIO_MASK);
ice->eeprom.gpiostate = eeprom_triple(ice, ICE_EEP2_GPIO_STATE);
ice->eeprom.gpiodir = eeprom_triple(ice, ICE_EEP2_GPIO_DIR);
......
......@@ -59,14 +59,14 @@ static void revo_set_rate_val(akm4xxx_t *ak, unsigned int rate)
reg = 1;
shift = 3;
}
tmp = ak->images[0][reg];
tmp = snd_akm4xxx_get(ak, 0, reg);
old = (tmp >> shift) & 0x03;
if (old == dfs)
return;
/* reset DFS */
snd_akm4xxx_reset(ak, 1);
tmp = ak->images[0][reg];
tmp = snd_akm4xxx_get(ak, 0, reg);
tmp &= ~(0x03 << shift);
tmp |= dfs << shift;
snd_akm4xxx_write(ak, 0, reg, tmp);
......@@ -121,6 +121,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
static int __devinit revo_init(ice1712_t *ice)
{
akm4xxx_t *ak;
int err;
/* determine I2C, DACs and ADCs */
switch (ice->eeprom.subvendor) {
......@@ -139,8 +140,10 @@ static int __devinit revo_init(ice1712_t *ice)
ice->akm_codecs = 2;
switch (ice->eeprom.subvendor) {
case VT1724_SUBDEVICE_REVOLUTION71:
snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice);
snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice);
if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0)
return err;
if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0)
return err;
/* unmute all codecs */
snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
break;
......
......@@ -564,6 +564,7 @@ static void snd_via82xx_channel_reset(via82xx_t *chip, viadev_t *viadev)
{
outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET,
VIADEV_REG(viadev, OFFSET_CONTROL));
inb(VIADEV_REG(viadev, OFFSET_CONTROL));
udelay(50);
/* disable interrupts */
outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL));
......
......@@ -1211,9 +1211,12 @@ static void snd_pmac_suspend(pmac_t *chip)
spin_lock_irqsave(&chip->reg_lock, flags);
snd_pmac_beep_stop(chip);
spin_unlock_irqrestore(&chip->reg_lock, flags);
disable_irq(chip->irq);
disable_irq(chip->tx_irq);
disable_irq(chip->rx_irq);
if (chip->irq >= 0)
disable_irq(chip->irq);
if (chip->tx_irq >= 0)
disable_irq(chip->tx_irq);
if (chip->rx_irq >= 0)
disable_irq(chip->rx_irq);
snd_pmac_sound_feature(chip, 0);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
}
......@@ -1237,9 +1240,12 @@ static void snd_pmac_resume(pmac_t *chip)
snd_pmac_pcm_set_format(chip);
enable_irq(chip->irq);
enable_irq(chip->tx_irq);
enable_irq(chip->rx_irq);
if (chip->irq >= 0)
enable_irq(chip->irq);
if (chip->tx_irq >= 0)
enable_irq(chip->tx_irq);
if (chip->rx_irq >= 0)
enable_irq(chip->rx_irq);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
}
......
......@@ -27,6 +27,7 @@
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <asm/io.h>
#include <asm/irq.h>
......@@ -79,7 +80,7 @@ typedef struct pmac_gpio {
int active_state;
} pmac_gpio_t;
typedef struct pmac_tumber_t {
typedef struct pmac_tumbler_t {
pmac_keywest_t i2c;
pmac_gpio_t audio_reset;
pmac_gpio_t amp_mute;
......@@ -92,11 +93,12 @@ typedef struct pmac_tumber_t {
unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
int drc_range;
int drc_enable;
#ifdef CONFIG_PMAC_PBOOK
struct work_struct resume_workq;
#endif
} pmac_tumbler_t;
#define number_of(ary) (sizeof(ary) / sizeof(ary[0]))
/*
*/
......@@ -168,16 +170,16 @@ static int tumbler_set_master_volume(pmac_tumbler_t *mix)
left_vol = 0;
else {
left_vol = mix->master_vol[0];
if (left_vol >= number_of(master_volume_table))
left_vol = number_of(master_volume_table) - 1;
if (left_vol >= ARRAY_SIZE(master_volume_table))
left_vol = ARRAY_SIZE(master_volume_table) - 1;
left_vol = master_volume_table[left_vol];
}
if (! mix->master_switch[1])
right_vol = 0;
else {
right_vol = mix->master_vol[1];
if (right_vol >= number_of(master_volume_table))
right_vol = number_of(master_volume_table) - 1;
if (right_vol >= ARRAY_SIZE(master_volume_table))
right_vol = ARRAY_SIZE(master_volume_table) - 1;
right_vol = master_volume_table[right_vol];
}
......@@ -203,7 +205,7 @@ static int tumbler_info_master_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_inf
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = number_of(master_volume_table) - 1;
uinfo->value.integer.max = ARRAY_SIZE(master_volume_table) - 1;
return 0;
}
......@@ -479,7 +481,7 @@ static struct tumbler_mono_vol tumbler_pcm_vol_info = {
.index = VOL_IDX_PCM_MONO,
.reg = TAS_REG_PCM,
.bytes = 3,
.max = number_of(mixer_volume_table),
.max = ARRAY_SIZE(mixer_volume_table),
.table = mixer_volume_table,
};
......@@ -487,7 +489,7 @@ static struct tumbler_mono_vol tumbler_bass_vol_info = {
.index = VOL_IDX_BASS,
.reg = TAS_REG_BASS,
.bytes = 1,
.max = number_of(bass_volume_table),
.max = ARRAY_SIZE(bass_volume_table),
.table = bass_volume_table,
};
......@@ -495,7 +497,7 @@ static struct tumbler_mono_vol tumbler_treble_vol_info = {
.index = VOL_IDX_TREBLE,
.reg = TAS_REG_TREBLE,
.bytes = 1,
.max = number_of(treble_volume_table),
.max = ARRAY_SIZE(treble_volume_table),
.table = treble_volume_table,
};
......@@ -504,7 +506,7 @@ static struct tumbler_mono_vol snapper_bass_vol_info = {
.index = VOL_IDX_BASS,
.reg = TAS_REG_BASS,
.bytes = 1,
.max = number_of(snapper_bass_volume_table),
.max = ARRAY_SIZE(snapper_bass_volume_table),
.table = snapper_bass_volume_table,
};
......@@ -512,7 +514,7 @@ static struct tumbler_mono_vol snapper_treble_vol_info = {
.index = VOL_IDX_TREBLE,
.reg = TAS_REG_TREBLE,
.bytes = 1,
.max = number_of(snapper_treble_volume_table),
.max = ARRAY_SIZE(snapper_treble_volume_table),
.table = snapper_treble_volume_table,
};
......@@ -546,8 +548,8 @@ static int snapper_set_mix_vol1(pmac_tumbler_t *mix, int idx, int ch, int reg)
unsigned char block[9];
vol = mix->mix_vol[idx][ch];
if (vol >= number_of(mixer_volume_table)) {
vol = number_of(mixer_volume_table) - 1;
if (vol >= ARRAY_SIZE(mixer_volume_table)) {
vol = ARRAY_SIZE(mixer_volume_table) - 1;
mix->mix_vol[idx][ch] = vol;
}
......@@ -579,7 +581,7 @@ static int snapper_info_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = number_of(mixer_volume_table) - 1;
uinfo->value.integer.max = ARRAY_SIZE(mixer_volume_table) - 1;
return 0;
}
......@@ -877,29 +879,47 @@ static void tumbler_reset_audio(pmac_t *chip)
#ifdef CONFIG_PMAC_PBOOK
/* resume mixer */
static void tumbler_resume(pmac_t *chip)
/* we call the i2c transfer in a workqueue because it may need either schedule()
* or completion from timer interrupts.
*/
static void tumbler_resume_work(void *arg)
{
pmac_t *chip = (pmac_t *)arg;
pmac_tumbler_t *mix = chip->mixer_data;
snd_assert(mix, return);
tumbler_reset_audio(chip);
if (mix->i2c.client)
tumbler_init_client(&mix->i2c);
if (mix->i2c.client) {
if (tumbler_init_client(&mix->i2c) < 0)
printk(KERN_ERR "tumbler_init_client error\n");
} else
printk(KERN_ERR "tumbler: i2c is not initialized\n");
if (chip->model == PMAC_TUMBLER) {
tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
tumbler_set_drc(mix);
} else {
snapper_set_mix_vol(mix, VOL_IDX_PCM);
snapper_set_mix_vol(mix, VOL_IDX_PCM2);
snapper_set_mix_vol(mix, VOL_IDX_ADC);
tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
snapper_set_drc(mix);
}
tumbler_set_drc(mix);
tumbler_set_master_volume(mix);
if (chip->update_automute)
chip->update_automute(chip, 0);
}
static void tumbler_resume(pmac_t *chip)
{
pmac_tumbler_t *mix = chip->mixer_data;
snd_assert(mix, return);
INIT_WORK(&mix->resume_workq, tumbler_resume_work, chip);
if (schedule_work(&mix->resume_workq))
return;
printk(KERN_ERR "ALSA tumbler: cannot schedule resume-workqueue.\n");
}
#endif
/* initialize tumbler */
......@@ -1001,12 +1021,12 @@ int __init snd_pmac_tumbler_init(pmac_t *chip)
sprintf(chip->card->mixername, "PowerMac %s", chipname);
if (chip->model == PMAC_TUMBLER) {
for (i = 0; i < number_of(tumbler_mixers); i++) {
for (i = 0; i < ARRAY_SIZE(tumbler_mixers); i++) {
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0)
return err;
}
} else {
for (i = 0; i < number_of(snapper_mixers); i++) {
for (i = 0; i < ARRAY_SIZE(snapper_mixers); i++) {
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0)
return err;
}
......
......@@ -55,6 +55,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 vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
static int nrpacks = 4; /* max. number of packets per urb */
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
......@@ -71,6 +72,9 @@ MODULE_PARM_SYNTAX(vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
MODULE_PARM(pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
MODULE_PARM(nrpacks, "i");
MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}");
/*
......@@ -98,7 +102,7 @@ MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
*
*/
#define NRPACKS 4 /* 4ms per urb */
#define MAX_PACKS 10
#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 */
......@@ -176,7 +180,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 * NRPACKS * 3]; /* sync buffer; it's so small - let's get static */
char syncbuf[SYNC_URBS * MAX_PACKS * 3]; /* sync buffer; it's so small - let's get static */
char *tmpbuf; /* temporary buffer for playback */
u64 formats; /* format bitmasks (all or'ed) */
......@@ -839,7 +843,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
/* allocate a temporary buffer for playback */
if (is_playback) {
subs->tmpbuf = kmalloc(maxsize * NRPACKS, GFP_KERNEL);
subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL);
if (! subs->tmpbuf) {
snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
return -ENOMEM;
......@@ -850,16 +854,16 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
total_packs = (frames_to_bytes(runtime, runtime->period_size) + 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 + nrpacks - 1) / nrpacks;
if (subs->nurbs > MAX_URBS) {
/* too much... */
subs->nurbs = MAX_URBS;
total_packs = MAX_URBS * NRPACKS;
total_packs = MAX_URBS * nrpacks;
}
n = total_packs;
for (i = 0; i < subs->nurbs; i++) {
npacks[i] = n > NRPACKS ? NRPACKS : n;
n -= NRPACKS;
npacks[i] = n > nrpacks ? nrpacks : n;
n -= nrpacks;
}
if (subs->nurbs <= 1) {
/* too little - we need at least two packets
......@@ -918,14 +922,14 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
snd_urb_ctx_t *u = &subs->syncurb[i];
u->index = i;
u->subs = subs;
u->packets = NRPACKS;
u->packets = nrpacks;
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
if (! u->urb) {
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 * 3;
u->urb->transfer_buffer_length = nrpacks * 3;
u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS;
......@@ -1096,16 +1100,6 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
attr = fmt->ep_attr & EP_ATTR_MASK;
if ((is_playback && attr == EP_ATTR_ASYNC) ||
(! is_playback && attr == EP_ATTR_ADAPTIVE)) {
/*
* QUIRK: plantronics headset has adaptive-in
* although it's really not...
*/
if ((dev->descriptor.idVendor == 0x047f &&
dev->descriptor.idProduct == 0x0ca1) ||
/* Griffin iMic (note that there is an older model 77d:223) */
(dev->descriptor.idVendor == 0x077d &&
dev->descriptor.idProduct == 0x07af))
goto _ok;
/* check endpoint */
if (altsd->bNumEndpoints < 2 ||
get_endpoint(alts, 1)->bmAttributes != 0x01 ||
......@@ -1129,7 +1123,6 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
}
_ok:
if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 ||
(err = init_usb_sample_rate(dev, subs->interface, alts, fmt,
runtime->rate)) < 0)
......@@ -1497,7 +1490,7 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
/* set the period time minimum 1ms */
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
1000 * MIN_PACKS_URB,
/*(NRPACKS * MAX_URBS) * 1000*/ UINT_MAX);
/*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
if (check_hw_params_convention(subs)) {
hwc_debug("setting extra hw constraints...\n");
......@@ -1656,11 +1649,9 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
* entry point for linux usb interface
*/
#ifndef OLD_USB
static int usb_audio_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_audio_disconnect(struct usb_interface *intf);
#endif
static struct usb_device_id usb_audio_ids [] = {
#include "usbquirks.h"
......@@ -1677,9 +1668,6 @@ static struct usb_driver usb_audio_driver = {
.name = "snd-usb-audio",
.probe = usb_audio_probe,
.disconnect = usb_audio_disconnect,
#ifdef OLD_USB
.driver_list = LIST_HEAD_INIT(usb_audio_driver.driver_list),
#endif
.id_table = usb_audio_ids,
};
......@@ -1944,7 +1932,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat
switch (format) {
case 0: /* some devices don't define this correctly... */
snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
dev->devnum, iface_no, altno);
dev->devnum, fp->iface, fp->altsetting);
/* fall-through */
case USB_AUDIO_FORMAT_PCM:
if (sample_width > sample_bytes * 8) {
......@@ -2238,6 +2226,33 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
fp->attributes = csep[3];
/* some quirks for attributes here */
/* workaround for AudioTrak Optoplay */
if (dev->descriptor.idVendor == 0x0a92 &&
dev->descriptor.idProduct == 0x0053) {
/* Optoplay sets the sample rate attribute although
* it seems not supporting it in fact.
*/
fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
}
/*
* plantronics headset and Griffin iMic have set adaptive-in
* although it's really not...
*/
if ((dev->descriptor.idVendor == 0x047f &&
dev->descriptor.idProduct == 0x0ca1) ||
/* Griffin iMic (note that there is an older model 77d:223) */
(dev->descriptor.idVendor == 0x077d &&
dev->descriptor.idProduct == 0x07af)) {
fp->ep_attr &= ~EP_ATTR_MASK;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
fp->ep_attr |= EP_ATTR_ADAPTIVE;
else
fp->ep_attr |= EP_ATTR_SYNC;
}
/* ok, let's parse further... */
if (parse_audio_format(dev, fp, format, fmt, stream) < 0) {
if (fp->rate_table)
kfree(fp->rate_table);
......@@ -2461,6 +2476,11 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
/*
* audio-interface quirks
*
* returns zero if no standard audio/MIDI parsing is needed.
* returns a postive value if standard audio/midi interfaces are parsed
* after this.
* returns a negative value at error.
*/
static int snd_usb_create_quirk(snd_usb_audio_t *chip,
struct usb_interface *iface,
......@@ -2749,7 +2769,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
}
}
#ifndef OLD_USB
/*
* new 2.5 USB kernel API
*/
......@@ -2770,12 +2789,14 @@ static void usb_audio_disconnect(struct usb_interface *intf)
snd_usb_audio_disconnect(interface_to_usbdev(intf),
dev_get_drvdata(&intf->dev));
}
#endif
static int __init snd_usb_audio_init(void)
{
if (nrpacks < 2 || nrpacks > MAX_PACKS) {
printk(KERN_WARNING "invalid nrpacks value.\n");
return -EINVAL;
}
usb_register(&usb_audio_driver);
return 0;
}
......
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