es1968.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,346 行 · 第 1/5 页

C
2,346
字号
#define ACPI_SB		( 1 << 5) /* sb emul */#define ACPI_FM		( 1 << 4) /* fm emul */#define ACPI_RB		( 1 << 3) /* ringbus / aclink */#define ACPI_MIDI	( 1 << 2) #define ACPI_GP		( 1 << 1) /* game port */#define ACPI_WP		( 1 << 0) /* wave processor */#define ACPI_ALL	(0xffff)#define ACPI_SLEEP	(~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \			ACPI_MIDI|ACPI_GP|ACPI_WP))#define ACPI_NONE	(ACPI__10)/* these masks indicate which units we care about at	which states */static u16 acpi_state_mask[] = {	[ACPI_D0] = ACPI_ALL,	[ACPI_D1] = ACPI_SLEEP,	[ACPI_D2] = ACPI_SLEEP,	[ACPI_D3] = ACPI_NONE};typedef struct snd_es1968 es1968_t;typedef struct snd_esschan esschan_t;typedef struct snd_esm_memory esm_memory_t;/* APU use in the driver */enum snd_enum_apu_type {	ESM_APU_PCM_PLAY,	ESM_APU_PCM_CAPTURE,	ESM_APU_PCM_RATECONV,	ESM_APU_FREE};/* chip type */enum {	TYPE_MAESTRO, TYPE_MAESTRO2, TYPE_MAESTRO2E};/* DMA Hack! */struct snd_esm_memory {	struct snd_dma_buffer buf;	int empty;	/* status */	struct list_head list;};/* Playback Channel */struct snd_esschan {	int running;	u8 apu[4];	u8 apu_mode[4];	/* playback/capture pcm buffer */	esm_memory_t *memory;	/* capture mixer buffer */	esm_memory_t *mixbuf;	unsigned int hwptr;	/* current hw pointer in bytes */	unsigned int count;	/* sample counter in bytes */	unsigned int dma_size;	/* total buffer size in bytes */	unsigned int frag_size;	/* period size in bytes */	unsigned int wav_shift;	u16 base[4];		/* offset for ptr */	/* stereo/16bit flag */	unsigned char fmt;	int mode;	/* playback / capture */	int bob_freq;	/* required timer frequency */	snd_pcm_substream_t *substream;	/* linked list */	struct list_head list;#ifdef CONFIG_PM	u16 wc_map[4];#endif};struct snd_es1968 {	/* Module Config */	int total_bufsize;			/* in bytes */	int playback_streams, capture_streams;	unsigned int clock;		/* clock */	/* buffer */	struct snd_dma_buffer dma;	/* Resources... */	int irq;	unsigned long io_port;	int type;	struct pci_dev *pci;	snd_card_t *card;	snd_pcm_t *pcm;	int do_pm;		/* power-management enabled */	/* DMA memory block */	struct list_head buf_list;	/* ALSA Stuff */	ac97_t *ac97;	snd_kcontrol_t *master_switch; /* for h/w volume control */	snd_kcontrol_t *master_volume;	snd_rawmidi_t *rmidi;	spinlock_t reg_lock;	struct tasklet_struct hwvol_tq;	/* Maestro Stuff */	u16 maestro_map[32];	int bobclient;		/* active timer instancs */	int bob_freq;		/* timer frequency */	struct semaphore memory_mutex;	/* memory lock */	/* APU states */	unsigned char apu[NR_APUS];	/* active substreams */	struct list_head substream_list;	spinlock_t substream_lock;#ifdef CONFIG_PM	u16 apu_map[NR_APUS][NR_APU_REGS];#endif#ifdef SUPPORT_JOYSTICK	struct gameport gameport;	struct resource *res_joystick;#endif};static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct pci_device_id snd_es1968_ids[] = {	/* Maestro 1 */        { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO },	/* Maestro 2 */	{ 0x125d, 0x1968, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2 },	/* Maestro 2E */        { 0x125d, 0x1978, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2E },	{ 0, }};MODULE_DEVICE_TABLE(pci, snd_es1968_ids);/* *********************   * Low Level Funcs!  *   *********************//* no spinlock */static void __maestro_write(es1968_t *chip, u16 reg, u16 data){	outw(reg, chip->io_port + ESM_INDEX);	outw(data, chip->io_port + ESM_DATA);	chip->maestro_map[reg] = data;}inline static void maestro_write(es1968_t *chip, u16 reg, u16 data){	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	__maestro_write(chip, reg, data);	spin_unlock_irqrestore(&chip->reg_lock, flags);}/* no spinlock */static u16 __maestro_read(es1968_t *chip, u16 reg){	if (READABLE_MAP & (1 << reg)) {		outw(reg, chip->io_port + ESM_INDEX);		chip->maestro_map[reg] = inw(chip->io_port + ESM_DATA);	}	return chip->maestro_map[reg];}inline static u16 maestro_read(es1968_t *chip, u16 reg){	unsigned long flags;	u16 result;	spin_lock_irqsave(&chip->reg_lock, flags);	result = __maestro_read(chip, reg);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return result;}#define big_mdelay(msec) do {\	set_current_state(TASK_UNINTERRUPTIBLE);\	schedule_timeout(((msec) * HZ + 999) / 1000);\} while (0)	/* Wait for the codec bus to be free */static int snd_es1968_ac97_wait(es1968_t *chip){	int timeout = 100000;	while (timeout-- > 0) {		if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1))			return 0;	}	snd_printd("es1968: ac97 timeout\n");	return 1; /* timeout */}static void snd_es1968_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val){	es1968_t *chip = ac97->private_data;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	snd_es1968_ac97_wait(chip);	/* Write the bus */	outw(val, chip->io_port + ESM_AC97_DATA);	mdelay(1);	outb(reg, chip->io_port + ESM_AC97_INDEX);	mdelay(1);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static unsigned short snd_es1968_ac97_read(ac97_t *ac97, unsigned short reg){	u16 data = 0;	es1968_t *chip = ac97->private_data;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	snd_es1968_ac97_wait(chip);	outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);	mdelay(1);	if (! snd_es1968_ac97_wait(chip)) {		data = inw(chip->io_port + ESM_AC97_DATA);		mdelay(1);	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	return data;}/* no spinlock */static void apu_index_set(es1968_t *chip, u16 index){	int i;	__maestro_write(chip, IDR1_CRAM_POINTER, index);	for (i = 0; i < 1000; i++)		if (__maestro_read(chip, IDR1_CRAM_POINTER) == index)			return;	snd_printd("es1968: APU register select failed. (Timeout)\n");}/* no spinlock */static void apu_data_set(es1968_t *chip, u16 data){	int i;	for (i = 0; i < 1000; i++) {		if (__maestro_read(chip, IDR0_DATA_PORT) == data)			return;		__maestro_write(chip, IDR0_DATA_PORT, data);	}	snd_printd("es1968: APU register set probably failed (Timeout)!\n");}/* no spinlock */static void __apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data){	snd_assert(channel < NR_APUS, return);#ifdef CONFIG_PM	chip->apu_map[channel][reg] = data;#endif	reg |= (channel << 4);	apu_index_set(chip, reg);	apu_data_set(chip, data);}inline static void apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data){	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	__apu_set_register(chip, channel, reg, data);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static u16 __apu_get_register(es1968_t *chip, u16 channel, u8 reg){	snd_assert(channel < NR_APUS, return 0);	reg |= (channel << 4);	apu_index_set(chip, reg);	return __maestro_read(chip, IDR0_DATA_PORT);}inline static u16 apu_get_register(es1968_t *chip, u16 channel, u8 reg){	unsigned long flags;	u16 v;	spin_lock_irqsave(&chip->reg_lock, flags);	v = __apu_get_register(chip, channel, reg);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return v;}#if 0 /* ASSP is not supported */static void assp_set_register(es1968_t *chip, u32 reg, u32 value){	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	outl(reg, chip->io_port + ASSP_INDEX);	outl(value, chip->io_port + ASSP_DATA);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static u32 assp_get_register(es1968_t *chip, u32 reg){	unsigned long flags;	u32 value;	spin_lock_irqsave(&chip->reg_lock, flags);	outl(reg, chip->io_port + ASSP_INDEX);	value = inl(chip->io_port + ASSP_DATA);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return value;}#endifstatic void wave_set_register(es1968_t *chip, u16 reg, u16 value){	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	outw(reg, chip->io_port + WC_INDEX);	outw(value, chip->io_port + WC_DATA);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static u16 wave_get_register(es1968_t *chip, u16 reg){	unsigned long flags;	u16 value;	spin_lock_irqsave(&chip->reg_lock, flags);	outw(reg, chip->io_port + WC_INDEX);	value = inw(chip->io_port + WC_DATA);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return value;}/* *******************   * Bob the Timer!  *   *******************/static void snd_es1968_bob_stop(es1968_t *chip){	u16 reg;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	reg = __maestro_read(chip, 0x11);	reg &= ~ESM_BOB_ENABLE;	__maestro_write(chip, 0x11, reg);	reg = __maestro_read(chip, 0x17);	reg &= ~ESM_BOB_START;	__maestro_write(chip, 0x17, reg);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_es1968_bob_start(es1968_t *chip){	int prescale;	int divide;	unsigned long flags;	/* compute ideal interrupt frequency for buffer size & play rate */	/* first, find best prescaler value to match freq */	for (prescale = 5; prescale < 12; prescale++)		if (chip->bob_freq > (ESS_SYSCLK >> (prescale + 9)))			break;	/* next, back off prescaler whilst getting divider into optimum range */	divide = 1;	while ((prescale > 5) && (divide < 32)) {		prescale--;		divide <<= 1;	}	divide >>= 1;	/* now fine-tune the divider for best match */	for (; divide < 31; divide++)		if (chip->bob_freq >		    ((ESS_SYSCLK >> (prescale + 9)) / (divide + 1))) break;	/* divide = 0 is illegal, but don't let prescale = 4! */	if (divide == 0) {		divide++;		if (prescale > 5)			prescale--;	} else if (divide > 1)		divide--;	spin_lock_irqsave(&chip->reg_lock, flags);	__maestro_write(chip, 6, 0x9000 | (prescale << 5) | divide);	/* set reg */	/* Now set IDR 11/17 */	__maestro_write(chip, 0x11, __maestro_read(chip, 0x11) | 1);	__maestro_write(chip, 0x17, __maestro_read(chip, 0x17) | 1);	spin_unlock_irqrestore(&chip->reg_lock, flags);}/* call with substream spinlock */static void snd_es1968_bob_inc(es1968_t *chip, int freq){	chip->bobclient++;	if (chip->bobclient == 1) {		chip->bob_freq = freq;		snd_es1968_bob_start(chip);	} else if (chip->bob_freq < freq) {		snd_es1968_bob_stop(chip);		chip->bob_freq = freq;		snd_es1968_bob_start(chip);	}}/* call with substream spinlock */static void snd_es1968_bob_dec(es1968_t *chip){	chip->bobclient--;	if (chip->bobclient <= 0)		snd_es1968_bob_stop(chip);	else if (chip->bob_freq > ESM_BOB_FREQ) {		/* check reduction of timer frequency */		struct list_head *p;		int max_freq = ESM_BOB_FREQ;		list_for_each(p, &chip->substream_list) {			esschan_t *es = list_entry(p, esschan_t, list);			if (max_freq < es->bob_freq)				max_freq = es->bob_freq;		}		if (max_freq != chip->bob_freq) {			snd_es1968_bob_stop(chip);			chip->bob_freq = max_freq;			snd_es1968_bob_start(chip);		}	}}static intsnd_es1968_calc_bob_rate(es1968_t *chip, esschan_t *es,			 snd_pcm_runtime_t *runtime){	/* we acquire 4 interrupts per period for precise control.. */	int freq = runtime->rate * 4;	if (es->fmt & ESS_FMT_STEREO)		freq <<= 1;	if (es->fmt & ESS_FMT_16BIT)		freq <<= 1;	freq /= es->frag_size;	if (freq < ESM_BOB_FREQ)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?