Commit 04c401f6 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Jaroslav Kysela

[PATCH] ALSA update [9/12] - 2002/09/11

  - AC'97 codec
    - added support/detection for MC'97 (modem codecs)
    - improved/updated register bit constants
    - AD1980 codec ID with patch code
    - added eMicro and Philips UCB1400 codecs
  - PCM Scatter-Gather support
    - added a function snd_pcm_sgbuf_get_addr()
  - rewritten PCI DMA allocation
  - ENS1371 - fixed IEC958 control index when AC'97 codec has S/PDIF capability, too
  - intel8x0
    - don't break when second codec cannot be initialized
  - via82xx
    - improved sg buffer handling
    - added "Input Source Select" control for via8233
    - fixed the registers for via8233
    - fixed the detection of via8233 chip
    - clean up the configuration of bd arrays
  - USB Audio
    - added the missing initialization of curframesize field (fixes capture)
parent c4eeeab4
......@@ -54,7 +54,7 @@
#define AC97_POWERDOWN 0x26 /* Powerdown control / status */
/* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
#define AC97_EXTENDED_ID 0x28 /* Extended Audio ID */
#define AC97_EXTENDED_STATUS 0x2a /* Extended Audio Status */
#define AC97_EXTENDED_STATUS 0x2a /* Extended Audio Status and Control */
#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 */
......@@ -64,10 +64,40 @@
#define AC97_SURROUND_MASTER 0x38 /* Surround (Rear) Master Volume */
#define AC97_SPDIF 0x3a /* S/PDIF control */
/* range 0x3c-0x58 - MODEM */
#define AC97_EXTENDED_MID 0x3c /* Extended Modem ID */
#define AC97_EXTENDED_MSTATUS 0x3e /* Extended Modem Status and Control */
#define AC97_LINE1_RATE 0x40 /* Line1 DAC/ADC Rate */
#define AC97_LINE2_RATE 0x42 /* Line2 DAC/ADC Rate */
#define AC97_HANDSET_RATE 0x44 /* Handset DAC/ADC Rate */
#define AC97_LINE1_LEVEL 0x46 /* Line1 DAC/ADC Level */
#define AC97_LINE2_LEVEL 0x48 /* Line2 DAC/ADC Level */
#define AC97_HANDSET_LEVEL 0x4a /* Handset DAC/ADC Level */
#define AC97_GPIO_CFG 0x4c /* GPIO Configuration */
#define AC97_GPIO_POLARITY 0x4e /* GPIO Pin Polarity/Type, 0=low, 1=high active */
#define AC97_GPIO_STICKY 0x50 /* GPIO Pin Sticky, 0=not, 1=sticky */
#define AC97_GPIO_WAKEUP 0x52 /* GPIO Pin Wakeup, 0=no int, 1=yes int */
#define AC97_GPIO_STATUS 0x54 /* GPIO Pin Status, slot 12 */
#define AC97_MISC_AFE 0x56 /* Miscellaneous Modem AFE Status and Control */
/* range 0x5a-0x7b - Vendor Specific */
#define AC97_VENDOR_ID1 0x7c /* Vendor ID1 */
#define AC97_VENDOR_ID2 0x7e /* Vendor ID2 / revision */
/* basic capabilities (reset register) */
#define AC97_BC_DEDICATED_MIC 0x0001 /* Dedicated Mic PCM In Channel */
#define AC97_BC_RESERVED1 0x0002 /* Reserved (was Modem Line Codec support) */
#define AC97_BC_BASS_TREBLE 0x0004 /* Bass & Treble Control */
#define AC97_BC_SIM_STEREO 0x0008 /* Simulated stereo */
#define AC97_BC_HEADPHONE 0x0010 /* Headphone Out Support */
#define AC97_BC_LOUDNESS 0x0020 /* Loudness (bass boost) Supporqt */
#define AC97_BC_16BIT_DAC 0x0000 /* 16-bit DAC resolution */
#define AC97_BC_18BIT_DAC 0x0040 /* 18-bit DAC resolution */
#define AC97_BC_20BIT_DAC 0x0080 /* 20-bit DAC resolution */
#define AC97_BC_DAC_MASK 0x00c0
#define AC97_BC_16BIT_ADC 0x0000 /* 16-bit ADC resolution */
#define AC97_BC_18BIT_ADC 0x0100 /* 18-bit ADC resolution */
#define AC97_BC_20BIT_ADC 0x0200 /* 20-bit ADC resolution */
#define AC97_BC_ADC_MASK 0x0300
/* extended audio ID bit defines */
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
#define AC97_EI_DRA 0x0002 /* Double rate supported */
......@@ -80,8 +110,8 @@
#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_REV_22 0x0400 /* AC'97 revision 2.2 */
#define AC97_EI_REV_SHIFT 10
#define AC97_EI_ADDR_MASK 0xc000 /* physical codec ID (address) */
#define AC97_EI_ADDR_SHIFT 14
......@@ -112,14 +142,25 @@
#define AC97_SC_COPY 0x0004 /* Copyright status */
#define AC97_SC_PRE 0x0008 /* Preemphasis status */
#define AC97_SC_CC_MASK 0x07f0 /* Category Code mask */
#define AC97_SC_CC_SHIFT 4
#define AC97_SC_L 0x0800 /* Generation Level status */
#define AC97_SC_SPSR_MASK 0xcfff /* S/PDIF Sample Rate bits */
#define AC97_SC_SPSR_MASK 0x3000 /* S/PDIF Sample Rate bits */
#define AC97_SC_SPSR_SHIFT 12
#define AC97_SC_SPSR_44K 0x0000 /* Use 44.1kHz Sample rate */
#define AC97_SC_SPSR_48K 0x2000 /* Use 48kHz Sample rate */
#define AC97_SC_SPSR_32K 0x3000 /* Use 32kHz Sample rate */
#define AC97_SC_DRS 0x4000 /* Double Rate S/PDIF */
#define AC97_SC_V 0x8000 /* Validity status */
/* extended modem ID bit defines */
#define AC97_MEI_LINE1 0x0001 /* Line1 present */
#define AC97_MEI_LINE2 0x0002 /* Line2 present */
#define AC97_MEI_HEADSET 0x0004 /* Headset present */
#define AC97_MEI_CID1 0x0008 /* caller ID decode for Line1 is supported */
#define AC97_MEI_CID2 0x0010 /* caller ID decode for Line2 is supported */
#define AC97_MEI_ADDR_MASK 0xc000 /* physical codec ID (address) */
#define AC97_MEI_ADDR_SHIFT 14
/* specific - SigmaTel */
#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */
#define AC97_SIGMATEL_DAC2INVERT 0x6e
......@@ -154,8 +195,10 @@
#define AC97_CXR_SPDIF_AC3 0x2
/* ac97->scaps */
#define AC97_SCAP_SURROUND_DAC (1<<0) /* surround L&R DACs are present */
#define AC97_SCAP_CENTER_LFE_DAC (1<<1) /* center and LFE DACs are present */
#define AC97_SCAP_AUDIO (1<<0) /* audio AC'97 codec */
#define AC97_SCAP_MODEM (1<<1) /* modem AC'97 codec */
#define AC97_SCAP_SURROUND_DAC (1<<2) /* surround L&R DACs are present */
#define AC97_SCAP_CENTER_LFE_DAC (1<<3) /* center and LFE DACs are present */
/* ac97->flags */
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
......@@ -195,6 +238,7 @@ struct _snd_ac97 {
unsigned int id; /* identification of codec */
unsigned short caps; /* capabilities (register 0) */
unsigned short ext_id; /* extended feature identification (register 28) */
unsigned short ext_mid; /* extended modem ID (register 3C) */
unsigned int scaps; /* driver capabilities */
unsigned int flags; /* specific code */
unsigned int clock; /* AC'97 clock (usually 48000Hz) */
......
......@@ -45,6 +45,13 @@ static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
/*
* return the physical address at the corresponding offset
*/
static inline dma_addr_t snd_pcm_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
{
return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
}
int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
......
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc3"
#define CONFIG_SND_DATE " (Fri Sep 06 15:06:56 2002 UTC)"
#define CONFIG_SND_DATE " (Wed Sep 11 18:36:14 2002 UTC)"
......@@ -3,17 +3,23 @@
# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
#
export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o \
pcm_sgbuf.o
export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o
snd-objs := sound.o init.o isadma.o memory.o info.o control.o misc.o \
snd-objs := sound.o init.o memory.o info.o control.o misc.o \
device.o wrappers.o
ifeq ($(CONFIG_ISA),y)
snd-objs += isadma.o
endif
ifeq ($(CONFIG_SND_OSSEMUL),y)
snd-objs += sound_oss.o info_oss.o
endif
snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o pcm_sgbuf.o
pcm_memory.o
ifeq ($(CONFIG_PCI),y)
snd-pcm-objs += pcm_sgbuf.o
export-objs += pcm_sgbuf.o
endif
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
......
......@@ -30,8 +30,6 @@
#include <sound/core.h>
#include <asm/dma.h>
#ifdef CONFIG_ISA
/*
*
*/
......@@ -78,5 +76,3 @@ unsigned int snd_dma_residue(unsigned long dma)
release_dma_lock(flags);
return result;
}
#endif /* CONFIG_ISA */
......@@ -545,35 +545,36 @@ int copy_from_user_toio(unsigned long dst, const void *src, size_t count)
*
* since pci_alloc_consistent always tries GFP_DMA when the requested
* pci memory region is below 32bit, it happens quite often that even
* 2 order or pages cannot be allocated.
* 2 order of pages cannot be allocated.
*
* so in the following, GFP_DMA is used only when the first allocation
* doesn't match the requested region.
* so in the following, we allocate at first without dma_mask, so that
* allocation will be done without GFP_DMA. if the area doesn't match
* with the requested region, then realloate with the original dma_mask
* again.
*/
#ifdef __i386__
#define get_phys_addr(x) virt_to_phys(x)
#else /* ppc and x86-64 */
#define get_phys_addr(x) virt_to_bus(x)
#endif
#undef pci_alloc_consistent
void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
{
void *ret;
int gfp = GFP_ATOMIC;
u64 dma_mask;
unsigned long rmask;
if (hwdev == NULL)
gfp |= GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));
if (ret) {
if (hwdev && ((get_phys_addr(ret) + size - 1) & ~hwdev->dma_mask)) {
free_pages((unsigned long)ret, get_order(size));
ret = (void *)__get_free_pages(gfp | GFP_DMA, get_order(size));
}
}
if (ret) {
memset(ret, 0, size);
*dma_handle = get_phys_addr(ret);
return pci_alloc_consistent(hwdev, size, dma_handle);
dma_mask = hwdev->dma_mask;
rmask = ~((unsigned long)dma_mask);
hwdev->dma_mask = 0xffffffff; /* do without masking */
ret = pci_alloc_consistent(hwdev, size, dma_handle);
if (ret && ((*dma_handle + size - 1) & rmask)) {
pci_free_consistent(hwdev, size, ret, *dma_handle);
ret = 0;
}
hwdev->dma_mask = dma_mask; /* restore */
if (! ret)
ret = pci_alloc_consistent(hwdev, size, dma_handle);
return ret;
}
#endif /* hack */
......@@ -446,7 +446,7 @@ static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
left = ucontrol->value.integer.value[0] % 101;
right = ucontrol->value.integer.value[1] % 101;
spin_lock_irqsave(&dummy->mixer_lock, flags);
change = dummy->mixer_volume[addr][0] != left &&
change = dummy->mixer_volume[addr][0] != left ||
dummy->mixer_volume[addr][1] != right;
dummy->mixer_volume[addr][0] = left;
dummy->mixer_volume[addr][1] = right;
......
......@@ -68,11 +68,13 @@ static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL },
{ 0x454d4300, 0xffffff00, "eMicro", NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL },
{ 0x48525300, 0xffffff00, "Intersil", NULL },
{ 0x49434500, 0xffffff00, "ICEnsemble", NULL },
{ 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL },
{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL },
{ 0x50534300, 0xffffff00, "Philips", NULL },
{ 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL },
{ 0x54524100, 0xffffff00, "TriTech", NULL },
{ 0x54584e00, 0xffffff00, "Texas Instruments", NULL },
......@@ -97,6 +99,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881 },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980 },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
......@@ -117,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif },
{ 0x43525960, 0xfffffff8, "CS4291", NULL },
{ 0x43585429, 0xffffffff, "Cx20468", patch_conexant },
{ 0x454d4328, 0xffffffff, "28028", NULL }, // same as TR28028?
{ 0x45838308, 0xffffffff, "ESS1988", NULL },
{ 0x48525300, 0xffffff00, "HMP9701", NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL },
......@@ -124,6 +128,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x49544520, 0xffffffff, "IT2226E", NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL },
{ 0x53494c22, 0xffffffff, "Si3036", NULL },
{ 0x53494c23, 0xffffffff, "Si3038", NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL },
......@@ -1503,57 +1508,83 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
/* the REC_GAIN register is used for tests */
end_time = jiffies + HZ;
do {
unsigned short ext_mid;
/* use preliminary reads to settle the communication */
snd_ac97_read(ac97, AC97_RESET);
snd_ac97_read(ac97, AC97_VENDOR_ID1);
snd_ac97_read(ac97, AC97_VENDOR_ID2);
/* test if we can write to the PCM volume register */
/* modem? */
ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (ext_mid != 0xffff && (ext_mid & 1) != 0)
goto __access_ok;
/* test if we can write to the record gain volume register */
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);
if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
goto __access_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
} 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_printk("AC'97 %d:%d does not respond - RESET [REC_GAIN = 0x%x]\n", ac97->num, ac97->addr, err);
snd_ac97_free(ac97);
return -ENXIO;
}
__access_ok:
ac97->caps = snd_ac97_read(ac97, AC97_RESET);
ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (ac97->ext_id == 0xffff) /* invalid combination */
ac97->ext_id = 0;
if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) {
snd_printk("AC'97 %d:%d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->addr, ac97->id);
snd_ac97_free(ac97);
return -EIO;
}
/* test for AC'97 */
/* test if we can write to the record gain volume register */
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06);
if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a06) {
ac97->scaps |= AC97_SCAP_AUDIO;
ac97->caps = snd_ac97_read(ac97, AC97_RESET);
ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (ac97->ext_id == 0xffff) /* invalid combination */
ac97->ext_id = 0;
}
/* test for MC'97 */
ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (ac97->ext_mid == 0xffff) /* invalid combination */
ac97->ext_mid = 0;
if (ac97->ext_mid & 1)
ac97->scaps |= AC97_SCAP_MODEM;
if (ac97->reset) // FIXME: always skipping?
goto __ready_ok;
/* FIXME: add powerdown control */
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */
udelay(100);
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10);
} while (time_after_eq(end_time, jiffies));
snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr);
if (ac97->scaps & AC97_SCAP_AUDIO) {
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */
udelay(100);
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10);
} 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->scaps & AC97_SCAP_AUDIO)
ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
else
ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_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 & AC97_EI_VRA) { /* VRA support */
......@@ -1595,9 +1626,17 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
strcat(card->mixername, name);
}
}
if ((err = snd_component_add(card, "AC97")) < 0) {
snd_ac97_free(ac97);
return err;
if (ac97->scaps & AC97_SCAP_AUDIO) {
if ((err = snd_component_add(card, "AC97a")) < 0) {
snd_ac97_free(ac97);
return err;
}
}
if (ac97->scaps & AC97_SCAP_MODEM) {
if ((err = snd_component_add(card, "AC97m")) < 0) {
snd_ac97_free(ac97);
return err;
}
}
if (snd_ac97_mixer_build(card, ac97) < 0) {
snd_ac97_free(ac97);
......@@ -1620,7 +1659,7 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, in
{
char name[64];
unsigned int id;
unsigned short val, tmp, ext;
unsigned short val, tmp, ext, mext;
static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" };
static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" };
static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" };
......@@ -1631,24 +1670,24 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, in
snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
val = snd_ac97_read(ac97, AC97_RESET);
snd_iprintf(buffer, "Capabilities :%s%s%s%s%s%s\n",
val & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
val & 0x0002 ? " -reserved1-" : "",
val & 0x0004 ? " -bass & treble-" : "",
val & 0x0008 ? " -simulated stereo-" : "",
val & 0x0010 ? " -headphone out-" : "",
val & 0x0020 ? " -loudness-" : "");
tmp = ac97->caps & 0x00c0;
val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "",
val & AC97_BC_RESERVED1 ? " -reserved1-" : "",
val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "",
val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "",
val & AC97_BC_HEADPHONE ? " -headphone out-" : "",
val & AC97_BC_LOUDNESS ? " -loudness-" : "");
tmp = ac97->caps & AC97_BC_DAC_MASK;
snd_iprintf(buffer, "DAC resolution : %s%s%s%s\n",
tmp == 0x0000 ? "16-bit" : "",
tmp == 0x0040 ? "18-bit" : "",
tmp == 0x0080 ? "20-bit" : "",
tmp == 0x00c0 ? "???" : "");
tmp = ac97->caps & 0x0300;
tmp == AC97_BC_16BIT_DAC ? "16-bit" : "",
tmp == AC97_BC_18BIT_DAC ? "18-bit" : "",
tmp == AC97_BC_20BIT_DAC ? "20-bit" : "",
tmp == AC97_BC_DAC_MASK ? "???" : "");
tmp = ac97->caps & AC97_BC_ADC_MASK;
snd_iprintf(buffer, "ADC resolution : %s%s%s%s\n",
tmp == 0x0000 ? "16-bit" : "",
tmp == 0x0100 ? "18-bit" : "",
tmp == 0x0200 ? "20-bit" : "",
tmp == 0x0300 ? "???" : "");
tmp == AC97_BC_16BIT_ADC ? "16-bit" : "",
tmp == AC97_BC_18BIT_ADC ? "18-bit" : "",
tmp == AC97_BC_20BIT_ADC ? "20-bit" : "",
tmp == AC97_BC_ADC_MASK ? "???" : "");
snd_iprintf(buffer, "3D enhancement : %s\n",
snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]);
snd_iprintf(buffer, "\nCurrent setup\n");
......@@ -1669,79 +1708,93 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, in
val & 0x0200 ? "Mic" : "MIX",
val & 0x0100 ? "Mic2" : "Mic1",
val & 0x0080 ? "on" : "off");
ext = snd_ac97_read(ac97, AC97_EXTENDED_ID);
ext = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (ext == 0)
return;
goto __modem;
snd_iprintf(buffer, "Extended ID : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n",
(ext >> 14) & 3,
(ext >> 10) & 3,
ext & 0x0200 ? " AMAP" : "",
ext & 0x0100 ? " LDAC" : "",
ext & 0x0080 ? " SDAC" : "",
ext & 0x0040 ? " CDAC" : "",
(ext >> 4) & 3,
ext & 0x0008 ? " VRM" : "",
ext & 0x0004 ? " SPDIF" : "",
ext & 0x0002 ? " DRA" : "",
ext & 0x0001 ? " VRA" : "");
(ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT,
(ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT,
ext & AC97_EI_AMAP ? " AMAP" : "",
ext & AC97_EI_LDAC ? " LDAC" : "",
ext & AC97_EI_SDAC ? " SDAC" : "",
ext & AC97_EI_CDAC ? " CDAC" : "",
(ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT,
ext & AC97_EI_VRM ? " VRM" : "",
ext & AC97_EI_SPDIF ? " SPDIF" : "",
ext & AC97_EI_DRA ? " DRA" : "",
ext & AC97_EI_VRA ? " VRA" : "");
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
snd_iprintf(buffer, "Extended status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
val & 0x4000 ? " PRL" : "",
val & 0x2000 ? " PRK" : "",
val & 0x1000 ? " PRJ" : "",
val & 0x0800 ? " PRI" : "",
val & 0x0400 ? " SPCV" : "",
val & 0x0200 ? " MADC" : "",
val & 0x0100 ? " LDAC" : "",
val & 0x0080 ? " SDAC" : "",
val & 0x0040 ? " CDAC" : "",
ext & 0x0004 ? spdif_slots[(val & 0x0030) >> 4] : "",
val & 0x0008 ? " VRM" : "",
val & 0x0004 ? " SPDIF" : "",
val & 0x0002 ? " DRA" : "",
val & 0x0001 ? " VRA" : "");
if (ext & 1) { /* VRA */
val & AC97_EA_PRL ? " PRL" : "",
val & AC97_EA_PRK ? " PRK" : "",
val & AC97_EA_PRJ ? " PRJ" : "",
val & AC97_EA_PRI ? " PRI" : "",
val & AC97_EA_SPCV ? " SPCV" : "",
val & AC97_EA_MDAC ? " MADC" : "",
val & AC97_EA_LDAC ? " LDAC" : "",
val & AC97_EA_SDAC ? " SDAC" : "",
val & AC97_EA_CDAC ? " CDAC" : "",
ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "",
val & AC97_EA_VRM ? " VRM" : "",
val & AC97_EA_SPDIF ? " SPDIF" : "",
val & AC97_EA_DRA ? " DRA" : "",
val & AC97_EA_VRA ? " VRA" : "");
if (ext & AC97_EI_VRA) { /* VRA */
val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE);
snd_iprintf(buffer, "PCM front DAC : %iHz\n", val);
if (ext & 0x0080) {
if (ext & AC97_EI_SDAC) {
val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE);
snd_iprintf(buffer, "PCM Surr DAC : %iHz\n", val);
}
if (ext & 0x0100) {
if (ext & AC97_EI_LDAC) {
val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE);
snd_iprintf(buffer, "PCM LFE DAC : %iHz\n", val);
}
val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE);
snd_iprintf(buffer, "PCM ADC : %iHz\n", val);
}
if (ext & 0x0008) {
if (ext & AC97_EI_VRM) {
val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE);
snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val);
}
if ((ext & 0x0004) || (ac97->flags & AC97_CS_SPDIF)) {
if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) {
if (ac97->flags & AC97_CS_SPDIF)
val = snd_ac97_read(ac97, AC97_CSR_SPDIF);
else
val = snd_ac97_read(ac97, AC97_SPDIF);
snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n",
val & 0x0001 ? " PRO" : " Consumer",
val & 0x0002 ? " Non-audio" : " PCM",
val & 0x0004 ? " Copyright" : "",
val & 0x0008 ? " Preemph50/15" : "",
(val & 0x07f0) >> 4,
(val & 0x0800) >> 11,
val & AC97_SC_PRO ? " PRO" : " Consumer",
val & AC97_SC_NAUDIO ? " Non-audio" : " PCM",
val & AC97_SC_COPY ? " Copyright" : "",
val & AC97_SC_PRE ? " Preemph50/15" : "",
(val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT,
(val & AC97_SC_L) >> 11,
(ac97->flags & AC97_CS_SPDIF) ?
spdif_rates_cs4205[(val & 0x3000) >> 12] :
spdif_rates[(val & 0x3000) >> 12],
spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] :
spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT],
(ac97->flags & AC97_CS_SPDIF) ?
(val & 0x4000 ? " Validity" : "") :
(val & 0x4000 ? " DRS" : ""),
(val & AC97_SC_DRS ? " Validity" : "") :
(val & AC97_SC_DRS ? " DRS" : ""),
(ac97->flags & AC97_CS_SPDIF) ?
(val & 0x8000 ? " Enabled" : "") :
(val & 0x8000 ? " Validity" : ""));
(val & AC97_SC_V ? " Enabled" : "") :
(val & AC97_SC_V ? " Validity" : ""));
}
__modem:
mext = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (mext == 0)
return;
snd_iprintf(buffer, "Extended modem ID: codec=%i %s%s%s%s%s\n",
(mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT,
mext & AC97_MEI_CID2 ? " CID2" : "",
mext & AC97_MEI_CID1 ? " CID1" : "",
mext & AC97_MEI_HEADSET ? " HSET" : "",
mext & AC97_MEI_LINE2 ? " LIN2" : "",
mext & AC97_MEI_LINE1 ? " LIN1" : "");
}
static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
......
......@@ -31,6 +31,7 @@
#include <sound/ac97_codec.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include "ac97_patch.h"
/*
* Chip specific initialization
......@@ -323,3 +324,15 @@ int patch_ad1886(ac97_t * ac97)
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
return 0;
}
int patch_ad1980(ac97_t * ac97)
{
unsigned short misc;
patch_ad1881(ac97);
/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
misc = snd_ac97_read(ac97, AC97_AD_MISC);
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | 0x0420);
return 0;
}
......@@ -37,3 +37,4 @@ int patch_ad1819(ac97_t * ac97);
int patch_ad1881(ac97_t * ac97);
int patch_ad1885(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97);
int patch_ad1980(ac97_t * ac97);
......@@ -1319,7 +1319,10 @@ static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq)
if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
ensoniq->pci->device == es1371_spdif_present[idx].did &&
ensoniq->rev == es1371_spdif_present[idx].rev) {
snd_ctl_add(card, snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq));
snd_kcontrol_t *kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq);
if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
kctl->id.index = 1;
snd_ctl_add(card, kctl);
break;
}
return 0;
......
......@@ -1580,8 +1580,11 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
goto __skip_secondary;
for (i = 1; i < codecs; i++) {
ac97.num = i;
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err;
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) {
snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta);
codecs = i;
break;
}
chip->ac97[i] = x97;
if (chip->device_type == DEVICE_INTEL_ICH4 && chip->ichd[ICHD_PCM2IN].ac97 == NULL)
chip->ichd[ICHD_PCM2IN].ac97 = x97;
......
/*
* Driver for ESS Maestro3/Allegro soundcards.
* Driver for ESS Maestro3/Allegro (ES1988) soundcards.
* Copyright (c) 2000 by Zach Brown <zab@zabbo.net>
* Takashi Iwai <tiwai@suse.de>
*
......@@ -52,6 +52,7 @@ MODULE_DESCRIPTION("ESS Maestro3 PCI");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{ESS,Maestro3 PCI},"
"{ESS,ES1988},"
"{ESS,Allegro PCI},"
"{ESS,Allegro-1 PCI},"
"{ESS,Canyon3D-2/LE PCI}}");
......
......@@ -124,7 +124,7 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA8233_REG_TYPE_16BIT 0x00200000 /* RW */
#define VIA8233_REG_TYPE_STEREO 0x00100000 /* RW */
#define VIA_REG_OFFSET_CURR_COUNT 0x0c /* dword - channel current count (24 bit) */
#define VIA_REG_OFFSET_CURR_INDEX 0x0f /* byte - channel current index */
#define VIA_REG_OFFSET_CURR_INDEX 0x0f /* byte - channel current index (for via8233 only) */
#define DEFINE_VIA_REGSET(name,val) \
enum {\
......@@ -159,8 +159,8 @@ DEFINE_VIA_REGSET(FM, 0x20);
#define VIA_REG_SGD_SHADOW 0x84 /* dword */
/* multi-channel and capture registers for via8233 */
DEFINE_VIA_REGSET(MULTPLAY, 0x20);
DEFINE_VIA_REGSET(CAPTURE_8233, 0x10);
DEFINE_VIA_REGSET(MULTPLAY, 0x40);
DEFINE_VIA_REGSET(CAPTURE_8233, 0x60);
/* via8233-specific registers */
#define VIA_REG_PLAYBACK_VOLUME_L 0x02 /* byte */
......@@ -183,66 +183,83 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x10);
* pcm stream
*/
struct snd_via_sg_table {
unsigned int offset;
unsigned int size;
} ;
#define VIA_TABLE_SIZE 255
typedef struct {
unsigned long reg_offset;
snd_pcm_substream_t *substream;
int running;
unsigned int size;
unsigned int fragsize;
unsigned int frags;
unsigned int lastptr;
unsigned int lastcount;
unsigned int page_per_frag;
unsigned int curidx;
unsigned int tbl_entries; /* number of descriptor table entries */
unsigned int tbl_size; /* size of a table entry */
unsigned int tbl_entries; /* # descriptors */
u32 *table; /* physical address + flag */
dma_addr_t table_addr;
struct snd_via_sg_table *idx_table;
} viadev_t;
static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
struct pci_dev *pci)
{
int i, size;
int i, idx, ofs, rest, fragsize;
snd_pcm_runtime_t *runtime = substream->runtime;
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
if (dev->table) {
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
if (! dev->table) {
/* the start of each lists must be aligned to 8 bytes,
* but the kernel pages are much bigger, so we don't care
*/
dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table_addr);
if (! dev->table)
return -ENOMEM;
}
/* allocate buffer descriptor lists */
if (dev->fragsize < PAGE_SIZE) {
dev->tbl_size = dev->fragsize;
dev->tbl_entries = dev->frags;
dev->page_per_frag = 1;
} else {
dev->tbl_size = PAGE_SIZE;
dev->tbl_entries = sgbuf->pages;
dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
if (! dev->idx_table) {
dev->idx_table = kmalloc(sizeof(unsigned int) * VIA_TABLE_SIZE, GFP_KERNEL);
if (! dev->idx_table)
return -ENOMEM;
}
/* the start of each lists must be aligned to 8 bytes,
* but the kernel pages are much bigger, so we don't care
*/
dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
if (! dev->table)
return -ENOMEM;
if (dev->tbl_size < PAGE_SIZE) {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
} else {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
}
size = dev->size;
for (i = 0; i < dev->tbl_entries - 1; i++) {
dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
size -= dev->tbl_size;
/* fill the entries */
fragsize = snd_pcm_lib_period_bytes(substream);
idx = 0;
ofs = 0;
for (i = 0; i < runtime->periods; i++) {
rest = fragsize;
/* fill descriptors for a period.
* a period can be split to several descriptors if it's
* over page boundary.
*/
do {
int r;
unsigned int flag;
dev->table[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
r = PAGE_SIZE - (ofs % PAGE_SIZE);
if (rest < r)
r = rest;
rest -= r;
if (! rest) {
if (i == runtime->periods - 1)
flag = VIA_TBL_BIT_EOL; /* buffer boundary */
else
flag = VIA_TBL_BIT_FLAG; /* period boundary */
} else
flag = 0; /* period continues to the next */
// printk("via: tbl %d: at %d size %d (rest %d)\n", idx, ofs, r, rest);
dev->table[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
dev->idx_table[idx].size = r;
ofs += r;
idx++;
if (idx >= VIA_TABLE_SIZE) {
snd_printk(KERN_ERR "via82xx: too much table size!\n");
return -EINVAL;
}
} while (rest > 0);
}
dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
dev->tbl_entries = idx;
return 0;
}
......@@ -254,13 +271,17 @@ static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
}
if (dev->idx_table) {
kfree(dev->idx_table);
dev->idx_table = NULL;
}
}
/*
*/
enum { TYPE_VIA686, TYPE_VIA8233 };
enum { TYPE_VIA686 = 1, TYPE_VIA8233 };
typedef struct _snd_via82xx via82xx_t;
#define chip_t via82xx_t
......@@ -295,8 +316,8 @@ struct _snd_via82xx {
};
static struct pci_device_id snd_via82xx_ids[] __devinitdata = {
{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 686A */
{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* VT8233 */
{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_VIA686, }, /* 686A */
{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_VIA8233, }, /* VT8233 */
{ 0, }
};
......@@ -456,21 +477,7 @@ static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev,
{
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long port = chip->port + viadev->reg_offset;
int v, err;
viadev->size = snd_pcm_lib_buffer_bytes(substream);
viadev->fragsize = snd_pcm_lib_period_bytes(substream);
viadev->frags = runtime->periods;
viadev->lastptr = ~0;
viadev->lastcount = ~0;
viadev->curidx = 0;
/* the period size must be in power of 2 */
v = ld2(viadev->fragsize);
if (viadev->fragsize != (1 << v)) {
snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
return -EINVAL;
}
int err;
snd_via82xx_channel_reset(chip, viadev);
......@@ -478,7 +485,6 @@ static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev,
if (err < 0)
return err;
runtime->dma_bytes = viadev->size;
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
switch (chip->chip_type) {
case TYPE_VIA686:
......@@ -524,13 +530,9 @@ static inline void snd_via82xx_update(via82xx_t *chip, viadev_t *viadev)
{
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
viadev->curidx++;
if (viadev->curidx >= viadev->page_per_frag) {
viadev->curidx = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
}
......@@ -613,10 +615,8 @@ static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
if (chip->chip_type == TYPE_VIA8233) {
outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
if (chip->chip_type == TYPE_VIA8233)
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
}
return snd_via82xx_setup_periods(chip, &chip->capture, substream);
}
......@@ -624,43 +624,33 @@ static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev
{
unsigned int val, ptr, count;
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset)/* & 0xffffff*/;
snd_assert(viadev->tbl_entries, return 0);
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
switch (chip->chip_type) {
case TYPE_VIA686:
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
if (ptr == viadev->lastptr && count > viadev->lastcount)
ptr += 8;
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
snd_assert(viadev->tbl_entries, return 0);
/* get index */
/* The via686a does not have the current index register,
* so we need to calculate the index from CURR_PTR.
*/
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset);
if (ptr <= (unsigned int)viadev->table_addr)
val = 0;
else
else /* CURR_PTR holds the address + 8 */
val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
viadev->lastptr = ptr;
viadev->lastcount = count;
break;
case TYPE_VIA8233:
default:
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have this current index register,
* this register makes life easier for us here. */
/* ah, this register makes life easier for us here. */
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
break;
}
/* convert to the linear position */
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
} else {
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
return val;
return viadev->idx_table[val].offset +
viadev->idx_table[val].size - count;
}
static snd_pcm_uframes_t snd_via82xx_playback_pointer(snd_pcm_substream_t * substream)
......@@ -691,7 +681,7 @@ static snd_pcm_hardware_t snd_via82xx_playback =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 128,
.periods_max = VIA_TABLE_SIZE / 2,
.fifo_size = 0,
};
......@@ -710,7 +700,7 @@ static snd_pcm_hardware_t snd_via82xx_capture =
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 128,
.periods_max = VIA_TABLE_SIZE / 2,
.fifo_size = 0,
};
......@@ -739,18 +729,10 @@ static int snd_via82xx_playback_open(snd_pcm_substream_t * substream)
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;
/* we may remove following constaint when we modify table entries
in interrupt */
#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.
*/
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
if (chip->chip_type == TYPE_VIA8233) {
runtime->hw.channels_max = 6;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
......@@ -771,12 +753,8 @@ static int snd_via82xx_capture_open(snd_pcm_substream_t * substream)
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;
}
......@@ -864,6 +842,52 @@ static int __devinit snd_via82xx_pcm(via82xx_t *chip, int device, snd_pcm_t ** r
* Mixer part
*/
static int snd_via8233_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
static char *texts[2] = {
"Line", "Mic"
};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 2;
if (uinfo->value.enumerated.item >= 2)
uinfo->value.enumerated.item = 1;
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
return 0;
}
static int snd_via8233_capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = inb(VIAREG(chip, CAPTURE_CHANNEL)) & VIA_REG_CAPTURE_CHANNEL_MIC ? 1 : 0;
return 0;
}
static int snd_via8233_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
u8 val, oval;
spin_lock_irqsave(&chip->reg_lock, flags);
oval = inb(VIAREG(chip, CAPTURE_CHANNEL));
val = oval & ~VIA_REG_CAPTURE_CHANNEL_MIC;
if (ucontrol->value.enumerated.item[0])
val |= VIA_REG_CAPTURE_CHANNEL_MIC;
if (val != oval)
outb(val, VIAREG(chip, CAPTURE_CHANNEL));
spin_unlock_irqrestore(&chip->reg_lock, flags);
return val != oval;
}
static snd_kcontrol_new_t snd_via8233_capture_source __devinitdata = {
.name = "Input Source Select",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_via8233_capture_source_info,
.get = snd_via8233_capture_source_get,
.put = snd_via8233_capture_source_put,
};
static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
{
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
......@@ -1271,6 +1295,14 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
} else {
/* VIA8233 */
err = snd_ctl_add(card, snd_ctl_new1(&snd_via8233_capture_source, chip));
if (err < 0) {
snd_card_free(card);
return err;
}
}
sprintf(card->longname, "%s at 0x%lx, irq %d",
......
......@@ -766,6 +766,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
subs->curpacksize = subs->maxpacksize;
else
subs->curpacksize = maxsize;
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
/* allocate a temporary buffer for playback */
if (is_playback) {
......
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