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))
......
......@@ -472,6 +472,8 @@ struct slot {
int channels;
snd_kcontrol_t *kcontrol[SNDRV_MIXER_OSS_ITEM_COUNT];
unsigned int capture_item;
struct snd_mixer_oss_assign_table *assigned;
unsigned int allocated: 1;
};
static snd_kcontrol_t *snd_mixer_oss_test_id(snd_mixer_oss_t *mixer, const char *name, int index)
......@@ -809,10 +811,26 @@ static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, c
static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn)
{
kfree(chn->private_data);
struct slot *p = (struct slot *)chn->private_data;
if (p) {
if (p->allocated && p->assigned) {
kfree(p->assigned->name);
kfree(p->assigned);
}
kfree(p);
}
}
static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot)
{
int idx = rslot->number; /* remember this */
if (rslot->private_free)
rslot->private_free(rslot);
memset(rslot, 0, sizeof(*rslot));
rslot->number = idx;
}
static void snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr)
static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated)
{
struct slot slot;
struct slot *pslot;
......@@ -823,49 +841,49 @@ static void snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_o
memset(&slot, 0, sizeof(slot));
if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index,
SNDRV_MIXER_OSS_ITEM_GLOBAL))
return;
return 0;
sprintf(str, "%s Switch", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_GSWITCH))
return;
return 0;
sprintf(str, "%s Route", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_GROUTE))
return;
return 0;
sprintf(str, "%s Volume", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_GVOLUME))
return;
return 0;
sprintf(str, "%s Playback Switch", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_PSWITCH))
return;
return 0;
sprintf(str, "%s Playback Route", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_PROUTE))
return;
return 0;
sprintf(str, "%s Playback Volume", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_PVOLUME))
return;
return 0;
sprintf(str, "%s Capture Switch", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_CSWITCH))
return;
return 0;
sprintf(str, "%s Capture Route", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_CROUTE))
return;
return 0;
sprintf(str, "%s Capture Volume", ptr->name);
if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
SNDRV_MIXER_OSS_ITEM_CVOLUME))
return;
return 0;
if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
snd_ctl_elem_info_t uinfo;
memset(&uinfo, 0, sizeof(uinfo));
if (kctl->info(kctl, &uinfo))
return;
return 0;
strcpy(str, ptr->name);
if (!strcmp(str, "Master"))
strcpy(str, "Mix");
......@@ -878,7 +896,7 @@ static void snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_o
for (slot.capture_item = 1; slot.capture_item < uinfo.value.enumerated.items; slot.capture_item++) {
uinfo.value.enumerated.item = slot.capture_item;
if (kctl->info(kctl, &uinfo))
return;
return 0;
if (!strcmp(uinfo.value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
break;
......@@ -888,10 +906,13 @@ static void snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_o
}
if (slot.present != 0) {
pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL);
snd_runtime_check(pslot != NULL, return);
snd_runtime_check(pslot != NULL, return -ENOMEM);
*pslot = slot;
pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
pslot->assigned = ptr;
pslot->allocated = ptr_allocated;
rslot = &mixer->slots[ptr->oss_id];
mixer_slot_clear(rslot);
rslot->stereo = slot.channels > 1 ? 1 : 0;
rslot->get_volume = snd_mixer_oss_get_volume1;
rslot->put_volume = snd_mixer_oss_put_volume1;
......@@ -907,6 +928,156 @@ static void snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_o
}
rslot->private_data = pslot;
rslot->private_free = snd_mixer_oss_slot_free;
return 1;
}
return 0;
}
/*
*/
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
MIXER_VOL(VOLUME),
MIXER_VOL(BASS),
MIXER_VOL(TREBLE),
MIXER_VOL(SYNTH),
MIXER_VOL(PCM),
MIXER_VOL(SPEAKER),
MIXER_VOL(LINE),
MIXER_VOL(MIC),
MIXER_VOL(CD),
MIXER_VOL(IMIX),
MIXER_VOL(ALTPCM),
MIXER_VOL(RECLEV),
MIXER_VOL(IGAIN),
MIXER_VOL(OGAIN),
MIXER_VOL(LINE1),
MIXER_VOL(LINE2),
MIXER_VOL(LINE3),
MIXER_VOL(DIGITAL1),
MIXER_VOL(DIGITAL2),
MIXER_VOL(DIGITAL3),
MIXER_VOL(PHONEIN),
MIXER_VOL(PHONEOUT),
MIXER_VOL(VIDEO),
MIXER_VOL(RADIO),
MIXER_VOL(MONITOR),
};
/*
* /proc interface
*/
static void snd_mixer_oss_proc_read(snd_info_entry_t *entry,
snd_info_buffer_t * buffer)
{
snd_mixer_oss_t *mixer = snd_magic_cast(snd_mixer_oss_t, entry->private_data, return);
int i;
down(&mixer->reg_mutex);
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
struct slot *p;
if (! oss_mixer_names[i])
continue;
p = (struct slot *)mixer->slots[i].private_data;
snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
if (p && p->assigned)
snd_iprintf(buffer, "\"%s\" %d\n",
p->assigned->name,
p->assigned->index);
else
snd_iprintf(buffer, "\"\" 0\n");
}
up(&mixer->reg_mutex);
}
static void snd_mixer_oss_proc_write(snd_info_entry_t *entry,
snd_info_buffer_t * buffer)
{
snd_mixer_oss_t *mixer = snd_magic_cast(snd_mixer_oss_t, entry->private_data, return);
char line[128], str[32], idxstr[16], *cptr;
int ch, idx;
struct snd_mixer_oss_assign_table *tbl;
struct slot *slot;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
cptr = snd_info_get_str(str, line, sizeof(str));
for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
break;
if (ch >= SNDRV_OSS_MAX_MIXERS) {
snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
continue;
}
cptr = snd_info_get_str(str, cptr, sizeof(str));
if (! *str) {
/* remove the entry */
down(&mixer->reg_mutex);
mixer_slot_clear(&mixer->slots[ch]);
up(&mixer->reg_mutex);
continue;
}
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
idx = simple_strtoul(idxstr, NULL, 10);
if (idx >= 0x4000) { /* too big */
snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
continue;
}
down(&mixer->reg_mutex);
slot = (struct slot *)mixer->slots[ch].private_data;
if (slot && slot->assigned &&
slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
/* not changed */
goto __unlock;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
if (! tbl) {
snd_printk(KERN_ERR "mixer_oss: no memory\n");
goto __unlock;
}
tbl->oss_id = ch;
tbl->name = snd_kmalloc_strdup(str, GFP_KERNEL);
if (! tbl->name) {
kfree(tbl);
goto __unlock;
}
tbl->index = idx;
if (snd_mixer_oss_build_input(mixer, tbl, 1) <= 0) {
kfree(tbl->name);
kfree(tbl);
}
__unlock:
up(&mixer->reg_mutex);
}
}
static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer)
{
snd_info_entry_t *entry;
entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
mixer->card->proc_root);
if (! entry)
return;
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
entry->c.text.read_size = 8192;
entry->c.text.read = snd_mixer_oss_proc_read;
entry->c.text.write_size = 8192;
entry->c.text.write = snd_mixer_oss_proc_write;
entry->private_data = mixer;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
}
mixer->proc_entry = entry;
}
static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer)
{
if (mixer->proc_entry) {
snd_info_unregister(mixer->proc_entry);
mixer->proc_entry = NULL;
}
}
......@@ -945,9 +1116,9 @@ static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
int idx;
for (idx = 0; idx < sizeof(table) / sizeof(struct snd_mixer_oss_assign_table); idx++)
snd_mixer_oss_build_input(mixer, &table[idx]);
snd_mixer_oss_build_input(mixer, &table[idx], 0);
if (mixer->slots[SOUND_MIXER_SYNTH].get_volume == NULL)
snd_mixer_oss_build_input(mixer, &fm_table);
snd_mixer_oss_build_input(mixer, &fm_table, 0);
if (mixer->mask_recsrc) {
mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
......@@ -968,7 +1139,7 @@ static int snd_mixer_oss_free1(void *private)
card = mixer->card;
snd_assert(mixer == card->mixer_oss, return -ENXIO);
card->mixer_oss = NULL;
for (idx = 0; idx < 31; idx++) {
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
snd_mixer_oss_slot_t *chn = &mixer->slots[idx];
if (chn->private_free)
chn->private_free(chn);
......@@ -987,6 +1158,7 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
mixer = snd_magic_kcalloc(snd_mixer_oss_t, sizeof(snd_mixer_oss_t), GFP_KERNEL);
if (mixer == NULL)
return -ENOMEM;
init_MUTEX(&mixer->reg_mutex);
sprintf(name, "mixer%i%i", card->number, 0);
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
......@@ -1001,16 +1173,18 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
card->number,
name);
for (idx = 0; idx < 31; idx++)
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
mixer->slots[idx].number = idx;
card->mixer_oss = mixer;
snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer);
} else {
snd_mixer_oss_t *mixer = card->mixer_oss;
if (mixer == NULL)
return 0;
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer);
}
return 0;
......
......@@ -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;
......
......@@ -855,6 +855,7 @@ static int snd_cs46xx_playback_copy(snd_pcm_substream_t *substream,
if (copy_from_user(hwbuf, src, bytes))
return -EFAULT;
spin_lock_irq(&runtime->lock);
snd_cs46xx_playback_transfer(substream, frames);
spin_unlock_irq(&runtime->lock);
......@@ -885,15 +886,17 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
{
cs46xx_t *chip = snd_pcm_substream_chip(substream);
/*snd_pcm_runtime_t *runtime = substream->runtime;*/
int result = 0;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
#else
spin_lock(&chip->reg_lock);
#endif
int result = 0;
spin_lock(&chip->reg_lock);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (! cpcm->pcm_channel) {
spin_unlock(&chip->reg_lock);
return -ENXIO;
}
#endif
......@@ -905,6 +908,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0);
/* raise playback volume */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0x80008000);
#else
......@@ -920,6 +924,8 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* mute channel */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0xffffffff);
if (!cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
#else
......@@ -934,7 +940,11 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
result = -EINVAL;
break;
}
#ifndef CONFIG_SND_CS46XX_NEW_DSP
spin_unlock(&chip->reg_lock);
#endif
return result;
}
......@@ -964,6 +974,7 @@ static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream,
break;
}
spin_unlock(&chip->reg_lock);
return result;
}
......@@ -994,6 +1005,7 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
return err;
substream->ops = &snd_cs46xx_playback_indirect_ops;
}
return 0;
}
......@@ -1011,6 +1023,7 @@ static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream)
runtime->dma_area = NULL;
runtime->dma_addr = 0;
runtime->dma_bytes = 0;
return 0;
}
......@@ -1025,7 +1038,8 @@ static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream)
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->dsp_spos_instance->pcm_mutex);
down (&chip->spos_mutex);
if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
cpcm->pcm_channel->sample_rate != runtime->rate) {
/* sample rate not set or we can reuse
......@@ -1034,23 +1048,25 @@ static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream)
cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,runtime->rate);
cpcm->pcm_channel->sample_rate = runtime->rate;
}
up (&chip->dsp_spos_instance->pcm_mutex);
if (cpcm->pcm_channel->sample_rate != runtime->rate &&
cpcm->pcm_channel->src_scb->ref_count != 1) {
int unlinked = cpcm->pcm_channel->unlinked;
cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr)) == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
up (&chip->spos_mutex);
return -ENXIO;
}
cs46xx_dsp_pcm_unlink (chip,cpcm->pcm_channel);
if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
cpcm->pcm_channel->sample_rate = runtime->rate;
}
pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
pfie &= ~0x0000f03f;
up (&chip->spos_mutex);
#else
/* old dsp */
pfie = snd_cs46xx_peek(chip, BA1_PFIE);
......@@ -1130,6 +1146,7 @@ static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream,
return err;
substream->ops = &snd_cs46xx_capture_indirect_ops;
}
return 0;
}
......@@ -1143,6 +1160,7 @@ static int snd_cs46xx_capture_hw_free(snd_pcm_substream_t * substream)
runtime->dma_area = NULL;
runtime->dma_addr = 0;
runtime->dma_bytes = 0;
return 0;
}
......@@ -1158,6 +1176,7 @@ static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream)
chip->capt.hw_data = chip->capt.hw_io = chip->capt.hw_ready = 0;
chip->capt.appl_ptr = 0;
snd_cs46xx_set_capture_sample_rate(chip, runtime->rate);
return 0;
}
......@@ -1183,6 +1202,7 @@ static void snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#ifdef CONFIG_SND_CS46XX_NEW_DSP
status2 = snd_cs46xx_peekBA0(chip, BA0_HSR0);
for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
if (i <= 15) {
if ( status1 & (1 << i) ) {
......@@ -1193,7 +1213,7 @@ static void snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (ins->pcm_channels[i].active &&
ins->pcm_channels[i].private_data &&
!ins->pcm_channels[i].unlinked) {
cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, goto _invalid_pointer);
cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue);
snd_pcm_period_elapsed(cpcm->substream);
}
}
......@@ -1203,16 +1223,13 @@ static void snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (ins->pcm_channels[i].active &&
ins->pcm_channels[i].private_data &&
!ins->pcm_channels[i].unlinked) {
cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, goto _invalid_pointer);
cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue);
snd_pcm_period_elapsed(cpcm->substream);
}
}
}
continue;
_invalid_pointer:
printk (KERN_ERR "cs46xx: (interrupt) invalid pointer at pcm_channel[%d]\n",i);
}
#else
/* old dsp */
if ((status1 & HISR_VC0) && chip->playback_pcm) {
......@@ -1324,16 +1341,18 @@ static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
cpcm->substream = substream;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex);
cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr);
if (cpcm->pcm_channel == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
snd_magic_kfree(cpcm);
up (&chip->spos_mutex);
return -ENOMEM;
}
cs46xx_dsp_pcm_unlink (chip,cpcm->pcm_channel);
up (&chip->spos_mutex);
#else
chip->playback_pcm = cpcm; /* HACK */
#endif
......@@ -1342,6 +1361,7 @@ static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
chip->active_ctrl(chip, 1);
chip->amplifier_ctrl(chip, 1);
return 0;
}
......@@ -1353,10 +1373,13 @@ static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream)
return -ENOMEM;
chip->capt.substream = substream;
substream->runtime->hw = snd_cs46xx_capture;
if (chip->accept_valid)
substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
chip->active_ctrl(chip, 1);
chip->amplifier_ctrl(chip, 1);
return 0;
}
......@@ -1369,10 +1392,12 @@ static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream)
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex);
if (cpcm->pcm_channel) {
cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel);
cpcm->pcm_channel = NULL;
}
up (&chip->spos_mutex);
#else
chip->playback_pcm = NULL;
#endif
......@@ -1381,6 +1406,7 @@ static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream)
snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
chip->active_ctrl(chip, -1);
chip->amplifier_ctrl(chip, -1);
return 0;
}
......@@ -1392,6 +1418,7 @@ static int snd_cs46xx_capture_close(snd_pcm_substream_t * substream)
snd_free_pci_pages(chip->pci, chip->capt.hw_size, chip->capt.hw_area, chip->capt.hw_addr);
chip->active_ctrl(chip, -1);
chip->amplifier_ctrl(chip, -1);
return 0;
}
......@@ -1550,6 +1577,7 @@ static int snd_cs46xx_vol_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
}
#endif
}
return change;
}
......@@ -1575,6 +1603,7 @@ static int snd_cs46xx_iec958_get(snd_kcontrol_t *kcontrol,
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_out;
else
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in;
return 0;
}
......@@ -1719,7 +1748,6 @@ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol,
#endif /* CONFIG_SND_CS46XX_NEW_DSP */
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
static int snd_cs46xx_egpio_select_info(snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo)
......@@ -1979,6 +2007,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
/* add cs4630 mixer controls */
_end:
/* dosoundcard specific mixer setup */
if (chip->mixer_init) {
snd_printdd ("calling chip->mixer_init(chip);\n");
......@@ -2447,7 +2476,7 @@ static int snd_cs46xx_free(cs46xx_t *chip)
chip->active_ctrl(chip, -chip->amplifier);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
cs46xx_dsp_spos_destroy(chip->dsp_spos_instance);
cs46xx_dsp_spos_destroy(chip);
#endif
snd_magic_kfree(chip);
return 0;
......@@ -2920,7 +2949,6 @@ static void amp_voyetra(cs46xx_t *chip, int change)
#endif
}
static void hercules_init(cs46xx_t *chip)
{
/* default: AMP off, and SPDIF input optical */
......@@ -2928,6 +2956,7 @@ static void hercules_init(cs46xx_t *chip)
snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIODR_GPOE0);
}
/*
* Game Theatre XP card - EGPIO[2] is used to enable the external amp.
*/
......@@ -2940,6 +2969,7 @@ static void amp_hercules(cs46xx_t *chip, int change)
chip->amplifier += change;
if (chip->amplifier && !old) {
snd_printdd ("Hercules amplifier ON\n");
snd_cs46xx_pokeBA0(chip, BA0_EGPIODR,
EGPIODR_GPOE2 | val1); /* enable EGPIO2 output */
snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR,
......@@ -2980,6 +3010,7 @@ static void hercules_mixer_init (cs46xx_t *chip)
#endif
}
#if 0
/*
* Untested
......
......@@ -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);
......
......@@ -75,7 +75,7 @@ static void cs46xx_dsp_proc_scb_info_read (snd_info_entry_t *entry, snd_info_buf
ins = chip->dsp_spos_instance;
down(&ins->scb_mutex);
down(&chip->spos_mutex);
snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
for (col = 0,j = 0;j < 0x10; j++,col++) {
......@@ -103,7 +103,7 @@ static void cs46xx_dsp_proc_scb_info_read (snd_info_entry_t *entry, snd_info_buf
scb->task_entry->address);
snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
up(&ins->scb_mutex);
up(&chip->spos_mutex);
}
static void _dsp_unlink_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb)
......@@ -180,11 +180,10 @@ void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
down(&ins->scb_mutex);
/* check integrety */
snd_assert ( (scb->index >= 0 &&
scb->index < ins->nscb &&
(ins->scbs + scb->index) == scb), goto _end );
(ins->scbs + scb->index) == scb), return );
#if 0
/* cant remove a SCB with childs before
......@@ -194,10 +193,12 @@ void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb)
goto _end);
#endif
spin_lock(&scb->lock);
_dsp_unlink_scb (chip,scb);
spin_unlock(&scb->lock);
cs46xx_dsp_proc_free_scb_desc(scb);
snd_assert (scb->scb_symbol != NULL, goto _end);
snd_assert (scb->scb_symbol != NULL, return );
remove_symbol (chip,scb->scb_symbol);
ins->scbs[scb->index].deleted = 1;
......@@ -219,11 +220,6 @@ void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb)
ins->scbs[i - 1].index = i - 1;
}
#endif
#ifdef CONFIG_SND_DEBUG
_end:
#endif
up(&ins->scb_mutex);
}
......@@ -248,7 +244,6 @@ void cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * sc
snd_info_entry_t * entry;
proc_scb_info_t * scb_info;
down(&ins->scb_mutex);
/* register to proc */
if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
scb->proc_info == NULL) {
......@@ -275,7 +270,6 @@ void cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * sc
scb->proc_info = entry;
}
up(&ins->scb_mutex);
}
static dsp_scb_descriptor_t *
......@@ -289,8 +283,7 @@ _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
unsigned long flags;
down(&ins->scb_mutex);
snd_assert (ins->the_null_scb != NULL,goto _fail_end);
snd_assert (ins->the_null_scb != NULL,return NULL);
/* fill the data that will be wroten to DSP */
scb_data[SCBsubListPtr] =
......@@ -321,17 +314,17 @@ _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
/* link to parent SCB */
if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
goto _fail_end);
return NULL);
scb->parent_scb_ptr->next_scb_ptr = scb;
} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
goto _fail_end);
return NULL);
scb->parent_scb_ptr->sub_list_ptr = scb;
} else {
snd_assert (0,goto _fail_end);
snd_assert (0,return NULL);
}
spin_lock_irqsave(&chip->reg_lock, flags);
......@@ -345,17 +338,9 @@ _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
}
up(&ins->scb_mutex);
cs46xx_dsp_proc_register_scb_desc (chip,scb);
return scb;
#ifdef CONFIG_SND_DEBUG
_fail_end:
up(&ins->scb_mutex);
return NULL;
#endif
}
dsp_scb_descriptor_t *
......@@ -914,6 +899,7 @@ cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
/* There is no correct initial value, it will depend upon the detected
rate etc */
0x18000000,
/* Mute stream */
0x8000,0x8000,
0xffff,0xffff
......@@ -1111,13 +1097,11 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb;
dsp_scb_descriptor_t * pcm_parent_scb;
/*dsp_scb_descriptor_t * pcm_parent_scb;*/
char scb_name[DSP_MAX_SCB_NAME];
int i,pcm_index = -1, insert_point, src_index = -1;
unsigned long flags;
down(&ins->pcm_mutex);
/* default sample rate is 44100 */
if (!sample_rate) sample_rate = 44100;
......@@ -1142,7 +1126,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
if (pcm_index == -1) {
snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
goto _end;
return NULL;
}
if (src_scb == NULL) {
......@@ -1150,7 +1134,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
goto _end;
return NULL;
}
/* find a free slot */
......@@ -1161,7 +1145,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
break;
}
}
snd_assert (src_index != -1,goto _end);
snd_assert (src_index != -1,return NULL);
/* we need to create a new SRC SCB */
if (ins->master_mix_scb->sub_list_ptr == ins->the_null_scb) {
......@@ -1185,32 +1169,13 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
if (!src_scb) {
snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
goto _end;
return NULL;
}
cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
ins->nsrc_scb ++;
/* insert point for the PCMreader task */
pcm_parent_scb = src_scb;
insert_point = SCB_ON_PARENT_SUBLIST_SCB;
} else {
/* if channel is unlinked then src_scb->sub_list_ptr == null_scb, and
that's a correct state.
snd_assert (src_scb->sub_list_ptr != ins->the_null_scb, goto _end);
*/
if (src_scb->sub_list_ptr != ins->the_null_scb) {
pcm_parent_scb = find_next_free_scb(chip,src_scb->sub_list_ptr);
insert_point = SCB_ON_PARENT_NEXT_SCB;
} else {
pcm_parent_scb = src_scb;
insert_point = SCB_ON_PARENT_SUBLIST_SCB;
}
}
snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
......@@ -1223,19 +1188,20 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
(pcm_index * 0x10) + 0x200,
pcm_index, /* virtual channel 0-31 */
hw_dma_addr, /* pcm hw addr */
pcm_parent_scb,
insert_point);
NULL, /* parent SCB ptr */
0 /* insert point */
);
if (!pcm_scb) {
snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
goto _end;
return NULL;
}
spin_lock_irqsave(&chip->reg_lock, flags);
ins->pcm_channels[pcm_index].sample_rate = sample_rate;
ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
ins->pcm_channels[pcm_index].src_scb = src_scb;
ins->pcm_channels[pcm_index].unlinked = 0;
ins->pcm_channels[pcm_index].unlinked = 1;
ins->pcm_channels[pcm_index].private_data = private_data;
ins->pcm_channels[pcm_index].src_slot = src_index;
ins->pcm_channels[pcm_index].active = 1;
......@@ -1243,12 +1209,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa
ins->npcm_channels ++;
spin_unlock_irqrestore(&chip->reg_lock, flags);
up(&ins->pcm_mutex);
return (ins->pcm_channels + pcm_index);
_end:
up(&ins->pcm_mutex);
return NULL;
}
void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
......@@ -1256,11 +1217,9 @@ void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t *
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
unsigned long flags;
down(&ins->pcm_mutex);
snd_assert(pcm_channel->active,goto _end);
snd_assert(ins->npcm_channels > 0,goto _end);
snd_assert(pcm_channel->src_scb->ref_count > 0,goto _end);
snd_assert(pcm_channel->active, return );
snd_assert(ins->npcm_channels > 0, return );
snd_assert(pcm_channel->src_scb->ref_count > 0, return );
spin_lock_irqsave(&chip->reg_lock, flags);
pcm_channel->unlinked = 1;
......@@ -1276,18 +1235,11 @@ void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t *
cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR,
goto _end);
return );
ins->src_scb_slots[pcm_channel->src_slot] = 0;
ins->nsrc_scb --;
}
#ifdef CONFIG_SND_DEBUG
_end:
#endif
up(&ins->pcm_mutex);
}
int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
......@@ -1295,14 +1247,15 @@ int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channe
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
unsigned long flags;
down(&ins->pcm_mutex);
down(&ins->scb_mutex);
snd_assert(pcm_channel->active,return -EIO);
snd_assert(ins->npcm_channels > 0,return -EIO);
snd_assert(pcm_channel->active,goto _end);
snd_assert(ins->npcm_channels > 0,goto _end);
spin_lock(&pcm_channel->src_scb->lock);
if (pcm_channel->unlinked)
goto _end;
if (pcm_channel->unlinked) {
spin_unlock(&pcm_channel->src_scb->lock);
return -EIO;
}
spin_lock_irqsave(&chip->reg_lock, flags);
pcm_channel->unlinked = 1;
......@@ -1310,10 +1263,7 @@ int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channe
_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
_end:
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
spin_unlock(&pcm_channel->src_scb->lock);
return 0;
}
......@@ -1324,25 +1274,32 @@ int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
dsp_scb_descriptor_t * src_scb = pcm_channel->src_scb;
unsigned long flags;
down(&ins->pcm_mutex);
down(&ins->scb_mutex);
spin_lock(&pcm_channel->src_scb->lock);
if (pcm_channel->unlinked == 0)
goto _end;
if (pcm_channel->unlinked == 0) {
spin_unlock(&pcm_channel->src_scb->lock);
return -EIO;
}
if (src_scb->sub_list_ptr == ins->the_null_scb) {
parent_scb = src_scb;
parent_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
} else {
parent_scb = find_next_free_scb(chip,src_scb->sub_list_ptr);
parent_scb->next_scb_ptr = pcm_channel->pcm_reader_scb;
if (src_scb->sub_list_ptr != ins->the_null_scb) {
src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
}
src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
/* update entry in DSP RAM */
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs46xx_poke(chip,
(pcm_channel->pcm_reader_scb->address + SCBsubListPtr) << 2,
(pcm_channel->pcm_reader_scb->sub_list_ptr->address << 0x10) |
(pcm_channel->pcm_reader_scb->next_scb_ptr->address));
snd_cs46xx_poke(chip,
(parent_scb->address + SCBsubListPtr) << 2,
(parent_scb->sub_list_ptr->address << 0x10) |
......@@ -1351,13 +1308,11 @@ int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
pcm_channel->unlinked = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
_end:
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
spin_unlock(&pcm_channel->src_scb->lock);
return 0;
}
#define GOF_PER_SEC 200
void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u32 rate)
......@@ -1414,8 +1369,7 @@ void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
dsp_scb_descriptor_t *
cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
u16 addr,char * scb_name)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
......@@ -1442,27 +1396,14 @@ cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
down(&ins->pcm_mutex);
down(&ins->scb_mutex);
snd_assert (src->parent_scb_ptr != NULL,goto _fail_end);
snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
/* mute SCB */
snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
_dsp_unlink_scb (chip,src);
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
return 0;
_fail_end:
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
return -EINVAL;
}
int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
......@@ -1471,11 +1412,8 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
dsp_scb_descriptor_t * parent_scb;
unsigned int flags;
down(&ins->pcm_mutex);
down(&ins->scb_mutex);
snd_assert (src->parent_scb_ptr == NULL,goto _fail_end);
snd_assert(ins->master_mix_scb !=NULL,goto _fail_end);
snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
......@@ -1497,14 +1435,5 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
spin_unlock_irqrestore(&chip->reg_lock, flags);
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
return 0;
_fail_end:
up(&ins->scb_mutex);
up(&ins->pcm_mutex);
return -EINVAL;
}
......@@ -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) {
......
......@@ -22,6 +22,7 @@
* 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
*
*/
......@@ -41,7 +42,7 @@
#include <sound/initval.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,MX440; SiS 7012");
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{Intel,82801AA-ICH},"
......@@ -53,7 +54,8 @@ MODULE_DEVICES("{{Intel,82801AA-ICH},"
"{SiS,SI7012},"
"{NVidia,NForce Audio},"
"{AMD,AMD768},"
"{AMD,AMD8111}}");
"{AMD,AMD8111},"
"{ALI,M5455}}");
#define SUPPORT_JOYSTICK 1
#define SUPPORT_MIDI 1
......@@ -126,50 +128,58 @@ MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},di
#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO 0x01b1
#endif
#define DEVICE_INTEL 0
#define DEVICE_SIS 1
enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI };
#define ICHREG(x) ICH_REG_##x
#define DEFINE_REGSET(name,base) \
enum { \
ICH_REG_##name##_BDBAR = base + 0x0, /* dword - buffer descriptor list base address */ \
ICH_REG_##name##_CIV = base + 0x04, /* byte - current index value */ \
ICH_REG_##name##_LVI = base + 0x05, /* byte - last valid index */ \
ICH_REG_##name##_SR = base + 0x06, /* byte - status register */ \
ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \
ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \
ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \
};
/* busmaster blocks */
DEFINE_REGSET(OFF, 0); /* offset */
DEFINE_REGSET(PI, 0x00); /* PCM in */
DEFINE_REGSET(PO, 0x10); /* PCM out */
DEFINE_REGSET(MC, 0x20); /* Mic in */
/* ICH4 busmater blocks */
DEFINE_REGSET(MC2, 0x40); /* Mic in 2 */
DEFINE_REGSET(PI2, 0x50); /* PCM in 2 */
DEFINE_REGSET(SP, 0x60); /* SPDIF out */
#define ICHREG(ice, x) ((ice)->bmport + ICH_REG_##x)
#define ICHREG2(ice, x) ((ice)->bmport + x)
/* values for each busmaster block */
/* capture block */
#define ICH_REG_PI_BDBAR 0x00 /* dword - buffer descriptor list base address */
#define ICH_REG_PI_CIV 0x04 /* byte - current index value */
#define ICH_REG_PI_LVI 0x05 /* byte - last valid index */
/* LVI */
#define ICH_REG_LVI_MASK 0x1f
#define ICH_REG_PI_SR 0x06 /* byte - status register */
/* SR */
#define ICH_FIFOE 0x10 /* FIFO error */
#define ICH_BCIS 0x08 /* buffer completion interrupt status */
#define ICH_LVBCI 0x04 /* last valid buffer completion interrupt */
#define ICH_CELV 0x02 /* current equals last valid */
#define ICH_DCH 0x01 /* DMA controller halted */
#define ICH_REG_PI_PICB 0x08 /* word - position in current buffer */
#define ICH_REG_PI_PIV 0x0a /* byte - prefetched index value */
/* PIV */
#define ICH_REG_PIV_MASK 0x1f /* mask */
#define ICH_REG_PI_CR 0x0b /* byte - control register */
/* CR */
#define ICH_IOCE 0x10 /* interrupt on completion enable */
#define ICH_FEIE 0x08 /* fifo error interrupt enable */
#define ICH_LVBIE 0x04 /* last valid buffer interrupt enable */
#define ICH_RESETREGS 0x02 /* reset busmaster registers */
#define ICH_STARTBM 0x01 /* start busmaster operation */
/* playback block */
#define ICH_REG_PO_BDBAR 0x10 /* dword - buffer descriptor list base address */
#define ICH_REG_PO_CIV 0x14 /* byte - current index value */
#define ICH_REG_PO_LVI 0x15 /* byte - last valid command */
#define ICH_REG_PO_SR 0x16 /* byte - status register */
#define ICH_REG_PO_PICB 0x18 /* word - position in current buffer */
#define ICH_REG_PO_PIV 0x1a /* byte - prefetched index value */
#define ICH_REG_PO_CR 0x1b /* byte - control register */
/* mic capture block */
#define ICH_REG_MC_BDBAR 0x20 /* dword - buffer descriptor list base address */
#define ICH_REG_MC_CIV 0x24 /* byte - current index value */
#define ICH_REG_MC_LVI 0x25 /* byte - last valid command */
#define ICH_REG_MC_SR 0x26 /* byte - status register */
#define ICH_REG_MC_PICB 0x28 /* word - position in current buffer */
#define ICH_REG_MC_PIV 0x2a /* byte - prefetched index value */
#define ICH_REG_MC_CR 0x2b /* byte - control register */
/* global block */
#define ICH_REG_GLOB_CNT 0x2c /* dword - global control */
#define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */
#define ICH_PCM_246_MASK 0x00300000 /* 6 channels (not all chips) */
#define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */
#define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */
......@@ -181,16 +191,24 @@ MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},di
#define ICH_AC97COLD 0x00000002 /* AC'97 cold reset */
#define ICH_GIE 0x00000001 /* GPI interrupt enable */
#define ICH_REG_GLOB_STA 0x30 /* dword - global status */
#define ICH_TRI 0x20000000 /* ICH4: tertiary (AC_SDIN2) resume interrupt */
#define ICH_TCR 0x10000000 /* ICH4: tertiary (AC_SDIN2) codec ready */
#define ICH_BCS 0x08000000 /* ICH4: bit clock stopped */
#define ICH_SPINT 0x04000000 /* ICH4: S/PDIF interrupt */
#define ICH_P2INT 0x02000000 /* ICH4: PCM2-In interrupt */
#define ICH_M2INT 0x01000000 /* ICH4: Mic2-In interrupt */
#define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */
#define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */
#define ICH_MD3 0x00020000 /* modem power down semaphore */
#define ICH_AD3 0x00010000 /* audio power down semaphore */
#define ICH_RCS 0x00008000 /* read completion status */
#define ICH_BIT3 0x00004000 /* bit 3 slot 12 */
#define ICH_BIT2 0x00002000 /* bit 2 slot 12 */
#define ICH_BIT1 0x00001000 /* bit 1 slot 12 */
#define ICH_SRI 0x00000800 /* secondary resume interrupt */
#define ICH_PRI 0x00000400 /* primary resume interrupt */
#define ICH_SCR 0x00000200 /* secondary codec ready */
#define ICH_PCR 0x00000100 /* primary codec ready */
#define ICH_SRI 0x00000800 /* secondary (AC_SDIN1) resume interrupt */
#define ICH_PRI 0x00000400 /* primary (AC_SDIN0) resume interrupt */
#define ICH_SCR 0x00000200 /* secondary (AC_SDIN1) codec ready */
#define ICH_PCR 0x00000100 /* primary (AC_SDIN0) codec ready */
#define ICH_MCINT 0x00000080 /* MIC capture interrupt */
#define ICH_POINT 0x00000040 /* playback interrupt */
#define ICH_PIINT 0x00000020 /* capture interrupt */
......@@ -199,15 +217,78 @@ MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},di
#define ICH_GSCI 0x00000001 /* GPI status change interrupt */
#define ICH_REG_ACC_SEMA 0x34 /* byte - codec write semaphore */
#define ICH_CAS 0x01 /* codec access semaphore */
#define ICH_REG_SDM 0x80
#define ICH_DI2L_MASK 0x000000c0 /* PCM In 2, Mic In 2 data in line */
#define ICH_DI2L_SHIFT 6
#define ICH_DI1L_MASK 0x00000030 /* PCM In 1, Mic In 1 data in line */
#define ICH_DI1L_SHIFT 4
#define ICH_SE 0x00000008 /* steer enable */
#define ICH_LDI_MASK 0x00000003 /* last codec read data input */
#define ICH_MAX_FRAGS 32 /* max hw frags */
/*
* registers for Ali5455
*/
/* ALi 5455 busmaster blocks */
DEFINE_REGSET(AL_PI, 0x40); /* ALi PCM in */
DEFINE_REGSET(AL_PO, 0x50); /* Ali PCM out */
DEFINE_REGSET(AL_MC, 0x60); /* Ali Mic in */
DEFINE_REGSET(AL_CDC_SPO, 0x70); /* Ali Codec SPDIF out */
DEFINE_REGSET(AL_CLR_SPI, 0xa0); /* Ali Controller SPDIF in */
DEFINE_REGSET(AL_CLR_SPO, 0xb0); /* Ali Controller SPDIF out */
enum {
ICH_REG_ALI_SCR = 0x00, /* System Control Register */
ICH_REG_ALI_SSR = 0x04, /* System Status Register */
ICH_REG_ALI_DMACR = 0x08, /* DMA Control Register */
ICH_REG_ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */
ICH_REG_ALI_INTERFACECR = 0x10, /* Interface Control Register */
ICH_REG_ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */
ICH_REG_ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */
ICH_REG_ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */
ICH_REG_ALI_CPR = 0x20, /* Command Port Register */
ICH_REG_ALI_SPR = 0x24, /* Status Port Register */
ICH_REG_ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */
ICH_REG_ALI_TTSR = 0x30, /* Transmit Tag Slot Register */
ICH_REG_ALI_RTSR = 0x34, /* Receive Tag Slot Register */
ICH_REG_ALI_CSPSR = 0x38, /* Command/Status Port Status Register */
ICH_REG_ALI_CAS = 0x3c, /* Codec Write Semaphore Register */
ICH_REG_ALI_SPDIFCSR = 0xf8, /* spdif channel status register */
ICH_REG_ALI_SPDIFICS = 0xfc /* spdif interface control/status */
};
/* interrupts for the whole chip by interrupt status register finish */
#define ALI_INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */
#define ALI_INT_SPDIFIN (1<<22)
#define ALI_INT_CODECSPDIFOUT (1<<19)
#define ALI_INT_MICIN (1<<18)
#define ALI_INT_PCMOUT (1<<17)
#define ALI_INT_PCMIN (1<<16)
#define ALI_INT_CPRAIS (1<<7)
#define ALI_INT_SPRAIS (1<<5)
#define ALI_INT_GPIO (1<<1)
#define ALI_INT_MASK (ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN)
#define ALI_PCM_CH4 0x100
#define ALI_PCM_CH6 0x200
#define ALI_PCM_MASK (ALI_PCM_CH4 | ALI_PCM_CH6)
/*
*
*/
enum { ICHD_PCMIN, ICHD_PCMOUT, ICHD_MIC, ICHD_MIC2, ICHD_PCM2IN, ICHD_SPBAR, ICHD_LAST = ICHD_SPBAR };
enum { ALID_PCMIN, ALID_PCMOUT, ALID_MIC, ALID_AC97SPDIFOUT, ALID_SPDIFIN, ALID_SPDIFOUT, ALID_LAST = ALID_SPDIFOUT };
#define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data)
typedef struct {
unsigned long reg_offset;
unsigned int ichd; /* ich device number */
unsigned long reg_offset; /* offset to bmaddr */
u32 *bdbar; /* CPU address (32bit) */
unsigned int bdbar_addr; /* PCI bus address (32bit) */
snd_pcm_substream_t *substream;
......@@ -221,11 +302,20 @@ typedef struct {
int lvi_frag;
int ack;
int ack_reload;
unsigned int ack_bit;
unsigned int roff_sr;
unsigned int roff_picb;
unsigned int int_sta_mask; /* interrupt status mask */
unsigned int ali_slot; /* ALI DMA slot */
ac97_t *ac97;
unsigned short ac97_rate_regs[3];
int ac97_rates_idx;
#ifdef CONFIG_PM
unsigned char civ_saved;
unsigned char piv_saved;
unsigned short picb_saved;
#endif
snd_info_entry_t *proc_entry;
} ichdev_t;
typedef struct _snd_intel8x0 intel8x0_t;
......@@ -242,27 +332,34 @@ struct _snd_intel8x0 {
int irq;
unsigned long port;
struct resource *res_port;
unsigned long bmport;
struct resource *res_bmport;
unsigned int mmio;
unsigned long addr;
unsigned long remap_addr;
struct resource *res;
unsigned int bm_mmio;
unsigned long bmaddr;
unsigned long remap_bmaddr;
struct resource *res_bm;
struct pci_dev *pci;
snd_card_t *card;
snd_pcm_t *pcm;
snd_pcm_t *pcm_mic;
ichdev_t playback;
ichdev_t capture;
ichdev_t capture_mic;
snd_pcm_t *pcm_mic2;
snd_pcm_t *pcm2;
snd_pcm_t *pcm_spdif;
snd_pcm_t *pcm_ac97spdif;
ichdev_t ichd[6];
int multi4: 1,
multi6: 1;
int in_ac97_init: 1;
int no_codec_check: 1;
multi6: 1,
smp20bit: 1;
int in_ac97_init: 1,
in_sdin_init: 1;
ac97_t *ac97;
ac97_t *ac97sec;
ac97_t *ac97[3];
unsigned int ac97_sdin[3];
snd_rawmidi_t *rmidi;
......@@ -270,15 +367,11 @@ struct _snd_intel8x0 {
spinlock_t ac97_lock;
snd_info_entry_t *proc_entry;
u32 bdbars_count;
u32 *bdbars;
dma_addr_t bdbars_addr;
unsigned int reg_pi_sr;
unsigned int reg_pi_picb;
unsigned int reg_po_sr;
unsigned int reg_po_picb;
unsigned int reg_mc_sr;
unsigned int reg_mc_picb;
u32 int_sta_reg; /* interrupt status register */
u32 int_sta_mask; /* interrupt status mask */
#ifdef CONFIG_PM
int in_suspend;
......@@ -290,34 +383,131 @@ static struct pci_device_id snd_intel8x0_ids[] __devinitdata = {
{ 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
{ 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
{ 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
{ 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
{ 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7012 */
{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* NFORCE */
{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
{ 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
{ 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids);
/*
* Lowlevel I/O - busmaster
*/
static u8 igetbyte(intel8x0_t *chip, u32 offset)
{
if (chip->bm_mmio)
return readb(chip->remap_bmaddr + offset);
else
return inb(chip->bmaddr + offset);
}
static u16 igetword(intel8x0_t *chip, u32 offset)
{
if (chip->bm_mmio)
return readw(chip->remap_bmaddr + offset);
else
return inw(chip->bmaddr + offset);
}
static u32 igetdword(intel8x0_t *chip, u32 offset)
{
if (chip->bm_mmio)
return readl(chip->remap_bmaddr + offset);
else
return inl(chip->bmaddr + offset);
}
static void iputbyte(intel8x0_t *chip, u32 offset, u8 val)
{
if (chip->bm_mmio)
writeb(val, chip->remap_bmaddr + offset);
else
return outb(val, chip->bmaddr + offset);
}
static void iputword(intel8x0_t *chip, u32 offset, u16 val)
{
if (chip->bm_mmio)
writew(val, chip->remap_bmaddr + offset);
else
return outw(val, chip->bmaddr + offset);
}
static void iputdword(intel8x0_t *chip, u32 offset, u32 val)
{
if (chip->bm_mmio)
writel(val, chip->remap_bmaddr + offset);
else
return outl(val, chip->bmaddr + offset);
}
/*
* Lowlevel I/O - AC'97 registers
*/
static u16 iagetword(intel8x0_t *chip, u32 offset)
{
if (chip->mmio)
return readw(chip->remap_addr + offset);
else
return inw(chip->addr + offset);
}
static void iaputword(intel8x0_t *chip, u32 offset, u16 val)
{
if (chip->mmio)
writew(val, chip->remap_addr + offset);
else
return outw(val, chip->addr + offset);
}
/*
* Basic I/O
*/
/*
* access to AC97 codec via normal i/o (for ICH and SIS7012)
*/
static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec)
{
int time;
/* codec ready ? */
if (! chip->no_codec_check) {
if ((inl(ICHREG(chip, GLOB_STA)) & (codec ? ICH_SCR : ICH_PCR)) == 0)
if (codec > 2)
return -EIO;
if (chip->in_sdin_init) {
/* we don't know the ready bit assignment at the moment */
/* so we check any */
codec = ICH_PCR | ICH_SCR | ICH_TCR;
} else {
if (chip->device_type == DEVICE_INTEL_ICH4) {
switch (chip->ac97_sdin[codec]) {
case 0: codec = ICH_PCR; break;
case 1: codec = ICH_SCR; break;
case 2: codec = ICH_TCR; break;
}
} else {
switch (codec) {
case 0: codec = ICH_PCR; break;
case 1: codec = ICH_SCR; break;
case 2: codec = ICH_TCR; break;
}
}
}
/* codec ready ? */
if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0)
return -EIO;
/* Anyone holding a semaphore for 1 msec should be shot... */
time = 100;
do {
if (!(inb(ICHREG(chip, ACC_SEMA)) & ICH_CAS))
if (!(igetbyte(chip, ICHREG(ACC_SEMA)) & ICH_CAS))
return 0;
udelay(10);
} while (time--);
......@@ -326,8 +516,8 @@ static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec)
* reset the semaphore. So even if you don't get the semaphore, still
* continue the access. We don't need the semaphore anyway. */
snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
inb(ICHREG(chip, ACC_SEMA)), inl(ICHREG(chip, GLOB_STA)));
inw(chip->port); /* clear semaphore flag */
igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
iagetword(chip, 0); /* clear semaphore flag */
/* I don't care about the semaphore */
return -EBUSY;
}
......@@ -343,7 +533,7 @@ static void snd_intel8x0_codec_write(ac97_t *ac97,
if (! chip->in_ac97_init)
snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
}
outw(val, chip->port + reg + ac97->num * 0x80);
iaputword(chip, reg + ac97->num * 0x80, val);
spin_unlock(&chip->ac97_lock);
}
......@@ -360,10 +550,10 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97,
snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
res = 0xffff;
} else {
res = inw(chip->port + reg + ac97->num * 0x80);
if ((tmp = inl(ICHREG(chip, GLOB_STA))) & ICH_RCS) {
res = iagetword(chip, reg + ac97->num * 0x80);
if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
/* reset RCS and preserve other R/WC bits */
outl(tmp & ~(ICH_SRI|ICH_PRI|ICH_GSCI), ICHREG(chip, GLOB_STA));
iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
if (! chip->in_ac97_init)
snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
res = 0xffff;
......@@ -373,46 +563,85 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97,
return res;
}
static int snd_intel8x0_trigger(intel8x0_t *chip, ichdev_t *ichdev, int cmd)
/*
* access to AC97 for Ali5455
*/
static int snd_intel8x0_ali_codec_ready(intel8x0_t *chip, int mask)
{
unsigned char val = 0;
unsigned long port = chip->bmport + ichdev->reg_offset;
int count = 0;
for (count = 0; count < 0x7f; count++) {
int val = igetbyte(chip, ICHREG(ALI_CSPSR));
if (val & mask)
return 0;
}
snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n");
return -EBUSY;
}
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
val = ICH_IOCE | ICH_STARTBM;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
val = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = ICH_IOCE;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = ICH_IOCE | ICH_STARTBM;
break;
default:
return -EINVAL;
static int snd_intel8x0_ali_codec_semaphore(intel8x0_t *chip)
{
int time = 100;
do {
if (igetdword(chip, ICHREG(ALI_CAS)) & 0x80000000)
return snd_intel8x0_ali_codec_ready(chip, 0x08);
udelay(1);
} while (time--);
snd_printk(KERN_WARNING "intel8x0: AC97 codec semaphore timeout.\n");
return -EBUSY;
}
static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short reg)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0);
unsigned short data, reg2;
spin_lock(&chip->ac97_lock);
if (snd_intel8x0_ali_codec_semaphore(chip))
goto __err;
reg |= 0x0080;
iputword(chip, ICHREG(ALI_CPR) + 2, reg | 0x0080);
if (snd_intel8x0_ali_codec_ready(chip, 0x02))
goto __err;
data = igetword(chip, ICHREG(ALI_SPR));
reg2 = igetword(chip, ICHREG(ALI_SPR) + 2);
if (reg != reg2) {
snd_printd(KERN_WARNING "intel8x0: AC97 read not completed?\n");
goto __err;
}
outb(val, port + ICH_REG_PI_CR);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
/* reset whole DMA things */
while (!(inb(port + chip->reg_pi_sr) & ICH_DCH)) ;
outb(ICH_RESETREGS, port + ICH_REG_PI_CR);
spin_unlock(&chip->ac97_lock);
return data;
__err:
spin_unlock(&chip->ac97_lock);
return 0xffff;
}
static void snd_intel8x0_ali_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return);
spin_lock(&chip->ac97_lock);
if (snd_intel8x0_ali_codec_semaphore(chip)) {
spin_unlock(&chip->ac97_lock);
return;
}
return 0;
iputword(chip, ICHREG(ALI_CPR), val);
iputbyte(chip, ICHREG(ALI_CPR) + 2, reg);
snd_intel8x0_ali_codec_ready(chip, 0x01);
spin_unlock(&chip->ac97_lock);
}
/*
* DMA I/O
*/
static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev)
{
int idx;
u32 *bdbar = ichdev->bdbar;
unsigned long port = chip->bmport + ichdev->reg_offset;
unsigned long port = ichdev->reg_offset;
int shiftlen = (chip->device_type == DEVICE_SIS) ? 0 : 1;
outl(ichdev->bdbar_addr, port + ICH_REG_PI_BDBAR);
iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
if (ichdev->size == ichdev->fragsize) {
ichdev->ack_reload = ichdev->ack = 2;
ichdev->fragsize1 = ichdev->fragsize >> 1;
......@@ -436,7 +665,7 @@ static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev)
}
ichdev->frags = ichdev->size / ichdev->fragsize;
}
outb(ichdev->lvi = ICH_REG_LVI_MASK, port + ICH_REG_PI_LVI);
iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK);
ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
ichdev->position = 0;
#if 0
......@@ -444,7 +673,7 @@ static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev)
ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
#endif
/* clear interrupts */
outb(ICH_FIFOE | ICH_BCIS | ICH_LVBCI, port + chip->reg_pi_sr);
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}
/*
......@@ -453,7 +682,7 @@ static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev)
static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev)
{
unsigned long port = chip->bmport + ichdev->reg_offset;
unsigned long port = ichdev->reg_offset;
int ack = 0;
spin_lock(&chip->reg_lock);
......@@ -461,80 +690,116 @@ static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev)
ichdev->position %= ichdev->size;
ichdev->lvi++;
ichdev->lvi &= ICH_REG_LVI_MASK;
outb(ichdev->lvi, port + ICH_REG_PI_LVI);
iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
ichdev->lvi_frag++;
ichdev->lvi_frag %= ichdev->frags;
ichdev->bdbar[ichdev->lvi * 2] = ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1;
// printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_PI_PIV + port), inl(port + 4), inb(port + ICH_REG_PI_CR));
ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
// printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR));
if ((ack = (--ichdev->ack == 0)) != 0)
ichdev->ack = ichdev->ack_reload;
spin_unlock(&chip->reg_lock);
if (ack && ichdev->substream)
snd_pcm_period_elapsed(ichdev->substream);
outb(ICH_FIFOE | ICH_BCIS | ICH_LVBCI, port + chip->reg_pi_sr);
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}
static void snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, dev_id, return);
ichdev_t *ichdev;
unsigned int status;
int i;
spin_lock(&chip->reg_lock);
status = inl(ICHREG(chip, GLOB_STA));
if ((status & (ICH_MCINT | ICH_POINT | ICH_PIINT)) == 0) {
status = igetdword(chip, chip->int_sta_reg);
if ((status & chip->int_sta_mask) == 0) {
spin_unlock(&chip->reg_lock);
return;
}
/* ack first */
outl(status & (ICH_MCINT | ICH_POINT | ICH_PIINT), ICHREG(chip, GLOB_STA));
iputdword(chip, chip->int_sta_reg, status & ~chip->int_sta_mask);
spin_unlock(&chip->reg_lock);
if (status & ICH_POINT)
snd_intel8x0_update(chip, &chip->playback);
if (status & ICH_PIINT)
snd_intel8x0_update(chip, &chip->capture);
if (status & ICH_MCINT)
snd_intel8x0_update(chip, &chip->capture_mic);
for (i = 0; i < chip->bdbars_count; i++) {
ichdev = &chip->ichd[i];
if (status & ichdev->int_sta_mask)
snd_intel8x0_update(chip, ichdev);
}
}
/*
* PCM part
*/
static int snd_intel8x0_playback_ioctl(snd_pcm_substream_t * substream,
unsigned int cmd,
void *arg)
{
int result;
result = snd_pcm_lib_ioctl(substream, cmd, arg);
if (result < 0)
return result;
return 0;
}
static int snd_intel8x0_capture_ioctl(snd_pcm_substream_t * substream,
unsigned int cmd,
void *arg)
{
int result;
result = snd_pcm_lib_ioctl(substream, cmd, arg);
if (result < 0)
return result;
return 0;
}
static int snd_intel8x0_playback_trigger(snd_pcm_substream_t *substream, int cmd)
static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
ichdev_t *ichdev = get_ichdev(substream);
unsigned char val = 0;
unsigned long port = ichdev->reg_offset;
return snd_intel8x0_trigger(chip, &chip->playback, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
val = ICH_IOCE | ICH_STARTBM;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
val = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = ICH_IOCE;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = ICH_IOCE | ICH_STARTBM;
break;
default:
return -EINVAL;
}
iputbyte(chip, port + ICH_REG_OFF_CR, val);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
/* reset whole DMA things */
while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ;
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
}
return 0;
}
static int snd_intel8x0_capture_trigger(snd_pcm_substream_t *substream, int cmd)
static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
ichdev_t *ichdev = get_ichdev(substream);
unsigned long port = ichdev->reg_offset;
return snd_intel8x0_trigger(chip, &chip->capture, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
iputbyte(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
iputbyte(chip, port + ICH_REG_OFF_CR, 0);
/* reset whole DMA things */
while (!(igetbyte(chip, port + ICH_REG_OFF_CR)))
;
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
/* clear interrupts */
iputbyte(chip, port + ICH_REG_OFF_SR, igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e);
iputdword(chip, ICHREG(ALI_INTERRUPTSR),
igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & (1 << (ichdev->ali_slot + 8)));
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
iputbyte(chip, port + ICH_REG_OFF_CR, 0);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
break;
default:
return -EINVAL;
}
return 0;
}
static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream,
......@@ -550,72 +815,52 @@ static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream)
static void snd_intel8x0_setup_multi_channels(intel8x0_t *chip, int channels)
{
unsigned int cnt = inl(ICHREG(chip, GLOB_CNT)) & ~ICH_PCM_246_MASK;
unsigned int cnt = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_246_MASK;
if (chip->multi4 && channels == 4)
cnt |= ICH_PCM_4;
else if (chip->multi6 && channels == 6)
cnt |= ICH_PCM_6;
outl(cnt, ICHREG(chip, GLOB_CNT));
iputdword(chip, ICHREG(GLOB_CNT), cnt);
}
static int snd_intel8x0_playback_prepare(snd_pcm_substream_t * substream)
static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
ichdev_t *ichdev = get_ichdev(substream);
int i;
chip->playback.physbuf = runtime->dma_addr;
chip->playback.size = snd_pcm_lib_buffer_bytes(substream);
chip->playback.fragsize = snd_pcm_lib_period_bytes(substream);
ichdev->physbuf = runtime->dma_addr;
ichdev->size = snd_pcm_lib_buffer_bytes(substream);
ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
if (ichdev->ichd == ICHD_PCMOUT && chip->device_type != DEVICE_ALI) {
spin_lock(&chip->reg_lock);
snd_intel8x0_setup_multi_channels(chip, runtime->channels);
spin_unlock(&chip->reg_lock);
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_intel8x0_setup_periods(chip, &chip->playback);
return 0;
}
static int snd_intel8x0_capture_prepare(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
chip->capture.physbuf = runtime->dma_addr;
chip->capture.size = snd_pcm_lib_buffer_bytes(substream);
chip->capture.fragsize = snd_pcm_lib_period_bytes(substream);
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
snd_intel8x0_setup_periods(chip, &chip->capture);
}
for (i = 0; i < 3; i++)
if (ichdev->ac97_rate_regs[i])
snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate);
snd_intel8x0_setup_periods(chip, ichdev);
return 0;
}
static snd_pcm_uframes_t snd_intel8x0_playback_pointer(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
size_t ptr;
ptr = chip->playback.fragsize1;
if (chip->device_type == DEVICE_SIS)
ptr -= inw(ICHREG2(chip,chip->reg_po_picb));
else
ptr -= inw(ICHREG2(chip,chip->reg_po_picb)) << 1;
ptr += chip->playback.position;
return bytes_to_frames(substream->runtime, ptr);
}
static snd_pcm_uframes_t snd_intel8x0_capture_pointer(snd_pcm_substream_t * substream)
static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
ichdev_t *ichdev = get_ichdev(substream);
size_t ptr;
ptr = chip->capture.fragsize1;
ptr = ichdev->fragsize1;
if (chip->device_type == DEVICE_SIS)
ptr -= inw(ICHREG2(chip,chip->reg_pi_picb));
ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
else
ptr -= inw(ICHREG2(chip,chip->reg_pi_picb)) << 1;
ptr += chip->capture.position;
ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1;
ptr += ichdev->position;
return bytes_to_frames(substream->runtime, ptr);
}
static snd_pcm_hardware_t snd_intel8x0_playback =
static snd_pcm_hardware_t snd_intel8x0_stream =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
......@@ -623,27 +868,7 @@ static snd_pcm_hardware_t snd_intel8x0_playback =
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
static snd_pcm_hardware_t snd_intel8x0_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
......@@ -680,15 +905,16 @@ static snd_pcm_hw_constraint_list_t hw_constraints_channels6 = {
.mask = 0,
};
static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream)
static int snd_intel8x0_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichdev)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->playback.substream = substream;
runtime->hw = snd_intel8x0_playback;
runtime->hw.rates = chip->ac97->rates_front_dac;
ichdev->substream = substream;
runtime->hw = snd_intel8x0_stream;
if (ichdev->ac97_rates_idx >= 0)
runtime->hw.rates = ichdev->ac97->rates[ichdev->ac97_rates_idx];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if (chip->device_type == DEVICE_SIS) {
......@@ -697,6 +923,17 @@ static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream)
}
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
runtime->private_data = ichdev;
return 0;
}
static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
err = snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMOUT]);
if (chip->multi6) {
runtime->hw.channels_max = 6;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels6);
......@@ -707,72 +944,270 @@ static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream)
return 0;
}
static int snd_intel8x0_capture_open(snd_pcm_substream_t * substream)
static int snd_intel8x0_playback_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->capture.substream = substream;
runtime->hw = snd_intel8x0_capture;
runtime->hw.rates = chip->ac97->rates_adc;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if (chip->device_type == DEVICE_SIS) {
runtime->hw.buffer_bytes_max = 64*1024;
runtime->hw.period_bytes_max = 64*1024;
}
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
chip->ichd[ICHD_PCMOUT].substream = NULL;
return 0;
}
static int snd_intel8x0_playback_close(snd_pcm_substream_t * substream)
static int snd_intel8x0_capture_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->playback.substream = NULL;
/* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
return 0;
return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMIN]);
}
static int snd_intel8x0_capture_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->capture.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
chip->ichd[ICHD_PCMIN].substream = NULL;
return 0;
}
static snd_pcm_ops_t snd_intel8x0_playback_ops = {
.open = snd_intel8x0_playback_open,
.close = snd_intel8x0_playback_close,
.ioctl = snd_intel8x0_playback_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_playback_prepare,
.trigger = snd_intel8x0_playback_trigger,
.pointer = snd_intel8x0_playback_pointer,
};
static int snd_intel8x0_mic_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
static snd_pcm_ops_t snd_intel8x0_capture_ops = {
.open = snd_intel8x0_capture_open,
.close = snd_intel8x0_capture_close,
.ioctl = snd_intel8x0_capture_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_capture_prepare,
.trigger = snd_intel8x0_capture_trigger,
.pointer = snd_intel8x0_capture_pointer,
};
return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC]);
}
static void snd_intel8x0_pcm_free(snd_pcm_t *pcm)
static int snd_intel8x0_mic_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm = NULL;
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ICHD_MIC].substream = NULL;
return 0;
}
static int snd_intel8x0_mic2_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC2]);
}
static int snd_intel8x0_mic2_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ICHD_MIC2].substream = NULL;
return 0;
}
static int snd_intel8x0_capture2_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCM2IN]);
}
static int snd_intel8x0_capture2_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ICHD_PCM2IN].substream = NULL;
return 0;
}
static int snd_intel8x0_spdif_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_SPBAR]);
}
static int snd_intel8x0_spdif_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ICHD_SPBAR].substream = NULL;
return 0;
}
static int snd_intel8x0_ali_ac97spdifout_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]);
}
static int snd_intel8x0_ali_ac97spdifout_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ALID_AC97SPDIFOUT].substream = NULL;
return 0;
}
static int snd_intel8x0_ali_spdifin_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFIN]);
}
static int snd_intel8x0_ali_spdifin_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ALID_SPDIFIN].substream = NULL;
return 0;
}
static int snd_intel8x0_ali_spdifout_open(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFOUT]);
}
static int snd_intel8x0_ali_spdifout_close(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
chip->ichd[ALID_SPDIFOUT].substream = NULL;
return 0;
}
static snd_pcm_ops_t snd_intel8x0_playback_ops = {
.open = snd_intel8x0_playback_open,
.close = snd_intel8x0_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_capture_ops = {
.open = snd_intel8x0_capture_open,
.close = snd_intel8x0_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_capture_mic_ops = {
.open = snd_intel8x0_mic_open,
.close = snd_intel8x0_mic_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_capture_mic2_ops = {
.open = snd_intel8x0_mic2_open,
.close = snd_intel8x0_mic2_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_capture2_ops = {
.open = snd_intel8x0_capture2_open,
.close = snd_intel8x0_capture2_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_spdif_ops = {
.open = snd_intel8x0_spdif_open,
.close = snd_intel8x0_spdif_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_playback_ops = {
.open = snd_intel8x0_playback_open,
.close = snd_intel8x0_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_ali_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_capture_ops = {
.open = snd_intel8x0_capture_open,
.close = snd_intel8x0_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_ali_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_capture_mic_ops = {
.open = snd_intel8x0_mic_open,
.close = snd_intel8x0_mic_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_ali_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_ac97spdifout_ops = {
.open = snd_intel8x0_ali_ac97spdifout_open,
.close = snd_intel8x0_ali_ac97spdifout_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_ali_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_spdifin_ops = {
.open = snd_intel8x0_ali_spdifin_open,
.close = snd_intel8x0_ali_spdifin_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static snd_pcm_ops_t snd_intel8x0_ali_spdifout_ops = {
.open = snd_intel8x0_ali_spdifout_open,
.close = snd_intel8x0_ali_spdifout_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_pcm_prepare,
.trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
static void snd_intel8x0_pcm_free(snd_pcm_t *pcm)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
......@@ -787,8 +1222,13 @@ static int __devinit snd_intel8x0_pcm(intel8x0_t *chip, int device, snd_pcm_t **
if (err < 0)
return err;
if (chip->device_type == DEVICE_ALI) {
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_ali_capture_ops);
} else {
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture_ops);
}
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_free;
......@@ -807,198 +1247,432 @@ static int __devinit snd_intel8x0_pcm(intel8x0_t *chip, int device, snd_pcm_t **
* PCM code - MIC
*/
static int snd_intel8x0_capture_mic_ioctl(snd_pcm_substream_t * substream,
unsigned int cmd,
void *arg)
static void snd_intel8x0_pcm_mic_free(snd_pcm_t *pcm)
{
int result;
result = snd_pcm_lib_ioctl(substream, cmd, arg);
if (result < 0)
return result;
return 0;
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm_mic = NULL;
}
static int snd_intel8x0_capture_mic_trigger(snd_pcm_substream_t * substream,
int cmd)
static int __devinit snd_intel8x0_pcm_mic(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_t *pcm;
int err;
return snd_intel8x0_trigger(chip, &chip->capture_mic, cmd);
}
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "Intel ICH - MIC ADC", device, 0, 1, &pcm);
if (err < 0)
return err;
static int snd_intel8x0_capture_mic_prepare(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
chip->device_type == DEVICE_ALI ?
&snd_intel8x0_ali_capture_mic_ops :
&snd_intel8x0_capture_mic_ops);
chip->capture_mic.physbuf = runtime->dma_addr;
chip->capture_mic.size = snd_pcm_lib_buffer_bytes(substream);
chip->capture_mic.fragsize = snd_pcm_lib_period_bytes(substream);
snd_ac97_set_rate(chip->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate);
snd_intel8x0_setup_periods(chip, &chip->capture_mic);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_mic_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - MIC ADC", chip->card->shortname);
chip->pcm_mic = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
static snd_pcm_uframes_t snd_intel8x0_capture_mic_pointer(snd_pcm_substream_t * substream)
/*
* PCM code - MIC2
*/
static void snd_intel8x0_pcm_mic2_free(snd_pcm_t *pcm)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
size_t ptr;
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm_mic2 = NULL;
}
ptr = chip->capture_mic.fragsize1;
if (chip->device_type == DEVICE_SIS)
ptr -= inw(ICHREG2(chip,chip->reg_mc_picb));
else
ptr -= inw(ICHREG2(chip,chip->reg_mc_picb)) << 1;
ptr += chip->capture_mic.position;
return bytes_to_frames(substream->runtime, ptr);
static int __devinit snd_intel8x0_pcm_mic2(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "Intel ICH - MIC2 ADC", device, 0, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture_mic2_ops);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_mic2_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - MIC2 ADC", chip->card->shortname);
chip->pcm_mic2 = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
static snd_pcm_hardware_t snd_intel8x0_capture_mic =
/*
* PCM code - capture2
*/
static void snd_intel8x0_pcm_capture2_free(snd_pcm_t *pcm)
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 1,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm2 = NULL;
}
static int snd_intel8x0_capture_mic_open(snd_pcm_substream_t * substream)
static int __devinit snd_intel8x0_pcm_capture2(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_t *pcm;
int err;
chip->capture_mic.substream = substream;
runtime->hw = snd_intel8x0_capture_mic;
runtime->hw.rates = chip->ac97->rates_mic_adc;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if (chip->device_type == DEVICE_SIS) {
runtime->hw.buffer_bytes_max = 64*1024;
runtime->hw.period_bytes_max = 64*1024;
}
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "Intel ICH - ADC2", device, 0, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture2_ops);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_capture2_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - ADC2", chip->card->shortname);
chip->pcm2 = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
static int snd_intel8x0_capture_mic_close(snd_pcm_substream_t * substream)
/*
* PCM code - S/PDIF
*/
static void snd_intel8x0_pcm_spdif_free(snd_pcm_t *pcm)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm_spdif = NULL;
}
static int __devinit snd_intel8x0_pcm_spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "Intel ICH - IEC958", device, 1, 0, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_spdif_ops);
chip->capture_mic.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS, 0x4000, 0x4000);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_spdif_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - IEC958", chip->card->shortname);
chip->pcm_spdif = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
static snd_pcm_ops_t snd_intel8x0_capture_mic_ops = {
.open = snd_intel8x0_capture_mic_open,
.close = snd_intel8x0_capture_mic_close,
.ioctl = snd_intel8x0_capture_mic_ioctl,
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0_capture_mic_prepare,
.trigger = snd_intel8x0_capture_mic_trigger,
.pointer = snd_intel8x0_capture_mic_pointer,
};
/*
* PCM code - ALI S/PDIF
*/
static void snd_intel8x0_pcm_mic_free(snd_pcm_t *pcm)
static void snd_intel8x0_ali_spdif_free(snd_pcm_t *pcm)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm_mic = NULL;
chip->pcm_spdif = NULL;
}
static int __devinit snd_intel8x0_pcm_mic(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
static int __devinit snd_intel8x0_ali_spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "Intel ICH - MIC ADC", device, 1, 1, &pcm);
err = snd_pcm_new(chip->card, "Intel ICH - IEC958", device, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture_mic_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_spdifout_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_ali_spdifin_ops);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_pcm_mic_free;
pcm->private_free = snd_intel8x0_ali_spdif_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - MIC ADC", chip->card->shortname);
sprintf(pcm->name, "%s - IEC958", chip->card->shortname);
chip->pcm_mic = pcm;
chip->pcm_spdif = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
/*
* Mixer part
* PCM code - ALI AC'97 S/PDIF
*/
static void snd_intel8x0_codec_init(ac97_t *ac97)
static void snd_intel8x0_ali_ac97spdif_free(snd_pcm_t *pcm)
{
// intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return);
intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return);
chip->pcm_ac97spdif = NULL;
}
/* 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 int __devinit snd_intel8x0_ali_ac97spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "ALI - AC97 IEC958", device, 0, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_ac97spdifout_ops);
pcm->private_data = chip;
pcm->private_free = snd_intel8x0_ali_ac97spdif_free;
pcm->info_flags = 0;
sprintf(pcm->name, "%s - AC97 IEC958", chip->card->shortname);
chip->pcm_ac97spdif = pcm;
if (rpcm)
*rpcm = pcm;
return 0;
}
/*
* Mixer part
*/
static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return);
if (ac97->num == 0) {
chip->ac97 = NULL;
} else {
chip->ac97sec = NULL;
}
chip->ac97[ac97->num] = NULL;
}
static struct _ac97_rate_regs {
unsigned int ichd;
unsigned short regs[3];
short rates_idx;
} ac97_rate_regs[] = {
{ ICHD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC },
{ ICHD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC },
{ ICHD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC },
{ ICHD_MIC2, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC },
{ ICHD_PCM2IN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC },
{ ICHD_SPBAR, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF },
};
static struct _ac97_ali_rate_regs {
unsigned int ichd;
unsigned short regs[3];
short rates_idx;
} ac97_ali_rate_regs[] = {
{ ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC },
{ ALID_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC },
{ ALID_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC },
{ ALID_AC97SPDIFOUT, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF },
{ ALID_SPDIFOUT, { 0, 0, 0 }, -1 },
{ ALID_SPDIFIN, { 0, 0, 0 }, -1 },
};
static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
{
ac97_t ac97;
int err;
ac97_t ac97, *x97;
ichdev_t *ichdev;
int err, i, channels = 2, codecs;
unsigned int glob_sta = 0;
for (i = 0; i <= ICHD_LAST; i++) {
if (chip->device_type != DEVICE_ALI) {
struct _ac97_rate_regs *aregs;
aregs = &ac97_rate_regs[i];
ichdev = &chip->ichd[aregs->ichd];
ichdev->ac97_rate_regs[0] = aregs->regs[0];
ichdev->ac97_rate_regs[1] = aregs->regs[1];
ichdev->ac97_rate_regs[2] = aregs->regs[2];
ichdev->ac97_rates_idx = aregs->rates_idx;
} else {
struct _ac97_ali_rate_regs *aregs;
aregs = &ac97_ali_rate_regs[i];
ichdev = &chip->ichd[aregs->ichd];
ichdev->ac97_rate_regs[0] = aregs->regs[0];
ichdev->ac97_rate_regs[1] = aregs->regs[1];
ichdev->ac97_rate_regs[2] = aregs->regs[2];
ichdev->ac97_rates_idx = aregs->rates_idx;
}
}
chip->in_ac97_init = 1;
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_intel8x0_codec_write;
ac97.read = snd_intel8x0_codec_read;
ac97.init = snd_intel8x0_codec_init;
ac97.private_data = chip;
ac97.private_free = snd_intel8x0_mixer_free_ac97;
if (ac97_clock >= 8000 && ac97_clock <= 48000)
ac97.clock = ac97_clock;
else
ac97.clock = 48000;
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
if (chip->device_type != DEVICE_ALI) {
glob_sta = igetdword(chip, ICHREG(GLOB_STA));
ac97.write = snd_intel8x0_codec_write;
ac97.read = snd_intel8x0_codec_read;
if (glob_sta & ICH_PCM_6)
channels = 6;
else if (glob_sta & ICH_PCM_4)
channels = 4;
if (chip->device_type == DEVICE_INTEL_ICH4) {
codecs = 0;
if (glob_sta & ICH_PCR)
codecs++;
if (glob_sta & ICH_SCR)
codecs++;
if (glob_sta & ICH_TCR)
codecs++;
chip->in_sdin_init = 1;
for (i = 0; i < codecs; i++) {
ac97.num = i;
snd_intel8x0_codec_read(&ac97, 0);
chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
}
ac97.num = 0;
chip->in_sdin_init = 0;
} else {
codecs = glob_sta & ICH_SCR ? 2 : 1;
}
} else {
ac97.write = snd_intel8x0_ali_codec_write;
ac97.read = snd_intel8x0_ali_codec_read;
channels = 6;
codecs = 1;
}
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err;
#if 0 /* it seems that SDIN signals are mixed together (at least for AD CNR boards) */
if (inl(ICHREG(chip, GLOB_STA)) & ICH_SCR) {
ac97.num = 1;
ac97.addr = 1;
snd_ac97_mixer(chip->card, &ac97, &chip->ac97sec);
chip->ac97[0] = x97;
chip->ichd[ICHD_PCMOUT].ac97 = x97;
chip->ichd[ICHD_PCMIN].ac97 = x97;
if (x97->ext_id & AC97_EI_VRM)
chip->ichd[ICHD_MIC].ac97 = x97;
if (x97->ext_id & AC97_EI_SPDIF) {
if (chip->device_type != DEVICE_ALI)
chip->ichd[ICHD_SPBAR].ac97 = x97;
else
chip->ichd[ALID_AC97SPDIFOUT].ac97 = x97;
}
#endif
if ((inl(ICHREG(chip, GLOB_STA)) & (ICH_PCM_4|ICH_PCM_6)) != (ICH_PCM_4|ICH_PCM_6))
return 0;
if ((chip->ac97->scaps & AC97_SCAP_SURROUND_DAC) ||
(chip->ac97sec && (chip->ac97sec->scaps & AC97_SCAP_SURROUND_DAC))) {
/* make sure, that we have DACs at right slot for rev2.2 */
if (ac97_is_rev22(x97))
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0);
/* can we have more AC'97 codecs with ALI chipset? */
if (chip->device_type == DEVICE_ALI)
goto __end;
/* AnalogDevices CNR boards uses special codec chaining */
/* skip standard test method for secondary codecs in this case */
if (x97->flags & AC97_AD_MULTI) {
codecs = 1;
goto __skip_secondary;
}
if (codecs < 2)
goto __skip_secondary;
for (i = 1; i < codecs; i++) {
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err;
chip->ac97[i] = x97;
if (chip->device_type == DEVICE_INTEL_ICH4 && chip->ichd[ICHD_PCM2IN].ac97 == NULL)
chip->ichd[ICHD_PCM2IN].ac97 = x97;
if (x97->ext_id & AC97_EI_VRM) {
if (chip->ichd[ICHD_MIC].ac97 == NULL)
chip->ichd[ICHD_MIC].ac97 = x97;
else if (chip->device_type == DEVICE_INTEL_ICH4 &&
chip->ichd[ICHD_MIC2].ac97 == NULL &&
chip->ichd[ICHD_PCM2IN].ac97 == x97)
chip->ichd[ICHD_MIC2].ac97 = x97;
}
if (x97->ext_id & AC97_EI_SPDIF) {
if (chip->device_type != DEVICE_ALI) {
if (chip->ichd[ICHD_SPBAR].ac97 == NULL)
chip->ichd[ICHD_SPBAR].ac97 = x97;
} else {
if (chip->ichd[ALID_AC97SPDIFOUT].ac97 == NULL)
chip->ichd[ALID_AC97SPDIFOUT].ac97 = x97;
}
}
}
__skip_secondary:
if (chip->device_type == DEVICE_INTEL_ICH4) {
u8 tmp = igetbyte(chip, ICHREG(SDM));
tmp &= ~(ICH_DI2L_MASK|ICH_DI1L_MASK);
if (chip->ichd[ICHD_PCM2IN].ac97) {
tmp |= ICH_SE; /* steer enable for multiple SDINs */
tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT;
tmp |= chip->ac97_sdin[chip->ichd[ICHD_PCM2IN].ac97->num] << ICH_DI2L_SHIFT;
} else {
tmp &= ~ICH_SE;
}
iputbyte(chip, ICHREG(SDM), tmp);
}
for (i = 0; i < 3; i++) {
if ((x97 = chip->ac97[i]) == NULL)
continue;
if (x97->scaps & AC97_SCAP_SURROUND_DAC)
chip->multi4 = 1;
if ((chip->ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) ||
(chip->ac97sec && (chip->ac97sec->scaps & AC97_SCAP_CENTER_LFE_DAC)))
}
for (i = 0; i < 3 && chip->multi4; i++) {
if ((x97 = chip->ac97[i]) == NULL)
continue;
if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC)
chip->multi6 = 1;
}
if (codecs > 1) {
/* assign right slots for rev2.2 codecs */
i = 1;
if (chip->multi4)
goto __6ch;
for ( ; i < codecs; i++) {
if (ac97_is_rev22(x97 = chip->ac97[i])) {
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1);
chip->multi4 = 1;
break;
}
}
__6ch:
for ( ; i < codecs && chip->multi4; i++) {
if (ac97_is_rev22(x97 = chip->ac97[i])) {
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2);
chip->multi6 = 1;
break;
}
}
/* ok, some older codecs might support only AMAP */
if (!chip->multi4) {
for (i = 1; i < codecs; i++) {
if (ac97_can_amap(x97 = chip->ac97[i])) {
if (x97->addr == 1) {
chip->multi4 = 1;
break;
}
}
}
for ( ; i < codecs && chip->multi4; i++) {
if (ac97_can_amap(x97 = chip->ac97[i])) {
if (x97->addr == 2) {
chip->multi6 = 1;
break;
}
}
}
}
}
__end:
chip->in_ac97_init = 0;
return 0;
}
......@@ -1008,6 +1682,16 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
*
*/
static void do_ali_reset(intel8x0_t *chip)
{
iputdword(chip, ICHREG(ALI_SCR), 0x8000000);
iputdword(chip, ICHREG(ALI_FIFOCR1), 0x83838383);
iputdword(chip, ICHREG(ALI_FIFOCR2), 0x83838383);
iputdword(chip, ICHREG(ALI_INTERFACECR), 0x04080002); /* no spdif? */
iputdword(chip, ICHREG(ALI_INTERRUPTCR), 0x00000000);
iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
}
static void do_delay(intel8x0_t *chip)
{
#ifdef CONFIG_PM
......@@ -1020,109 +1704,168 @@ static void do_delay(intel8x0_t *chip)
schedule_timeout(1);
}
static int snd_intel8x0_chip_init(intel8x0_t *chip)
static int snd_intel8x0_ich_chip_init(intel8x0_t *chip)
{
signed long end_time;
unsigned int cnt;
unsigned int cnt, status, nstatus;
/* put logic to right state */
/* first clear status bits */
cnt = inl(ICHREG(chip, GLOB_STA));
outl(cnt & (ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT), ICHREG(chip, GLOB_STA));
cnt = igetdword(chip, ICHREG(GLOB_STA));
iputdword(chip, ICHREG(GLOB_STA), cnt & (ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT));
/* ACLink on, 2 channels */
cnt = inl(ICHREG(chip, GLOB_CNT));
cnt = igetdword(chip, ICHREG(GLOB_CNT));
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
/* finish cold or do warm reset */
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
outl(cnt, ICHREG(chip, GLOB_CNT));
iputdword(chip, ICHREG(GLOB_CNT), cnt);
end_time = (jiffies + (HZ / 4)) + 1;
do {
if ((inl(ICHREG(chip, GLOB_CNT)) & ICH_AC97WARM) == 0)
if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
goto __ok;
do_delay(chip);
} while (end_time - (signed long)jiffies >= 0);
snd_printk("AC'97 warm reset still in progress? [0x%x]\n", inl(ICHREG(chip, GLOB_CNT)));
} while (time_after_eq(end_time, jiffies));
snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT)));
return -EIO;
__ok:
/* wait for primary codec ready status.
/* wait for any codec ready status.
* Once it becomes ready it should remain ready
* as long as we do not disable the ac97 link.
*/
end_time = jiffies + HZ / 10;
end_time = jiffies + HZ;
do {
if (inl(ICHREG(chip, GLOB_STA)) & ICH_PCR)
status = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
if (status)
goto __ok1;
do_delay(chip);
} while (end_time - (signed long)jiffies >= 0);
if (chip->pci->device == PCI_DEVICE_ID_INTEL_ICH4) {
/* FIXME: ICH4 may have no PCR and SCR bits... */
snd_printd(KERN_INFO "intel8x0: no codec is probed, perhaps PCR and SCR bits are deactivated.\n");
chip->no_codec_check = 1;
} while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA)));
return -EIO;
__ok1:
if (status == (ICH_PCR | ICH_SCR | ICH_TCR))
goto __ok3;
/* wait for other codecs ready status. No secondary codecs? , ok */
end_time = jiffies + HZ / 4;
do {
nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
if (nstatus != status) {
status = nstatus;
goto __ok2;
}
/* check a bit longer... */
end_time = jiffies + HZ;
do_delay(chip);
} while (time_after_eq(end_time, jiffies));
__ok2:
if (status == (ICH_PCR | ICH_SCR | ICH_TCR))
goto __ok3;
/* wait for other codecs ready status. No other secondary codecs? , ok */
/* end_time is not initialized here */
do {
if (inl(ICHREG(chip, GLOB_STA)) & ICH_PCR)
goto __ok1;
nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
if (nstatus != status) {
status = nstatus;
goto __ok2;
}
do_delay(chip);
} while (end_time - (signed long)jiffies >= 0);
snd_printk(KERN_ERR "codec_ready: primary codec is not ready [0x%x]\n", inl(ICHREG(chip, GLOB_STA)));
} while (time_after_eq(end_time, jiffies));
__ok3:
return 0;
}
static int snd_intel8x0_ali_chip_init(intel8x0_t *chip)
{
u32 reg;
int i = 0;
reg = igetdword(chip, ICHREG(ALI_SCR));
if ((reg & 2) == 0) /* Cold required */
reg |= 2;
else
reg |= 1; /* Warm */
reg &= ~0x80000000; /* ACLink on */
iputdword(chip, ICHREG(ALI_SCR), reg);
for (i = 0; i < HZ / 2; i++) {
if (! (igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ALI_INT_GPIO))
goto __ok;
do_delay(chip);
}
snd_printk(KERN_ERR "AC'97 reset failed.\n");
return -EIO;
__ok1:
/* wait for secondary codec ready status. No secondary codec? , ok */
/* the end_time variable is not initialized again */
do {
if (inl(ICHREG(chip, GLOB_STA)) & ICH_SCR)
__ok:
for (i = 0; i < HZ / 2; i++) {
reg = igetdword(chip, ICHREG(ALI_RTSR));
if (reg & 0x80) /* primary codec */
break;
iputdword(chip, ICHREG(ALI_RTSR), reg | 0x80);
do_delay(chip);
} while (end_time - (signed long)jiffies >= 0);
}
__ok2:
inw(chip->port); /* clear semaphore flag */
do_ali_reset(chip);
return 0;
}
static int snd_intel8x0_chip_init(intel8x0_t *chip)
{
int i, err;
if (chip->device_type != DEVICE_ALI)
err = snd_intel8x0_ich_chip_init(chip);
else
err = snd_intel8x0_ali_chip_init(chip);
if (err < 0)
return err;
iagetword(chip, 0); /* clear semaphore flag */
/* disable interrupts */
outb(0x00, ICHREG(chip, PI_CR));
outb(0x00, ICHREG(chip, PO_CR));
outb(0x00, ICHREG(chip, MC_CR));
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00);
/* reset channels */
outb(ICH_RESETREGS, ICHREG(chip, PI_CR));
outb(ICH_RESETREGS, ICHREG(chip, PO_CR));
outb(ICH_RESETREGS, ICHREG(chip, MC_CR));
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
/* initialize Buffer Descriptor Lists */
outl(chip->playback.bdbar_addr, ICHREG(chip, PO_BDBAR));
outl(chip->capture.bdbar_addr, ICHREG(chip, PI_BDBAR));
outl(chip->capture_mic.bdbar_addr, ICHREG(chip, MC_BDBAR));
for (i = 0; i < chip->bdbars_count; i++)
iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, chip->ichd[i].bdbar_addr);
return 0;
}
static void snd_intel8x0_proc_done(intel8x0_t * chip);
static int snd_intel8x0_free(intel8x0_t *chip)
{
int i;
if (chip->irq < 0)
goto __hw_end;
/* disable interrupts */
outb(0x00, ICHREG(chip, PI_CR));
outb(0x00, ICHREG(chip, PO_CR));
outb(0x00, ICHREG(chip, MC_CR));
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00);
/* reset channels */
outb(ICH_RESETREGS, ICHREG(chip, PI_CR));
outb(ICH_RESETREGS, ICHREG(chip, PO_CR));
outb(ICH_RESETREGS, ICHREG(chip, MC_CR));
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
/* --- */
synchronize_irq(chip->irq);
__hw_end:
snd_intel8x0_proc_done(chip);
if (chip->bdbars)
snd_free_pci_pages(chip->pci, 3 * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr);
if (chip->res_port) {
release_resource(chip->res_port);
kfree_nocheck(chip->res_port);
snd_free_pci_pages(chip->pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr);
if (chip->remap_addr)
iounmap((void *) chip->remap_addr);
if (chip->remap_bmaddr)
iounmap((void *) chip->remap_bmaddr);
if (chip->res) {
release_resource(chip->res);
kfree_nocheck(chip->res);
}
if (chip->res_bmport) {
release_resource(chip->res_bmport);
kfree_nocheck(chip->res_bmport);
if (chip->res_bm) {
release_resource(chip->res_bm);
kfree_nocheck(chip->res_bm);
}
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
......@@ -1154,6 +1897,7 @@ static void intel8x0_suspend(intel8x0_t *chip)
static void intel8x0_resume(intel8x0_t *chip)
{
snd_card_t *card = chip->card;
int i;
snd_power_lock(card);
if (card->power_state == SNDRV_CTL_POWER_D0)
......@@ -1161,7 +1905,9 @@ static void intel8x0_resume(intel8x0_t *chip)
pci_enable_device(chip->pci);
snd_intel8x0_chip_init(chip);
snd_ac97_resume(chip->ac97);
for (i = 0; i < 3; i++)
if (chip->ac97[i])
snd_ac97_resume(chip->ac97[i]);
chip->in_suspend = 0;
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
......@@ -1222,12 +1968,13 @@ static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_sta
static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
{
snd_pcm_substream_t *subs;
ichdev_t *ichdev;
unsigned long port;
unsigned long pos, t;
unsigned long flags;
struct timeval start_time, stop_time;
if (chip->ac97->clock != 48000)
if (chip->ac97[0]->clock != 48000)
return; /* specified in module option */
subs = chip->pcm->streams[0].substream;
......@@ -1235,19 +1982,20 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
snd_printk("no playback buffer allocated - aborting measure ac97 clock\n");
return;
}
chip->playback.physbuf = subs->dma_addr;
chip->playback.size = chip->playback.fragsize = INTEL8X0_TESTBUF_SIZE;
chip->playback.substream = NULL; /* don't process interrupts */
ichdev = &chip->ichd[ICHD_PCMOUT];
ichdev->physbuf = subs->dma_addr;
ichdev->size = chip->ichd[ICHD_PCMOUT].fragsize = INTEL8X0_TESTBUF_SIZE;
ichdev->substream = NULL; /* don't process interrupts */
/* set rate */
if (snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97->clock);
if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97[0]->clock);
return;
}
snd_intel8x0_setup_periods(chip, &chip->playback);
port = chip->bmport + chip->playback.reg_offset;
snd_intel8x0_setup_periods(chip, ichdev);
port = ichdev->reg_offset;
spin_lock_irqsave(&chip->reg_lock, flags);
outb(ICH_IOCE | ICH_STARTBM, port + ICH_REG_PI_CR); /* trigger */
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); /* trigger */
do_gettimeofday(&start_time);
spin_unlock_irqrestore(&chip->reg_lock, flags);
#if 0
......@@ -1259,18 +2007,18 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
/* check the position */
pos = chip->playback.fragsize1;
pos = ichdev->fragsize1;
if (chip->device_type == DEVICE_SIS)
pos -= inw(ICHREG2(chip,chip->reg_po_picb));
pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
else
pos -= inw(ICHREG2(chip,chip->reg_po_picb)) << 1;
pos += chip->playback.position;
pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1;
pos += ichdev->position;
do_gettimeofday(&stop_time);
outb(0, port + ICH_REG_PI_CR); /* stop */
iputbyte(chip, port + ICH_REG_OFF_CR, 0); /* stop */
/* reset whole DMA things */
while (!(inb(port + chip->reg_pi_sr) & ICH_DCH))
while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
;
outb(ICH_RESETREGS, port + ICH_REG_PI_CR);
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
spin_unlock_irqrestore(&chip->reg_lock, flags);
t = stop_time.tv_sec - start_time.tv_sec;
......@@ -1290,8 +2038,60 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
else if (pos < 47500 || pos > 48500)
/* not 48000Hz, tuning the clock.. */
chip->ac97->clock = (chip->ac97->clock * 48000) / pos;
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97->clock);
chip->ac97[0]->clock = (chip->ac97[0]->clock * 48000) / pos;
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97[0]->clock);
}
static void snd_intel8x0_proc_read(snd_info_entry_t * entry,
snd_info_buffer_t * buffer)
{
intel8x0_t *chip = snd_magic_cast(intel8x0_t, entry->private_data, return);
unsigned int tmp;
snd_iprintf(buffer, "Intel8x0\n\n");
if (chip->device_type == DEVICE_ALI)
return;
tmp = igetdword(chip, ICHREG(GLOB_STA));
snd_iprintf(buffer, "Global control : 0x%08x\n", igetdword(chip, ICHREG(GLOB_CNT)));
snd_iprintf(buffer, "Global status : 0x%08x\n", tmp);
if (chip->device_type == DEVICE_INTEL_ICH4)
snd_iprintf(buffer, "SDM : 0x%08x\n", igetdword(chip, ICHREG(SDM)));
snd_iprintf(buffer, "AC'97 codecs ready :%s%s%s%s\n",
tmp & ICH_PCR ? " primary" : "",
tmp & ICH_SCR ? " secondary" : "",
tmp & ICH_TCR ? " tertiary" : "",
(tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : "");
if (chip->device_type == DEVICE_INTEL_ICH4)
snd_iprintf(buffer, "AC'97 codecs SDIN : %i %i %i\n",
chip->ac97_sdin[0],
chip->ac97_sdin[1],
chip->ac97_sdin[2]);
}
static void __devinit snd_intel8x0_proc_init(intel8x0_t * chip)
{
snd_info_entry_t *entry;
if ((entry = snd_info_create_card_entry(chip->card, "intel8x0", chip->card->proc_root)) != NULL) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
entry->c.text.read_size = 2048;
entry->c.text.read = snd_intel8x0_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
}
}
chip->proc_entry = entry;
}
static void snd_intel8x0_proc_done(intel8x0_t * chip)
{
if (chip->proc_entry) {
snd_info_unregister(chip->proc_entry);
chip->proc_entry = NULL;
}
}
static int snd_intel8x0_dev_free(snd_device_t *device)
......@@ -1306,10 +2106,22 @@ static int __devinit snd_intel8x0_create(snd_card_t * card,
intel8x0_t ** r_intel8x0)
{
intel8x0_t *chip;
int err;
int err, i;
unsigned int int_sta_masks;
ichdev_t *ichdev;
static snd_device_ops_t ops = {
.dev_free = snd_intel8x0_dev_free,
};
static u32 intel_int_sta_masks[6] = {
ICH_PIINT, ICH_POINT, ICH_MCINT, ICH_M2INT, ICH_P2INT, ICH_SPINT
};
static u32 ali_int_sta_masks[6] = {
ALI_INT_PCMIN, ALI_INT_PCMOUT, ALI_INT_MICIN,
ALI_INT_CODECSPDIFOUT, ALI_INT_SPDIFIN, ALI_INT_SPDIFOUT
};
static u32 ali_reg_offsets[6] = {
0x40, 0x50, 0x60, 0x70, 0xa0, 0xb0
};
*r_intel8x0 = NULL;
......@@ -1325,20 +2137,51 @@ static int __devinit snd_intel8x0_create(snd_card_t * card,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->port = pci_resource_start(pci, 0);
snd_intel8x0_proc_init(chip);
if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and higher */
chip->mmio = chip->bm_mmio = 1;
chip->addr = pci_resource_start(pci, 2);
sprintf(chip->ac97_name, "%s - AC'97", card->shortname);
if ((chip->res_port = request_region(chip->port, 256, chip->ac97_name)) == NULL) {
if ((chip->res = request_mem_region(chip->addr, 512, chip->ac97_name)) == NULL) {
snd_intel8x0_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->addr, chip->addr + 512 - 1);
return -EBUSY;
}
chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, 512);
if (chip->remap_addr == 0) {
snd_intel8x0_free(chip);
snd_printk("AC'97 space ioremap problem\n");
return -EIO;
}
sprintf(chip->ctrl_name, "%s - Controller", card->shortname);
chip->bmport = pci_resource_start(pci, 1);
if ((chip->res_bmport = request_region(chip->bmport, 64, chip->ctrl_name)) == NULL) {
chip->bmaddr = pci_resource_start(pci, 3);
if ((chip->res_bm = request_mem_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) {
snd_intel8x0_free(chip);
snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 512 - 1);
return -EBUSY;
}
chip->remap_bmaddr = (unsigned long) ioremap_nocache(chip->bmaddr, 256);
if (chip->remap_bmaddr == 0) {
snd_intel8x0_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmport, chip->bmport + 64 - 1);
snd_printk("Controller space ioremap problem\n");
return -EIO;
}
} else {
chip->addr = pci_resource_start(pci, 0);
sprintf(chip->ac97_name, "%s - AC'97", card->shortname);
if ((chip->res = request_region(chip->addr, 256, chip->ac97_name)) == NULL) {
snd_intel8x0_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->addr, chip->addr + 256 - 1);
return -EBUSY;
}
sprintf(chip->ctrl_name, "%s - Controller", card->shortname);
chip->bmaddr = pci_resource_start(pci, 1);
if ((chip->res_bm = request_region(chip->bmaddr, 64, chip->ctrl_name)) == NULL) {
snd_intel8x0_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 64 - 1);
return -EBUSY;
}
}
if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {
snd_intel8x0_free(chip);
snd_printk("unable to grab IRQ %d\n", pci->irq);
......@@ -1349,27 +2192,36 @@ static int __devinit snd_intel8x0_create(snd_card_t * card,
synchronize_irq(chip->irq);
/* initialize offsets */
chip->reg_pi_sr = ICH_REG_PI_SR;
chip->reg_pi_picb = ICH_REG_PI_PICB;
chip->reg_po_sr = ICH_REG_PO_SR;
chip->reg_po_picb = ICH_REG_PO_PICB;
chip->reg_mc_sr = ICH_REG_MC_SR;
chip->reg_mc_picb = ICH_REG_MC_PICB;
if (device_type == DEVICE_SIS) {
chip->reg_pi_sr = ICH_REG_PI_PICB;
chip->reg_pi_picb = ICH_REG_PI_SR;
chip->reg_po_sr = ICH_REG_PO_PICB;
chip->reg_po_picb = ICH_REG_PO_SR;
chip->reg_mc_sr = ICH_REG_MC_PICB;
chip->reg_mc_picb = ICH_REG_MC_SR;
}
chip->playback.reg_offset = 0x10;
chip->capture.reg_offset = 0;
chip->capture_mic.reg_offset = 0x20;
for (i = 0; i <= ICHD_LAST; i++) {
ichdev = &chip->ichd[i];
ichdev->ichd = i;
ichdev->reg_offset = i * 0x10 + (i >= 0x30 ? 0x10 : 0);
ichdev->roff_sr = ICH_REG_OFF_SR;
ichdev->roff_picb = ICH_REG_OFF_PICB;
ichdev->int_sta_mask = device_type == DEVICE_ALI ? ali_int_sta_masks[i] : intel_int_sta_masks[i];
}
switch (device_type) {
case DEVICE_SIS:
for (i = 0; i <= ICHD_LAST; i++) {
ichdev = &chip->ichd[i];
ichdev->roff_sr = ICH_REG_OFF_PICB;
ichdev->roff_picb = ICH_REG_OFF_SR;
}
break;
case DEVICE_ALI:
for (i = 0; i <= ALID_LAST; i++) {
ichdev = &chip->ichd[i];
ichdev->reg_offset = ali_reg_offsets[i];
ichdev->ali_slot = i + 1; /* is this right for last three devices? --jk */
}
}
/* allocate buffer descriptor lists */
/* the start of each lists must be aligned to 8 bytes */
chip->bdbars = (u32 *)snd_malloc_pci_pages(pci, 3 * sizeof(unsigned int) * ICH_MAX_FRAGS * 2, &chip->bdbars_addr);
chip->bdbars_count = 3;
if (device_type == DEVICE_INTEL_ICH4 || device_type == DEVICE_ALI)
chip->bdbars_count = 6;
chip->bdbars = (u32 *)snd_malloc_pci_pages(pci, chip->bdbars_count * sizeof(unsigned int) * ICH_MAX_FRAGS * 2, &chip->bdbars_addr);
if (chip->bdbars == NULL) {
snd_intel8x0_free(chip);
return -ENOMEM;
......@@ -1384,12 +2236,15 @@ static int __devinit snd_intel8x0_create(snd_card_t * card,
return -ENOMEM;
}
#endif
chip->playback.bdbar = chip->bdbars; /* crop to 32bit */
chip->playback.bdbar_addr = (unsigned int)chip->bdbars_addr;
chip->capture.bdbar = chip->playback.bdbar + ICH_MAX_FRAGS * 2;
chip->capture.bdbar_addr = chip->playback.bdbar_addr + sizeof(u32) * ICH_MAX_FRAGS * 2;
chip->capture_mic.bdbar = chip->capture.bdbar + ICH_MAX_FRAGS * 2;
chip->capture_mic.bdbar_addr = chip->capture.bdbar_addr + sizeof(u32) * ICH_MAX_FRAGS * 2;
int_sta_masks = 0;
for (i = 0; i < chip->bdbars_count; i++) {
ichdev = &chip->ichd[i];
ichdev->bdbar = chip->bdbars + (i * ICH_MAX_FRAGS * 2);
ichdev->bdbar_addr = chip->bdbars_addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2);
int_sta_masks |= ichdev->int_sta_mask;
}
chip->int_sta_reg = device_type == DEVICE_ALI ? ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA;
chip->int_sta_mask = int_sta_masks;
if ((err = snd_intel8x0_chip_init(chip)) < 0) {
snd_intel8x0_free(chip);
......@@ -1469,15 +2324,52 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
if (chip->ac97->ext_id & 0x0008) { /* MIC VRM */
/* activate MIC PCM only when associated AC'97 codec */
if (chip->ichd[ICHD_MIC].ac97) {
if ((err = snd_intel8x0_pcm_mic(chip, pcm_dev++, NULL)) < 0) {
snd_card_free(card);
return err;
}
}
if (chip->device_type == DEVICE_ALI) {
if ((err = snd_intel8x0_ali_spdif(chip, pcm_dev++, NULL)) < 0) {
snd_card_free(card);
return err;
}
}
/* activate AC'97 S/PDIF only when associated AC'97 codec */
if (chip->bdbars_count > 3) {
err = 0;
if (chip->device_type == DEVICE_ALI) {
if (chip->ichd[ALID_AC97SPDIFOUT].ac97)
err = snd_intel8x0_ali_ac97spdif(chip, pcm_dev++, NULL);
} else {
if (chip->ichd[ICHD_SPBAR].ac97)
err = snd_intel8x0_pcm_spdif(chip, pcm_dev++, NULL);
}
if (err < 0) {
snd_card_free(card);
return err;
}
if (chip->device_type != DEVICE_ALI) {
/* activate MIC2 only when associated AC'97 codec */
if (chip->ichd[ICHD_MIC2].ac97)
if ((err = snd_intel8x0_pcm_mic2(chip, pcm_dev++, NULL)) < 0) {
snd_card_free(card);
return err;
}
/* activate PCM2IN only when associated AC'97 codec */
if (chip->ichd[ICHD_PCM2IN].ac97)
if ((err = snd_intel8x0_pcm_capture2(chip, pcm_dev++, NULL)) < 0) {
snd_card_free(card);
return err;
}
}
}
if (snd_mpu_port[dev] == 0x300 || snd_mpu_port[dev] == 0x330) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_INTEL8X0,
snd_mpu_port[dev], 0,
-1, 0, &chip->rmidi)) < 0) {
printk(KERN_ERR "intel8x0: no UART401 device at 0x%x, skipping.\n", snd_mpu_port[dev]);
......@@ -1487,7 +2379,7 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
snd_mpu_port[dev] = 0;
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->port, chip->irq);
card->shortname, chip->addr, chip->irq);
if (! snd_ac97_clock[dev])
intel8x0_measure_ac97_clock(chip);
......
......@@ -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];
};
......
......@@ -40,7 +40,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <asm/semaphore.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/asequencer.h>
......@@ -48,59 +47,13 @@
#include <sound/seq_kernel.h>
#include <sound/seq_virmidi.h>
#include <sound/seq_midi_event.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
#include "usbaudio.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("USB MIDI");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{Generic,USB MIDI},"
"{Roland/EDIROL,PC-300},"
"{Roland/EDIROL,SC-8820},"
"{Roland/EDIROL,SC-8850},"
"{Roland/EDIROL,SC-D70},"
"{Roland/EDIROL,SD-20},"
"{Roland/EDIROL,SD-80},"
"{Roland/EDIROL,SD-90},"
"{Roland/EDIROL,SK-500},"
"{Roland/EDIROL,U-8},"
"{Roland/EDIROL,UA-100(G)},"
"{Roland/EDIROL,UA-700},"
"{Roland/EDIROL,UM-1(S)},"
"{Roland/EDIROL,UM-2(E)},"
"{Roland/EDIROL,UM-4},"
"{Roland/EDIROL,UM-550},"
"{Roland/EDIROL,UM-880},"
"{Roland/EDIROL,XV-5050},"
"{Yamaha,MU1000},"
"{Yamaha,UX256}}");
static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int snd_vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor id of this card */
static int snd_pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product id of this card */
static int snd_int_transfer[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Use interrupt transfers for this card */
MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_index, "Index value for USB MIDI.");
MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
MODULE_PARM_DESC(snd_id, "ID string for USB MIDI.");
MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_enable, "Enable USB MIDI.");
MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
MODULE_PARM(snd_vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_vid, "USB Vendor ID for USB MIDI.");
MODULE_PARM_SYNTAX(snd_vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
MODULE_PARM(snd_pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_pid, "USB Product ID for USB MIDI.");
MODULE_PARM_SYNTAX(snd_pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
MODULE_PARM(snd_int_transfer, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_int_transfer, "Use interrupt transfers for USB MIDI input.");
MODULE_PARM_SYNTAX(snd_int_transfer, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC ",skill:advanced");
/* size of the per-endpoint output buffer, must be a multiple of 4 */
#define OUTPUT_BUFFER_SIZE 0x400
......@@ -108,26 +61,6 @@ MODULE_PARM_SYNTAX(snd_int_transfer, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC
/* max. size of incoming sysex messages */
#define INPUT_BUFFER_SIZE 0x200
#define MAX_ENDPOINTS 2
#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
#ifndef USB_SUBCLASS_MIDISTREAMING
#define USB_SUBCLASS_MIDISTREAMING 3
#endif
#ifndef USB_DT_CS_INTERFACE
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
#endif
#ifndef USB_DST_MS_HEADER
#define USB_DST_MS_HEADER 0x01
#define USB_DST_MS_GENERAL 0x01
#define USB_DST_MS_HEADER_SIZE 7
#define USB_DST_MS_GENERAL_SIZE 4
#endif
typedef struct usb_driver usb_driver_t;
typedef struct usb_device usb_device_t;
typedef struct usb_device_id usb_device_id_t;
......@@ -153,47 +86,11 @@ struct usb_ms_endpoint_descriptor {
__u8 baAssocJackID[0];
} __attribute__ ((packed));
typedef struct usbmidi usbmidi_t;
typedef struct usbmidi_device_info usbmidi_device_info_t;
typedef struct usbmidi_endpoint_info usbmidi_endpoint_info_t;
typedef struct usbmidi_endpoint usbmidi_endpoint_t;
typedef struct usbmidi_out_endpoint usbmidi_out_endpoint_t;
typedef struct usbmidi_out_port usbmidi_out_port_t;
typedef struct usbmidi_in_endpoint usbmidi_in_endpoint_t;
typedef struct usbmidi_in_port usbmidi_in_port_t;
/*
* Describes the capabilities of a USB MIDI device.
* This structure is filled after parsing the USB descriptors,
* or is supplied explicitly for broken devices.
*/
struct usbmidi_device_info {
char vendor[32]; /* vendor name */
char product[32]; /* device name */
int16_t ifnum; /* interface number */
struct usbmidi_endpoint_info {
int16_t epnum; /* endpoint number,
-1: autodetect (first ep only) */
uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */
} endpoints[MAX_ENDPOINTS];
};
struct usbmidi {
snd_card_t* card;
usb_device_t* usb_device;
int dev;
int seq_client;
usbmidi_device_info_t device_info;
struct usbmidi_endpoint {
usbmidi_out_endpoint_t* out;
usbmidi_in_endpoint_t* in;
snd_rawmidi_t* rmidi[0x10];
} endpoints[MAX_ENDPOINTS];
};
struct usbmidi_out_endpoint {
usbmidi_t* umidi;
struct snd_usb_midi_out_endpoint {
snd_usb_midi_t* umidi;
struct urb* urb;
int max_transfer; /* size of urb buffer */
struct tasklet_struct tasklet;
......@@ -204,16 +101,16 @@ struct usbmidi_out_endpoint {
spinlock_t buffer_lock;
struct usbmidi_out_port {
usbmidi_out_endpoint_t* ep;
snd_usb_midi_out_endpoint_t* ep;
uint8_t cable; /* cable number << 4 */
uint8_t sysex_len;
uint8_t sysex[2];
} ports[0x10];
};
struct usbmidi_in_endpoint {
usbmidi_t* umidi;
usbmidi_endpoint_t* ep;
struct snd_usb_midi_in_endpoint {
snd_usb_midi_t* umidi;
snd_usb_midi_endpoint_t* ep;
struct urb* urb;
struct usbmidi_in_port {
int seq_port;
......@@ -221,10 +118,7 @@ struct usbmidi_in_endpoint {
} ports[0x10];
};
static int snd_usbmidi_card_used[SNDRV_CARDS];
static DECLARE_MUTEX(snd_usbmidi_open_mutex);
static void snd_usbmidi_do_output(usbmidi_out_endpoint_t* ep);
static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep);
/*
* Submits the URB, with error handling.
......@@ -255,7 +149,7 @@ static int snd_usbmidi_urb_error(int status)
/*
* Converts a USB MIDI packet into an ALSA sequencer event.
*/
static void snd_usbmidi_input_packet(usbmidi_in_endpoint_t* ep,
static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
uint8_t packet[4])
{
static const uint8_t cin_length[] = {
......@@ -285,7 +179,7 @@ static void snd_usbmidi_input_packet(usbmidi_in_endpoint_t* ep,
*/
static void snd_usbmidi_in_urb_complete(struct urb* urb)
{
usbmidi_in_endpoint_t* ep = snd_magic_cast(usbmidi_in_endpoint_t, urb->context, return);
snd_usb_midi_in_endpoint_t* ep = snd_magic_cast(snd_usb_midi_in_endpoint_t, urb->context, return);
if (urb->status == 0) {
uint8_t* buffer = (uint8_t*)ep->urb->transfer_buffer;
......@@ -300,14 +194,14 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
}
if (!usb_pipeint(urb->pipe)) {
urb->dev = ep->umidi->usb_device;
urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
}
}
static void snd_usbmidi_out_urb_complete(struct urb* urb)
{
usbmidi_out_endpoint_t* ep = snd_magic_cast(usbmidi_out_endpoint_t, urb->context, return);
snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, urb->context, return);
unsigned long flags;
if (urb->status < 0) {
......@@ -324,7 +218,7 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
* (after the reception of one or more sequencer events, or after completion
* of the previous transfer). ep->buffer_lock must be held.
*/
static void snd_usbmidi_do_output(usbmidi_out_endpoint_t* ep)
static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
{
int len;
uint8_t* buffer;
......@@ -361,14 +255,14 @@ static void snd_usbmidi_do_output(usbmidi_out_endpoint_t* ep)
}
if (len > 0) {
ep->urb->dev = ep->umidi->usb_device;
ep->urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(ep->urb, GFP_ATOMIC);
}
}
static void snd_usbmidi_out_tasklet(unsigned long data)
{
usbmidi_out_endpoint_t* ep = snd_magic_cast(usbmidi_out_endpoint_t, (void*)data, return);
snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, (void*)data, return);
unsigned long flags;
spin_lock_irqsave(&ep->buffer_lock, flags);
......@@ -382,7 +276,7 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
static void output_packet(usbmidi_out_port_t* port,
uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3)
{
usbmidi_out_endpoint_t* ep = port->ep;
snd_usb_midi_out_endpoint_t* ep = port->ep;
unsigned long flags;
spin_lock_irqsave(&ep->buffer_lock, flags);
......@@ -568,7 +462,7 @@ static int snd_usbmidi_event_input(snd_seq_event_t* ev, int direct,
* Frees an input endpoint.
* May be called when ep hasn't been initialized completely.
*/
static void snd_usbmidi_in_endpoint_delete(usbmidi_in_endpoint_t* ep)
static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
{
int i;
......@@ -586,53 +480,54 @@ static void snd_usbmidi_in_endpoint_delete(usbmidi_in_endpoint_t* ep)
}
/*
* Searches for an alternate setting in which the endpoint uses interrupt
* For Roland devices, use the alternate setting which uses interrupt
* transfers for input.
*/
static int snd_usbmidi_get_int_ep(usbmidi_t* umidi, uint8_t epnum,
usb_endpoint_descriptor_t** descriptor)
static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
uint8_t epnum)
{
usb_interface_t* intf;
int i, j;
usb_interface_descriptor_t* intfd;
*descriptor = NULL;
intf = usb_ifnum_to_if(umidi->usb_device, umidi->device_info.ifnum);
if (!intf)
return -ENXIO;
for (i = 0; i < intf->num_altsetting; ++i) {
usb_interface_descriptor_t* intfd = &intf->altsetting[i];
for (j = 0; j < intfd->bNumEndpoints; ++j) {
usb_endpoint_descriptor_t* epd = &intfd->endpoint[j];
if ((epd->bEndpointAddress & (USB_ENDPOINT_NUMBER_MASK | USB_ENDPOINT_DIR_MASK)) == (epnum | USB_DIR_IN) &&
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
usb_set_interface(umidi->usb_device,
intfd->bInterfaceNumber,
if (umidi->chip->dev->descriptor.idVendor != 0x0582)
return NULL;
intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
if (!intf || intf->num_altsetting != 2)
return NULL;
intfd = &intf->altsetting[0];
if (intfd->bNumEndpoints != 2 ||
(intfd->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
(intfd->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
return NULL;
intfd = &intf->altsetting[1];
if (intfd->bNumEndpoints != 2 ||
(intfd->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
(intfd->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
return NULL;
usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
intfd->bAlternateSetting);
*descriptor = &intfd->endpoint[j];
return 0;
}
}
}
return -ENXIO;
return &intfd->endpoint[1];
}
/*
* Creates an input endpoint, and initalizes input ports.
* ALSA ports are created later.
*/
static int snd_usbmidi_in_endpoint_create(usbmidi_t* umidi,
usbmidi_endpoint_info_t* ep_info,
usbmidi_endpoint_t* rep)
static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* ep_info,
snd_usb_midi_endpoint_t* rep)
{
usbmidi_in_endpoint_t* ep;
int do_int_transfer;
usb_endpoint_descriptor_t* epd;
snd_usb_midi_in_endpoint_t* ep;
usb_endpoint_descriptor_t* int_epd;
void* buffer;
unsigned int pipe;
int length, i, err;
rep->in = NULL;
ep = snd_magic_kcalloc(usbmidi_in_endpoint_t, 0, GFP_KERNEL);
ep = snd_magic_kcalloc(snd_usb_midi_in_endpoint_t, 0, GFP_KERNEL);
if (!ep)
return -ENOMEM;
ep->umidi = umidi;
......@@ -640,34 +535,28 @@ static int snd_usbmidi_in_endpoint_create(usbmidi_t* umidi,
for (i = 0; i < 0x10; ++i)
ep->ports[i].seq_port = -1;
do_int_transfer = snd_int_transfer[umidi->dev];
if (do_int_transfer) {
if (snd_usbmidi_get_int_ep(umidi, ep_info->epnum, &epd) < 0) {
printk(KERN_WARNING "snd-usb-midi: interrupt endpoint not found\n");
do_int_transfer = 0;
}
}
int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum);
ep->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ep->urb) {
snd_usbmidi_in_endpoint_delete(ep);
return -ENOMEM;
}
if (do_int_transfer)
pipe = usb_rcvintpipe(umidi->usb_device, ep_info->epnum);
if (int_epd)
pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->epnum);
else
pipe = usb_rcvbulkpipe(umidi->usb_device, ep_info->epnum);
length = usb_maxpacket(umidi->usb_device, pipe, 0);
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->epnum);
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
buffer = kmalloc(length, GFP_KERNEL);
if (!buffer) {
snd_usbmidi_in_endpoint_delete(ep);
return -ENOMEM;
}
if (do_int_transfer)
FILL_INT_URB(ep->urb, umidi->usb_device, pipe, buffer, length,
snd_usbmidi_in_urb_complete, ep, epd->bInterval);
if (int_epd)
FILL_INT_URB(ep->urb, umidi->chip->dev, pipe, buffer, length,
snd_usbmidi_in_urb_complete, ep, int_epd->bInterval);
else
FILL_BULK_URB(ep->urb, umidi->usb_device, pipe, buffer, length,
FILL_BULK_URB(ep->urb, umidi->chip->dev, pipe, buffer, length,
snd_usbmidi_in_urb_complete, ep);
for (i = 0; i < 0x10; ++i)
......@@ -697,7 +586,7 @@ static int snd_usbmidi_count_bits(uint16_t x)
* Frees an output endpoint.
* May be called when ep hasn't been initialized completely.
*/
static void snd_usbmidi_out_endpoint_delete(usbmidi_out_endpoint_t* ep)
static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
{
if (ep->tasklet.func)
tasklet_kill(&ep->tasklet);
......@@ -715,17 +604,17 @@ static void snd_usbmidi_out_endpoint_delete(usbmidi_out_endpoint_t* ep)
* Creates an output endpoint, and initializes output ports.
* ALSA ports are created later.
*/
static int snd_usbmidi_out_endpoint_create(usbmidi_t* umidi,
usbmidi_endpoint_info_t* ep_info,
usbmidi_endpoint_t* rep)
static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* ep_info,
snd_usb_midi_endpoint_t* rep)
{
usbmidi_out_endpoint_t* ep;
snd_usb_midi_out_endpoint_t* ep;
int i;
unsigned int pipe;
void* buffer;
rep->out = NULL;
ep = snd_magic_kcalloc(usbmidi_out_endpoint_t, 0, GFP_KERNEL);
ep = snd_magic_kcalloc(snd_usb_midi_out_endpoint_t, 0, GFP_KERNEL);
if (!ep)
return -ENOMEM;
ep->umidi = umidi;
......@@ -735,14 +624,14 @@ static int snd_usbmidi_out_endpoint_create(usbmidi_t* umidi,
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
}
pipe = usb_sndbulkpipe(umidi->usb_device, ep_info->epnum);
ep->max_transfer = usb_maxpacket(umidi->usb_device, pipe, 1) & ~3;
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->epnum);
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1) & ~3;
buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
if (!buffer) {
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
}
FILL_BULK_URB(ep->urb, umidi->usb_device, pipe, buffer,
FILL_BULK_URB(ep->urb, umidi->chip->dev, pipe, buffer,
ep->max_transfer, snd_usbmidi_out_urb_complete, ep);
spin_lock_init(&ep->buffer_lock);
......@@ -763,17 +652,17 @@ static int snd_usbmidi_out_endpoint_create(usbmidi_t* umidi,
*/
static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
{
usbmidi_t* umidi;
snd_usb_midi_t* umidi;
int i, j;
umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
if (umidi->seq_client >= 0) {
snd_seq_delete_kernel_client(umidi->seq_client);
umidi->seq_client = -1;
}
for (i = 0; i < MAX_ENDPOINTS; ++i) {
usbmidi_endpoint_t* ep = &umidi->endpoints[i];
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
if (ep->out) {
snd_usbmidi_out_endpoint_delete(ep->out);
ep->out = NULL;
......@@ -784,7 +673,7 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
}
for (j = 0; j < 0x10; ++j)
if (ep->rmidi[j]) {
snd_device_free(umidi->card, ep->rmidi[j]);
snd_device_free(umidi->chip->card, ep->rmidi[j]);
ep->rmidi[j] = NULL;
}
}
......@@ -796,10 +685,9 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
* the ALSA port for each input/output port pair in the endpoint.
* *port_idx is the port number, which must be unique over all endpoints.
*/
static int snd_usbmidi_create_endpoint_ports(usbmidi_t* umidi, int ep,
int* port_idx)
static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int* port_idx,
snd_usb_midi_endpoint_info_t* ep_info)
{
usbmidi_endpoint_info_t* ep_info = &umidi->device_info.endpoints[ep];
int c, err;
int cap, type, port;
int out, in;
......@@ -830,8 +718,8 @@ static int snd_usbmidi_create_endpoint_ports(usbmidi_t* umidi, int ep,
/* TODO: read type bits from element descriptor */
type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
/* TODO: read port name from jack descriptor */
sprintf(port_name, "%s Port %d",
umidi->device_info.product, *port_idx);
snprintf(port_name, sizeof(port_name), "%s Port %d",
umidi->chip->card->shortname, *port_idx);
port = snd_seq_event_port_attach(umidi->seq_client,
&port_callback,
cap, type, port_name);
......@@ -845,7 +733,7 @@ static int snd_usbmidi_create_endpoint_ports(usbmidi_t* umidi, int ep,
if (*port_idx < SNDRV_MINOR_RAWMIDIS) {
snd_rawmidi_t *rmidi;
snd_virmidi_dev_t *rdev;
err = snd_virmidi_new(umidi->card, *port_idx, &rmidi);
err = snd_virmidi_new(umidi->chip->card, *port_idx, &rmidi);
if (err < 0)
return err;
rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO);
......@@ -853,9 +741,9 @@ static int snd_usbmidi_create_endpoint_ports(usbmidi_t* umidi, int ep,
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
rdev->client = umidi->seq_client;
rdev->port = port;
err = snd_device_register(umidi->card, rmidi);
err = snd_device_register(umidi->chip->card, rmidi);
if (err < 0) {
snd_device_free(umidi->card, rmidi);
snd_device_free(umidi->chip->card, rmidi);
return err;
}
umidi->endpoints[ep].rmidi[c] = rmidi;
......@@ -866,219 +754,45 @@ static int snd_usbmidi_create_endpoint_ports(usbmidi_t* umidi, int ep,
}
/*
* Create the endpoints and their ports.
* Creates the endpoints and their ports.
*/
static int snd_usbmidi_create_endpoints(usbmidi_t* umidi)
static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoints)
{
int i, err, port_idx = 0;
for (i = 0; i < MAX_ENDPOINTS; ++i) {
usbmidi_endpoint_info_t* ep_info = &umidi->device_info.endpoints[i];
if (!ep_info->epnum)
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
if (!endpoints[i].epnum)
continue;
if (ep_info->out_cables) {
err = snd_usbmidi_out_endpoint_create(umidi, ep_info,
if (endpoints[i].out_cables) {
err = snd_usbmidi_out_endpoint_create(umidi, &endpoints[i],
&umidi->endpoints[i]);
if (err < 0)
return err;
}
if (ep_info->in_cables) {
err = snd_usbmidi_in_endpoint_create(umidi, ep_info,
if (endpoints[i].in_cables) {
err = snd_usbmidi_in_endpoint_create(umidi, &endpoints[i],
&umidi->endpoints[i]);
if (err < 0)
return err;
}
err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx);
err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx,
&endpoints[i]);
if (err < 0)
return err;
printk(KERN_INFO "snd-usb-midi: endpoint %d: created %d output and %d input ports\n",
ep_info->epnum,
snd_usbmidi_count_bits(ep_info->out_cables),
snd_usbmidi_count_bits(ep_info->in_cables));
endpoints[i].epnum,
snd_usbmidi_count_bits(endpoints[i].out_cables),
snd_usbmidi_count_bits(endpoints[i].in_cables));
}
return 0;
}
/*
* Initialize the sequencer device.
* Returns MIDIStreaming device capabilities.
*/
static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
{
usbmidi_t* umidi;
snd_seq_client_callback_t client_callback;
snd_seq_client_info_t client_info;
int i, err;
umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
memset(&client_callback, 0, sizeof(client_callback));
client_callback.allow_output = 1;
client_callback.allow_input = 1;
umidi->seq_client = snd_seq_create_kernel_client(umidi->card, 0,
&client_callback);
if (umidi->seq_client < 0)
return umidi->seq_client;
memset(&client_info, 0, sizeof(client_info));
client_info.client = umidi->seq_client;
client_info.type = KERNEL_CLIENT;
sprintf(client_info.name, "%s %s",
umidi->device_info.vendor, umidi->device_info.product);
snd_seq_kernel_client_ctl(umidi->seq_client,
SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
&client_info);
err = snd_usbmidi_create_endpoints(umidi);
if (err < 0) {
snd_usbmidi_seq_device_delete(seq_device);
return err;
}
for (i = 0; i < MAX_ENDPOINTS; ++i)
if (umidi->endpoints[i].in)
snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb,
GFP_KERNEL);
return 0;
}
static int snd_usbmidi_card_create(usb_device_t* usb_device,
usbmidi_device_info_t* device_info,
snd_card_t** rcard)
{
snd_card_t* card;
snd_seq_device_t* seq_device;
usbmidi_t* umidi;
int dev, err;
if (rcard)
*rcard = NULL;
down(&snd_usbmidi_open_mutex);
for (dev = 0; dev < SNDRV_CARDS; ++dev) {
if (snd_enable[dev] && !snd_usbmidi_card_used[dev] &&
(snd_vid[dev] == -1 ||
snd_vid[dev] == usb_device->descriptor.idVendor) &&
(snd_pid[dev] == -1 ||
snd_pid[dev] == usb_device->descriptor.idProduct))
break;
}
if (dev >= SNDRV_CARDS) {
up(&snd_usbmidi_open_mutex);
return -ENOENT;
}
card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
if (!card) {
up(&snd_usbmidi_open_mutex);
return -ENOMEM;
}
strcpy(card->driver, "USB MIDI");
snprintf(card->shortname, sizeof(card->shortname), "%s %s",
device_info->vendor, device_info->product);
snprintf(card->longname, sizeof(card->longname), "%s %s at %03d/%03d if %d",
device_info->vendor, device_info->product,
usb_device->bus->busnum, usb_device->devnum,
device_info->ifnum);
card->private_data = (void*)dev;
err = snd_seq_device_new(card, 0, SNDRV_SEQ_DEV_ID_USBMIDI,
sizeof(usbmidi_t), &seq_device);
if (err < 0) {
snd_card_free(card);
up(&snd_usbmidi_open_mutex);
return err;
}
strcpy(seq_device->name, card->shortname);
umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
umidi->card = card;
umidi->usb_device = usb_device;
umidi->dev = dev;
umidi->seq_client = -1;
umidi->device_info = *device_info;
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
up(&snd_usbmidi_open_mutex);
return err;
}
snd_usbmidi_card_used[dev] = 1;
up(&snd_usbmidi_open_mutex);
if (rcard)
*rcard = card;
return 0;
}
/*
* If the first endpoint isn't specified, use the first endpoint in the
* first alternate setting of the interface.
*/
static int snd_usbmidi_detect_endpoint(usb_device_t* usb_device,
usbmidi_device_info_t* device_info)
{
usb_interface_t* intf;
usb_interface_descriptor_t* intfd;
usb_endpoint_descriptor_t* epd;
if (device_info->endpoints[0].epnum == -1) {
intf = usb_ifnum_to_if(usb_device, device_info->ifnum);
if (!intf || intf->num_altsetting < 1)
return -ENOENT;
intfd = intf->altsetting;
if (intfd->bNumEndpoints < 1)
return -ENOENT;
epd = intfd->endpoint;
device_info->endpoints[0].epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
return 0;
}
/*
* Searches for the alternate setting with the greatest number of bulk transfer
* endpoints.
*/
static usb_interface_descriptor_t* snd_usbmidi_get_altsetting(usb_device_t* usb_device,
usb_interface_t* intf)
{
int i, best = -1;
int best_out = 0, best_in = 0;
usb_interface_descriptor_t* intfd;
if (intf->num_altsetting == 1)
return &intf->altsetting[0];
for (i = 0; i < intf->num_altsetting; ++i) {
int out = 0, in = 0, j;
for (j = 0; j < intf->altsetting[i].bNumEndpoints; ++j) {
usb_endpoint_descriptor_t* ep = &intf->altsetting[i].endpoint[j];
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (ep->bEndpointAddress & USB_DIR_IN)
++in;
else
++out;
}
}
if ((out >= best_out && in >= best_in) &&
(out > best_out || in > best_in)) {
best_out = out;
best_in = in;
best = i;
}
}
if (best < 0)
return NULL;
intfd = &intf->altsetting[best];
usb_set_interface(usb_device, intfd->bInterfaceNumber, intfd->bAlternateSetting);
return intfd;
}
/*
* Returns MIDIStreaming device capabilities in device_info.
*/
static int snd_usbmidi_get_ms_info(usb_device_t* usb_device,
unsigned int ifnum,
usbmidi_device_info_t* device_info)
static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoints)
{
usb_interface_t* intf;
usb_interface_descriptor_t* intfd;
......@@ -1087,34 +801,17 @@ static int snd_usbmidi_get_ms_info(usb_device_t* usb_device,
usb_ms_endpoint_descriptor_t* ms_ep;
int i, epidx;
memset(device_info, 0, sizeof(*device_info));
if (usb_device->descriptor.iManufacturer == 0 ||
usb_string(usb_device, usb_device->descriptor.iManufacturer,
device_info->vendor, sizeof(device_info->vendor)) < 0)
sprintf(device_info->vendor, "Unknown Vendor %x", usb_device->descriptor.idVendor);
if (usb_device->descriptor.iProduct == 0 ||
usb_string(usb_device, usb_device->descriptor.iProduct,
device_info->product, sizeof(device_info->product)) < 0)
sprintf(device_info->product, "Unknown Device %x", usb_device->descriptor.idProduct);
memset(endpoints, 0, sizeof(*endpoints) * MIDI_MAX_ENDPOINTS);
intf = usb_ifnum_to_if(usb_device, ifnum);
intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
if (!intf)
return -ENXIO;
device_info->ifnum = ifnum;
printk(KERN_INFO "snd-usb-midi: using interface %d\n",
intf->altsetting[0].bInterfaceNumber);
intfd = snd_usbmidi_get_altsetting(usb_device, intf);
if (!intfd) {
printk(KERN_ERR "snd-usb-midi: could not determine altsetting\n");
return -ENXIO;
}
intfd = &intf->altsetting[0];
ms_header = (usb_ms_header_descriptor_t*)intfd->extra;
if (intfd->extralen >= USB_DST_MS_HEADER_SIZE &&
ms_header->bLength >= USB_DST_MS_HEADER_SIZE &&
if (intfd->extralen >= 7 &&
ms_header->bLength >= 7 &&
ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
ms_header->bDescriptorSubtype == USB_DST_MS_HEADER)
ms_header->bDescriptorSubtype == HEADER)
printk(KERN_INFO "snd-usb-midi: MIDIStreaming version %02x.%02x\n",
ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
else
......@@ -1126,242 +823,124 @@ static int snd_usbmidi_get_ms_info(usb_device_t* usb_device,
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
continue;
ms_ep = (usb_ms_endpoint_descriptor_t*)ep->extra;
if (ep->extralen < USB_DST_MS_GENERAL_SIZE ||
ms_ep->bLength < USB_DST_MS_GENERAL_SIZE ||
if (ep->extralen < 4 ||
ms_ep->bLength < 4 ||
ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
ms_ep->bDescriptorSubtype != USB_DST_MS_GENERAL)
ms_ep->bDescriptorSubtype != MS_GENERAL)
continue;
if (device_info->endpoints[epidx].epnum != 0 &&
device_info->endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
if (endpoints[epidx].epnum != 0 &&
endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
++epidx;
if (epidx >= MAX_ENDPOINTS) {
if (epidx >= MIDI_MAX_ENDPOINTS) {
printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
break;
}
}
device_info->endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if (ep->bEndpointAddress & USB_DIR_IN) {
device_info->endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
} else {
device_info->endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
}
printk(KERN_INFO "snd-usb-midi: detected %d %s jack(s) on endpoint %d\n",
ms_ep->bNumEmbMIDIJack,
ep->bEndpointAddress & USB_DIR_IN ? "input" : "output",
device_info->endpoints[epidx].epnum);
endpoints[epidx].epnum);
}
return 0;
}
/*
* Returns device capabilities, either explicitly supplied or from the
* class-specific descriptors.
*/
static int snd_usbmidi_get_device_info(usb_device_t* usb_device,
unsigned int ifnum,
const usb_device_id_t* usb_device_id,
usbmidi_device_info_t* device_info)
{
if (usb_device_id->driver_info) {
usbmidi_device_info_t* id_info = (usbmidi_device_info_t*)usb_device_id->driver_info;
if (ifnum != id_info->ifnum)
return -ENXIO;
*device_info = *id_info;
if (snd_usbmidi_detect_endpoint(usb_device, device_info) < 0)
return -ENXIO;
} else {
if (snd_usbmidi_get_ms_info(usb_device, ifnum, device_info) < 0)
return -ENXIO;
}
return 0;
}
/*
* Probes for a supported device.
* If the first endpoint isn't specified, use the first endpoint in the
* first alternate setting of the interface.
*/
static void* snd_usbmidi_usb_probe(usb_device_t* device,
unsigned int ifnum,
const usb_device_id_t* device_id)
static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoint)
{
usbmidi_device_info_t device_info;
snd_card_t* card = NULL;
int err;
usb_interface_t* intf;
usb_interface_descriptor_t* intfd;
usb_endpoint_descriptor_t* epd;
if (snd_usbmidi_get_device_info(device, ifnum, device_id,
&device_info) == 0) {
printk(KERN_INFO "snd-usb-midi: detected %s %s\n",
device_info.vendor, device_info.product);
err = snd_usbmidi_card_create(device, &device_info, &card);
if (err < 0)
snd_printk(KERN_ERR "cannot create card (error code %d)\n", err);
if (endpoint->epnum == -1) {
intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
if (!intf || intf->num_altsetting < 1)
return -ENOENT;
intfd = intf->altsetting;
if (intfd->bNumEndpoints < 1)
return -ENOENT;
epd = intfd->endpoint;
endpoint->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
return card;
return 0;
}
/*
* Frees the device.
* Initialize the sequencer device.
*/
static void snd_usbmidi_usb_disconnect(usb_device_t* usb_device, void* ptr)
static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
{
snd_card_t* card = (snd_card_t*)ptr;
int dev = (int)card->private_data;
snd_card_free(card);
down(&snd_usbmidi_open_mutex);
snd_usbmidi_card_used[dev] = 0;
up(&snd_usbmidi_open_mutex);
}
snd_usb_midi_t* umidi;
usb_device_t* dev;
snd_seq_client_callback_t client_callback;
snd_seq_client_info_t client_info;
snd_usb_midi_endpoint_info_t endpoints[MIDI_MAX_ENDPOINTS];
int i, err;
/*
* Information about devices with broken descriptors.
*/
umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
static usbmidi_device_info_t snd_usbmidi_yamaha_ux256_info = {
/* from NetBSD's umidi driver */
.vendor = "Yamaha", .product = "UX256",
.ifnum = 0,
.endpoints = {{ -1, 0xffff, 0x00ff }}
};
static usbmidi_device_info_t snd_usbmidi_yamaha_mu1000_info = {
/* from Nagano Daisuke's usb-midi driver */
.vendor = "Yamaha", .product = "MU1000",
.ifnum = 0,
.endpoints = {{ 1, 0x000f, 0x0001 }}
};
/*
* There ain't no such thing as a standard-compliant Roland device.
* Apparently, Roland decided not to risk to have wrong entries in the USB
* descriptors. The consequence is that class-specific descriptors are
* conspicuous by their absence.
*
* And now you may guess which company was responsible for writing the
* USB Device Class Definition for MIDI Devices.
*/
static usbmidi_device_info_t snd_usbmidi_roland_ua100_info = {
.vendor = "Roland", .product = "UA-100",
.ifnum = 2,
.endpoints = {{ -1, 0x0007, 0x0007 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_um4_info = {
.vendor = "EDIROL", .product = "UM-4",
.ifnum = 2,
.endpoints = {{ -1, 0x000f, 0x000f }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sc8850_info = {
.vendor = "Roland", .product = "SC-8850",
.ifnum = 2,
.endpoints = {{ -1, 0x003f, 0x003f }}
};
static usbmidi_device_info_t snd_usbmidi_roland_u8_info = {
.vendor = "Roland", .product = "U-8",
.ifnum = 2,
.endpoints = {{ -1, 0x0003, 0x0003 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_um2_info = {
.vendor = "EDIROL", .product = "UM-2",
.ifnum = 2,
.endpoints = {{ -1, 0x0003, 0x0003 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sc8820_info = {
.vendor = "Roland", .product = "SC-8820",
.ifnum = 2,
.endpoints = {{ -1, 0x0013, 0x0013 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_pc300_info = {
.vendor = "Roland", .product = "PC-300",
.ifnum = 2,
.endpoints = {{ -1, 0x0001, 0x0001 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_um1_info = {
.vendor = "EDIROL", .product = "UM-1",
.ifnum = 2,
.endpoints = {{ -1, 0x0001, 0x0001 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sk500_info = {
.vendor = "Roland", .product = "SK-500",
.ifnum = 2,
.endpoints = {{ -1, 0x0013, 0x0013 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_scd70_info = {
.vendor = "Roland", .product = "SC-D70",
.ifnum = 2,
.endpoints = {{ -1, 0x0007, 0x0007 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_xv5050_info = {
.vendor = "Roland", .product = "XV-5050",
.ifnum = 0,
.endpoints = {{ -1, 0x0001, 0x0001 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_um880_info = {
.vendor = "EDIROL", .product = "UM-880",
.ifnum = 0,
.endpoints = {{ -1, 0x01ff, 0x01ff }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sd90_info = {
.vendor = "EDIROL", .product = "SD-90",
.ifnum = 2,
.endpoints = {{ -1, 0x000f, 0x000f }}
};
static usbmidi_device_info_t snd_usbmidi_roland_um550_info = {
.vendor = "EDIROL", .product = "UM-550",
.ifnum = 0,
.endpoints = {{ -1, 0x003f, 0x003f }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sd20_info = {
.vendor = "EDIROL", .product = "SD-20",
.ifnum = 0,
.endpoints = {{ -1, 0x0003, 0x0007 }}
};
static usbmidi_device_info_t snd_usbmidi_roland_sd80_info = {
.vendor = "EDIROL", .product = "SD-80",
.ifnum = 0,
.endpoints = {{ -1, 0x000f, 0x000f }}
};
static usbmidi_device_info_t snd_usbmidi_roland_ua700_info = {
.vendor = "EDIROL", .product = "UA-700",
.ifnum = 3,
.endpoints = {{ -1, 0x0003, 0x0003 }}
};
memset(&client_callback, 0, sizeof(client_callback));
client_callback.allow_output = 1;
client_callback.allow_input = 1;
umidi->seq_client = snd_seq_create_kernel_client(umidi->chip->card, 0,
&client_callback);
if (umidi->seq_client < 0)
return umidi->seq_client;
#define USBMIDI_NONCOMPLIANT_DEVICE(vid, pid, name) \
USB_DEVICE(vid, pid), \
driver_info: (unsigned long)&snd_usbmidi_##name##_info
static usb_device_id_t snd_usbmidi_usb_id_table[] = {
{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
bInterfaceClass: USB_CLASS_AUDIO,
bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0499, 0x1000, yamaha_ux256) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0499, 0x1001, yamaha_mu1000) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0000, roland_ua100) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0002, roland_um4) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0003, roland_sc8850) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0004, roland_u8) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0005, roland_um2) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0007, roland_sc8820) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0008, roland_pc300) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0009, roland_um1) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x000b, roland_sk500) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x000c, roland_scd70) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0012, roland_xv5050) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0014, roland_um880) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0016, roland_sd90) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0023, roland_um550) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0027, roland_sd20) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0029, roland_sd80) },
{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x002b, roland_ua700) },
{ /* terminator */ }
};
memset(&client_info, 0, sizeof(client_info));
client_info.client = umidi->seq_client;
client_info.type = KERNEL_CLIENT;
dev = umidi->chip->dev;
if (dev->descriptor.iProduct)
err = usb_string(dev, dev->descriptor.iProduct,
client_info.name, sizeof(client_info.name));
else
err = 0;
if (err <= 0) {
if (umidi->quirk && umidi->quirk->product_name) {
strncpy(client_info.name, umidi->quirk->product_name,
sizeof(client_info.name) - 1);
client_info.name[sizeof(client_info.name) - 1] = '\0';
} else {
sprintf(client_info.name, "USB Device %#04x:%#04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
}
}
snd_seq_kernel_client_ctl(umidi->seq_client,
SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
&client_info);
MODULE_DEVICE_TABLE(usb, snd_usbmidi_usb_id_table);
if (umidi->quirk) {
memcpy(endpoints, umidi->quirk->endpoints, sizeof(endpoints));
err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
} else {
err = snd_usbmidi_get_ms_info(umidi, endpoints);
}
if (err < 0) {
snd_usbmidi_seq_device_delete(seq_device);
return err;
}
err = snd_usbmidi_create_endpoints(umidi, endpoints);
if (err < 0) {
snd_usbmidi_seq_device_delete(seq_device);
return err;
}
static usb_driver_t snd_usbmidi_usb_driver = {
.name = "snd-usb-midi",
.probe = snd_usbmidi_usb_probe,
.disconnect = snd_usbmidi_usb_disconnect,
.id_table = snd_usbmidi_usb_id_table,
.driver_list = LIST_HEAD_INIT(snd_usbmidi_usb_driver.driver_list)
};
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
if (umidi->endpoints[i].in)
snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb,
GFP_KERNEL);
return 0;
}
static int __init snd_usbmidi_module_init(void)
{
......@@ -1369,51 +948,15 @@ static int __init snd_usbmidi_module_init(void)
snd_usbmidi_seq_device_new,
snd_usbmidi_seq_device_delete
};
int err;
err = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_USBMIDI, &ops,
sizeof(usbmidi_t));
if (err < 0)
return err;
err = usb_register(&snd_usbmidi_usb_driver);
if (err < 0) {
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_USBMIDI);
return err;
}
return 0;
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_USBMIDI, &ops,
sizeof(snd_usb_midi_t));
}
static void __exit snd_usbmidi_module_exit(void)
{
usb_deregister(&snd_usbmidi_usb_driver);
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_USBMIDI);
}
module_init(snd_usbmidi_module_init)
module_exit(snd_usbmidi_module_exit)
#ifndef MODULE
/*
* format is snd-usb-midi=snd_enable,snd_index,snd_id,
* snd_vid,snd_pid,snd_int_transfer
*/
static int __init snd_usbmidi_module_setup(char* str)
{
static unsigned __initdata nr_dev = 0;
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str, &snd_enable[nr_dev]) == 2 &&
get_option(&str, &snd_index[nr_dev]) == 2 &&
get_id(&str, &snd_id[nr_dev]) == 2 &&
get_option(&str, &snd_vid[nr_dev]) == 2 &&
get_option(&str, &snd_pid[nr_dev]) == 2 &&
get_option(&str, &snd_int_transfer[nr_dev]) == 2);
++nr_dev;
return 1;
}
__setup("snd-usb-midi=", snd_usbmidi_module_setup);
#endif /* !MODULE */
/*
* 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