⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 es1968.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* playback/capture pcm buffer */	struct esm_memory *memory;	/* capture mixer buffer */	struct esm_memory *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 */	struct snd_pcm_substream *substream;	/* linked list */	struct list_head list;#ifdef CONFIG_PM	u16 wc_map[4];#endif};struct es1968 {	/* Module Config */	int total_bufsize;			/* in bytes */	int playback_streams, capture_streams;	unsigned int clock;		/* clock */	/* for clock measurement */	unsigned int in_measurement: 1;	unsigned int measure_apu;	unsigned int measure_lastpos;	unsigned int measure_count;	/* buffer */	struct snd_dma_buffer dma;	/* Resources... */	int irq;	unsigned long io_port;	int type;	struct pci_dev *pci;	struct snd_card *card;	struct snd_pcm *pcm;	int do_pm;		/* power-management enabled */	/* DMA memory block */	struct list_head buf_list;	/* ALSA Stuff */	struct snd_ac97 *ac97;	struct snd_kcontrol *master_switch; /* for h/w volume control */	struct snd_kcontrol *master_volume;	struct snd_rawmidi *rmidi;	spinlock_t reg_lock;	spinlock_t ac97_lock;	struct tasklet_struct hwvol_tq;	unsigned int in_suspend;	/* Maestro Stuff */	u16 maestro_map[32];	int bobclient;		/* active timer instancs */	int bob_freq;		/* timer frequency */	struct mutex 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;#endif};static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);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(struct es1968 *chip, u16 reg, u16 data){	outw(reg, chip->io_port + ESM_INDEX);	outw(data, chip->io_port + ESM_DATA);	chip->maestro_map[reg] = data;}static inline void maestro_write(struct es1968 *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(struct es1968 *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];}static inline u16 maestro_read(struct es1968 *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;}/* Wait for the codec bus to be free */static int snd_es1968_ac97_wait(struct es1968 *chip){	int timeout = 100000;	while (timeout-- > 0) {		if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1))			return 0;		cond_resched();	}	snd_printd("es1968: ac97 timeout\n");	return 1; /* timeout */}static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val){	struct es1968 *chip = ac97->private_data;	unsigned long flags;	snd_es1968_ac97_wait(chip);	/* Write the bus */	spin_lock_irqsave(&chip->ac97_lock, flags);	outw(val, chip->io_port + ESM_AC97_DATA);	/*msleep(1);*/	outb(reg, chip->io_port + ESM_AC97_INDEX);	/*msleep(1);*/	spin_unlock_irqrestore(&chip->ac97_lock, flags);}static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg){	u16 data = 0;	struct es1968 *chip = ac97->private_data;	unsigned long flags;	snd_es1968_ac97_wait(chip);	spin_lock_irqsave(&chip->ac97_lock, flags);	outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);	/*msleep(1);*/	if (! snd_es1968_ac97_wait(chip)) {		data = inw(chip->io_port + ESM_AC97_DATA);		/*msleep(1);*/	}	spin_unlock_irqrestore(&chip->ac97_lock, flags);	return data;}/* no spinlock */static void apu_index_set(struct es1968 *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(struct es1968 *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(struct es1968 *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);}static void apu_set_register(struct es1968 *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(struct es1968 *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);}static u16 apu_get_register(struct es1968 *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(struct es1968 *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(struct es1968 *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(struct es1968 *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(struct es1968 *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(struct es1968 *chip){	u16 reg;	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);}static void snd_es1968_bob_start(struct es1968 *chip){	int prescale;	int divide;	/* 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--;	__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);}/* call with substream spinlock */static void snd_es1968_bob_inc(struct es1968 *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(struct es1968 *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 */		int max_freq = ESM_BOB_FREQ;		struct esschan *es;		list_for_each_entry(es, &chip->substream_list, 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(struct es1968 *chip, struct esschan *es,			 struct snd_pcm_runtime *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)		freq = ESM_BOB_FREQ;	else if (freq > ESM_BOB_FREQ_MAX)		freq = ESM_BOB_FREQ_MAX;	return freq;}/************* *  PCM Part * *************/static u32 snd_es1968_compute_rate(struct es1968 *chip, u32 freq){	u32 rate = (freq << 16) / chip->clock;#if 0 /* XXX: do we need this? */ 	if (rate > 0x10000)		rate = 0x10000;#endif	return rate;}/* get current pointer */static inline unsigned intsnd_es1968_get_dma_ptr(struct es1968 *chip, struct esschan *es){	unsigned int offset;	offset = apu_get_register(chip, es->apu[0], 5);	offset -= es->base[0];	return (offset & 0xFFFE);	/* hardware is in words */}static void snd_es1968_apu_set_freq(struct es1968 *chip, int apu, int freq){	apu_set_register(chip, apu, 2,			   (apu_get_register(chip, apu, 2) & 0x00FF) |			   ((freq & 0xff) << 8) | 0x10);	apu_set_register(chip, apu, 3, freq >> 8);}/* spin lock held */static inline void snd_es1968_trigger_apu(struct es1968 *esm, int apu, int mode){	/* set the APU mode */	__apu_set_register(esm, apu, 0,			   (__apu_get_register(esm, apu, 0) & 0xff0f) |			   (mode << 4));}static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es){

⌨️ 快捷键说明

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