Commit e2094b53 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Jaroslav Kysela

[PATCH] ALSA update [7/12] - 2002/08/26

  - AC'97 codec
    - added ac97_can_amap() condition
    - removed powerup/powerdown sequence when sample rate is changed
    - added ac97_is_rev22 check function
    - added AC97_EI_* defines
    - available rates are in array
  - CS46xx
    - improved the SCB link mechanism
    - SMP deadlock should have been fixed now
  - OSS mixer emulation
    - added the proc interface for the configuration of OSS mixer volumes
  - rawmidi midlevel
    - removed unused snd_rawmidi_transmit_reset and snd_rawmidi_receive_reset functions
  - USB MIDI driver
    - integration of USB MIDI driver into USB audio driver by Clemens
  - intel8x0 - the big intel8x0 driver update
    - added support for ICH4
    - rewrited I/O (the third AC'97 codec registers are available only through memory)
    - code cleanups
    - ALI5455 specific code
    - added proc interface
  - VIA686, VIA8233
    - set the max periods to 128
parent a2755d79
......@@ -58,7 +58,7 @@
#define AC97_PCM_FRONT_DAC_RATE 0x2c /* PCM Front DAC Rate */
#define AC97_PCM_SURR_DAC_RATE 0x2e /* PCM Surround DAC Rate */
#define AC97_PCM_LFE_DAC_RATE 0x30 /* PCM LFE DAC Rate */
#define AC97_PCM_LR_ADC_RATE 0x32 /* PCM LR DAC Rate */
#define AC97_PCM_LR_ADC_RATE 0x32 /* PCM LR ADC Rate */
#define AC97_PCM_MIC_ADC_RATE 0x34 /* PCM MIC ADC Rate */
#define AC97_CENTER_LFE_MASTER 0x36 /* Center + LFE Master Volume */
#define AC97_SURROUND_MASTER 0x38 /* Surround (Rear) Master Volume */
......@@ -68,25 +68,43 @@
#define AC97_VENDOR_ID1 0x7c /* Vendor ID1 */
#define AC97_VENDOR_ID2 0x7e /* Vendor ID2 / revision */
/* extended audio ID bit defines */
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
#define AC97_EI_DRA 0x0002 /* Double rate supported */
#define AC97_EI_SPDIF 0x0004 /* S/PDIF out supported */
#define AC97_EI_VRM 0x0008 /* Variable bit rate supported for MIC */
#define AC97_EI_DACS_SLOT_MASK 0x0030 /* DACs slot assignment */
#define AC97_EI_DACS_SLOT_SHIFT 4
#define AC97_EI_CDAC 0x0040 /* PCM Center DAC available */
#define AC97_EI_SDAC 0x0080 /* PCM Surround DACs available */
#define AC97_EI_LDAC 0x0100 /* PCM LFE DAC available */
#define AC97_EI_AMAP 0x0200 /* indicates optional slot/DAC mapping based on codec ID */
#define AC97_EI_REV_MASK 0x0c00 /* AC'97 revision mask */
#define AC97_EI_REV_22 0x0100 /* AC'97 revision 2.2 */
#define AC97_EI_REV_SHIFT 8
#define AC97_EI_ADDR_MASK 0xc000 /* physical codec ID (address) */
#define AC97_EI_ADDR_SHIFT 14
/* extended audio status and control bit defines */
#define AC97_EA_VRA 0x0001 /* Variable bit rate enable bit */
#define AC97_EA_DRA 0x0002 /* Double-rate audio enable bit */
#define AC97_EA_SPDIF 0x0004 /* S/PDIF Enable bit */
#define AC97_EA_SPDIF 0x0004 /* S/PDIF out enable bit */
#define AC97_EA_VRM 0x0008 /* Variable bit rate for MIC enable bit */
#define AC97_EA_SPSA_SLOT_MASK 0x0030 /* Mask for slot assignment bits */
#define AC97_EA_SPSA_SLOT_SHIFT 4
#define AC97_EA_SPSA_3_4 0x0000 /* Slot assigned to 3 & 4 */
#define AC97_EA_SPSA_7_8 0x0010 /* Slot assigned to 7 & 8 */
#define AC97_EA_SPSA_6_9 0x0020 /* Slot assigned to 6 & 9 */
#define AC97_EA_SPSA_10_11 0x0030 /* Slot assigned to 10 & 11 */
#define AC97_EA_CDAC 0x0040 /* PCM Center DAC is ready (Read only) */
#define AC97_EA_SDAC 0x0040 /* PCM Surround DACs are ready (Read only) */
#define AC97_EA_LDAC 0x0080 /* PCM LFE DAC is ready (Read only) */
#define AC97_EA_MDAC 0x0100 /* MIC ADC is ready (Read only) */
#define AC97_EA_SDAC 0x0080 /* PCM Surround DACs are ready (Read only) */
#define AC97_EA_LDAC 0x0100 /* PCM LFE DAC is ready (Read only) */
#define AC97_EA_MDAC 0x0200 /* MIC ADC is ready (Read only) */
#define AC97_EA_SPCV 0x0400 /* S/PDIF configuration valid (Read only) */
#define AC97_EA_PRI 0x0800 /* Turns the PCM Center DAC off */
#define AC97_EA_PRJ 0x1000 /* Turns the PCM Surround DACs off */
#define AC97_EA_PRK 0x2000 /* Turns the PCM LFE DAC off */
#define AC97_EA_PRL 0x4000 /* Turns the MIC ADC off */
#define AC97_EA_SLOT_MASK 0xffcf /* Mask for slot assignment bits */
#define AC97_EA_SPSA_3_4 0x0000 /* Slot assigned to 3 & 4 */
#define AC97_EA_SPSA_7_8 0x0010 /* Slot assigned to 7 & 8 */
#define AC97_EA_SPSA_6_9 0x0020 /* Slot assigned to 6 & 9 */
#define AC97_EA_SPSA_10_11 0x0030 /* Slot assigned to 10 & 11 */
/* S/PDIF control bit defines */
#define AC97_SC_PRO 0x0001 /* Professional status */
......@@ -145,8 +163,16 @@
#define AC97_CS_SPDIF (1<<2) /* Cirrus Logic uses funky SPDIF */
#define AC97_CX_SPDIF (1<<3) /* Conexant's spdif interface */
/*
/* rates indexes */
#define AC97_RATES_FRONT_DAC 0
#define AC97_RATES_SURR_DAC 1
#define AC97_RATES_LFE_DAC 2
#define AC97_RATES_ADC 3
#define AC97_RATES_MIC_ADC 4
#define AC97_RATES_SPDIF 5
/*
*
*/
typedef struct _snd_ac97 ac97_t;
......@@ -172,11 +198,7 @@ struct _snd_ac97 {
unsigned int scaps; /* driver capabilities */
unsigned int flags; /* specific code */
unsigned int clock; /* AC'97 clock (usually 48000Hz) */
unsigned int rates_front_dac;
unsigned int rates_surr_dac;
unsigned int rates_lfe_dac;
unsigned int rates_adc;
unsigned int rates_mic_adc;
unsigned int rates[6]; /* see AC97_RATES_* defines */
unsigned int spdif_status;
unsigned short regs[0x80]; /* register cache */
unsigned int limited_regs; /* allow limited registers only */
......@@ -192,6 +214,17 @@ struct _snd_ac97 {
} spec;
};
/* conditions */
static inline int ac97_is_rev22(ac97_t * ac97)
{
return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
}
static inline int ac97_can_amap(ac97_t * ac97)
{
return (ac97->ext_id & AC97_EI_AMAP) != 0;
}
/* functions */
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);
void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value);
......
......@@ -1817,6 +1817,8 @@ struct _snd_cs46xx {
int current_gpio;
#endif
#ifdef CONFIG_SND_CS46XX_NEW_DSP
struct semaphore spos_mutex;
dsp_spos_instance_t * dsp_spos_instance;
#else /* for compatibility */
cs46xx_pcm_t *playback_pcm;
......
......@@ -109,6 +109,7 @@ typedef struct _dsp_scb_descriptor_t {
snd_info_entry_t *proc_info;
int ref_count;
spinlock_t lock;
int deleted;
} dsp_scb_descriptor_t;
......@@ -141,8 +142,6 @@ typedef struct _dsp_spos_instance_t {
segment_desc_t code;
/* PCM playback */
struct semaphore pcm_mutex;
dsp_scb_descriptor_t * master_mix_scb;
int npcm_channels;
int nsrc_scb;
......@@ -162,7 +161,6 @@ typedef struct _dsp_spos_instance_t {
snd_info_entry_t * proc_sample_dump_info_entry;
/* SCB's descriptors */
struct semaphore scb_mutex;
int nscb;
int scb_highest_frag_index;
dsp_scb_descriptor_t scbs[DSP_MAX_SCB_DESC];
......
......@@ -34,6 +34,8 @@ typedef int (*snd_mixer_oss_put_recsrc_t)(snd_mixer_oss_file_t *fmixer, snd_mixe
typedef int (*snd_mixer_oss_get_recsrce_t)(snd_mixer_oss_file_t *fmixer, int *active_index);
typedef int (*snd_mixer_oss_put_recsrce_t)(snd_mixer_oss_file_t *fmixer, int active_index);
#define SNDRV_OSS_MAX_MIXERS 32
struct _snd_oss_mixer_slot {
int number;
int stereo: 1;
......@@ -50,12 +52,14 @@ struct _snd_oss_mixer {
snd_card_t *card;
char id[16];
char name[32];
snd_mixer_oss_slot_t slots[32]; /* OSS mixer slots */
snd_mixer_oss_slot_t slots[SNDRV_OSS_MAX_MIXERS]; /* OSS mixer slots */
unsigned int mask_recsrc; /* exclusive recsrc mask */
snd_mixer_oss_get_recsrce_t get_recsrc;
snd_mixer_oss_put_recsrce_t put_recsrc;
void *private_data_recsrc;
void (*private_free_recsrc)(snd_mixer_oss_t *mixer);
struct semaphore reg_mutex;
snd_info_entry_t *proc_entry;
/* --- */
int oss_recsrc;
};
......
......@@ -40,6 +40,7 @@
#define MPU401_HW_YMFPCI 14 /* YMF DS-XG PCI */
#define MPU401_HW_CMIPCI 15 /* CMIPCI MPU-401 UART */
#define MPU401_HW_ALS4000 16 /* Avance Logic ALS4000 */
#define MPU401_HW_INTEL8X0 17 /* Intel8x0 driver */
#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
......
......@@ -140,9 +140,9 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define snd_usb_audio_t_magic 0xa15a3e01
#define usb_mixer_elem_info_t_magic 0xa15a3e02
#define snd_usb_stream_t_magic 0xa15a3e03
#define usbmidi_t_magic 0xa15a3f01
#define usbmidi_out_endpoint_t_magic 0xa15a3f02
#define usbmidi_in_endpoint_t_magic 0xa15a3f03
#define snd_usb_midi_t_magic 0xa15a3f01
#define snd_usb_midi_out_endpoint_t_magic 0xa15a3f02
#define snd_usb_midi_in_endpoint_t_magic 0xa15a3f03
#else
......
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc3"
#define CONFIG_SND_DATE " (Wed Aug 21 14:00:18 2002 UTC)"
#define CONFIG_SND_DATE " (Mon Aug 26 16:28:35 2002 UTC)"
......@@ -95,6 +95,7 @@ ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-hwdep.o
obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
endif
obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd.o
obj-m := $(sort $(obj-m))
......
This diff is collapsed.
......@@ -173,11 +173,11 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
continue;
#ifdef RULES_DEBUG
printk("%s = ", snd_pcm_hw_param_names[k]);
printk("%x -> ", *m);
printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
#ifdef RULES_DEBUG
printk("%x\n", *m);
printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
if (changed)
params->cmask |= 1 << k;
......
......@@ -820,11 +820,6 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
return -ENOIOCTLCMD;
}
void snd_rawmidi_receive_reset(snd_rawmidi_substream_t * substream)
{
/* TODO: reset current state */
}
int snd_rawmidi_receive(snd_rawmidi_substream_t * substream, const unsigned char *buffer, int count)
{
unsigned long flags;
......@@ -969,11 +964,6 @@ static ssize_t snd_rawmidi_read(struct file *file, char *buf, size_t count, loff
return result;
}
void snd_rawmidi_transmit_reset(snd_rawmidi_substream_t * substream)
{
/* TODO: reset current state */
}
int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream)
{
snd_rawmidi_runtime_t *runtime = substream->runtime;
......@@ -1564,9 +1554,7 @@ EXPORT_SYMBOL(snd_rawmidi_input_params);
EXPORT_SYMBOL(snd_rawmidi_drop_output);
EXPORT_SYMBOL(snd_rawmidi_drain_output);
EXPORT_SYMBOL(snd_rawmidi_drain_input);
EXPORT_SYMBOL(snd_rawmidi_receive_reset);
EXPORT_SYMBOL(snd_rawmidi_receive);
EXPORT_SYMBOL(snd_rawmidi_transmit_reset);
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
......
......@@ -73,6 +73,7 @@ obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-mi
obj-$(CONFIG_SND_EMU10K1) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(CONFIG_SND_TRIDENT) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_YMFPCI) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_USB_AUDIO) += snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-virmidi.o
obj-m := $(sort $(obj-m))
......
......@@ -50,7 +50,6 @@ static void snd_gf1_interrupt_midi_in(snd_gus_card_t * gus)
if (stat & 0x10) { /* framing error */
gus->gf1.uart_framing++;
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
snd_rawmidi_receive_reset(gus->midi_substream_input);
continue;
}
byte = snd_gf1_uart_get(gus);
......@@ -58,7 +57,6 @@ static void snd_gf1_interrupt_midi_in(snd_gus_card_t * gus)
snd_rawmidi_receive(gus->midi_substream_input, &byte, 1);
if (stat & 0x20) {
gus->gf1.uart_overrun++;
snd_rawmidi_receive_reset(gus->midi_substream_input);
}
}
}
......
......@@ -1501,7 +1501,7 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
goto __access_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
} while (end_time - (signed long)jiffies >= 0);
} while (time_after_eq(end_time, jiffies));
snd_printd("AC'97 %d:%d does not respond - RESET [REC_GAIN = 0x%x]\n", ac97->num, ac97->addr, err);
snd_ac97_free(ac97);
return -ENXIO;
......@@ -1536,31 +1536,38 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10);
} while (end_time - (signed long)jiffies >= 0);
} while (time_after_eq(end_time, jiffies));
snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr);
__ready_ok:
if (ac97->clock == 0)
ac97->clock = 48000; /* standard value */
ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
if (ac97->ext_id & 0x0189) /* L/R, MIC, SDAC, LDAC VRA support */
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189);
if (ac97->ext_id & 0x0001) { /* VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates_front_dac);
snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates_adc);
if (ac97->ext_id & AC97_EI_VRA) { /* VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_FRONT_DAC]);
snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates[AC97_RATES_ADC]);
} else {
ac97->rates_front_dac = SNDRV_PCM_RATE_48000;
ac97->rates_adc = SNDRV_PCM_RATE_48000;
ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000;
ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000;
}
if (ac97->ext_id & 0x0008) { /* MIC VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates_mic_adc);
if (ac97->ext_id & AC97_EI_SPDIF) {
/* codec specific code (patch) should override these values */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000;
}
if (ac97->ext_id & AC97_EI_VRM) { /* MIC VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates[AC97_RATES_MIC_ADC]);
} else {
ac97->rates_mic_adc = SNDRV_PCM_RATE_48000;
ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000;
}
if (ac97->ext_id & 0x0080) { /* SDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates_surr_dac);
if (ac97->ext_id & AC97_EI_SDAC) { /* SDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
ac97->scaps |= AC97_SCAP_SURROUND_DAC;
}
if (ac97->ext_id & 0x0100) { /* LDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates_lfe_dac);
if (ac97->ext_id & AC97_EI_LDAC) { /* LDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
}
/* additional initializations */
......@@ -1849,54 +1856,35 @@ int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate)
{
unsigned short mask;
unsigned int tmp;
signed long end_time;
switch (reg) {
case AC97_PCM_MIC_ADC_RATE:
mask = 0x0000;
if ((ac97->regs[AC97_EXTENDED_STATUS] & 0x0008) == 0) /* MIC VRA */
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
if (rate != 48000)
return -EINVAL;
break;
case AC97_PCM_FRONT_DAC_RATE:
mask = 0x0200;
if ((ac97->regs[AC97_EXTENDED_STATUS] & 0x0001) == 0) /* VRA */
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */
if (rate != 48000)
return -EINVAL;
break;
case AC97_PCM_LR_ADC_RATE:
mask = 0x0100;
if ((ac97->regs[AC97_EXTENDED_STATUS] & 0x0001) == 0) /* VRA */
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */
if (rate != 48000)
return -EINVAL;
break;
case AC97_SPDIF:
return 0;
default: return -EINVAL;
}
tmp = ((unsigned int)rate * ac97->clock) / 48000;
if (tmp > 65535)
return -EINVAL;
snd_ac97_update_bits(ac97, AC97_POWERDOWN, mask, mask);
end_time = jiffies + (HZ / 50);
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_ac97_update(ac97, reg, tmp & 0xffff);
udelay(10);
// XXXX update spdif rate here too?
snd_ac97_update_bits(ac97, AC97_POWERDOWN, mask, 0);
end_time = jiffies + (HZ / 50);
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0003) == 0x0003)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_ac97_read(ac97, reg);
return 0;
}
......
......@@ -166,6 +166,7 @@ int patch_cirrus_spdif(ac97_t * ac97)
*/
ac97->flags |= AC97_CS_SPDIF;
ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
return 0;
......
This diff is collapsed.
......@@ -84,7 +84,7 @@ static inline unsigned int snd_cs46xx_peekBA0(cs46xx_t *chip, unsigned long offs
}
dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip);
void cs46xx_dsp_spos_destroy (dsp_spos_instance_t * instance);
void cs46xx_dsp_spos_destroy (cs46xx_t * chip);
int cs46xx_dsp_load_module (cs46xx_t * chip,dsp_module_desc_t * module);
symbol_entry_t * cs46xx_dsp_lookup_symbol (cs46xx_t * chip,char * symbol_name,int symbol_type);
symbol_entry_t * cs46xx_dsp_lookup_symbol_addr (cs46xx_t * chip,u32 address,int symbol_type);
......
......@@ -222,16 +222,13 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip)
return NULL;
memset(ins, 0, sizeof(*ins));
init_MUTEX(&ins->scb_mutex);
init_MUTEX(&ins->pcm_mutex);
/* better to use vmalloc for this big table */
ins->symbol_table.nsymbols = 0;
ins->symbol_table.symbols = vmalloc(sizeof(symbol_entry_t) * DSP_MAX_SYMBOLS);
ins->symbol_table.highest_frag_index = 0;
if (ins->symbol_table.symbols == NULL) {
cs46xx_dsp_spos_destroy(ins);
cs46xx_dsp_spos_destroy(chip);
return NULL;
}
......@@ -240,7 +237,7 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip)
ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
if (ins->code.data == NULL) {
cs46xx_dsp_spos_destroy(ins);
cs46xx_dsp_spos_destroy(chip);
return NULL;
}
......@@ -251,7 +248,7 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip)
ins->modules = kmalloc(sizeof(dsp_module_desc_t) * DSP_MAX_MODULES, GFP_KERNEL);
if (ins->modules == NULL) {
cs46xx_dsp_spos_destroy(ins);
cs46xx_dsp_spos_destroy(chip);
return NULL;
}
......@@ -265,19 +262,19 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip)
return ins;
}
void cs46xx_dsp_spos_destroy (dsp_spos_instance_t * ins)
void cs46xx_dsp_spos_destroy (cs46xx_t * chip)
{
int i;
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
snd_assert(ins != NULL, return);
down(&ins->scb_mutex);
down(&chip->spos_mutex);
for (i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
}
up(&ins->scb_mutex);
if (ins->code.data)
kfree(ins->code.data);
......@@ -286,6 +283,7 @@ void cs46xx_dsp_spos_destroy (dsp_spos_instance_t * ins)
if (ins->modules)
kfree(ins->modules);
kfree(ins);
up(&chip->spos_mutex);
}
int cs46xx_dsp_load_module (cs46xx_t * chip, dsp_module_desc_t * module)
......@@ -479,6 +477,7 @@ static void cs46xx_dsp_proc_modules_read (snd_info_entry_t *entry, snd_info_buff
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
int i,j;
down(&chip->spos_mutex);
snd_iprintf(buffer, "MODULES:\n");
for ( i = 0; i < ins->nmodules; ++i ) {
snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
......@@ -491,6 +490,7 @@ static void cs46xx_dsp_proc_modules_read (snd_info_entry_t *entry, snd_info_buff
desc->segment_type,desc->offset, desc->size);
}
}
up(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
......@@ -500,6 +500,7 @@ static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_bu
int i,j,col;
unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
down(&chip->spos_mutex);
snd_iprintf(buffer, "TASK TREES:\n");
for ( i = 0; i < ins->ntask; ++i) {
snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
......@@ -516,6 +517,7 @@ static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_bu
}
snd_iprintf(buffer,"\n");
up(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
......@@ -524,6 +526,7 @@ static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
int i;
down(&chip->spos_mutex);
snd_iprintf(buffer, "SCB's:\n");
for ( i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted)
......@@ -546,6 +549,7 @@ static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t
}
snd_iprintf(buffer,"\n");
up(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_parameter_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
......@@ -809,12 +813,14 @@ int cs46xx_dsp_proc_init (snd_card_t * card, cs46xx_t *chip)
}
ins->proc_scb_info_entry = entry;
down(&chip->spos_mutex);
/* register/update SCB's entries on proc */
for (i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
}
up(&chip->spos_mutex);
return 0;
}
......@@ -854,12 +860,12 @@ int cs46xx_dsp_proc_done (cs46xx_t *chip)
ins->proc_task_info_entry = NULL;
}
down(&ins->scb_mutex);
down(&chip->spos_mutex);
for (i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
}
up(&ins->scb_mutex);
up(&chip->spos_mutex);
if (ins->proc_dsp_dir) {
snd_info_unregister (ins->proc_dsp_dir);
......@@ -930,6 +936,7 @@ static dsp_scb_descriptor_t * _map_scb (cs46xx_t *chip,char * name,u32 dest)
ins->scbs[index].proc_info = NULL;
ins->scbs[index].ref_count = 1;
ins->scbs[index].deleted = 0;
spin_lock_init(&ins->scbs[index].lock);
desc = (ins->scbs + index);
ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
......@@ -1313,9 +1320,11 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip)
codec_out_scb,
sec_codec_out_scb,
SCB_ON_PARENT_SUBLIST_SCB);
if (!magic_snoop_scb) goto _fail_end;
ins->ref_snoop_scb = magic_snoop_scb;
/* The asynch. transfer task */
asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
SPDIFO_SCB_INST,
......@@ -1576,6 +1585,8 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
down(&chip->spos_mutex);
/* create and start the asynchronous receiver SCB */
ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
ASYNCRX_SCB_ADDR,
......@@ -1586,6 +1597,7 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
save_flags(flags);
cli();
/* reset SPDIF input sample buffer pointer */
snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
(SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);
......@@ -1605,6 +1617,7 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
/* monitor state */
ins->spdif_status_in = 1;
up(&chip->spos_mutex);
return 0;
}
......@@ -1616,6 +1629,7 @@ int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip)
snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
down(&chip->spos_mutex);
/* Remove the asynchronous receiver SCB */
cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
ins->asynch_rx_scb = NULL;
......@@ -1624,6 +1638,7 @@ int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip)
/* monitor state */
ins->spdif_status_in = 0;
up(&chip->spos_mutex);
/* restore amplifier */
chip->active_ctrl(chip, -1);
......@@ -1639,8 +1654,10 @@ int cs46xx_dsp_enable_pcm_capture (cs46xx_t *chip)
snd_assert (ins->pcm_input == NULL,return -EINVAL);
snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
down(&chip->spos_mutex);
ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
"PCMSerialInput_Wave");
up(&chip->spos_mutex);
return 0;
}
......@@ -1651,8 +1668,10 @@ int cs46xx_dsp_disable_pcm_capture (cs46xx_t *chip)
snd_assert (ins->pcm_input != NULL,return -EINVAL);
down(&chip->spos_mutex);
cs46xx_dsp_remove_scb (chip,ins->pcm_input);
ins->pcm_input = NULL;
up(&chip->spos_mutex);
return 0;
}
......@@ -1664,8 +1683,10 @@ int cs46xx_dsp_enable_adc_capture (cs46xx_t *chip)
snd_assert (ins->adc_input == NULL,return -EINVAL);
snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
down(&chip->spos_mutex);
ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
"PCMSerialInput_ADC");
up(&chip->spos_mutex);
return 0;
}
......@@ -1676,8 +1697,10 @@ int cs46xx_dsp_disable_adc_capture (cs46xx_t *chip)
snd_assert (ins->adc_input != NULL,return -EINVAL);
down(&chip->spos_mutex);
cs46xx_dsp_remove_scb (chip,ins->adc_input);
ins->adc_input = NULL;
up(&chip->spos_mutex);
return 0;
}
......@@ -1697,7 +1720,7 @@ int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data)
snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR << 2), temp);
snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2*/
snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */
/* Poke this location to tell the task to start */
snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
......
This diff is collapsed.
......@@ -1628,7 +1628,7 @@ static int snd_ice1712_capture_open(snd_pcm_substream_t * substream)
ice->capture_con_substream = substream;
runtime->hw = snd_ice1712_capture;
runtime->hw.rates = ice->ac97->rates_adc;
runtime->hw.rates = ice->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
return 0;
......@@ -1660,8 +1660,6 @@ static int snd_ice1712_capture_close(snd_pcm_substream_t * substream)
{
ice1712_t *ice = snd_pcm_substream_chip(substream);
/* disable ADC power */
snd_ac97_update_bits(ice->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
ice->capture_con_substream = NULL;
return 0;
}
......@@ -2396,14 +2394,6 @@ static int __init snd_ice1712_build_pro_mixer(ice1712_t *ice)
return 0;
}
static void snd_ice1712_ac97_init(ac97_t *ac97)
{
// ice1712_t *ice = snd_magic_cast(ice1712_t, ac97->private_data, return);
/* disable center DAC/surround DAC/LFE DAC/MIC ADC */
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, 0xe800, 0xe800);
}
static void snd_ice1712_mixer_free_ac97(ac97_t *ac97)
{
ice1712_t *ice = snd_magic_cast(ice1712_t, ac97->private_data, return);
......@@ -2419,7 +2409,6 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_ice1712_ac97_write;
ac97.read = snd_ice1712_ac97_read;
ac97.init = snd_ice1712_ac97_init;
ac97.private_data = ice;
ac97.private_free = snd_ice1712_mixer_free_ac97;
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
......@@ -2437,7 +2426,6 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_ice1712_pro_ac97_write;
ac97.read = snd_ice1712_pro_ac97_read;
ac97.init = snd_ice1712_ac97_init;
ac97.private_data = ice;
ac97.private_free = snd_ice1712_mixer_free_ac97;
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
......
This diff is collapsed.
......@@ -605,7 +605,7 @@ static snd_pcm_hardware_t snd_via686a_playback =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 1024,
.periods_max = 128,
.fifo_size = 0,
};
......@@ -624,7 +624,7 @@ static snd_pcm_hardware_t snd_via686a_capture =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 1024,
.periods_max = 128,
.fifo_size = 0,
};
......@@ -636,21 +636,17 @@ static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
chip->playback.substream = substream;
runtime->hw = snd_via686a_playback;
runtime->hw.rates = chip->ac97->rates_front_dac;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
/* applying the following constraint together with the power-of-2 rule
* above may result in too narrow space.
* this one is not strictly necessary, so let's disable it.
*/
/* we may remove following constaint when we modify table entries
in interrupt */
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
return 0;
}
......@@ -662,17 +658,15 @@ static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
chip->capture.substream = substream;
runtime->hw = snd_via686a_capture;
runtime->hw.rates = chip->ac97->rates_adc;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
return 0;
}
......@@ -683,8 +677,6 @@ static int snd_via686a_playback_close(snd_pcm_substream_t * substream)
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL;
/* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
return 0;
}
......@@ -695,8 +687,6 @@ static int snd_via686a_capture_close(snd_pcm_substream_t * substream)
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
return 0;
}
......@@ -764,16 +754,6 @@ static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** r
* Mixer part
*/
static void snd_via686a_codec_init(ac97_t *ac97)
{
// via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
/* disable DAC & ADC power */
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x0300, 0x0300);
/* disable center DAC/surround DAC/LFE DAC/MIC ADC */
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, 0xe800, 0xe800);
}
static void snd_via686a_mixer_free_ac97(ac97_t *ac97)
{
via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
......@@ -788,7 +768,6 @@ static int __devinit snd_via686a_mixer(via686a_t *chip)
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_via686a_codec_write;
ac97.read = snd_via686a_codec_read;
ac97.init = snd_via686a_codec_init;
ac97.wait = snd_via686a_codec_wait;
ac97.private_data = chip;
ac97.private_free = snd_via686a_mixer_free_ac97;
......
......@@ -591,7 +591,7 @@ static snd_pcm_hardware_t snd_via8233_playback =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 1024,
.periods_max = 128,
.fifo_size = 0,
};
......@@ -610,7 +610,7 @@ static snd_pcm_hardware_t snd_via8233_capture =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 1024,
.periods_max = 128,
.fifo_size = 0,
};
......@@ -634,17 +634,15 @@ static int snd_via8233_playback_open(snd_pcm_substream_t * substream)
chip->playback.substream = substream;
runtime->hw = snd_via8233_playback;
runtime->hw.rates = chip->ac97->rates_front_dac;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0;
}
......@@ -657,17 +655,15 @@ static int snd_via8233_capture_open(snd_pcm_substream_t * substream)
chip->capture.substream = substream;
runtime->hw = snd_via8233_capture;
runtime->hw.rates = chip->ac97->rates_adc;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
return 0;
}
......@@ -679,8 +675,6 @@ static int snd_via8233_playback_close(snd_pcm_substream_t * substream)
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL;
/* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
return 0;
}
......@@ -692,8 +686,6 @@ static int snd_via8233_capture_close(snd_pcm_substream_t * substream)
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
return 0;
}
......@@ -760,16 +752,6 @@ static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** r
* Mixer part
*/
static void snd_via8233_codec_init(ac97_t *ac97)
{
// via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
/* disable DAC & ADC power */
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x0300, 0x0300);
/* disable center DAC/surround DAC/LFE DAC/MIC ADC */
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, 0xe800, 0xe800);
}
static void snd_via8233_mixer_free_ac97(ac97_t *ac97)
{
via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
......@@ -784,7 +766,6 @@ static int __devinit snd_via8233_mixer(via8233_t *chip)
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_via8233_codec_write;
ac97.read = snd_via8233_codec_read;
ac97.init = snd_via8233_codec_init;
ac97.private_data = chip;
ac97.private_free = snd_via8233_mixer_free_ac97;
ac97.clock = chip->ac97_clock;
......
CONFIG_SND_USB_AUDIO
Say 'Y' or 'M' to include support for USB audio devices.
CONFIG_SND_USB_MIDI
Say 'Y' or 'M' to include support for MIDI devices connected via USB.
To support USB MIDI devices, you need to enable ALSA sequencer support
(CONFIG_SND_SEQUENCER).
......@@ -3,7 +3,6 @@
mainmenu_option next_comment
comment 'ALSA USB devices'
dep_tristate 'USB Audio driver' CONFIG_SND_USB_AUDIO $CONFIG_SND
dep_tristate 'USB MIDI driver' CONFIG_SND_USB_MIDI $CONFIG_SND $CONFIG_SND_SEQUENCER
dep_tristate 'USB Audio/MIDI driver' CONFIG_SND_USB_AUDIO $CONFIG_SND
endmenu
......@@ -3,10 +3,14 @@
#
snd-usb-audio-objs := usbaudio.o usbmixer.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
snd-usb-midi-objs := usbmidi.o
endif
# Toplevel Module Dependency
obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o
obj-$(CONFIG_SND_USB_MIDI) += snd-usb-midi.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-midi.o
endif
include $(TOPDIR)/Rules.make
......@@ -36,6 +36,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/seq_device.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
......@@ -1234,6 +1235,7 @@ static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
static struct usb_device_id usb_audio_ids [] = {
#include "usbquirks.h"
{ .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL },
......@@ -1716,10 +1718,13 @@ static int snd_usb_audio_stream_new(snd_usb_audio_t *chip, unsigned char *buffer
/*
* parse audio control descriptor and create pcm streams
* parse audio control descriptor and create pcm/midi streams
*/
static int snd_usb_create_pcm(snd_usb_audio_t *chip, int ctrlif,
static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
const snd_usb_audio_quirk_t *quirk);
static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
unsigned char *buffer, int buflen)
{
struct usb_device *dev = chip->dev;
......@@ -1752,6 +1757,15 @@ static int snd_usb_create_pcm(snd_usb_audio_t *chip, int ctrlif,
continue;
}
iface = &config->interface[j];
if (iface->altsetting[0].bInterfaceClass == USB_CLASS_AUDIO &&
iface->altsetting[0].bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
if (snd_usb_create_midi_interface(chip, j, NULL) < 0) {
snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
continue;
}
usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
continue;
}
if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
iface->altsetting[0].bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, iface->altsetting[0].bInterfaceClass);
......@@ -1808,6 +1822,37 @@ static int snd_usb_create_pcm(snd_usb_audio_t *chip, int ctrlif,
return 0;
}
static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
const snd_usb_audio_quirk_t *quirk)
{
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
snd_seq_device_t *seq_device;
snd_usb_midi_t *umidi;
int err;
err = snd_seq_device_new(chip->card, chip->next_seq_device,
SNDRV_SEQ_DEV_ID_USBMIDI,
sizeof(snd_usb_midi_t), &seq_device);
if (err < 0)
return err;
chip->next_seq_device++;
strcpy(seq_device->name, chip->card->shortname);
umidi = (snd_usb_midi_t *)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
umidi->chip = chip;
umidi->ifnum = ifnum;
umidi->quirk = quirk;
umidi->seq_client = -1;
#endif
return 0;
}
static inline int snd_usb_create_quirk(snd_usb_audio_t *chip, int ifnum,
const snd_usb_audio_quirk_t *quirk)
{
/* in the future, there may be quirks for PCM devices */
return snd_usb_create_midi_interface(chip, ifnum, quirk);
}
/*
* free the chip instance
......@@ -1835,7 +1880,9 @@ static int snd_usb_audio_dev_free(snd_device_t *device)
/*
* create a chip instance and set its names.
*/
static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, snd_usb_audio_t **rchip)
static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
const snd_usb_audio_quirk_t *quirk,
snd_usb_audio_t **rchip)
{
snd_usb_audio_t *chip;
int err, len;
......@@ -1858,18 +1905,50 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, snd_us
}
strcpy(card->driver, "USB-Audio");
strcpy(card->shortname, "USB Audio Driver");
/* retrieve the device string as shortname */
if (dev->descriptor.iProduct)
len = usb_string(dev, dev->descriptor.iProduct,
card->shortname, sizeof(card->shortname));
else
len = 0;
if (len <= 0) {
if (quirk && quirk->product_name) {
strncpy(card->shortname, quirk->product_name, sizeof(card->shortname) - 1);
card->shortname[sizeof(card->shortname) - 1] = '\0';
} else {
sprintf(card->shortname, "USB Device %#04x:%#04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
}
}
/* retrieve the vendor and device strings as longname */
len = usb_string(dev, 1, card->longname, sizeof(card->longname) - 1);
if (len <= 0)
if (dev->descriptor.iManufacturer)
len = usb_string(dev, dev->descriptor.iManufacturer,
card->longname, sizeof(card->longname) - 1);
else
len = 0;
else {
if (len <= 0) {
if (quirk && quirk->vendor_name) {
strncpy(card->longname, quirk->vendor_name, sizeof(card->longname) - 2);
card->longname[sizeof(card->longname) - 2] = '\0';
len = strlen(card->longname);
} else {
len = 0;
}
}
if (len > 0) {
card->longname[len] = ' ';
len++;
}
card->longname[len] = 0;
usb_string(dev, 2, card->longname + len, sizeof(card->longname) - len);
card->longname[len] = '\0';
if ((!dev->descriptor.iProduct
|| usb_string(dev, dev->descriptor.iProduct,
card->longname + len, sizeof(card->longname) - len) <= 0)
&& quirk && quirk->product_name) {
strncpy(card->longname + len, quirk->product_name, sizeof(card->longname) - len - 1);
card->longname[sizeof(card->longname) - 1] = '\0';
}
*rchip = chip;
return 0;
......@@ -1926,12 +2005,16 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct usb_config_descriptor *config = dev->actconfig;
const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)id->driver_info;
unsigned char *buffer;
unsigned int index;
int i, buflen;
snd_card_t *card;
snd_usb_audio_t *chip;
if (quirk && ifnum != quirk->ifnum)
return NULL;
if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", config->bConfigurationValue);
return NULL;
......@@ -1966,7 +2049,7 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
goto __error;
}
if (snd_usb_audio_create(card, dev, &chip) < 0) {
if (snd_usb_audio_create(card, dev, quirk, &chip) < 0) {
snd_card_free(card);
goto __error;
}
......@@ -1980,10 +2063,15 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
}
}
if (snd_usb_create_pcm(chip, ifnum, buffer, buflen) < 0)
if (!quirk) {
if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0)
goto __error;
if (snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0)
goto __error;
} else {
if (snd_usb_create_quirk(chip, ifnum, quirk) < 0)
goto __error;
}
/* we are allowed to call snd_card_register() many times */
if (snd_card_register(chip->card) < 0) {
......
......@@ -27,6 +27,7 @@
#define USB_SUBCLASS_AUDIO_CONTROL 0x01
#define USB_SUBCLASS_AUDIO_STREAMING 0x02
#define USB_SUBCLASS_MIDI_STREAMING 0x03
#define USB_DT_CS_DEVICE 0x21
#define USB_DT_CS_CONFIG 0x22
......@@ -56,6 +57,8 @@
#define EP_GENERAL 0x01
#define MS_GENERAL 0x01
/* endpoint attributes */
#define EP_ATTR_MASK 0x0c
#define EP_ATTR_ASYNC 0x04
......@@ -115,6 +118,11 @@
#define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS 0x2006
/* maximum number of endpoints per interface */
#define MIDI_MAX_ENDPOINTS 2
#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
/*
*/
......@@ -130,6 +138,51 @@ struct snd_usb_audio {
struct list_head pcm_list; /* list of pcm streams */
int pcm_devs;
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
int next_seq_device;
#endif
};
/*
* Information about devices with broken descriptors
*/
typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
struct snd_usb_audio_quirk {
const char *vendor_name;
const char *product_name;
int ifnum;
/* MIDI specific */
struct snd_usb_midi_endpoint_info {
int16_t epnum; /* ep number, -1 autodetect */
uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */
} endpoints[MIDI_MAX_ENDPOINTS];
};
/*
* USB MIDI sequencer device data
*/
typedef struct snd_usb_midi snd_usb_midi_t;
typedef struct snd_usb_midi_endpoint snd_usb_midi_endpoint_t;
typedef struct snd_usb_midi_out_endpoint snd_usb_midi_out_endpoint_t;
typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
struct snd_usb_midi {
/* filled by usbaudio.c */
snd_usb_audio_t *chip;
int ifnum;
const snd_usb_audio_quirk_t *quirk;
/* used internally in usbmidi.c */
int seq_client;
struct snd_usb_midi_endpoint {
snd_usb_midi_out_endpoint_t *out;
snd_usb_midi_in_endpoint_t *in;
snd_rawmidi_t *rmidi[0x10];
} endpoints[MIDI_MAX_ENDPOINTS];
};
......
This diff is collapsed.
/*
* ALSA USB Audio Driver
*
* Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>,
* Clemens Ladisch <clemens@ladisch.de>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* The contents of this file are part of the driver's id_table.
*
* In a perfect world, this file would be empty.
*/
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
{
/* from NetBSD's umidi driver */
USB_DEVICE(0x0499, 0x1000), /* Yamaha UX256 */
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0xffff,
.in_cables = 0x00ff
}
}
}
},
{
/* from Nagano Daisuke's usb-midi driver */
USB_DEVICE(0x0499, 0x1001), /* Yamaha MU1000 */
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.ifnum = 0,
.endpoints = {
{
.epnum = 1,
.out_cables = 0x000f,
.in_cables = 0x0001
}
}
}
},
/*
* I don't know whether the following Yamaha devices need entries or not:
* 0x1002 MU2000 0x1008 UX96
* 0x1003 MU500 0x1009 UX16
* 0x1004 UW500 0x100e S08
* 0x1005 MOTIF6 0x100f CLP-150
* 0x1006 MOTIF7 0x1010 CLP-170
* 0x1007 MOTIF8
*/
/*
* Once upon a time people thought, "Wouldn't it be nice if there was a
* standard for USB MIDI devices, so that device drivers would not be forced
* to know about the quirks of specific devices?" So Roland went ahead and
* wrote the USB Device Class Definition for MIDI Devices, and the USB-IF
* endorsed it, and now everybody designing USB MIDI devices does so in
* agreement with this standard (or at least tries to).
*
* And if you prefer a happy end, you can imagine that Roland devices set a
* good example. Instead of being completely fucked up due to the lack of
* class-specific descriptors.
*/
{
USB_DEVICE(0x0582, 0x0000),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "UA-100",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0007,
.in_cables = 0x0007
}
}
}
},
{
USB_DEVICE(0x0582, 0x0002),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-4",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
}
}
},
{
USB_DEVICE(0x0582, 0x0003),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-8850",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x003f,
.in_cables = 0x003f
}
}
}
},
{
USB_DEVICE(0x0582, 0x0004),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "U-8",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
}
}
},
{
USB_DEVICE(0x0582, 0x0005),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-2",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
}
}
},
{
USB_DEVICE(0x0582, 0x0007),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-8820",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0013,
.in_cables = 0x0013
}
}
}
},
{
USB_DEVICE(0x0582, 0x0008),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "PC-300",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
}
},
{
USB_DEVICE(0x0582, 0x0009),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-1",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
}
},
{
USB_DEVICE(0x0582, 0x000b),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SK-500",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0013,
.in_cables = 0x0013
}
}
}
},
{
USB_DEVICE(0x0582, 0x000c),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-D70",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0007,
.in_cables = 0x0007
}
}
}
},
{
USB_DEVICE(0x0582, 0x0012),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "XV-5050",
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
}
}
},
{
USB_DEVICE(0x0582, 0x0014),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-880",
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x01ff,
.in_cables = 0x01ff
}
}
}
},
{
USB_DEVICE(0x0582, 0x0016),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "SD-90",
.ifnum = 2,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
}
}
},
{
USB_DEVICE(0x0582, 0x0023),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-550",
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x003f,
.in_cables = 0x003f
}
}
}
},
{
USB_DEVICE(0x0582, 0x0027),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "SD-20",
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0007
}
}
}
},
{
USB_DEVICE(0x0582, 0x0029),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "SD-80",
.ifnum = 0,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
}
}
},
{
USB_DEVICE(0x0582, 0x002b),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UA-700",
.ifnum = 3,
.endpoints = {
{
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
}
}
},
#endif /* CONFIG_SND_SEQUENCER(_MODULE) */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment