dect
/
linux-2.6
Archived
13
0
Fork 0

Merge HEAD from master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa

This commit is contained in:
Linus Torvalds 2005-08-30 07:47:01 -07:00
commit 444bd6fc18
84 changed files with 2033 additions and 700 deletions

View File

@ -132,6 +132,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
mpu_irq - IRQ # for MPU-401 UART (PnP setup)
dma1 - first DMA # for AD1816A chip (PnP setup)
dma2 - second DMA # for AD1816A chip (PnP setup)
clockfreq - Clock frequency for AD1816A chip (default = 0, 33000Hz)
Module supports up to 8 cards, autoprobe and PnP.

View File

@ -3422,10 +3422,17 @@ struct _snd_pcm_runtime {
<para>
The <structfield>iface</structfield> field specifies the type of
the control,
<constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>. There are
<constant>MIXER</constant>, <constant>PCM</constant>,
<constant>CARD</constant>, etc.
the control, <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>, which
is usually <constant>MIXER</constant>.
Use <constant>CARD</constant> for global controls that are not
logically part of the mixer.
If the control is closely associated with some specific device on
the sound card, use <constant>HWDEP</constant>,
<constant>PCM</constant>, <constant>RAWMIDI</constant>,
<constant>TIMER</constant>, or <constant>SEQUENCER</constant>, and
specify the device number with the
<structfield>device</structfield> and
<structfield>subdevice</structfield> fields.
</para>
<para>

View File

@ -29,7 +29,9 @@
* Sound core interface functions
*/
struct device;
extern int register_sound_special(struct file_operations *fops, int unit);
extern int register_sound_special_device(struct file_operations *fops, int unit, struct device *dev);
extern int register_sound_mixer(struct file_operations *fops, int dev);
extern int register_sound_midi(struct file_operations *fops, int dev);
extern int register_sound_dsp(struct file_operations *fops, int dev);

View File

@ -26,6 +26,7 @@
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include "pcm.h"
#include "control.h"
#include "info.h"
@ -374,6 +375,9 @@
#define AC97_HAS_NO_PC_BEEP (1<<12) /* no PC Beep volume */
#define AC97_HAS_NO_VIDEO (1<<13) /* no Video volume */
#define AC97_HAS_NO_CD (1<<14) /* no CD volume */
#define AC97_HAS_NO_MIC (1<<15) /* no MIC volume */
#define AC97_HAS_NO_TONE (1<<16) /* no Tone volume */
#define AC97_HAS_NO_STD_PCM (1<<17) /* no standard AC97 PCM volume and mute */
/* rates indexes */
#define AC97_RATES_FRONT_DAC 0
@ -520,6 +524,7 @@ struct _snd_ac97 {
/* jack-sharing info */
unsigned char indep_surround;
unsigned char channel_mode;
struct device dev;
};
/* conditions */
@ -599,4 +604,8 @@ struct ac97_enum {
unsigned short mask;
const char **texts;
};
/* ad hoc AC97 device driver access */
extern struct bus_type ac97_bus_type;
#endif /* __SOUND_AC97_CODEC_H */

View File

@ -138,6 +138,7 @@ struct _snd_ad1816a {
spinlock_t lock;
unsigned short mode;
unsigned int clock_freq;
snd_card_t *card;
snd_pcm_t *pcm;

View File

@ -560,7 +560,7 @@ enum {
* Timer section - /dev/snd/timer
*/
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5)
enum sndrv_timer_class {
SNDRV_TIMER_CLASS_NONE = -1,
@ -693,11 +693,15 @@ enum sndrv_timer_event {
SNDRV_TIMER_EVENT_CONTINUE, /* val = resolution in ns */
SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */
SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */
SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */
SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */
/* master timer events for slave timer instances */
SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
};
struct sndrv_timer_tread {

View File

@ -1748,7 +1748,7 @@ int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
int snd_cs46xx_pcm_center_lfe(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
int snd_cs46xx_mixer(cs46xx_t *chip);
int snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device);
int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
int snd_cs46xx_start_dsp(cs46xx_t *chip);
int snd_cs46xx_gameport(cs46xx_t *chip);

View File

@ -1178,7 +1178,7 @@ int snd_p16v_free(emu10k1_t * emu);
int snd_p16v_mixer(emu10k1_t * emu);
int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
int snd_emu10k1_mixer(emu10k1_t * emu);
int snd_emu10k1_mixer(emu10k1_t * emu, int pcm_device, int multi_device);
int snd_emu10k1_timer(emu10k1_t * emu, int device);
int snd_emu10k1_fx8010_new(emu10k1_t *emu, int device, snd_hwdep_t ** rhwdep);

View File

@ -512,13 +512,13 @@ extern void snd_gf1_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
extern void snd_gf1_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
extern unsigned char snd_gf1_look8(snd_gus_card_t * gus, unsigned char reg);
extern inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
static inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
{
return snd_gf1_look8(gus, reg | 0x80);
}
extern void snd_gf1_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
extern unsigned short snd_gf1_look16(snd_gus_card_t * gus, unsigned char reg);
extern inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
static inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
{
return snd_gf1_look16(gus, reg | 0x80);
}
@ -532,12 +532,12 @@ extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
extern void snd_gf1_i_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
extern unsigned char snd_gf1_i_look8(snd_gus_card_t * gus, unsigned char reg);
extern void snd_gf1_i_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
extern inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
static inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
{
return snd_gf1_i_look8(gus, reg | 0x80);
}
extern unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg);
extern inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
static inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
{
return snd_gf1_i_look16(gus, reg | 0x80);
}

View File

@ -379,7 +379,6 @@ struct _snd_pcm_substream {
unsigned int dma_buf_id;
size_t dma_max;
/* -- hardware operations -- */
unsigned int open_flag: 1; /* lowlevel device has been opened */
snd_pcm_ops_t *ops;
/* -- runtime information -- */
snd_pcm_runtime_t *runtime;

View File

@ -1,3 +1,3 @@
/* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "1.0.9b"
#define CONFIG_SND_DATE " (Thu Jul 28 12:20:13 2005 UTC)"
#define CONFIG_SND_VERSION "1.0.10rc1"
#define CONFIG_SND_DATE " (Tue Aug 30 05:31:08 2005 UTC)"

View File

@ -295,6 +295,7 @@ struct _snd_ymfpci_pcm {
unsigned int running: 1;
unsigned int output_front: 1;
unsigned int output_rear: 1;
unsigned int update_pcm_vol;
u32 period_size; /* cached from runtime->period_size */
u32 buffer_size; /* cached from runtime->buffer_size */
u32 period_pos;
@ -367,6 +368,11 @@ struct _snd_ymfpci {
int mode_dup4ch;
int rear_opened;
int spdif_opened;
struct {
u16 left;
u16 right;
snd_kcontrol_t *ctl;
} pcm_mixer[32];
spinlock_t reg_lock;
spinlock_t voice_lock;

View File

@ -132,9 +132,9 @@ static void pxa2xx_ac97_reset(ac97_t *ac97)
udelay(10);
GCR |= GCR_WARM_RST;
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
udelay(50);
udelay(500);
#else
GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;;
GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
#endif
@ -261,7 +261,7 @@ static int pxa2xx_ac97_do_suspend(snd_card_t *card, unsigned int state)
return 0;
}
static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
static int pxa2xx_ac97_do_resume(snd_card_t *card)
{
if (card->power_state != SNDRV_CTL_POWER_D0) {
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@ -275,13 +275,13 @@ static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
return 0;
}
static int pxa2xx_ac97_suspend(struct device *_dev, u32 state, u32 level)
static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state, u32 level)
{
snd_card_t *card = dev_get_drvdata(_dev);
int ret = 0;
if (card && level == SUSPEND_DISABLE)
ret = pxa2xx_ac97_do_suspend(card, SNDRV_CTL_POWER_D3cold);
ret = pxa2xx_ac97_do_suspend(card, PMSG_SUSPEND);
return ret;
}
@ -292,7 +292,7 @@ static int pxa2xx_ac97_resume(struct device *_dev, u32 level)
int ret = 0;
if (card && level == RESUME_ENABLE)
ret = pxa2xx_ac97_do_resume(card, SNDRV_CTL_POWER_D0);
ret = pxa2xx_ac97_do_resume(card);
return ret;
}

View File

@ -512,7 +512,7 @@ static void free_all_reserved_pages(void)
* proc file interface
*/
#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
struct proc_dir_entry *snd_mem_proc;
static struct proc_dir_entry *snd_mem_proc;
static int snd_mem_proc_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
@ -655,8 +655,7 @@ static int __init snd_mem_init(void)
static void __exit snd_mem_exit(void)
{
if (snd_mem_proc)
remove_proc_entry(SND_MEM_PROC_FILE, NULL);
remove_proc_entry(SND_MEM_PROC_FILE, NULL);
free_all_reserved_pages();
if (snd_allocated_pages > 0)
printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);

View File

@ -56,7 +56,7 @@ static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
#define VMALLOC_MAGIC 0x87654320
static snd_info_entry_t *snd_memory_info_entry;
void snd_memory_init(void)
void __init snd_memory_init(void)
{
snd_alloc_kmalloc = 0;
snd_alloc_vmalloc = 0;

View File

@ -1705,13 +1705,12 @@ static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
if (snd_pcm_running(substream))
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
snd_pcm_stream_unlock_irq(substream);
if (substream->open_flag) {
if (substream->ffile != NULL) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
substream->open_flag = 0;
substream->ffile = NULL;
}
substream->ffile = NULL;
snd_pcm_oss_release_substream(substream);
snd_pcm_release_substream(substream);
}
@ -1778,14 +1777,13 @@ static int snd_pcm_oss_open_file(struct file *file,
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
psubstream->open_flag = 1;
psubstream->ffile = file;
err = snd_pcm_hw_constraints_complete(psubstream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraint_complete failed\n");
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
psubstream->ffile = file;
snd_pcm_oss_init_substream(psubstream, psetup, minor);
}
if (csubstream != NULL) {
@ -1800,14 +1798,13 @@ static int snd_pcm_oss_open_file(struct file *file,
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
csubstream->open_flag = 1;
csubstream->ffile = file;
err = snd_pcm_hw_constraints_complete(csubstream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraint_complete failed\n");
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
csubstream->ffile = file;
snd_pcm_oss_init_substream(csubstream, csetup, minor);
}

View File

@ -103,10 +103,24 @@ struct sndrv_pcm_sw_params32 {
unsigned char reserved[64];
};
/* recalcuate the boundary within 32bit */
static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
{
snd_pcm_uframes_t boundary;
if (! runtime->buffer_size)
return 0;
boundary = runtime->buffer_size;
while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
boundary *= 2;
return boundary;
}
static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
struct sndrv_pcm_sw_params32 __user *src)
{
snd_pcm_sw_params_t params;
snd_pcm_uframes_t boundary;
int err;
memset(&params, 0, sizeof(params));
@ -120,10 +134,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
get_user(params.silence_threshold, &src->silence_threshold) ||
get_user(params.silence_size, &src->silence_size))
return -EFAULT;
/*
* Check silent_size parameter. Since we have 64bit boundary,
* silence_size must be compared with the 32bit boundary.
*/
boundary = recalculate_boundary(substream->runtime);
if (boundary && params.silence_size >= boundary)
params.silence_size = substream->runtime->boundary;
err = snd_pcm_sw_params(substream, &params);
if (err < 0)
return err;
if (put_user(params.boundary, &src->boundary))
if (boundary && put_user(boundary, &src->boundary))
return -EFAULT;
return err;
}
@ -199,16 +220,6 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
return err;
}
/* recalcuate the boundary within 32bit */
static void recalculate_boundary(snd_pcm_runtime_t *runtime)
{
if (! runtime->buffer_size)
return;
runtime->boundary = runtime->buffer_size;
while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
runtime->boundary *= 2;
}
/* both for HW_PARAMS and HW_REFINE */
static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
int refine,
@ -241,8 +252,11 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
goto error;
}
if (! refine)
recalculate_boundary(runtime);
if (! refine) {
unsigned int new_boundary = recalculate_boundary(runtime);
if (new_boundary)
runtime->boundary = new_boundary;
}
error:
kfree(data);
return err;
@ -380,6 +394,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
u32 sflags;
struct sndrv_pcm_mmap_control scontrol;
struct sndrv_pcm_mmap_status sstatus;
snd_pcm_uframes_t boundary;
int err;
snd_assert(runtime, return -EINVAL);
@ -395,17 +410,21 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
}
status = runtime->status;
control = runtime->control;
boundary = recalculate_boundary(runtime);
if (! boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr;
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
snd_pcm_stream_unlock_irq(substream);

View File

@ -1584,8 +1584,8 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
return snd_pcm_hw_param_value(params, var, NULL);
}
int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, const snd_mask_t *val)
static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, const snd_mask_t *val)
{
int changed;
assert(hw_is_mask(var));
@ -2063,7 +2063,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
if (((avail < runtime->control->avail_min && size > avail) ||
(size >= runtime->xfer_align && avail < runtime->xfer_align))) {
wait_queue_t wait;
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
long tout;
if (nonblock) {
@ -2097,6 +2097,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
case SNDRV_PCM_STATE_SUSPENDED:
state = SUSPENDED;
goto _end_loop;
case SNDRV_PCM_STATE_SETUP:
state = DROPPED;
goto _end_loop;
default:
break;
}
@ -2123,6 +2126,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
snd_printd("playback write error (DMA or IRQ trouble?)\n");
err = -EIO;
goto _end_unlock;
case DROPPED:
err = -EBADFD;
goto _end_unlock;
default:
break;
}
@ -2359,7 +2365,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
} else if ((avail < runtime->control->avail_min && size > avail) ||
(size >= runtime->xfer_align && avail < runtime->xfer_align)) {
wait_queue_t wait;
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
long tout;
if (nonblock) {
@ -2394,6 +2400,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
goto _end_loop;
case SNDRV_PCM_STATE_DRAINING:
goto __draining;
case SNDRV_PCM_STATE_SETUP:
state = DROPPED;
goto _end_loop;
default:
break;
}
@ -2420,6 +2429,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
snd_printd("capture read error (DMA or IRQ trouble?)\n");
err = -EIO;
goto _end_unlock;
case DROPPED:
err = -EBADFD;
goto _end_unlock;
default:
break;
}

View File

@ -1025,7 +1025,7 @@ static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp);
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
snd_pcm_tick_set(substream, 0);
@ -1115,7 +1115,7 @@ static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp);
runtime->status->state = runtime->status->suspended_state;
if (runtime->sleep_min)
snd_pcm_tick_prepare(substream);
@ -1967,13 +1967,12 @@ static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
runtime = substream->runtime;
str = substream->pstr;
snd_pcm_unlink(substream);
if (substream->open_flag) {
if (substream->ffile != NULL) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
substream->open_flag = 0;
substream->ffile = NULL;
}
substream->ffile = NULL;
snd_pcm_remove_file(str, pcm_file);
snd_pcm_release_substream(substream);
kfree(pcm_file);
@ -2022,18 +2021,15 @@ static int snd_pcm_open_file(struct file *file,
snd_pcm_release_file(pcm_file);
return err;
}
substream->open_flag = 1;
substream->ffile = file;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_complete failed\n");
substream->ops->close(substream);
snd_pcm_release_file(pcm_file);
return err;
}
substream->ffile = file;
file->private_data = pcm_file;
*rpcm_file = pcm_file;
return 0;

View File

@ -98,6 +98,7 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
int cidx = SNDRV_MINOR_OSS_CARD(minor);
int track2 = -1;
int register1 = -1, register2 = -1;
struct device *carddev = NULL;
if (minor < 0)
return minor;
@ -121,11 +122,13 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
register1 = register_sound_special(reg->f_ops, minor);
if (card)
carddev = card->dev;
register1 = register_sound_special_device(reg->f_ops, minor, carddev);
if (register1 != minor)
goto __end;
if (track2 >= 0) {
register2 = register_sound_special(reg->f_ops, track2);
register2 = register_sound_special_device(reg->f_ops, track2, carddev);
if (register2 != track2)
goto __end;
}

View File

@ -799,13 +799,13 @@ static int snd_timer_free(snd_timer_t *timer)
return 0;
}
int snd_timer_dev_free(snd_device_t *device)
static int snd_timer_dev_free(snd_device_t *device)
{
snd_timer_t *timer = device->device_data;
return snd_timer_free(timer);
}
int snd_timer_dev_register(snd_device_t *dev)
static int snd_timer_dev_register(snd_device_t *dev)
{
snd_timer_t *timer = dev->device_data;
snd_timer_t *timer1;
@ -880,9 +880,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
struct list_head *p, *n;
snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);
snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return);
spin_lock_irqsave(&timer->lock, flags);
if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
event == SNDRV_TIMER_EVENT_MRESUME) {
if (timer->hw.c_resolution)
resolution = timer->hw.c_resolution(timer);
else
@ -1555,10 +1557,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
(1<<SNDRV_TIMER_EVENT_STOP)|
(1<<SNDRV_TIMER_EVENT_CONTINUE)|
(1<<SNDRV_TIMER_EVENT_PAUSE)|
(1<<SNDRV_TIMER_EVENT_SUSPEND)|
(1<<SNDRV_TIMER_EVENT_RESUME)|
(1<<SNDRV_TIMER_EVENT_MSTART)|
(1<<SNDRV_TIMER_EVENT_MSTOP)|
(1<<SNDRV_TIMER_EVENT_MCONTINUE)|
(1<<SNDRV_TIMER_EVENT_MPAUSE))) {
(1<<SNDRV_TIMER_EVENT_MPAUSE)|
(1<<SNDRV_TIMER_EVENT_MSUSPEND)|
(1<<SNDRV_TIMER_EVENT_MRESUME))) {
err = -EINVAL;
goto _end;
}

View File

@ -796,14 +796,14 @@ static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontro
static snd_kcontrol_new_t vx_control_iec958_mask = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = vx_iec958_info, /* shared */
.get = vx_iec958_mask_get,
};
static snd_kcontrol_new_t vx_control_iec958 = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = vx_iec958_info,
.get = vx_iec958_get,

View File

@ -549,8 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe)
static snd_pcm_hardware_t vx_pcm_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
/*SNDRV_PCM_INFO_RESUME*/),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,
@ -949,8 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = {
static snd_pcm_hardware_t vx_pcm_capture_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
/*SNDRV_PCM_INFO_RESUME*/),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,

View File

@ -53,6 +53,7 @@ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
static int clockfreq[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard.");
@ -74,6 +75,8 @@ module_param_array(dma1, int, NULL, 0444);
MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
module_param_array(dma2, int, NULL, 0444);
MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
module_param_array(clockfreq, int, NULL, 0444);
MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
struct snd_card_ad1816a {
struct pnp_dev *dev;
@ -209,6 +212,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
snd_card_free(card);
return error;
}
if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000)
chip->clock_freq = clockfreq[dev];
strcpy(card->driver, "AD1816A");
strcpy(card->shortname, "ADI SoundPort AD1816A");

View File

@ -234,7 +234,7 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
ad1816a_t *chip = snd_pcm_substream_chip(substream);
unsigned long flags;
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int size;
unsigned int size, rate;
spin_lock_irqsave(&chip->lock, flags);
@ -245,7 +245,10 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
snd_dma_program(chip->dma1, runtime->dma_addr, size,
DMA_MODE_WRITE | DMA_AUTOINIT);
snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, runtime->rate);
rate = runtime->rate;
if (chip->clock_freq)
rate = (rate * 33000) / chip->clock_freq;
snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, rate);
snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
snd_ad1816a_get_format(chip, runtime->format,
@ -263,7 +266,7 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
ad1816a_t *chip = snd_pcm_substream_chip(substream);
unsigned long flags;
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int size;
unsigned int size, rate;
spin_lock_irqsave(&chip->lock, flags);
@ -274,7 +277,10 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
snd_dma_program(chip->dma2, runtime->dma_addr, size,
DMA_MODE_READ | DMA_AUTOINIT);
snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, runtime->rate);
rate = runtime->rate;
if (chip->clock_freq)
rate = (rate * 33000) / chip->clock_freq;
snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
snd_ad1816a_get_format(chip, runtime->format,

View File

@ -1196,6 +1196,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un
.put = snd_ad1848_put_double,
},
[AD1848_MIX_CAPTURE] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_ad1848_info_mux,
.get = snd_ad1848_get_mux,
.put = snd_ad1848_put_mux,

View File

@ -194,8 +194,8 @@ AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4
AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
AD1848_SINGLE("IEC958 Input Capture Switch", 0, CMI8330_RMUX3D, 7, 1, 1),
AD1848_SINGLE("IEC958 Input Playback Switch", 0, CMI8330_MUTEMUX, 7, 1, 1),
AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
};
#ifdef ENABLE_SB_MIXER

View File

@ -1346,6 +1346,8 @@ static void snd_cs4231_suspend(cs4231_t *chip)
int reg;
unsigned long flags;
if (chip->pcm)
snd_pcm_suspend_all(chip->pcm);
spin_lock_irqsave(&chip->reg_lock, flags);
for (reg = 0; reg < 32; reg++)
chip->image[reg] = snd_cs4231_in(chip, reg);

View File

@ -269,8 +269,9 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg,
#endif /* 0 */
unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
unsigned char reg, short w_16bit)
#ifdef CONFIG_SND_DEBUG
static unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
unsigned char reg, short w_16bit)
{
unsigned int res;
unsigned long flags;
@ -280,6 +281,7 @@ unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
spin_unlock_irqrestore(&gus->reg_lock, flags);
return res;
}
#endif
/*

View File

@ -145,6 +145,14 @@ static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
#ifdef CONFIG_PNP
static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = {
{ .id = "YMH0021" },
{ .id = "NMX2210" }, /* Gateway Solo 2500 */
{ .id = "" } /* end */
};
MODULE_DEVICE_TABLE(pnp, snd_opl3sa2_pnpbiosids);
static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
/* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
{ .id = "YMH0020", .devs = { { "YMH0021" } } },
@ -568,20 +576,18 @@ static int snd_opl3sa2_resume(snd_card_t *card)
#ifdef CONFIG_PNP
static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
struct pnp_card_link *card,
const struct pnp_card_device_id *id)
struct pnp_dev *pdev,
int isapnp)
{
struct pnp_dev *pdev;
struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
struct pnp_resource_table * cfg;
int err;
if (!isapnp && pnp_device_is_isapnp(pdev))
return -ENOENT; /* we have another procedure - card */
cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
pdev = chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
if (chip->dev == NULL) {
kfree(cfg);
return -EBUSY;
}
/* PnP initialization */
pnp_init_resource_table(cfg);
if (sb_port[dev] != SNDRV_AUTO_PORT)
@ -601,7 +607,7 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
if (irq[dev] != SNDRV_AUTO_IRQ)
pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
err = pnp_manual_config_dev(pdev, cfg, 0);
if (err < 0)
if (err < 0 && isapnp)
snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
@ -617,13 +623,31 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
dma1[dev] = pnp_dma(pdev, 0);
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
snd_printdd("PnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
snd_printdd("PnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
port[dev], dma1[dev], dma2[dev], irq[dev]);
snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
kfree(cfg);
chip->dev = pdev;
return 0;
}
static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *chip,
struct pnp_card_link *card,
const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
if (pdev == NULL) {
kfree(cfg);
return -EBUSY;
}
return snd_opl3sa2_pnp(dev, chip, pdev, 1);
}
#endif /* CONFIG_PNP */
static int snd_opl3sa2_free(opl3sa2_t *chip)
@ -645,6 +669,7 @@ static int snd_opl3sa2_dev_free(snd_device_t *device)
}
static int __devinit snd_opl3sa2_probe(int dev,
struct pnp_dev *pdev,
struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
{
@ -695,8 +720,13 @@ static int __devinit snd_opl3sa2_probe(int dev,
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
goto __error;
#ifdef CONFIG_PNP
if (isapnp[dev]) {
if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0)
if (pdev) {
if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0)
goto __error;
snd_card_set_dev(card, &pdev->dev);
}
if (pcard) {
if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0)
goto __error;
snd_card_set_dev(card, &pcard->card->dev);
}
@ -768,7 +798,9 @@ static int __devinit snd_opl3sa2_probe(int dev,
if ((err = snd_card_register(card)) < 0)
goto __error;
if (pcard)
if (pdev)
pnp_set_drvdata(pdev, card);
else if (pcard)
pnp_set_card_drvdata(pcard, card);
else
snd_opl3sa2_legacy[dev] = card;
@ -780,8 +812,8 @@ static int __devinit snd_opl3sa2_probe(int dev,
}
#ifdef CONFIG_PNP
static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
const struct pnp_card_device_id *id)
static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
const struct pnp_device_id *id)
{
static int dev;
int res;
@ -789,7 +821,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
res = snd_opl3sa2_probe(dev, card, id);
res = snd_opl3sa2_probe(dev, pdev, NULL, NULL);
if (res < 0)
return res;
dev++;
@ -798,7 +830,40 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
return -ENODEV;
}
static void __devexit snd_opl3sa2_pnp_remove(struct pnp_card_link * pcard)
static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
{
snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev);
snd_card_disconnect(card);
snd_card_free_in_thread(card);
}
static struct pnp_driver opl3sa2_pnp_driver = {
.name = "opl3sa2-pnpbios",
.id_table = snd_opl3sa2_pnpbiosids,
.probe = snd_opl3sa2_pnp_detect,
.remove = __devexit_p(snd_opl3sa2_pnp_remove),
};
static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card,
const struct pnp_card_device_id *id)
{
static int dev;
int res;
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
res = snd_opl3sa2_probe(dev, NULL, card, id);
if (res < 0)
return res;
dev++;
return 0;
}
return -ENODEV;
}
static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
{
snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
@ -810,8 +875,8 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "opl3sa2",
.id_table = snd_opl3sa2_pnpids,
.probe = snd_opl3sa2_pnp_detect,
.remove = __devexit_p(snd_opl3sa2_pnp_remove),
.probe = snd_opl3sa2_pnp_cdetect,
.remove = __devexit_p(snd_opl3sa2_pnp_cremove),
};
#endif /* CONFIG_PNP */
@ -826,10 +891,11 @@ static int __init alsa_card_opl3sa2_init(void)
if (isapnp[dev])
continue;
#endif
if (snd_opl3sa2_probe(dev, NULL, NULL) >= 0)
if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0)
cards++;
}
#ifdef CONFIG_PNP
cards += pnp_register_driver(&opl3sa2_pnp_driver);
cards += pnp_register_card_driver(&opl3sa2_pnpc_driver);
#endif
if (!cards) {

View File

@ -729,7 +729,7 @@ static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
static snd_kcontrol_new_t snd_sb16_dma_control = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "16-bit DMA Allocation",
.info = snd_sb16_dma_control_info,
.get = snd_sb16_dma_control_get,

View File

@ -1,11 +1,15 @@
# ALSA PCI drivers
menu "PCI devices"
depends on SND!=n && PCI
config SND_AC97_CODEC
tristate
select SND_PCM
select SND_AC97_BUS
config SND_AC97_BUS
tristate
menu "PCI devices"
depends on SND!=n && PCI
config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"

View File

@ -10,9 +10,11 @@ snd-ac97-codec-objs += ac97_proc.o
endif
snd-ak4531-codec-objs := ak4531_codec.o
snd-ac97-bus-objs := ac97_bus.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
obj-$(CONFIG_SND_AC97_BUS) += snd-ac97-bus.o
obj-m := $(sort $(obj-m))

79
sound/pci/ac97/ac97_bus.c Normal file
View File

@ -0,0 +1,79 @@
/*
* Linux driver model AC97 bus interface
*
* Author: Nicolas Pitre
* Created: Jan 14, 2005
* Copyright: (C) MontaVista Software Inc.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/string.h>
/*
* Codec families have names seperated by commas, so we search for an
* individual codec name within the family string.
*/
static int ac97_bus_match(struct device *dev, struct device_driver *drv)
{
return (strstr(dev->bus_id, drv->name) != NULL);
}
static int ac97_bus_suspend(struct device *dev, pm_message_t state)
{
int ret = 0;
if (dev->driver && dev->driver->suspend) {
ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
if (ret == 0)
ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
if (ret == 0)
ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
}
return ret;
}
static int ac97_bus_resume(struct device *dev)
{
int ret = 0;
if (dev->driver && dev->driver->resume) {
ret = dev->driver->resume(dev, RESUME_POWER_ON);
if (ret == 0)
ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
if (ret == 0)
ret = dev->driver->resume(dev, RESUME_ENABLE);
}
return ret;
}
struct bus_type ac97_bus_type = {
.name = "ac97",
.match = ac97_bus_match,
.suspend = ac97_bus_suspend,
.resume = ac97_bus_resume,
};
static int __init ac97_bus_init(void)
{
return bus_register(&ac97_bus_type);
}
subsys_initcall(ac97_bus_init);
static void __exit ac97_bus_exit(void)
{
bus_unregister(&ac97_bus_type);
}
module_exit(ac97_bus_exit);
EXPORT_SYMBOL(ac97_bus_type);
MODULE_LICENSE("GPL");

View File

@ -157,6 +157,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", NULL, NULL },
{ 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@ -1307,16 +1308,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
/* build master tone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
for (idx = 0; idx < 2; idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
return err;
if (ac97->id == AC97_ID_YMF753) {
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= 7 << 16;
if (!(ac97->flags & AC97_HAS_NO_TONE)) {
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
for (idx = 0; idx < 2; idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
return err;
if (ac97->id == AC97_ID_YMF753) {
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= 7 << 16;
}
}
snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
}
snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
}
/* build PC Speaker controls */
@ -1339,11 +1342,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
/* build MIC controls */
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
return err;
if (!(ac97->flags & AC97_HAS_NO_MIC)) {
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
return err;
}
}
/* build Line controls */
@ -1402,12 +1407,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
} else {
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
else
err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
if (err < 0)
return err;
if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
else
err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
if (err < 0)
return err;
}
}
/* build Capture controls */
@ -1807,6 +1814,39 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
return 0;
}
/* stop no dev release warning */
static void ac97_device_release(struct device * dev)
{
}
/* register ac97 codec to bus */
static int snd_ac97_dev_register(snd_device_t *device)
{
ac97_t *ac97 = device->device_data;
int err;
ac97->dev.bus = &ac97_bus_type;
ac97->dev.parent = ac97->bus->card->dev;
ac97->dev.platform_data = ac97;
ac97->dev.release = ac97_device_release;
snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
if ((err = device_register(&ac97->dev)) < 0) {
snd_printk(KERN_ERR "Can't register ac97 bus\n");
ac97->dev.bus = NULL;
return err;
}
return 0;
}
/* unregister ac97 codec */
static int snd_ac97_dev_unregister(snd_device_t *device)
{
ac97_t *ac97 = device->device_data;
if (ac97->dev.bus)
device_unregister(&ac97->dev);
return snd_ac97_free(ac97);
}
/* build_ops to do nothing */
static struct snd_ac97_build_ops null_build_ops;
@ -1840,6 +1880,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
const ac97_codec_id_t *pid;
static snd_device_ops_t ops = {
.dev_free = snd_ac97_dev_free,
.dev_register = snd_ac97_dev_register,
.dev_unregister = snd_ac97_dev_unregister,
};
snd_assert(rac97 != NULL, return -EINVAL);
@ -2539,8 +2581,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
{
int result;
snd_assert(quirk, return -EINVAL);
/* quirk overriden? */
if (override && strcmp(override, "-1") && strcmp(override, "default")) {
result = apply_quirk_str(ac97, override);
@ -2549,6 +2589,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
return result;
}
if (! quirk)
return -EINVAL;
for (; quirk->subvendor; quirk++) {
if (quirk->subvendor != ac97->subsystem_vendor)
continue;

View File

@ -370,141 +370,387 @@ int patch_yamaha_ymf753(ac97_t * ac97)
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
*/
int patch_wolfson03(ac97_t * ac97)
static const snd_kcontrol_new_t wm97xx_snd_ac97_controls[] = {
AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
};
static int patch_wolfson_wm9703_specific(ac97_t * ac97)
{
/* This is known to work for the ViewSonic ViewPad 1000
Randolph Bentson <bentson@holmsjoen.com> */
// WM9703/9707/9708/9717
snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x8000);
* Randolph Bentson <bentson@holmsjoen.com>
* WM9703/9707/9708/9717
*/
int err, i;
for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
return 0;
}
static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
.build_specific = patch_wolfson_wm9703_specific,
};
int patch_wolfson03(ac97_t * ac97)
{
ac97->build_ops = &patch_wolfson_wm9703_ops;
return 0;
}
static const snd_kcontrol_new_t wm9704_snd_ac97_controls[] = {
AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
AC97_DOUBLE("Rear Playback Volume", AC97_WM9704_RMIXER_VOL, 8, 0, 31, 1),
AC97_SINGLE("Rear Playback Switch", AC97_WM9704_RMIXER_VOL, 15, 1, 1),
AC97_DOUBLE("Rear DAC Volume", AC97_WM9704_RPCM_VOL, 8, 0, 31, 1),
AC97_DOUBLE("Surround Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
};
static int patch_wolfson_wm9704_specific(ac97_t * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm9704_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97))) < 0)
return err;
}
/* patch for DVD noise */
snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200);
return 0;
}
static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
.build_specific = patch_wolfson_wm9704_specific,
};
int patch_wolfson04(ac97_t * ac97)
{
// WM9704M/9704Q
// set front and rear mixer volume
snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
snd_ac97_write_cache(ac97, AC97_WM9704_RMIXER_VOL, 0x0808);
// patch for DVD noise
snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200);
// init vol
snd_ac97_write_cache(ac97, AC97_WM9704_RPCM_VOL, 0x0808);
// set rear surround volume
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
/* WM9704M/9704Q */
ac97->build_ops = &patch_wolfson_wm9704_ops;
return 0;
}
static int patch_wolfson_wm9705_specific(ac97_t * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, 0x72, 0x0808);
return 0;
}
static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
.build_specific = patch_wolfson_wm9705_specific,
};
int patch_wolfson05(ac97_t * ac97)
{
// WM9705, WM9710
// set front mixer volume
snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
/* WM9705, WM9710 */
ac97->build_ops = &patch_wolfson_wm9705_ops;
return 0;
}
static const char* wm9711_alc_select[] = {"None", "Left", "Right", "Stereo"};
static const char* wm9711_alc_mix[] = {"Stereo", "Right", "Left", "None"};
static const char* wm9711_out3_src[] = {"Left", "VREF", "Left + Right", "Mono"};
static const char* wm9711_out3_lrsrc[] = {"Master Mix", "Headphone Mix"};
static const char* wm9711_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
static const char* wm9711_base[] = {"Linear Control", "Adaptive Boost"};
static const char* wm9711_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
static const char* wm9711_mic[] = {"Mic 1", "Differential", "Mic 2", "Stereo"};
static const char* wm9711_rec_sel[] =
{"Mic 1", "NC", "NC", "Master Mix", "Line", "Headphone Mix", "Phone Mix", "Phone"};
static const char* wm9711_ng_type[] = {"Constant Gain", "Mute"};
static const struct ac97_enum wm9711_enum[] = {
AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9711_alc_select),
AC97_ENUM_SINGLE(AC97_VIDEO, 10, 4, wm9711_alc_mix),
AC97_ENUM_SINGLE(AC97_AUX, 9, 4, wm9711_out3_src),
AC97_ENUM_SINGLE(AC97_AUX, 8, 2, wm9711_out3_lrsrc),
AC97_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9711_rec_adc),
AC97_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9711_base),
AC97_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9711_rec_gain),
AC97_ENUM_SINGLE(AC97_MIC, 5, 4, wm9711_mic),
AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, wm9711_rec_sel),
AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9711_ng_type),
};
static const snd_kcontrol_new_t wm9711_snd_ac97_controls[] = {
AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
AC97_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
AC97_ENUM("ALC Function", wm9711_enum[0]),
AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 1),
AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
AC97_ENUM("ALC NG Type", wm9711_enum[9]),
AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
AC97_SINGLE("Side Tone Switch", AC97_VIDEO, 15, 1, 1),
AC97_SINGLE("Side Tone Volume", AC97_VIDEO, 12, 7, 1),
AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]),
AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
AC97_ENUM("Out3 Mux", wm9711_enum[2]),
AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
AC97_SINGLE("Beep to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
AC97_SINGLE("Beep to Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
AC97_SINGLE("Beep to Side Tone Switch", AC97_PC_BEEP, 11, 1, 1),
AC97_SINGLE("Beep to Side Tone Volume", AC97_PC_BEEP, 8, 7, 1),
AC97_SINGLE("Beep to Phone Switch", AC97_PC_BEEP, 7, 1, 1),
AC97_SINGLE("Beep to Phone Volume", AC97_PC_BEEP, 4, 7, 1),
AC97_SINGLE("Aux to Headphone Switch", AC97_CD, 15, 1, 1),
AC97_SINGLE("Aux to Headphone Volume", AC97_CD, 12, 7, 1),
AC97_SINGLE("Aux to Side Tone Switch", AC97_CD, 11, 1, 1),
AC97_SINGLE("Aux to Side Tone Volume", AC97_CD, 8, 7, 1),
AC97_SINGLE("Aux to Phone Switch", AC97_CD, 7, 1, 1),
AC97_SINGLE("Aux to Phone Volume", AC97_CD, 4, 7, 1),
AC97_SINGLE("Phone to Headphone Switch", AC97_PHONE, 15, 1, 1),
AC97_SINGLE("Phone to Master Switch", AC97_PHONE, 14, 1, 1),
AC97_SINGLE("Line to Headphone Switch", AC97_LINE, 15, 1, 1),
AC97_SINGLE("Line to Master Switch", AC97_LINE, 14, 1, 1),
AC97_SINGLE("Line to Phone Switch", AC97_LINE, 13, 1, 1),
AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PCM, 15, 1, 1),
AC97_SINGLE("PCM Playback to Master Switch", AC97_PCM, 14, 1, 1),
AC97_SINGLE("PCM Playback to Phone Switch", AC97_PCM, 13, 1, 1),
AC97_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
AC97_ENUM("Capture to Phone Mux", wm9711_enum[4]),
AC97_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
AC97_ENUM("Capture Select", wm9711_enum[8]),
AC97_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
AC97_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
AC97_ENUM("Bass Control", wm9711_enum[5]),
AC97_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
AC97_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
AC97_ENUM("Mic Select Source", wm9711_enum[7]),
AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0),
AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
};
static int patch_wolfson_wm9711_specific(ac97_t * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm9711_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x0808);
snd_ac97_write_cache(ac97, AC97_PCI_SVID, 0x0808);
snd_ac97_write_cache(ac97, AC97_VIDEO, 0x0808);
snd_ac97_write_cache(ac97, AC97_AUX, 0x0808);
snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
snd_ac97_write_cache(ac97, AC97_CD, 0x0000);
return 0;
}
static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
.build_specific = patch_wolfson_wm9711_specific,
};
int patch_wolfson11(ac97_t * ac97)
{
// WM9711, WM9712
// set out3 volume
snd_ac97_write_cache(ac97, AC97_WM9711_OUT3VOL, 0x0808);
/* WM9711, WM9712 */
ac97->build_ops = &patch_wolfson_wm9711_ops;
ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_MIC |
AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
return 0;
}
static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
static const char* wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
static const char* wm9713_rec_src[] =
{"Mic 1", "Mic 2", "Line", "Mono In", "Headphone Mix", "Master Mix",
"Mono Mix", "Zh"};
static const char* wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
static const char* wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
static const char* wm9713_mono_pga[] = {"Vmid", "Zh", "Mono Mix", "Inv 1"};
static const char* wm9713_spk_pga[] =
{"Vmid", "Zh", "Headphone Mix", "Master Mix", "Inv", "NC", "NC", "NC"};
static const char* wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone Mix", "NC"};
static const char* wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "NC"};
static const char* wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "NC"};
static const char* wm9713_dac_inv[] =
{"Off", "Mono Mix", "Master Mix", "Headphone Mix L", "Headphone Mix R",
"Headphone Mix Mono", "NC", "Vmid"};
static const char* wm9713_base[] = {"Linear Control", "Adaptive Boost"};
static const char* wm9713_ng_type[] = {"Constant Gain", "Mute"};
static const struct ac97_enum wm9713_enum[] = {
AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
AC97_ENUM_DOUBLE(AC97_VIDEO, 3, 0, 8, wm9713_rec_src),
AC97_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain),
AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select),
AC97_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga),
AC97_ENUM_DOUBLE(AC97_REC_GAIN, 11, 8, 8, wm9713_spk_pga),
AC97_ENUM_DOUBLE(AC97_REC_GAIN, 6, 4, 4, wm9713_hp_pga),
AC97_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga),
AC97_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga),
AC97_ENUM_DOUBLE(AC97_REC_GAIN_MIC, 13, 10, 8, wm9713_dac_inv),
AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_base),
AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type),
};
static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
static const snd_kcontrol_new_t wm13_snd_ac97_controls[] = {
AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
AC97_SINGLE("Line In to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
AC97_SINGLE("Line In to Master Switch", AC97_PC_BEEP, 14, 1, 1),
AC97_SINGLE("Line In to Mono Switch", AC97_PC_BEEP, 13, 1, 1),
AC97_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PHONE, 15, 1, 1),
AC97_SINGLE("PCM Playback to Master Switch", AC97_PHONE, 14, 1, 1),
AC97_SINGLE("PCM Playback to Mono Switch", AC97_PHONE, 13, 1, 1),
AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
AC97_SINGLE("Mic 1 to Mono Switch", AC97_LINE, 7, 1, 1),
AC97_SINGLE("Mic 2 to Mono Switch", AC97_LINE, 6, 1, 1),
AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
AC97_ENUM("Mic to Headphone Mux", wm9713_enum[0]),
AC97_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
AC97_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
AC97_ENUM("Capture Volume Steps", wm9713_enum[4]),
AC97_DOUBLE("Capture Volume", AC97_CD, 8, 0, 15, 0),
AC97_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
AC97_ENUM("Capture to Headphone Mux", wm9713_enum[1]),
AC97_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
AC97_ENUM("Capture to Mono Mux", wm9713_enum[2]),
AC97_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
AC97_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
AC97_ENUM("Capture Select", wm9713_enum[3]),
AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
AC97_SINGLE("ALC Decay Time ", AC97_CODEC_CLASS_REV, 4, 15, 0),
AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
AC97_ENUM("ALC Function", wm9713_enum[5]),
AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
AC97_ENUM("ALC NG Type", wm9713_enum[13]),
AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
AC97_DOUBLE("Master ZC Switch", AC97_MASTER, 14, 6, 1, 0),
AC97_DOUBLE("Headphone ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
AC97_DOUBLE("Out3/4 ZC Switch", AC97_MASTER_MONO, 14, 6, 1, 0),
AC97_SINGLE("Master Right Switch", AC97_MASTER, 7, 1, 1),
AC97_SINGLE("Headphone Right Switch", AC97_HEADPHONE, 7, 1, 1),
AC97_SINGLE("Out3/4 Right Switch", AC97_MASTER_MONO, 7, 1, 1),
AC97_SINGLE("Mono In to Headphone Switch", AC97_MASTER_TONE, 15, 1, 1),
AC97_SINGLE("Mono In to Master Switch", AC97_MASTER_TONE, 14, 1, 1),
AC97_SINGLE("Mono In Volume", AC97_MASTER_TONE, 8, 31, 1),
AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
AC97_SINGLE("Voice to Master Switch", AC97_PCM, 11, 1, 1),
AC97_SINGLE("Voice to Master Volume", AC97_PCM, 8, 7, 1),
AC97_SINGLE("Voice to Mono Switch", AC97_PCM, 7, 1, 1),
AC97_SINGLE("Voice to Mono Volume", AC97_PCM, 4, 7, 1),
AC97_SINGLE("Aux to Headphone Switch", AC97_REC_SEL, 15, 1, 1),
AC97_SINGLE("Aux to Headphone Volume", AC97_REC_SEL, 12, 7, 1),
AC97_SINGLE("Aux to Master Switch", AC97_REC_SEL, 11, 1, 1),
AC97_SINGLE("Aux to Master Volume", AC97_REC_SEL, 8, 7, 1),
AC97_SINGLE("Aux to Mono Switch", AC97_REC_SEL, 7, 1, 1),
AC97_SINGLE("Aux to Mono Volume", AC97_REC_SEL, 4, 7, 1),
AC97_ENUM("Mono Input Mux", wm9713_enum[6]),
AC97_ENUM("Master Input Mux", wm9713_enum[7]),
AC97_ENUM("Headphone Input Mux", wm9713_enum[8]),
AC97_ENUM("Out 3 Input Mux", wm9713_enum[9]),
AC97_ENUM("Out 4 Input Mux", wm9713_enum[10]),
AC97_ENUM("Bass Control", wm9713_enum[12]),
AC97_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
AC97_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
AC97_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
AC97_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
};
static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
static const snd_kcontrol_new_t wm13_snd_ac97_controls_3d[] = {
AC97_ENUM("Inv Input Mux", wm9713_enum[11]),
AC97_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
AC97_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
AC97_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
};
static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
};
static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
};
static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
AC97_ENUM("Record Select Left", wm9713_enum[3]),
AC97_ENUM("Record Select Right", wm9713_enum[4]),
};
static int patch_wolfson_wm9713_3d (ac97_t * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_3d); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97))) < 0)
return err;
}
return 0;
}
static int patch_wolfson_wm9713_specific(ac97_t * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
return 0;
}
@ -525,6 +771,7 @@ static void patch_wolfson_wm9713_resume (ac97_t * ac97)
static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
.build_specific = patch_wolfson_wm9713_specific,
.build_3d = patch_wolfson_wm9713_3d,
#ifdef CONFIG_PM
.suspend = patch_wolfson_wm9713_suspend,
.resume = patch_wolfson_wm9713_resume
@ -533,10 +780,13 @@ static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
int patch_wolfson13(ac97_t * ac97)
{
/* WM9713, WM9714 */
ac97->build_ops = &patch_wolfson_wm9713_ops;
ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD | AC97_HAS_NO_TONE |
AC97_HAS_NO_STD_PCM;
ac97->scaps &= ~AC97_SCAP_MODEM;
snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
@ -1379,6 +1629,7 @@ static void check_ad1981_hp_jack_sense(ac97_t *ac97)
u32 subid = ((u32)ac97->subsystem_vendor << 16) | ac97->subsystem_device;
switch (subid) {
case 0x103c0890: /* HP nc6000 */
case 0x103c099c: /* HP nx6110 */
case 0x103c006d: /* HP nx9105 */
case 0x17340088: /* FSC Scenic-W */
/* enable headphone jack sense */
@ -1706,7 +1957,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0),
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
/* disable this controls since it doesn't work as expected */
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
@ -1849,12 +2100,12 @@ static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
}
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
AC97_PAGE_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0, 0),
/* disable this controls since it doesn't work as expected */
/* AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0), */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Route",
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = alc655_iec958_route_info,
.get = alc655_iec958_route_get,
.put = alc655_iec958_route_put,
@ -2415,6 +2666,16 @@ int patch_vt1616(ac97_t * ac97)
return 0;
}
/*
* VT1617A codec
*/
int patch_vt1617a(ac97_t * ac97)
{
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
return 0;
}
/*
*/
static void it2646_update_jacks(ac97_t *ac97)
@ -2433,7 +2694,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0),
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0x76, 11, 1, 0),
AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0),
AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),
};

View File

@ -56,5 +56,6 @@ int patch_cm9739(ac97_t * ac97);
int patch_cm9761(ac97_t * ac97);
int patch_cm9780(ac97_t * ac97);
int patch_vt1616(ac97_t * ac97);
int patch_vt1617a(ac97_t * ac97);
int patch_it2646(ac97_t * ac97);
int mpatch_si3036(ac97_t * ac97);

View File

@ -1842,7 +1842,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr
return 0;
}
struct ali_pcm_description ali_pcms[] = {
static struct ali_pcm_description ali_pcms[] = {
{ "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
{ "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
};
@ -1959,9 +1959,9 @@ static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
static snd_kcontrol_new_t snd_ali5451_mixer_spdif[] __devinitdata = {
/* spdif aplayback switch */
/* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */
ALI5451_SPDIF("IEC958 Output switch", 0, 0),
ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),
/* spdif out to spdif channel */
ALI5451_SPDIF("IEC958 Channel Output Switch", 0, 1),
ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),
/* spdif in from spdif channel */
ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)
};

View File

@ -248,6 +248,7 @@ struct snd_atiixp_dma {
unsigned int period_bytes, periods;
int opened;
int running;
int suspended;
int pcm_open_flag;
int ac97_pcm_type; /* index # of ac97_pcm to access, -1 = not used */
unsigned int saved_curptr;
@ -699,12 +700,18 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
dma->ops->enable_transfer(chip, 1);
dma->running = 1;
dma->suspended = 0;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
dma->ops->enable_transfer(chip, 0);
dma->running = 0;
dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND;
break;
default:
err = -EINVAL;
@ -975,6 +982,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm_hw =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
@ -1443,7 +1451,7 @@ static int snd_atiixp_resume(snd_card_t *card)
for (i = 0; i < NUM_ATI_PCMDEVS; i++)
if (chip->pcmdevs[i]) {
atiixp_dma_t *dma = &chip->dmas[i];
if (dma->substream && dma->running) {
if (dma->substream && dma->suspended) {
dma->ops->enable_dma(chip, 1);
writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
chip->remap_addr + dma->ops->llp_offset);

View File

@ -33,7 +33,7 @@
/* hardware definition */
static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
.info =
(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@ -58,7 +58,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
#ifndef CHIP_AU8820
static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
.info =
(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@ -78,7 +78,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
#endif
static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
.info =
(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@ -220,8 +220,10 @@ snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
vortex_adb_allocroute(chip, -1,
params_channels(hw_params),
substream->stream, type);
if (dma < 0)
if (dma < 0) {
spin_unlock_irq(&chip->lock);
return dma;
}
stream = substream->runtime->private_data = &chip->dma_adb[dma];
stream->substream = substream;
/* Setup Buffers. */

View File

@ -188,6 +188,14 @@ static ca0106_details_t ca0106_chip_details[] = {
.name = "MSI K8N Diamond MB [SB0438]",
.gpio_type = 1,
.i2c_adc = 1 } ,
/* Shuttle XPC SD31P which has an onboard Creative Labs Sound Blaster Live! 24-bit EAX
* high-definition 7.1 audio processor".
* Added using info from andrewvegan in alsa bug #1298
*/
{ .serial = 0x30381297,
.name = "Shuttle XPC SD31P [SD31P]",
.gpio_type = 1,
.i2c_adc = 1 } ,
{ .serial = 0,
.name = "AudigyLS [Unknown]" }
};

View File

@ -297,7 +297,7 @@ static int snd_ca0106_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 4,
.info = snd_ca0106_spdif_info,
@ -306,7 +306,7 @@ static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
static snd_kcontrol_new_t snd_ca0106_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 4,
.info = snd_ca0106_spdif_info,

View File

@ -1029,7 +1029,7 @@ static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_cmipci_spdif_mask_info,
.get = snd_cmipci_spdif_mask_get,

View File

@ -113,7 +113,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
return err;
}
#endif
if ((err = snd_cs46xx_mixer(chip)) < 0) {
if ((err = snd_cs46xx_mixer(chip, 2)) < 0) {
snd_card_free(card);
return err;
}

View File

@ -1243,8 +1243,8 @@ static snd_pcm_hardware_t snd_cs46xx_playback =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
/*SNDRV_PCM_INFO_RESUME*/),
.formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@ -1265,8 +1265,8 @@ static snd_pcm_hardware_t snd_cs46xx_capture =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
/*SNDRV_PCM_INFO_RESUME*/),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5500,
@ -2231,7 +2231,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Output Switch",
.name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
@ -2239,7 +2239,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Input Switch",
.name = SNDRV_CTL_NAME_IEC958("Input ",NONE,SWITCH),
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
@ -2249,7 +2249,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
/* Input IEC958 volume does not work for the moment. (Benny) */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Input Volume",
.name = SNDRV_CTL_NAME_IEC958("Input ",NONE,VOLUME),
.info = snd_cs46xx_vol_info,
.get = snd_cs46xx_vol_iec958_get,
.put = snd_cs46xx_vol_iec958_put,
@ -2440,7 +2440,7 @@ static int __devinit cs46xx_detect_codec(cs46xx_t *chip, int codec)
return -ENXIO;
}
int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
int __devinit snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device)
{
snd_card_t *card = chip->card;
snd_ctl_elem_id_t id;
@ -2476,6 +2476,8 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
for (idx = 0; idx < ARRAY_SIZE(snd_cs46xx_controls); idx++) {
snd_kcontrol_t *kctl;
kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip);
if (kctl && kctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM)
kctl->id.device = spdif_device;
if ((err = snd_ctl_add(card, kctl)) < 0)
return err;
}

View File

@ -149,7 +149,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
}
}
if ((err = snd_emu10k1_mixer(emu)) < 0) {
if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) {
snd_card_free(card);
return err;
}

View File

@ -741,12 +741,20 @@ static emu_chip_details_t emu_chip_details[] = {
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by Thomas Zehetbauer 27th Aug 2005 */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
.driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
.driver = "EMU10K1", .name = "SB Live 5.1",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by alsa bugtrack user "hus" 12th Sept 2005 */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
.driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]",
.id = "Live",

View File

@ -1183,7 +1183,7 @@ static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 3,
.info = snd_emu10k1x_spdif_info,
@ -1192,7 +1192,7 @@ static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
static snd_kcontrol_new_t snd_emu10k1x_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 3,
.info = snd_emu10k1x_spdif_info,

View File

@ -1159,12 +1159,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/* Optical SPDIF Playback Volume */
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0);
snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* Optical SPDIF Capture Volume */
A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0);
snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
gpr += 2;
/* Line2 Playback Volume */
@ -1389,7 +1389,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
}
}
snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
gpr += 2;
A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
@ -1716,7 +1716,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 TTL Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Playback Volume", gpr, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 TTL Capture Volume + Switch */
@ -1724,8 +1724,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Capture Volume", gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 TTL Capture Switch", gpr + 2, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@ -1750,7 +1750,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 Optical Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 Optical Capture Volume */
@ -1758,8 +1758,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@ -1784,7 +1784,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 Coax Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Playback Volume", gpr, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 Coax Capture Volume + Switch */
@ -1792,8 +1792,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Capture Volume", gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Coaxial Capture Switch", gpr + 2, 0);
snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@ -1920,7 +1920,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
#endif
}
snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Raw Playback Switch", gpr, 0);
snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
gpr += 2;
}

View File

@ -181,7 +181,7 @@ static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 4,
.info = snd_emu10k1_spdif_info,
@ -190,7 +190,7 @@ static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
static snd_kcontrol_new_t snd_emu10k1_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 4,
.info = snd_emu10k1_spdif_info,
@ -295,7 +295,7 @@ static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Send Routing",
.count = 32,
.info = snd_emu10k1_send_routing_info,
@ -364,7 +364,7 @@ static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Send Volume",
.count = 32,
.info = snd_emu10k1_send_volume_info,
@ -427,7 +427,7 @@ static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_attn_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Volume",
.count = 32,
.info = snd_emu10k1_attn_info,
@ -737,7 +737,8 @@ static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
return -ENOENT;
}
int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
int __devinit snd_emu10k1_mixer(emu10k1_t *emu,
int pcm_device, int multi_device)
{
int err, pcm;
snd_kcontrol_t *kctl;
@ -852,29 +853,35 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
return -ENOMEM;
kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
@ -924,10 +931,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
/* sb live! and audigy */
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return -ENOMEM;
if (!emu->audigy)
kctl->id.device = emu->pcm_efx->device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
return -ENOMEM;
if (!emu->audigy)
kctl->id.device = emu->pcm_efx->device;
if ((err = snd_ctl_add(card, kctl)))
return err;
}

View File

@ -1682,6 +1682,7 @@ static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm)
int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
snd_kcontrol_t *kctl;
int err;
if (rpcm)
@ -1714,7 +1715,11 @@ int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm
emu->efx_voices_mask[0] = 0xffff0000;
emu->efx_voices_mask[1] = 0;
}
snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
if (!kctl)
return -ENOMEM;
kctl->id.device = device;
snd_ctl_add(emu->card, kctl);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);

View File

@ -1444,7 +1444,7 @@ static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
/* spdif controls */
static snd_kcontrol_new_t snd_es1371_mixer_spdif[] __devinitdata = {
ES1371_SPDIF("IEC958 Playback Switch"),
ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)),
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),

View File

@ -1155,10 +1155,10 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
static snd_kcontrol_new_t snd_fm801_controls_multi[] __devinitdata = {
FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0),
FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0),
FM801_SINGLE("IEC958 Capture Switch", FM801_I2S_MODE, 8, 1, 0),
FM801_SINGLE("IEC958 Raw Data Playback Switch", FM801_I2S_MODE, 9, 1, 0),
FM801_SINGLE("IEC958 Raw Data Capture Switch", FM801_I2S_MODE, 10, 1, 0),
FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0),
FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0),
FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",PLAYBACK,SWITCH), FM801_I2S_MODE, 9, 1, 0),
FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",CAPTURE,SWITCH), FM801_I2S_MODE, 10, 1, 0),
FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), FM801_GEN_CTRL, 2, 1, 0),
};
static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus)

View File

@ -1,5 +1,5 @@
snd-hda-intel-objs := hda_intel.o
snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o
snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif

View File

@ -432,22 +432,26 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
}
/*
* look for an AFG node
*
* return 0 if not found
* look for an AFG and MFG nodes
*/
static int look_for_afg_node(struct hda_codec *codec)
static void setup_fg_nodes(struct hda_codec *codec)
{
int i, total_nodes;
hda_nid_t nid;
total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
for (i = 0; i < total_nodes; i++, nid++) {
if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) ==
AC_GRP_AUDIO_FUNCTION)
return nid;
switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) {
case AC_GRP_AUDIO_FUNCTION:
codec->afg = nid;
break;
case AC_GRP_MODEM_FUNCTION:
codec->mfg = nid;
break;
default:
break;
}
}
return 0;
}
/*
@ -507,10 +511,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
/* FIXME: support for multiple AFGs? */
codec->afg = look_for_afg_node(codec);
if (! codec->afg) {
snd_printdd("hda_codec: no AFG node found\n");
setup_fg_nodes(codec);
if (! codec->afg && ! codec->mfg) {
snd_printdd("hda_codec: no AFG or MFG node found\n");
snd_hda_codec_free(codec);
return -ENODEV;
}
@ -749,12 +752,14 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
long *valp = ucontrol->value.integer.value;
int change = 0;
if (chs & 1)
if (chs & 1) {
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
0x7f, *valp);
valp++;
}
if (chs & 2)
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
0x7f, valp[1]);
0x7f, *valp);
return change;
}
@ -796,12 +801,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
long *valp = ucontrol->value.integer.value;
int change = 0;
if (chs & 1)
if (chs & 1) {
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
0x80, *valp ? 0 : 0x80);
valp++;
}
if (chs & 2)
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
0x80, valp[1] ? 0 : 0x80);
0x80, *valp ? 0 : 0x80);
return change;
}
@ -1155,8 +1163,16 @@ int snd_hda_build_controls(struct hda_bus *bus)
/*
* stream formats
*/
static unsigned int rate_bits[][3] = {
struct hda_rate_tbl {
unsigned int hz;
unsigned int alsa_bits;
unsigned int hda_fmt;
};
static struct hda_rate_tbl rate_bits[] = {
/* rate in Hz, ALSA rate bitmask, HDA format value */
/* autodetected value used in snd_hda_query_supported_pcm */
{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
@ -1168,7 +1184,11 @@ static unsigned int rate_bits[][3] = {
{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
{ 0 }
/* not autodetected value */
{ 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
{ 0 } /* terminator */
};
/**
@ -1190,12 +1210,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
int i;
unsigned int val = 0;
for (i = 0; rate_bits[i][0]; i++)
if (rate_bits[i][0] == rate) {
val = rate_bits[i][2];
for (i = 0; rate_bits[i].hz; i++)
if (rate_bits[i].hz == rate) {
val = rate_bits[i].hda_fmt;
break;
}
if (! rate_bits[i][0]) {
if (! rate_bits[i].hz) {
snd_printdd("invalid rate %d\n", rate);
return 0;
}
@ -1258,9 +1278,9 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
if (ratesp) {
u32 rates = 0;
for (i = 0; rate_bits[i][0]; i++) {
for (i = 0; rate_bits[i].hz; i++) {
if (val & (1 << i))
rates |= rate_bits[i][1];
rates |= rate_bits[i].alsa_bits;
}
*ratesp = rates;
}
@ -1352,13 +1372,13 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
}
rate = format & 0xff00;
for (i = 0; rate_bits[i][0]; i++)
if (rate_bits[i][2] == rate) {
for (i = 0; rate_bits[i].hz; i++)
if (rate_bits[i].hda_fmt == rate) {
if (val & (1 << i))
break;
return 0;
}
if (! rate_bits[i][0])
if (! rate_bits[i].hz)
return 0;
stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
@ -1541,8 +1561,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_c
for (c = tbl; c->modelname || c->pci_subvendor; c++) {
if (c->pci_subvendor == subsystem_vendor &&
(! c->pci_subdevice /* all match */||
(c->pci_subdevice == subsystem_device)))
(c->pci_subdevice == subsystem_device))) {
snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
subsystem_vendor, subsystem_device, c->config);
return c->config;
}
}
}
return -1;
@ -1803,11 +1826,25 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
cfg->line_out_pins[j] = nid;
}
/* Swap surround and CLFE: the association order is front/CLFE/surr/back */
if (cfg->line_outs >= 3) {
/* Reorder the surround channels
* ALSA sequence is front/surr/clfe/side
* HDA sequence is:
* 4-ch: front/surr => OK as it is
* 6-ch: front/clfe/surr
* 8-ch: front/clfe/side/surr
*/
switch (cfg->line_outs) {
case 3:
nid = cfg->line_out_pins[1];
cfg->line_out_pins[1] = cfg->line_out_pins[2];
cfg->line_out_pins[2] = nid;
break;
case 4:
nid = cfg->line_out_pins[1];
cfg->line_out_pins[1] = cfg->line_out_pins[3];
cfg->line_out_pins[3] = cfg->line_out_pins[2];
cfg->line_out_pins[2] = nid;
break;
}
return 0;

View File

@ -514,6 +514,7 @@ struct hda_codec {
struct list_head list; /* list point */
hda_nid_t afg; /* AFG node id */
hda_nid_t mfg; /* MFG node id */
/* ids */
u32 vendor_id;

View File

@ -881,6 +881,11 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
struct hda_gspec *spec;
int err;
if(!codec->afg) {
snd_printdd("hda_generic: no generic modem yet\n");
return -ENODEV;
}
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL) {
printk(KERN_ERR "hda_generic: can't allocate spec\n");

View File

@ -71,7 +71,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ESB2},"
"{ATI, SB450},"
"{VIA, VT8251},"
"{VIA, VT8237A}}");
"{VIA, VT8237A},"
"{SiS, SIS966},"
"{ULI, M5461}}");
MODULE_DESCRIPTION("Intel HDA driver");
#define SFX "hda-intel: "
@ -141,9 +143,24 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
*/
/* max number of SDs */
#define MAX_ICH6_DEV 8
/* ICH, ATI and VIA have 4 playback and 4 capture */
#define ICH6_CAPTURE_INDEX 0
#define ICH6_NUM_CAPTURE 4
#define ICH6_PLAYBACK_INDEX 4
#define ICH6_NUM_PLAYBACK 4
/* ULI has 6 playback and 5 capture */
#define ULI_CAPTURE_INDEX 0
#define ULI_NUM_CAPTURE 5
#define ULI_PLAYBACK_INDEX 5
#define ULI_NUM_PLAYBACK 6
/* this number is statically defined for simplicity */
#define MAX_AZX_DEV 16
/* max number of fragments - we may use more if allocating more pages for BDL */
#define AZX_MAX_FRAG (PAGE_SIZE / (MAX_ICH6_DEV * 16))
#define BDL_SIZE PAGE_ALIGN(8192)
#define AZX_MAX_FRAG (BDL_SIZE / (MAX_AZX_DEV * 16))
/* max buffer size - no h/w limit, you can increase as you like */
#define AZX_MAX_BUF_SIZE (1024*1024*1024)
/* max number of PCM devics per card */
@ -200,7 +217,6 @@ enum {
};
/* Defines for ATI HD Audio support in SB450 south bridge */
#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b
#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
@ -258,6 +274,14 @@ struct snd_azx {
snd_card_t *card;
struct pci_dev *pci;
/* chip type specific */
int driver_type;
int playback_streams;
int playback_index_offset;
int capture_streams;
int capture_index_offset;
int num_streams;
/* pci resources */
unsigned long addr;
void __iomem *remap_addr;
@ -267,8 +291,8 @@ struct snd_azx {
spinlock_t reg_lock;
struct semaphore open_mutex;
/* streams */
azx_dev_t azx_dev[MAX_ICH6_DEV];
/* streams (x num_streams) */
azx_dev_t *azx_dev;
/* PCM */
unsigned int pcm_devs;
@ -292,6 +316,23 @@ struct snd_azx {
unsigned int initialized: 1;
};
/* driver types */
enum {
AZX_DRIVER_ICH,
AZX_DRIVER_ATI,
AZX_DRIVER_VIA,
AZX_DRIVER_SIS,
AZX_DRIVER_ULI,
};
static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_ATI] = "HDA ATI SB",
[AZX_DRIVER_VIA] = "HDA VIA VT82xx",
[AZX_DRIVER_SIS] = "HDA SIS966",
[AZX_DRIVER_ULI] = "HDA ULI M5461"
};
/*
* macros for easy use
*/
@ -360,6 +401,8 @@ static void azx_init_cmd_io(azx_t *chip)
azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
/* set the corb size to 256 entries (ULI requires explicitly) */
azx_writeb(chip, CORBSIZE, 0x02);
/* set the corb write pointer to 0 */
azx_writew(chip, CORBWP, 0);
/* reset the corb hw read pointer */
@ -373,6 +416,8 @@ static void azx_init_cmd_io(azx_t *chip)
azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
/* set the rirb size to 256 entries (ULI requires explicitly) */
azx_writeb(chip, RIRBSIZE, 0x02);
/* reset the rirb hw write pointer */
azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
/* set N=1, get RIRB response interrupt for new entry */
@ -596,7 +641,7 @@ static void azx_int_disable(azx_t *chip)
int i;
/* disable interrupts in stream descriptor */
for (i = 0; i < MAX_ICH6_DEV; i++) {
for (i = 0; i < chip->num_streams; i++) {
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_sd_writeb(azx_dev, SD_CTL,
azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
@ -616,7 +661,7 @@ static void azx_int_clear(azx_t *chip)
int i;
/* clear stream status */
for (i = 0; i < MAX_ICH6_DEV; i++) {
for (i = 0; i < chip->num_streams; i++) {
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
}
@ -686,8 +731,7 @@ static void azx_init_chip(azx_t *chip)
}
/* For ATI SB450 azalia HD audio, we need to enable snoop */
if (chip->pci->vendor == PCI_VENDOR_ID_ATI &&
chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) {
if (chip->driver_type == AZX_DRIVER_ATI) {
pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
&ati_misc_cntl2);
pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
@ -714,7 +758,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
return IRQ_NONE;
}
for (i = 0; i < MAX_ICH6_DEV; i++) {
for (i = 0; i < chip->num_streams; i++) {
azx_dev = &chip->azx_dev[i];
if (status & azx_dev->sd_int_sta_mask) {
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
@ -879,9 +923,15 @@ static int __devinit azx_codec_create(azx_t *chip, const char *model)
/* assign a stream for the PCM */
static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
{
int dev, i;
dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
for (i = 0; i < 4; i++, dev++)
int dev, i, nums;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev = chip->playback_index_offset;
nums = chip->playback_streams;
} else {
dev = chip->capture_index_offset;
nums = chip->capture_streams;
}
for (i = 0; i < nums; i++, dev++)
if (! chip->azx_dev[dev].opened) {
chip->azx_dev[dev].opened = 1;
return &chip->azx_dev[dev];
@ -899,8 +949,8 @@ static snd_pcm_hardware_t azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /*|*/
/*SNDRV_PCM_INFO_RESUME*/),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@ -1049,6 +1099,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
azx_dev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
azx_stream_stop(chip, azx_dev);
azx_dev->running = 0;
@ -1058,6 +1109,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
}
spin_unlock(&chip->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
cmd == SNDRV_PCM_TRIGGER_STOP) {
int timeout = 5000;
while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
@ -1136,6 +1188,7 @@ static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
snd_dma_pci_data(chip->pci),
1024 * 64, 1024 * 128);
chip->pcm[pcm_dev] = pcm;
chip->pcm_devs = pcm_dev + 1;
return 0;
}
@ -1186,7 +1239,7 @@ static int __devinit azx_init_stream(azx_t *chip)
/* initialize each stream (aka device)
* assign the starting bdl address to each stream (device) and initialize
*/
for (i = 0; i < MAX_ICH6_DEV; i++) {
for (i = 0; i < chip->num_streams; i++) {
unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
@ -1245,7 +1298,7 @@ static int azx_free(azx_t *chip)
if (chip->initialized) {
int i;
for (i = 0; i < MAX_ICH6_DEV; i++)
for (i = 0; i < chip->num_streams; i++)
azx_stream_stop(chip, &chip->azx_dev[i]);
/* disable interrupts */
@ -1261,10 +1314,10 @@ static int azx_free(azx_t *chip)
/* wait a little for interrupts to finish */
msleep(1);
iounmap(chip->remap_addr);
}
if (chip->remap_addr)
iounmap(chip->remap_addr);
if (chip->irq >= 0)
free_irq(chip->irq, (void*)chip);
@ -1276,6 +1329,7 @@ static int azx_free(azx_t *chip)
snd_dma_free_pages(&chip->posbuf);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip->azx_dev);
kfree(chip);
return 0;
@ -1290,7 +1344,8 @@ static int azx_dev_free(snd_device_t *device)
* constructor
*/
static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
int posfix, azx_t **rchip)
int posfix, int driver_type,
azx_t **rchip)
{
azx_t *chip;
int err = 0;
@ -1316,9 +1371,20 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->driver_type = driver_type;
chip->position_fix = posfix;
#if BITS_PER_LONG != 64
/* Fix up base address on ULI M5461 */
if (chip->driver_type == AZX_DRIVER_ULI) {
u16 tmp3;
pci_read_config_word(pci, 0x40, &tmp3);
pci_write_config_word(pci, 0x40, tmp3 | 0x10);
pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
}
#endif
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
kfree(chip);
pci_disable_device(pci);
@ -1344,16 +1410,37 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
pci_set_master(pci);
synchronize_irq(chip->irq);
switch (chip->driver_type) {
case AZX_DRIVER_ULI:
chip->playback_streams = ULI_NUM_PLAYBACK;
chip->capture_streams = ULI_NUM_CAPTURE;
chip->playback_index_offset = ULI_PLAYBACK_INDEX;
chip->capture_index_offset = ULI_CAPTURE_INDEX;
break;
default:
chip->playback_streams = ICH6_NUM_PLAYBACK;
chip->capture_streams = ICH6_NUM_CAPTURE;
chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
chip->capture_index_offset = ICH6_CAPTURE_INDEX;
break;
}
chip->num_streams = chip->playback_streams + chip->capture_streams;
chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
if (! chip->azx_dev) {
snd_printk(KERN_ERR "cannot malloc azx_dev\n");
goto errout;
}
/* allocate memory for the BDL for each stream */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
PAGE_SIZE, &chip->bdl)) < 0) {
BDL_SIZE, &chip->bdl)) < 0) {
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
goto errout;
}
if (chip->position_fix == POS_FIX_POSBUF) {
/* allocate memory for the position buffer */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
chip->num_streams * 8, &chip->posbuf)) < 0) {
snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
goto errout;
}
@ -1382,6 +1469,10 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
goto errout;
}
strcpy(card->driver, "HDA-Intel");
strcpy(card->shortname, driver_short_names[chip->driver_type]);
sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
*rchip = chip;
return 0;
@ -1410,15 +1501,12 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
return -ENOMEM;
}
if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data,
&chip)) < 0) {
snd_card_free(card);
return err;
}
strcpy(card->driver, "HDA-Intel");
strcpy(card->shortname, "HDA Intel");
sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
/* create codec instances */
if ((err = azx_codec_create(chip, model[dev])) < 0) {
snd_card_free(card);
@ -1459,12 +1547,13 @@ static void __devexit azx_remove(struct pci_dev *pci)
/* PCI IDs */
static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);

View File

@ -10,11 +10,14 @@ extern struct hda_codec_preset snd_hda_preset_cmedia[];
extern struct hda_codec_preset snd_hda_preset_analog[];
/* SigmaTel codecs */
extern struct hda_codec_preset snd_hda_preset_sigmatel[];
/* SiLabs 3054/3055 modem codecs */
extern struct hda_codec_preset snd_hda_preset_si3054[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
snd_hda_preset_cmedia,
snd_hda_preset_analog,
snd_hda_preset_sigmatel,
snd_hda_preset_si3054,
NULL
};

View File

@ -572,7 +572,7 @@ static snd_kcontrol_new_t ad1983_mixers[] = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Route",
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,
@ -705,7 +705,7 @@ static snd_kcontrol_new_t ad1981_mixers[] = {
/* identical with AD1983 */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Route",
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,

View File

@ -647,6 +647,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = {
{ .modelname = "min_fp", .config = CMI_MIN_FP },
{ .modelname = "full", .config = CMI_FULL },
{ .modelname = "full_dig", .config = CMI_FULL_DIG },
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
{ .modelname = "allout", .config = CMI_ALLOUT },
{ .modelname = "auto", .config = CMI_AUTO },
{} /* terminator */

View File

@ -687,6 +687,12 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
{ } /* end */
};
/* additional mixers to alc880_asus_mixer */
static snd_kcontrol_new_t alc880_pcbeep_mixer[] = {
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
{ } /* end */
};
/*
* build control elements
@ -1524,6 +1530,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
@ -1734,7 +1741,7 @@ static struct alc_config_preset alc880_presets[] = {
.input_mux = &alc880_capture_source,
},
[ALC880_UNIWILL_DIG] = {
.mixers = { alc880_asus_mixer },
.mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
.init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
.dac_nids = alc880_asus_dac_nids,

View File

@ -0,0 +1,300 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
* HD audio interface patch for Silicon Labs 3054/5 modem codec
*
* Copyright (c) 2005 Sasha Khapyorsky <sashak@smlink.com>
* Takashi Iwai <tiwai@suse.de>
*
*
* This driver 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 driver 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
*/
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
/* si3054 verbs */
#define SI3054_VERB_READ_NODE 0x900
#define SI3054_VERB_WRITE_NODE 0x100
/* si3054 nodes (registers) */
#define SI3054_EXTENDED_MID 2
#define SI3054_LINE_RATE 3
#define SI3054_LINE_LEVEL 4
#define SI3054_GPIO_CFG 5
#define SI3054_GPIO_POLARITY 6
#define SI3054_GPIO_STICKY 7
#define SI3054_GPIO_WAKEUP 8
#define SI3054_GPIO_STATUS 9
#define SI3054_GPIO_CONTROL 10
#define SI3054_MISC_AFE 11
#define SI3054_CHIPID 12
#define SI3054_LINE_CFG1 13
#define SI3054_LINE_STATUS 14
#define SI3054_DC_TERMINATION 15
#define SI3054_LINE_CONFIG 16
#define SI3054_CALLPROG_ATT 17
#define SI3054_SQ_CONTROL 18
#define SI3054_MISC_CONTROL 19
#define SI3054_RING_CTRL1 20
#define SI3054_RING_CTRL2 21
/* extended MID */
#define SI3054_MEI_READY 0xf
/* line level */
#define SI3054_ATAG_MASK 0x00f0
#define SI3054_DTAG_MASK 0xf000
/* GPIO bits */
#define SI3054_GPIO_OH 0x0001
#define SI3054_GPIO_CID 0x0002
/* chipid and revisions */
#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
#define SI3054_CHIPID_DAA_REV_MASK 0x00f0
#define SI3054_CHIPID_INTERNATIONAL 0x0100
#define SI3054_CHIPID_DAA_ID 0x0f00
#define SI3054_CHIPID_CODEC_ID (1<<12)
/* si3054 codec registers (nodes) access macros */
#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
struct si3054_spec {
unsigned international;
struct hda_pcm pcm;
};
/*
* Modem mixer
*/
#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
#define PRIVATE_REG(val) ((val>>16)&0xffff)
#define PRIVATE_MASK(val) (val&0xffff)
static int si3054_switch_info(snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int si3054_switch_get(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *uvalue)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
u16 reg = PRIVATE_REG(kcontrol->private_value);
u16 mask = PRIVATE_MASK(kcontrol->private_value);
uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
return 0;
}
static int si3054_switch_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *uvalue)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
u16 reg = PRIVATE_REG(kcontrol->private_value);
u16 mask = PRIVATE_MASK(kcontrol->private_value);
if (uvalue->value.integer.value[0])
SET_REG(codec, reg, (GET_REG(codec, reg)) | mask);
else
SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask);
return 0;
}
#define SI3054_KCONTROL(kname,reg,mask) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = kname, \
.info = si3054_switch_info, \
.get = si3054_switch_get, \
.put = si3054_switch_put, \
.private_value = PRIVATE_VALUE(reg,mask), \
}
static snd_kcontrol_new_t si3054_modem_mixer[] = {
SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
{}
};
static int si3054_build_controls(struct hda_codec *codec)
{
return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
}
/*
* PCM callbacks
*/
static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
snd_pcm_substream_t *substream)
{
u16 val;
SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
val = GET_REG(codec, SI3054_LINE_LEVEL);
val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
SET_REG(codec, SI3054_LINE_LEVEL, val);
snd_hda_codec_setup_stream(codec, hinfo->nid,
stream_tag, 0, format);
return 0;
}
static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
snd_pcm_substream_t *substream)
{
static unsigned int rates[] = { 8000, 9600, 16000 };
static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
substream->runtime->hw.period_bytes_min = 80;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
}
static struct hda_pcm_stream si3054_pcm = {
.substreams = 1,
.channels_min = 1,
.channels_max = 1,
.nid = 0x1,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.maxbps = 16,
.ops = {
.open = si3054_pcm_open,
.prepare = si3054_pcm_prepare,
},
};
static int si3054_build_pcms(struct hda_codec *codec)
{
struct si3054_spec *spec = codec->spec;
struct hda_pcm *info = &spec->pcm;
si3054_pcm.nid = codec->mfg;
codec->num_pcms = 1;
codec->pcm_info = info;
info->name = "Si3054 Modem";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm;
return 0;
}
/*
* Init part
*/
static int si3054_init(struct hda_codec *codec)
{
struct si3054_spec *spec = codec->spec;
unsigned wait_count;
u16 val;
snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
SET_REG(codec, SI3054_LINE_RATE, 9600);
SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
SET_REG(codec, SI3054_EXTENDED_MID, 0);
wait_count = 10;
do {
msleep(2);
val = GET_REG(codec, SI3054_EXTENDED_MID);
} while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
return -EACCES;
}
SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
SET_REG(codec, SI3054_GPIO_CFG, 0x0);
SET_REG(codec, SI3054_MISC_AFE, 0);
SET_REG(codec, SI3054_LINE_CFG1,0x200);
if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
GET_REG(codec,SI3054_LINE_STATUS));
}
spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
return 0;
}
static void si3054_free(struct hda_codec *codec)
{
kfree(codec->spec);
}
/*
*/
static struct hda_codec_ops si3054_patch_ops = {
.build_controls = si3054_build_controls,
.build_pcms = si3054_build_pcms,
.init = si3054_init,
.free = si3054_free,
#ifdef CONFIG_PM
//.suspend = si3054_suspend,
.resume = si3054_init,
#endif
};
static int patch_si3054(struct hda_codec *codec)
{
struct si3054_spec *spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
codec->patch_ops = si3054_patch_ops;
return 0;
}
/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_si3054[] = {
{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
{}
};

View File

@ -618,15 +618,15 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
*/
static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
static snd_kcontrol_new_t snd_ice1712_delta1010lt_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
static snd_kcontrol_new_t snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
static snd_kcontrol_new_t snd_ice1712_delta_spdif_in_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice)

View File

@ -1422,7 +1422,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata
static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Multi Capture Switch",
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
.info = snd_ice1712_pro_mixer_switch_info,
.get = snd_ice1712_pro_mixer_switch_get,
.put = snd_ice1712_pro_mixer_switch_put,
@ -1441,7 +1441,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata
static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Multi Capture Volume",
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
.info = snd_ice1712_pro_mixer_volume_info,
.get = snd_ice1712_pro_mixer_volume_get,
.put = snd_ice1712_pro_mixer_volume_put,
@ -1715,7 +1715,7 @@ static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_ice1712_spdif_info,
.get = snd_ice1712_spdif_maskc_get,
@ -1724,7 +1724,7 @@ static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_ice1712_spdif_info,
.get = snd_ice1712_spdif_maskp_get,
@ -2203,7 +2203,7 @@ static snd_kcontrol_new_t snd_ice1712_mixer_pro_analog_route __devinitdata = {
static snd_kcontrol_new_t snd_ice1712_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Route",
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_ice1712_pro_route_info,
.get = snd_ice1712_pro_route_spdif_get,
.put = snd_ice1712_pro_route_spdif_put,

View File

@ -1414,7 +1414,7 @@ static int snd_vt1724_spdif_maskp_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_vt1724_spdif_info,
.get = snd_vt1724_spdif_maskc_get,
@ -1423,7 +1423,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
static snd_kcontrol_new_t snd_vt1724_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_vt1724_spdif_info,
.get = snd_vt1724_spdif_maskp_get,
@ -1466,7 +1466,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_switch __devinitdata =
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* FIXME: the following conflict with IEC958 Playback Route */
// .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
.name = "IEC958 Output Switch",
.name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.info = snd_vt1724_spdif_sw_info,
.get = snd_vt1724_spdif_sw_get,
.put = snd_vt1724_spdif_sw_put

View File

@ -389,6 +389,7 @@ typedef struct {
struct ac97_pcm *pcm;
int pcm_open_flag;
unsigned int page_attr_changed: 1;
unsigned int suspended: 1;
} ichdev_t;
typedef struct _snd_intel8x0 intel8x0_t;
@ -862,12 +863,16 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
unsigned long port = ichdev->reg_offset;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
ichdev->suspended = 0;
/* fallthru */
case SNDRV_PCM_TRIGGER_START:
val = ICH_IOCE | ICH_STARTBM;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
ichdev->suspended = 1;
/* fallthru */
case SNDRV_PCM_TRIGGER_STOP:
val = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@ -899,9 +904,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
val = igetdword(chip, ICHREG(ALI_DMACR));
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
ichdev->suspended = 0;
/* fallthru */
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* clear FIFO for synchronization of channels */
fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
@ -913,9 +920,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
ichdev->suspended = 1;
/* fallthru */
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
iputbyte(chip, port + ICH_REG_OFF_CR, 0);
while (igetbyte(chip, port + ICH_REG_OFF_CR))
@ -994,6 +1003,8 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
{
unsigned int cnt;
int dbl = runtime->rate > 48000;
spin_lock_irq(&chip->reg_lock);
switch (chip->device_type) {
case DEVICE_ALI:
cnt = igetdword(chip, ICHREG(ALI_SCR));
@ -1037,6 +1048,7 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
iputdword(chip, ICHREG(GLOB_CNT), cnt);
break;
}
spin_unlock_irq(&chip->reg_lock);
}
static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@ -1048,15 +1060,12 @@ static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
ichdev->physbuf = runtime->dma_addr;
ichdev->size = snd_pcm_lib_buffer_bytes(substream);
ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
spin_lock_irq(&chip->reg_lock);
if (ichdev->ichd == ICHD_PCMOUT) {
snd_intel8x0_setup_pcm_out(chip, runtime);
if (chip->device_type == DEVICE_INTEL_ICH4) {
if (chip->device_type == DEVICE_INTEL_ICH4)
ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
}
}
snd_intel8x0_setup_periods(chip, ichdev);
spin_unlock_irq(&chip->reg_lock);
return 0;
}
@ -1815,6 +1824,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
.name = "HP nc6000",
.type = AC97_TUNE_MUTE_LED
},
{
.subvendor = 0x103c,
.subdevice = 0x0934,
.name = "HP nx8220",
.type = AC97_TUNE_MUTE_LED
},
{
.subvendor = 0x103c,
.subdevice = 0x099c,
.name = "HP nx6110", /* AD1981B */
.type = AC97_TUNE_HP_ONLY
},
{
.subvendor = 0x103c,
.subdevice = 0x129d,
@ -1869,6 +1890,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
.name = "Fujitsu S6210", /* STAC9750/51 */
.type = AC97_TUNE_HP_ONLY
},
{
.subvendor = 0x10cf,
.subdevice = 0x12ec,
.name = "Fujitsu-Siemens 4010",
.type = AC97_TUNE_HP_ONLY
},
{
.subvendor = 0x10f1,
.subdevice = 0x2665,
@ -2424,6 +2451,20 @@ static int intel8x0_resume(snd_card_t *card)
}
}
/* resume status */
for (i = 0; i < chip->bdbars_count; i++) {
ichdev_t *ichdev = &chip->ichd[i];
unsigned long port = ichdev->reg_offset;
if (! ichdev->substream || ! ichdev->suspended)
continue;
if (ichdev->ichd == ICHD_PCMOUT)
snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime);
iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ);
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}
return 0;
}
#endif /* CONFIG_PM */

View File

@ -2067,7 +2067,7 @@ static int snd_korg1212_control_sync_put(snd_kcontrol_t * kcontrol, snd_ctl_elem
}, \
{ \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, \
.iface = SNDRV_CTL_ELEM_IFACE_PCM, \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = c_name " Monitor Phase Invert", \
.info = snd_korg1212_control_phase_info, \
.get = snd_korg1212_control_phase_get, \
@ -2082,7 +2082,7 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
MON_MIXER(4, "ADAT-5"), MON_MIXER(5, "ADAT-6"), MON_MIXER(6, "ADAT-7"), MON_MIXER(7, "ADAT-8"),
{
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Sync Source",
.info = snd_korg1212_control_sync_info,
.get = snd_korg1212_control_sync_get,

View File

@ -189,6 +189,7 @@ struct snd_nm256_stream {
nm256_t *chip;
snd_pcm_substream_t *substream;
int running;
int suspended;
u32 buf; /* offset from chip->buffer */
int bufsize; /* buffer size in bytes */
@ -231,8 +232,10 @@ struct snd_nm256 {
int mixer_status_mask; /* bit mask to test the mixer status */
int irq;
int irq_acks;
irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
int badintrcount; /* counter to check bogus interrupts */
struct semaphore irq_mutex;
nm256_stream_t streams[2];
@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
}
}
/* acquire interrupt */
static int snd_nm256_acquire_irq(nm256_t *chip)
{
down(&chip->irq_mutex);
if (chip->irq < 0) {
if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
chip->card->driver, (void*)chip)) {
snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
up(&chip->irq_mutex);
return -EBUSY;
}
chip->irq = chip->pci->irq;
}
chip->irq_acks++;
up(&chip->irq_mutex);
return 0;
}
/* release interrupt */
static void snd_nm256_release_irq(nm256_t *chip)
{
down(&chip->irq_mutex);
if (chip->irq_acks > 0)
chip->irq_acks--;
if (chip->irq_acks == 0 && chip->irq >= 0) {
free_irq(chip->irq, (void*)chip);
chip->irq = -1;
}
up(&chip->irq_mutex);
}
/*
* start / stop
*/
@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)
spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
s->suspended = 0;
/* fallthru */
case SNDRV_PCM_TRIGGER_START:
if (! s->running) {
snd_nm256_playback_start(chip, s, substream);
s->running = 1;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
s->suspended = 1;
/* fallthru */
case SNDRV_PCM_TRIGGER_STOP:
if (s->running) {
snd_nm256_playback_stop(chip);
s->running = 0;
@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
if (snd_nm256_acquire_irq(chip) < 0)
return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
substream, &snd_nm256_playback);
return 0;
@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
if (snd_nm256_acquire_irq(chip) < 0)
return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
substream, &snd_nm256_capture);
return 0;
@ -839,6 +881,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
static int
snd_nm256_playback_close(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
snd_nm256_release_irq(chip);
return 0;
}
@ -846,6 +891,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream)
static int
snd_nm256_capture_close(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
snd_nm256_release_irq(chip);
return 0;
}
@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
static void
snd_nm256_init_chip(nm256_t *chip)
{
spin_lock_irq(&chip->reg_lock);
/* Reset everything. */
snd_nm256_writeb(chip, 0x0, 0x11);
snd_nm256_writew(chip, 0x214, 0);
/* stop sounds.. */
//snd_nm256_playback_stop(chip);
//snd_nm256_capture_stop(chip);
spin_unlock_irq(&chip->reg_lock);
}
static inline void
static irqreturn_t
snd_nm256_intr_check(nm256_t *chip)
{
if (chip->badintrcount++ > 1000) {
@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
snd_nm256_capture_stop(chip);
chip->badintrcount = 0;
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/*
@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readw(chip, NM_INT_REG);
/* Not ours. */
if (status == 0) {
snd_nm256_intr_check(chip);
return IRQ_NONE;
}
if (status == 0)
return snd_nm256_intr_check(chip);
chip->badintrcount = 0;
@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readl(chip, NM_INT_REG);
/* Not ours. */
if (status == 0) {
snd_nm256_intr_check(chip);
return IRQ_NONE;
}
if (status == 0)
return snd_nm256_intr_check(chip);
chip->badintrcount = 0;
@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
AC97_EXTENDED_ID,
/*AC97_EXTENDED_ID,*/
AC97_VENDOR_ID1, AC97_VENDOR_ID2,
-1
};
@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
for (i = 0; mixer_regs[i] >= 0; i++)
set_bit(mixer_regs[i], ac97.reg_accessed);
ac97.private_data = chip;
pbus->no_vra = 1;
err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
if (err < 0)
return err;
@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
static int nm256_resume(snd_card_t *card)
{
nm256_t *chip = card->pm_private_data;
int i;
/* Perform a full reset on the hardware */
pci_enable_device(chip->pci);
@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
/* restore ac97 */
snd_ac97_resume(chip->ac97);
for (i = 0; i < 2; i++) {
nm256_stream_t *s = &chip->streams[i];
if (s->substream && s->suspended) {
spin_lock_irq(&chip->reg_lock);
snd_nm256_set_format(chip, s, s->substream);
spin_unlock_irq(&chip->reg_lock);
}
}
return 0;
}
#endif /* CONFIG_PM */
@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->use_cache = usecache;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
init_MUTEX(&chip->irq_mutex);
chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
}
/* acquire interrupt */
if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
card->driver, (void*)chip)) {
err = -EBUSY;
snd_printk("unable to grab IRQ %d\n", pci->irq);
goto __error;
}
chip->irq = pci->irq;
/* Fixed setting. */
chip->mixer_base = NM_MIXER_OFFSET;

View File

@ -1900,7 +1900,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
.info = snd_rme32_control_spdif_mask_info,
.get = snd_rme32_control_spdif_mask_get,
@ -1908,7 +1908,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
.info = snd_rme32_control_spdif_mask_info,
.get = snd_rme32_control_spdif_mask_get,

View File

@ -2266,7 +2266,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_rme96_control_spdif_mask_info,
.get = snd_rme96_control_spdif_mask_get,
@ -2276,7 +2276,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_rme96_control_spdif_mask_info,
.get = snd_rme96_control_spdif_mask_get,

View File

@ -1524,7 +1524,7 @@ static int snd_hdsp_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_SPDIF_IN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_spdif_in, \
@ -1584,7 +1584,7 @@ static int snd_hdsp_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_SPDIF_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
@ -1638,7 +1638,7 @@ static int snd_hdsp_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
}
#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
@ -1683,7 +1683,7 @@ static int snd_hdsp_put_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_SPDIF_EMPHASIS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
@ -1728,7 +1728,7 @@ static int snd_hdsp_put_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
}
#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
@ -1773,7 +1773,7 @@ static int snd_hdsp_put_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
}
#define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1834,7 +1834,7 @@ static int snd_hdsp_get_spdif_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_ele
}
#define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1858,7 +1858,7 @@ static int snd_hdsp_get_system_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1918,7 +1918,7 @@ static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_
}
#define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1958,7 +1958,7 @@ static int snd_hdsp_get_system_clock_mode(snd_kcontrol_t * kcontrol, snd_ctl_ele
}
#define HDSP_CLOCK_SOURCE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_clock_source, \
@ -2124,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_ele
}
#define HDSP_DA_GAIN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_da_gain, \
@ -2210,7 +2210,7 @@ static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_AD_GAIN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_ad_gain, \
@ -2296,7 +2296,7 @@ static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_PHONE_GAIN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_phone_gain, \
@ -2382,7 +2382,7 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value
}
#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_xlr_breakout_cable, \
@ -2447,7 +2447,7 @@ static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_el
Switching this on desactivates external ADAT
*/
#define HDSP_AEB(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_aeb, \
@ -2508,7 +2508,7 @@ static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * uc
}
#define HDSP_PREF_SYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_pref_sync_ref, \
@ -2641,7 +2641,7 @@ static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define HDSP_AUTOSYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -2697,7 +2697,7 @@ static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define HDSP_LINE_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_line_out, \
@ -2757,7 +2757,7 @@ static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_PRECISE_POINTER(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_precise_pointer, \
@ -2811,7 +2811,7 @@ static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_
}
#define HDSP_USE_MIDI_TASKLET(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_use_midi_tasklet, \
@ -2868,6 +2868,7 @@ static int snd_hdsp_put_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
.name = xname, \
.index = xindex, \
.device = 0, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdsp_info_mixer, \
@ -2939,7 +2940,7 @@ static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
}
#define HDSP_WC_SYNC_CHECK(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@ -2983,7 +2984,7 @@ static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@ -3015,7 +3016,7 @@ static int snd_hdsp_get_spdif_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem
}
#define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@ -3046,7 +3047,7 @@ static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_e
}
#define HDSP_ADAT_SYNC_CHECK \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdsp_info_sync_check, \
.get = snd_hdsp_get_adat_sync_check \
@ -3119,7 +3120,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_hdsp_control_spdif_mask_info,
.get = snd_hdsp_control_spdif_mask_get,
@ -3129,7 +3130,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_hdsp_control_spdif_mask_info,
.get = snd_hdsp_control_spdif_mask_get,
@ -3146,8 +3147,6 @@ HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
{
/* FIXME: should be PCM or MIXER? */
/* .iface = SNDRV_CTL_ELEM_IFACE_PCM, */
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Sample Clock Source Locking",
.info = snd_hdsp_info_clock_source_lock,

View File

@ -65,7 +65,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
module_param_array(precise_ptr, bool, NULL, 0444);
MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable.");
MODULE_PARM_DESC(precise_ptr, "Enable or disable precise pointer.");
module_param_array(line_outs_monitor, bool, NULL, 0444);
MODULE_PARM_DESC(line_outs_monitor,
@ -1104,14 +1104,14 @@ static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream)
return 0;
}
snd_rawmidi_ops_t snd_hdspm_midi_output =
static snd_rawmidi_ops_t snd_hdspm_midi_output =
{
.open = snd_hdspm_midi_output_open,
.close = snd_hdspm_midi_output_close,
.trigger = snd_hdspm_midi_output_trigger,
};
snd_rawmidi_ops_t snd_hdspm_midi_input =
static snd_rawmidi_ops_t snd_hdspm_midi_input =
{
.open = snd_hdspm_midi_input_open,
.close = snd_hdspm_midi_input_close,
@ -1168,7 +1168,7 @@ static void hdspm_midi_tasklet(unsigned long arg)
/* get the system sample rate which is set */
#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1195,7 +1195,7 @@ static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol,
}
#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1264,7 +1264,7 @@ static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol,
}
#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1310,7 +1310,7 @@ static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol,
}
#define HDSPM_CLOCK_SOURCE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_clock_source, \
@ -1457,7 +1457,7 @@ static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol,
}
#define HDSPM_PREF_SYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_pref_sync_ref, \
@ -1547,7 +1547,7 @@ static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol,
}
#define HDSPM_AUTOSYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@ -1604,7 +1604,7 @@ static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol,
}
#define HDSPM_LINE_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_line_out, \
@ -1668,7 +1668,7 @@ static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol,
}
#define HDSPM_TX_64(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_tx_64, \
@ -1731,7 +1731,7 @@ static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol,
}
#define HDSPM_C_TMS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_c_tms, \
@ -1794,7 +1794,7 @@ static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol,
}
#define HDSPM_SAFE_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_safe_mode, \
@ -1857,7 +1857,7 @@ static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol,
}
#define HDSPM_INPUT_SELECT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_input_select, \
@ -1941,6 +1941,7 @@ static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol,
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
.name = xname, \
.index = xindex, \
.device = 0, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdspm_info_mixer, \
@ -2124,7 +2125,7 @@ static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol,
}
#define HDSPM_WC_SYNC_CHECK(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@ -2170,7 +2171,7 @@ static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol,
#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \

View File

@ -893,7 +893,7 @@ static int snd_rme9652_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl
}
#define RME9652_ADAT1_IN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_adat1_in, \
.get = snd_rme9652_get_adat1_in, \
.put = snd_rme9652_put_adat1_in }
@ -971,7 +971,7 @@ static int snd_rme9652_put_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
#define RME9652_SPDIF_IN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_in, \
.get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
@ -1042,7 +1042,7 @@ static int snd_rme9652_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
#define RME9652_SPDIF_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_out, \
.get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
@ -1110,7 +1110,7 @@ static int snd_rme9652_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_SYNC_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_mode, \
.get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
@ -1195,7 +1195,7 @@ static int snd_rme9652_put_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_SYNC_PREF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_pref, \
.get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
@ -1340,7 +1340,7 @@ static int snd_rme9652_put_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define RME9652_PASSTHRU(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_passthru, \
.put = snd_rme9652_put_passthru, \
.get = snd_rme9652_get_passthru }
@ -1386,7 +1386,7 @@ static int snd_rme9652_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
/* Read-only switches */
#define RME9652_SPDIF_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_spdif_rate, \
.get = snd_rme9652_get_spdif_rate }
@ -1411,7 +1411,7 @@ static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define RME9652_ADAT_SYNC(xname, xindex, xidx) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_adat_sync, \
.get = snd_rme9652_get_adat_sync, .private_value = xidx }
@ -1447,7 +1447,7 @@ static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_TC_VALID(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_tc_valid, \
.get = snd_rme9652_get_tc_valid }
@ -1545,7 +1545,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
@ -1555,7 +1555,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
@ -1568,7 +1568,7 @@ RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
RME9652_SYNC_MODE("Sync Mode", 0),
RME9652_SYNC_PREF("Preferred Sync Source", 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channels Thru",
.index = 0,
.info = snd_rme9652_info_thru,

View File

@ -1689,7 +1689,7 @@ static snd_pcm_hardware_t snd_trident_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@ -1714,7 +1714,7 @@ static snd_pcm_hardware_t snd_trident_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@ -1739,7 +1739,7 @@ static snd_pcm_hardware_t snd_trident_foldback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@ -1763,7 +1763,7 @@ static snd_pcm_hardware_t snd_trident_spdif =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000),
@ -1784,7 +1784,7 @@ static snd_pcm_hardware_t snd_trident_spdif_7018 =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,

View File

@ -663,10 +663,12 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
val = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
val |= VIA_REG_CTRL_START;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break;
@ -929,12 +931,12 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0)
return rate_changed;
if (rate_changed) {
if (rate_changed)
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
chip->no_vra ? 48000 : runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF,
chip->no_vra ? 48000 : runtime->rate);
}
if (chip->spdif_on && viadev->reg_offset == 0x30)
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
if (runtime->rate == 48000)
rbits = 0xfffff;
else
@ -1035,7 +1037,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
/* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
@ -1484,7 +1486,7 @@ static int snd_via8233_dxs3_spdif_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
}
static snd_kcontrol_new_t snd_via8233_dxs3_spdif_control __devinitdata = {
.name = "IEC958 Output Switch",
.name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_via8233_dxs3_spdif_info,
.get = snd_via8233_dxs3_spdif_get,
@ -2153,6 +2155,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
{ .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
{ .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
{ .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
{ .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
{ .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
{ .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
@ -2168,10 +2171,12 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
{ .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
{ .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
{ .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
{ .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
{ .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
{ .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
{ .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
{ .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
{ .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
{ .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
{ .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */

View File

@ -521,6 +521,7 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_SUSPEND:
val |= VIA_REG_CTRL_START;
viadev->running = 1;
break;
@ -697,7 +698,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
/* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,

View File

@ -321,6 +321,26 @@ static void snd_ymfpci_pcm_interrupt(ymfpci_t *chip, ymfpci_voice_t *voice)
snd_pcm_period_elapsed(ypcm->substream);
spin_lock(&chip->reg_lock);
}
if (unlikely(ypcm->update_pcm_vol)) {
unsigned int subs = ypcm->substream->number;
unsigned int next_bank = 1 - chip->active_bank;
snd_ymfpci_playback_bank_t *bank;
u32 volume;
bank = &voice->bank[next_bank];
volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
bank->left_gain_end = volume;
if (ypcm->output_rear)
bank->eff2_gain_end = volume;
if (ypcm->voices[1])
bank = &ypcm->voices[1]->bank[next_bank];
volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
bank->right_gain_end = volume;
if (ypcm->output_rear)
bank->eff3_gain_end = volume;
ypcm->update_pcm_vol--;
}
}
spin_unlock(&chip->reg_lock);
}
@ -451,87 +471,74 @@ static int snd_ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices)
return 0;
}
static void snd_ymfpci_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
int rate, int w_16, unsigned long addr,
unsigned int end,
int output_front, int output_rear)
static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx,
snd_pcm_runtime_t *runtime,
int has_pcm_volume)
{
ymfpci_voice_t *voice = ypcm->voices[voiceidx];
u32 format;
u32 delta = snd_ymfpci_calc_delta(rate);
u32 lpfQ = snd_ymfpci_calc_lpfQ(rate);
u32 lpfK = snd_ymfpci_calc_lpfK(rate);
u32 delta = snd_ymfpci_calc_delta(runtime->rate);
u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
snd_ymfpci_playback_bank_t *bank;
unsigned int nbank;
u32 vol_left, vol_right;
u8 use_left, use_right;
snd_assert(voice != NULL, return);
format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
if (runtime->channels == 1) {
use_left = 1;
use_right = 1;
} else {
use_left = (voiceidx & 1) == 0;
use_right = !use_left;
}
if (has_pcm_volume) {
vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
[ypcm->substream->number].left << 15);
vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
[ypcm->substream->number].right << 15);
} else {
vol_left = cpu_to_le32(0x40000000);
vol_right = cpu_to_le32(0x40000000);
}
format = runtime->channels == 2 ? 0x00010000 : 0;
if (snd_pcm_format_width(runtime->format) == 8)
format |= 0x80000000;
if (runtime->channels == 2 && (voiceidx & 1) != 0)
format |= 1;
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
memset(bank, 0, sizeof(*bank));
bank->format = cpu_to_le32(format);
bank->loop_default = 0;
bank->base = cpu_to_le32(addr);
bank->loop_start = 0;
bank->loop_end = cpu_to_le32(end);
bank->loop_frac = 0;
bank->eg_gain_end = cpu_to_le32(0x40000000);
bank->base = cpu_to_le32(runtime->dma_addr);
bank->loop_end = cpu_to_le32(ypcm->buffer_size);
bank->lpfQ = cpu_to_le32(lpfQ);
bank->status = 0;
bank->num_of_frames = 0;
bank->loop_count = 0;
bank->start = 0;
bank->start_frac = 0;
bank->delta =
bank->delta_end = cpu_to_le32(delta);
bank->lpfK =
bank->lpfK_end = cpu_to_le32(lpfK);
bank->eg_gain = cpu_to_le32(0x40000000);
bank->lpfD1 =
bank->lpfD2 = 0;
bank->eg_gain =
bank->eg_gain_end = cpu_to_le32(0x40000000);
bank->left_gain =
bank->right_gain =
bank->left_gain_end =
bank->right_gain_end =
bank->eff1_gain =
bank->eff2_gain =
bank->eff3_gain =
bank->eff1_gain_end =
bank->eff2_gain_end =
bank->eff3_gain_end = 0;
if (!stereo) {
if (output_front) {
bank->left_gain =
if (ypcm->output_front) {
if (use_left) {
bank->left_gain =
bank->left_gain_end = vol_left;
}
if (use_right) {
bank->right_gain =
bank->left_gain_end =
bank->right_gain_end = cpu_to_le32(0x40000000);
bank->right_gain_end = vol_right;
}
if (output_rear) {
}
if (ypcm->output_rear) {
if (use_left) {
bank->eff2_gain =
bank->eff2_gain_end =
bank->eff2_gain_end = vol_left;
}
if (use_right) {
bank->eff3_gain =
bank->eff3_gain_end = cpu_to_le32(0x40000000);
}
} else {
if (output_front) {
if ((voice->number & 1) == 0) {
bank->left_gain =
bank->left_gain_end = cpu_to_le32(0x40000000);
} else {
bank->format |= cpu_to_le32(1);
bank->right_gain =
bank->right_gain_end = cpu_to_le32(0x40000000);
}
}
if (output_rear) {
if ((voice->number & 1) == 0) {
bank->eff3_gain =
bank->eff3_gain_end = cpu_to_le32(0x40000000);
} else {
bank->format |= cpu_to_le32(1);
bank->eff2_gain =
bank->eff2_gain_end = cpu_to_le32(0x40000000);
}
bank->eff3_gain_end = vol_right;
}
}
}
@ -613,7 +620,7 @@ static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream)
static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
{
// ymfpci_t *chip = snd_pcm_substream_chip(substream);
ymfpci_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
ymfpci_pcm_t *ypcm = runtime->private_data;
unsigned int nvoice;
@ -623,14 +630,8 @@ static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
ypcm->period_pos = 0;
ypcm->last_pos = 0;
for (nvoice = 0; nvoice < runtime->channels; nvoice++)
snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice],
runtime->channels == 2,
runtime->rate,
snd_pcm_format_width(runtime->format) == 16,
runtime->dma_addr,
ypcm->buffer_size,
ypcm->output_front,
ypcm->output_rear);
snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
substream->pcm == chip->pcm);
return 0;
}
@ -882,6 +883,7 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
ymfpci_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
ymfpci_pcm_t *ypcm;
snd_kcontrol_t *kctl;
int err;
if ((err = snd_ymfpci_playback_open_1(substream)) < 0)
@ -895,6 +897,10 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
chip->rear_opened++;
}
spin_unlock_irq(&chip->reg_lock);
kctl = chip->pcm_mixer[substream->number].ctl;
kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return 0;
}
@ -987,6 +993,7 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
{
ymfpci_t *chip = snd_pcm_substream_chip(substream);
ymfpci_pcm_t *ypcm = substream->runtime->private_data;
snd_kcontrol_t *kctl;
spin_lock_irq(&chip->reg_lock);
if (ypcm->output_rear && chip->rear_opened > 0) {
@ -994,6 +1001,9 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
ymfpci_close_extension(chip);
}
spin_unlock_irq(&chip->reg_lock);
kctl = chip->pcm_mixer[substream->number].ctl;
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return snd_ymfpci_playback_close_1(substream);
}
@ -1665,6 +1675,66 @@ static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = {
.private_value = 2,
};
/*
* PCM voice volume
*/
static int snd_ymfpci_pcm_vol_info(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 = 0x8000;
return 0;
}
static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
unsigned int subs = kcontrol->id.subdevice;
ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
return 0;
}
static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
unsigned int subs = kcontrol->id.subdevice;
snd_pcm_substream_t *substream;
unsigned long flags;
if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
substream = (snd_pcm_substream_t *)kcontrol->private_value;
spin_lock_irqsave(&chip->voice_lock, flags);
if (substream->runtime && substream->runtime->private_data) {
ymfpci_pcm_t *ypcm = substream->runtime->private_data;
ypcm->update_pcm_vol = 2;
}
spin_unlock_irqrestore(&chip->voice_lock, flags);
return 1;
}
return 0;
}
static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PCM Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.info = snd_ymfpci_pcm_vol_info,
.get = snd_ymfpci_pcm_vol_get,
.put = snd_ymfpci_pcm_vol_put,
};
/*
* Mixer routines
@ -1686,6 +1756,7 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
{
ac97_template_t ac97;
snd_kcontrol_t *kctl;
snd_pcm_substream_t *substream;
unsigned int idx;
int err;
static ac97_bus_ops_t ops = {
@ -1739,6 +1810,23 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
return err;
}
/* per-voice volume */
substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
for (idx = 0; idx < 32; ++idx) {
kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
if (!kctl)
return -ENOMEM;
kctl->id.device = chip->pcm->device;
kctl->id.subdevice = idx;
kctl->private_value = (unsigned long)substream;
if ((err = snd_ctl_add(chip->card, kctl)) < 0)
return err;
chip->pcm_mixer[idx].left = 0x8000;
chip->pcm_mixer[idx].right = 0x8000;
chip->pcm_mixer[idx].ctl = kctl;
substream = substream->next;
}
return 0;
}

View File

@ -297,6 +297,7 @@ static void vxpocket_config(dev_link_t *link)
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
chip->dev = &handle_to_dev(link->handle);
snd_card_set_dev(chip->card, chip->dev);
if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
goto failed;
@ -376,7 +377,7 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
/*
*/
static dev_link_t *vxp_attach(void)
static dev_link_t *vxpocket_attach(void)
{
snd_card_t *card;
struct snd_vxpocket *vxp;
@ -407,7 +408,7 @@ static dev_link_t *vxp_attach(void)
return NULL;
}
vxp->index = index[i];
vxp->index = i;
card_alloc |= 1 << i;
/* Chain drivers */
@ -417,7 +418,7 @@ static dev_link_t *vxp_attach(void)
return &vxp->link;
}
static void vxp_detach(dev_link_t *link)
static void vxpocket_detach(dev_link_t *link)
{
struct snd_vxpocket *vxp;
vx_core_t *chip;
@ -458,8 +459,9 @@ static struct pcmcia_driver vxp_cs_driver = {
.drv = {
.name = "snd-vxpocket",
},
.attach = vxp_attach,
.detach = vxp_detach,
.attach = vxpocket_attach,
.detach = vxpocket_detach,
.event = vxpocket_event,
.id_table = vxp_ids,
};

View File

@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(sound_loader_lock);
* list. Acquires locks as needed
*/
static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
{
struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
int r;
@ -175,7 +175,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
S_IFCHR | mode, s->name);
class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
NULL, s->name+6);
dev, s->name+6);
return r;
fail:
@ -227,16 +227,18 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
static struct sound_unit *chains[SOUND_STEP];
/**
* register_sound_special - register a special sound node
* register_sound_special_device - register a special sound node
* @fops: File operations for the driver
* @unit: Unit number to allocate
* @dev: device pointer
*
* Allocate a special sound device by minor number from the sound
* subsystem. The allocated number is returned on succes. On failure
* a negative error code is returned.
*/
int register_sound_special(struct file_operations *fops, int unit)
int register_sound_special_device(struct file_operations *fops, int unit,
struct device *dev)
{
const int chain = unit % SOUND_STEP;
int max_unit = 128 + chain;
@ -294,9 +296,16 @@ int register_sound_special(struct file_operations *fops, int unit)
break;
}
return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
name, S_IRUSR | S_IWUSR);
name, S_IRUSR | S_IWUSR, dev);
}
EXPORT_SYMBOL(register_sound_special_device);
int register_sound_special(struct file_operations *fops, int unit)
{
return register_sound_special_device(fops, unit, NULL);
}
EXPORT_SYMBOL(register_sound_special);
/**
@ -312,7 +321,7 @@ EXPORT_SYMBOL(register_sound_special);
int register_sound_mixer(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[0], fops, dev, 0, 128,
"mixer", S_IRUSR | S_IWUSR);
"mixer", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_mixer);
@ -330,7 +339,7 @@ EXPORT_SYMBOL(register_sound_mixer);
int register_sound_midi(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[2], fops, dev, 2, 130,
"midi", S_IRUSR | S_IWUSR);
"midi", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_midi);
@ -356,7 +365,7 @@ EXPORT_SYMBOL(register_sound_midi);
int register_sound_dsp(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[3], fops, dev, 3, 131,
"dsp", S_IWUSR | S_IRUSR);
"dsp", S_IWUSR | S_IRUSR, NULL);
}
EXPORT_SYMBOL(register_sound_dsp);
@ -375,7 +384,7 @@ EXPORT_SYMBOL(register_sound_dsp);
int register_sound_synth(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[9], fops, dev, 9, 137,
"synth", S_IRUSR | S_IWUSR);
"synth", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_synth);

View File

@ -98,7 +98,6 @@ snd_emux_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
vp = emu->ops.get_voice(emu, port);
if (vp == NULL || vp->ch < 0)
continue;
snd_assert(vp->emu != NULL && vp->hw != NULL, return);
if (STATE_IS_PLAYING(vp->state))
emu->ops.terminate(vp);

View File

@ -41,10 +41,12 @@
#include <sound/driver.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/info.h>
@ -79,7 +81,7 @@ module_param_array(vid, int, NULL, 0444);
MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
module_param_array(pid, int, NULL, 0444);
MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
module_param(nrpacks, int, 0444);
module_param(nrpacks, int, 0644);
MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
module_param(async_unlink, bool, 0444);
MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
@ -97,7 +99,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
#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 8
#define SYNC_URBS 4 /* always four urbs for sync */
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
@ -126,11 +128,10 @@ struct audioformat {
struct snd_urb_ctx {
struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
snd_usb_substream_t *subs;
int index; /* index for urb array */
int packets; /* number of packets per urb */
int transfer; /* transferred size */
char *buf; /* buffer for capture */
};
struct snd_urb_ops {
@ -165,12 +166,11 @@ struct snd_usb_substream {
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int fill_max: 1; /* fill max packet size always */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int packs_per_ms; /* packets per millisecond (for playback) */
unsigned int running: 1; /* running status */
unsigned int hwptr; /* free frame position in the buffer (only for playback) */
unsigned int hwptr_done; /* processed frame position in the buffer */
unsigned int transfer_sched; /* scheduled frames since last period (for playback) */
unsigned int transfer_done; /* processed frames since last period update */
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
@ -178,13 +178,14 @@ 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 * 4]; /* sync buffer; it's so small - let's get static */
char *tmpbuf; /* temporary buffer for playback */
char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
struct list_head fmt_list; /* format list */
spinlock_t lock;
struct tasklet_struct start_period_elapsed; /* for start trigger */
struct snd_urb_ops ops; /* callbacks (must be filled at init) */
};
@ -311,27 +312,17 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
struct urb *urb)
{
int i, offs;
unsigned long flags;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
offs = 0;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->number_of_packets = 0;
spin_lock_irqsave(&subs->lock, flags);
for (i = 0; i < ctx->packets; i++) {
urb->iso_frame_desc[i].offset = offs;
urb->iso_frame_desc[i].length = subs->curpacksize;
offs += subs->curpacksize;
urb->number_of_packets++;
subs->transfer_sched += subs->curframesize;
if (subs->transfer_sched >= runtime->period_size) {
subs->transfer_sched -= runtime->period_size;
break;
}
}
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer = ctx->buf;
urb->transfer_buffer_length = offs;
urb->number_of_packets = ctx->packets;
#if 0 // for check
if (! urb->bandwidth) {
int bustime;
@ -359,6 +350,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
unsigned char *cp;
int i;
unsigned int stride, len, oldptr;
int period_elapsed = 0;
stride = runtime->frame_bits >> 3;
@ -378,6 +370,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
if (subs->hwptr_done >= runtime->buffer_size)
subs->hwptr_done -= runtime->buffer_size;
subs->transfer_done += len;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
}
spin_unlock_irqrestore(&subs->lock, flags);
/* copy a data chunk */
if (oldptr + len > runtime->buffer_size) {
@ -388,15 +384,9 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
} else {
memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
}
/* update the pointer, call callback if necessary */
spin_lock_irqsave(&subs->lock, flags);
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
spin_unlock_irqrestore(&subs->lock, flags);
snd_pcm_period_elapsed(subs->pcm_substream);
} else
spin_unlock_irqrestore(&subs->lock, flags);
}
if (period_elapsed)
snd_pcm_period_elapsed(subs->pcm_substream);
return 0;
}
@ -492,12 +482,10 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
/*
* prepare urb for playback data pipe
*
* we copy the data directly from the pcm buffer.
* the current position to be copied is held in hwptr field.
* since a urb can handle only a single linear buffer, if the total
* transferred area overflows the buffer boundary, we cannot send
* it directly from the buffer. thus the data is once copied to
* a temporary buffer and urb points to that.
* Since a URB can handle only a single linear buffer, we must use double
* buffering when the data to be transferred overflows the buffer boundary.
* To avoid inconsistencies when updating hwptr_done, we use double buffering
* for all URBs.
*/
static int prepare_playback_urb(snd_usb_substream_t *subs,
snd_pcm_runtime_t *runtime,
@ -506,6 +494,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
int i, stride, offs;
unsigned int counts;
unsigned long flags;
int period_elapsed = 0;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
stride = runtime->frame_bits >> 3;
@ -530,80 +519,85 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
urb->iso_frame_desc[i].length = counts * stride;
offs += counts;
urb->number_of_packets++;
subs->transfer_sched += counts;
if (subs->transfer_sched >= runtime->period_size) {
subs->transfer_sched -= runtime->period_size;
subs->transfer_done += counts;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
if (subs->fmt_type == USB_FORMAT_TYPE_II) {
if (subs->transfer_sched > 0) {
/* FIXME: fill-max mode is not supported yet */
offs -= subs->transfer_sched;
counts -= subs->transfer_sched;
urb->iso_frame_desc[i].length = counts * stride;
subs->transfer_sched = 0;
if (subs->transfer_done > 0) {
/* FIXME: fill-max mode is not
* supported yet */
offs -= subs->transfer_done;
counts -= subs->transfer_done;
urb->iso_frame_desc[i].length =
counts * stride;
subs->transfer_done = 0;
}
i++;
if (i < ctx->packets) {
/* add a transfer delimiter */
urb->iso_frame_desc[i].offset = offs * stride;
urb->iso_frame_desc[i].offset =
offs * stride;
urb->iso_frame_desc[i].length = 0;
urb->number_of_packets++;
}
break;
}
break;
}
/* finish at the frame boundary at/after the period boundary */
if (period_elapsed &&
(i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
break;
}
if (subs->hwptr + offs > runtime->buffer_size) {
/* err, the transferred area goes over buffer boundary.
* copy the data to the temp buffer.
*/
int len;
len = runtime->buffer_size - subs->hwptr;
urb->transfer_buffer = subs->tmpbuf;
memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride);
memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride);
subs->hwptr += offs;
subs->hwptr -= runtime->buffer_size;
if (subs->hwptr_done + offs > runtime->buffer_size) {
/* err, the transferred area goes over buffer boundary. */
unsigned int len = runtime->buffer_size - subs->hwptr_done;
memcpy(urb->transfer_buffer,
runtime->dma_area + subs->hwptr_done * stride,
len * stride);
memcpy(urb->transfer_buffer + len * stride,
runtime->dma_area,
(offs - len) * stride);
} else {
/* set the buffer pointer */
urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
subs->hwptr += offs;
if (subs->hwptr == runtime->buffer_size)
subs->hwptr = 0;
memcpy(urb->transfer_buffer,
runtime->dma_area + subs->hwptr_done * stride,
offs * stride);
}
subs->hwptr_done += offs;
if (subs->hwptr_done >= runtime->buffer_size)
subs->hwptr_done -= runtime->buffer_size;
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride;
ctx->transfer = offs;
if (period_elapsed) {
if (likely(subs->running))
snd_pcm_period_elapsed(subs->pcm_substream);
else
tasklet_hi_schedule(&subs->start_period_elapsed);
}
return 0;
}
/*
* process after playback data complete
*
* update the current position and call callback if a period is processed.
* - nothing to do
*/
static int retire_playback_urb(snd_usb_substream_t *subs,
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
unsigned long flags;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
spin_lock_irqsave(&subs->lock, flags);
subs->transfer_done += ctx->transfer;
subs->hwptr_done += ctx->transfer;
ctx->transfer = 0;
if (subs->hwptr_done >= runtime->buffer_size)
subs->hwptr_done -= runtime->buffer_size;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
spin_unlock_irqrestore(&subs->lock, flags);
snd_pcm_period_elapsed(subs->pcm_substream);
} else
spin_unlock_irqrestore(&subs->lock, flags);
return 0;
}
/*
* Delay the snd_pcm_period_elapsed() call until after the start trigger
* callback so that we're not longer in the substream's lock.
*/
static void start_period_elapsed(unsigned long data)
{
snd_usb_substream_t *subs = (snd_usb_substream_t *)data;
snd_pcm_period_elapsed(subs->pcm_substream);
}
/*
*/
@ -683,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
}
/* get the physical page pointer at the given offset */
static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
unsigned long offset)
{
void *pageptr = subs->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
/* allocate virtual buffer; may be called more than once */
static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
{
snd_pcm_runtime_t *runtime = subs->runtime;
if (runtime->dma_area) {
if (runtime->dma_bytes >= size)
return 0; /* already large enough */
vfree_nocheck(runtime->dma_area);
}
runtime->dma_area = vmalloc_nocheck(size);
if (! runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 0;
}
/* free virtual buffer; may be called more than once */
static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
{
snd_pcm_runtime_t *runtime = subs->runtime;
if (runtime->dma_area) {
vfree_nocheck(runtime->dma_area);
runtime->dma_area = NULL;
}
return 0;
}
/*
* unlink active urbs.
*/
@ -824,8 +854,14 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
*/
static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
{
snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
return subs->hwptr_done;
snd_usb_substream_t *subs;
snd_pcm_uframes_t hwptr_done;
subs = (snd_usb_substream_t *)substream->runtime->private_data;
spin_lock(&subs->lock);
hwptr_done = subs->hwptr_done;
spin_unlock(&subs->lock);
return hwptr_done;
}
@ -858,11 +894,13 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
static void release_urb_ctx(snd_urb_ctx_t *u)
{
if (u->urb) {
if (u->buffer_size)
usb_buffer_free(u->subs->dev, u->buffer_size,
u->urb->transfer_buffer,
u->urb->transfer_dma);
usb_free_urb(u->urb);
u->urb = NULL;
}
kfree(u->buf);
u->buf = NULL;
}
/*
@ -880,8 +918,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
release_urb_ctx(&subs->dataurb[i]);
for (i = 0; i < SYNC_URBS; i++)
release_urb_ctx(&subs->syncurb[i]);
kfree(subs->tmpbuf);
subs->tmpbuf = NULL;
usb_buffer_free(subs->dev, SYNC_URBS * 4,
subs->syncbuf, subs->sync_dma);
subs->syncbuf = NULL;
subs->nurbs = 0;
}
@ -893,7 +932,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
{
unsigned int maxsize, n, i;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int npacks[MAX_URBS], urb_packs, total_packs;
unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
/* calculate the frequency in 16.16 format */
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@ -920,24 +959,40 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
else
subs->curpacksize = maxsize;
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
urb_packs = nrpacks;
if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
packs_per_ms = 8 >> subs->datainterval;
else
urb_packs = (nrpacks * 8) >> subs->datainterval;
packs_per_ms = 1;
subs->packs_per_ms = packs_per_ms;
/* allocate a temporary buffer for playback */
if (is_playback) {
subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
if (! subs->tmpbuf) {
snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
return -ENOMEM;
}
}
urb_packs = nrpacks;
urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
} else
urb_packs = 1;
urb_packs *= packs_per_ms;
/* decide how many packets to be used */
total_packs = (period_bytes + maxsize - 1) / maxsize;
if (total_packs < 2 * MIN_PACKS_URB)
total_packs = 2 * MIN_PACKS_URB;
if (is_playback) {
unsigned int minsize;
/* determine how small a packet can be */
minsize = (subs->freqn >> (16 - subs->datainterval))
* (frame_bits >> 3);
/* with sync from device, assume it can be 12% lower */
if (subs->syncpipe)
minsize -= minsize >> 3;
minsize = max(minsize, 1u);
total_packs = (period_bytes + minsize - 1) / minsize;
/* round up to multiple of packs_per_ms */
total_packs = (total_packs + packs_per_ms - 1)
& ~(packs_per_ms - 1);
/* we need at least two URBs for queueing */
if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
} else {
total_packs = MAX_URBS * urb_packs;
}
subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
if (subs->nurbs > MAX_URBS) {
/* too much... */
@ -956,7 +1011,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
subs->nurbs = 2;
npacks[0] = (total_packs + 1) / 2;
npacks[1] = total_packs - npacks[0];
} else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
} else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
/* the last packet is too small.. */
if (subs->nurbs > 2) {
/* merge to the first one */
@ -975,27 +1030,20 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
snd_urb_ctx_t *u = &subs->dataurb[i];
u->index = i;
u->subs = subs;
u->transfer = 0;
u->packets = npacks[i];
u->buffer_size = maxsize * u->packets;
if (subs->fmt_type == USB_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */
if (! is_playback) {
/* allocate a capture buffer per urb */
u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
if (! u->buf) {
release_substream_urbs(subs, 0);
return -ENOMEM;
}
}
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
if (! u->urb) {
release_substream_urbs(subs, 0);
return -ENOMEM;
}
u->urb->dev = subs->dev;
if (! u->urb)
goto out_of_memory;
u->urb->transfer_buffer =
usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
&u->urb->transfer_dma);
if (! u->urb->transfer_buffer)
goto out_of_memory;
u->urb->pipe = subs->datapipe;
u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->number_of_packets = u->packets;
u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
u->urb->interval = 1 << subs->datainterval;
u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
@ -1003,21 +1051,24 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
if (subs->syncpipe) {
/* allocate and initialize sync urbs */
subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
GFP_KERNEL, &subs->sync_dma);
if (! subs->syncbuf)
goto out_of_memory;
for (i = 0; i < SYNC_URBS; i++) {
snd_urb_ctx_t *u = &subs->syncurb[i];
u->index = i;
u->subs = subs;
u->packets = 1;
u->urb = usb_alloc_urb(1, GFP_KERNEL);
if (! u->urb) {
release_substream_urbs(subs, 0);
return -ENOMEM;
}
if (! u->urb)
goto out_of_memory;
u->urb->transfer_buffer = subs->syncbuf + i * 4;
u->urb->transfer_dma = subs->sync_dma + i * 4;
u->urb->transfer_buffer_length = 4;
u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP;
u->urb->transfer_flags = URB_ISO_ASAP |
URB_NO_TRANSFER_DMA_MAP;
u->urb->number_of_packets = 1;
u->urb->interval = 1 << subs->syncinterval;
u->urb->context = u;
@ -1025,6 +1076,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
}
}
return 0;
out_of_memory:
release_substream_urbs(subs, 0);
return -ENOMEM;
}
@ -1293,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
unsigned int channels, rate, format;
int ret, changed;
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
ret = snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
@ -1349,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
subs->cur_rate = 0;
subs->period_bytes = 0;
release_substream_urbs(subs, 0);
return snd_pcm_lib_free_pages(substream);
return snd_pcm_free_vmalloc_buffer(substream);
}
/*
@ -1372,9 +1428,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
/* reset the pointer */
subs->hwptr = 0;
subs->hwptr_done = 0;
subs->transfer_sched = 0;
subs->transfer_done = 0;
subs->phase = 0;
@ -1390,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024),
.buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
@ -1402,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024),
.buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
@ -1794,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
};
static snd_pcm_ops_t snd_usb_capture_ops = {
@ -1805,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
};
@ -2021,6 +2077,9 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
INIT_LIST_HEAD(&subs->fmt_list);
spin_lock_init(&subs->lock);
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
tasklet_init(&subs->start_period_elapsed, start_period_elapsed,
(unsigned long)subs);
subs->stream = as;
subs->direction = stream;
@ -2029,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->ops = audio_urb_ops[stream];
else
subs->ops = audio_urb_ops_high_speed[stream];
snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
64 * 1024, 128 * 1024);
snd_pcm_set_ops(as->pcm, stream,
stream == SNDRV_PCM_STREAM_PLAYBACK ?
&snd_usb_playback_ops : &snd_usb_capture_ops);
@ -2078,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
snd_usb_stream_t *stream = pcm->private_data;
if (stream) {
stream->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_usb_audio_stream_free(stream);
}
}

View File

@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/minors.h>
@ -56,6 +57,12 @@
*/
/* #define DUMP_PACKETS */
/*
* how long to wait after some USB errors, so that khubd can disconnect() us
* without too many spurious errors
*/
#define ERROR_DELAY_JIFFIES (HZ / 10)
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@ -100,6 +107,7 @@ struct snd_usb_midi {
snd_rawmidi_t* rmidi;
struct usb_protocol_ops* usb_protocol_ops;
struct list_head list;
struct timer_list error_timer;
struct snd_usb_midi_endpoint {
snd_usb_midi_out_endpoint_t *out;
@ -141,7 +149,8 @@ struct snd_usb_midi_in_endpoint {
struct usbmidi_in_port {
snd_rawmidi_substream_t* substream;
} ports[0x10];
int seen_f5;
u8 seen_f5;
u8 error_resubmit;
int current_port;
};
@ -167,14 +176,22 @@ static int snd_usbmidi_submit_urb(struct urb* urb, int flags)
*/
static int snd_usbmidi_urb_error(int status)
{
if (status == -ENOENT)
return status; /* killed */
if (status == -EILSEQ ||
status == -ECONNRESET ||
status == -ETIMEDOUT)
return -ENODEV; /* device removed/shutdown */
snd_printk(KERN_ERR "urb status %d\n", status);
return 0; /* continue */
switch (status) {
/* manually unlinked, or device gone */
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
case -ENODEV:
return -ENODEV;
/* errors that might occur during unplugging */
case -EPROTO: /* EHCI */
case -ETIMEDOUT: /* OHCI */
case -EILSEQ: /* UHCI */
return -EIO;
default:
snd_printk(KERN_ERR "urb status %d\n", status);
return 0; /* continue */
}
}
/*
@ -218,8 +235,15 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
urb->actual_length);
} else {
if (snd_usbmidi_urb_error(urb->status) < 0)
int err = snd_usbmidi_urb_error(urb->status);
if (err < 0) {
if (err != -ENODEV) {
ep->error_resubmit = 1;
mod_timer(&ep->umidi->error_timer,
jiffies + ERROR_DELAY_JIFFIES);
}
return;
}
}
if (usb_pipe_needs_resubmit(urb->pipe)) {
@ -236,8 +260,13 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
ep->urb_active = 0;
spin_unlock(&ep->buffer_lock);
if (urb->status < 0) {
if (snd_usbmidi_urb_error(urb->status) < 0)
int err = snd_usbmidi_urb_error(urb->status);
if (err < 0) {
if (err != -ENODEV)
mod_timer(&ep->umidi->error_timer,
jiffies + ERROR_DELAY_JIFFIES);
return;
}
}
snd_usbmidi_do_output(ep);
}
@ -276,6 +305,24 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
snd_usbmidi_do_output(ep);
}
/* called after transfers had been interrupted due to some USB error */
static void snd_usbmidi_error_timer(unsigned long data)
{
snd_usb_midi_t *umidi = (snd_usb_midi_t *)data;
int i;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in;
if (in && in->error_resubmit) {
in->error_resubmit = 0;
in->urb->dev = umidi->chip->dev;
snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
}
if (umidi->endpoints[i].out)
snd_usbmidi_do_output(umidi->endpoints[i].out);
}
}
/* helper function to send static data that may not DMA-able */
static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
const void *data, int len)
@ -594,17 +641,20 @@ static void snd_usbmidi_emagic_finish_out(snd_usb_midi_out_endpoint_t* ep)
static void snd_usbmidi_emagic_input(snd_usb_midi_in_endpoint_t* ep,
uint8_t* buffer, int buffer_length)
{
/* ignore padding bytes at end of buffer */
while (buffer_length > 0 && buffer[buffer_length - 1] == 0xff)
--buffer_length;
int i;
/* FF indicates end of valid data */
for (i = 0; i < buffer_length; ++i)
if (buffer[i] == 0xff) {
buffer_length = i;
break;
}
/* handle F5 at end of last buffer */
if (ep->seen_f5)
goto switch_port;
while (buffer_length > 0) {
int i;
/* determine size of data until next F5 */
for (i = 0; i < buffer_length; ++i)
if (buffer[i] == 0xf5)
@ -671,6 +721,10 @@ static void snd_usbmidi_emagic_output(snd_usb_midi_out_endpoint_t* ep)
break;
}
}
if (buf_free < ep->max_transfer && buf_free > 0) {
*buf = 0xff;
--buf_free;
}
ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
}
@ -765,7 +819,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
{
if (ep->urb) {
kfree(ep->urb->transfer_buffer);
usb_buffer_free(ep->umidi->chip->dev,
ep->urb->transfer_buffer_length,
ep->urb->transfer_buffer,
ep->urb->transfer_dma);
usb_free_urb(ep->urb);
}
kfree(ep);
@ -799,7 +856,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
else
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
buffer = kmalloc(length, GFP_KERNEL);
buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
&ep->urb->transfer_dma);
if (!buffer) {
snd_usbmidi_in_endpoint_delete(ep);
return -ENOMEM;
@ -812,6 +870,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
ep);
ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
rep->in = ep;
return 0;
@ -832,10 +891,10 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x)
*/
static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
{
if (ep->tasklet.func)
tasklet_kill(&ep->tasklet);
if (ep->urb) {
kfree(ep->urb->transfer_buffer);
usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
ep->urb->transfer_buffer,
ep->urb->transfer_dma);
usb_free_urb(ep->urb);
}
kfree(ep);
@ -867,7 +926,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
/* we never use interrupt output pipes */
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
GFP_KERNEL, &ep->urb->transfer_dma);
if (!buffer) {
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
@ -875,6 +935,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
ep->max_transfer,
snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep);
ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
spin_lock_init(&ep->buffer_lock);
tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
@ -918,8 +979,11 @@ void snd_usbmidi_disconnect(struct list_head* p)
int i;
umidi = list_entry(p, snd_usb_midi_t, list);
del_timer_sync(&umidi->error_timer);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
if (ep->out)
tasklet_kill(&ep->out->tasklet);
if (ep->out && ep->out->urb) {
usb_kill_urb(ep->out->urb);
if (umidi->usb_protocol_ops->finish_out_endpoint)
@ -1480,6 +1544,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
umidi->iface = iface;
umidi->quirk = quirk;
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
init_timer(&umidi->error_timer);
umidi->error_timer.function = snd_usbmidi_error_timer;
umidi->error_timer.data = (unsigned long)umidi;
/* detect the endpoint(s) to use */
memset(endpoints, 0, sizeof(endpoints));

View File

@ -624,7 +624,7 @@ static int usX2Y_pcms_lock_check(snd_card_t *card)
for (s = 0; s < 2; ++s) {
snd_pcm_substream_t *substream;
substream = pcm->streams[s].substream;
if (substream && substream->open_flag)
if (substream && substream->ffile != NULL)
err = -EBUSY;
}
}