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

📄 sb_common.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sound/sb_common.c * * Common routines for Sound Blaster compatible cards. * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts *                       for full duplex support ( only sb16 by now ) * Rolf Fokkens:	 Added (BETA?) support for ES1887 chips. * (fokkensr@vertis.nl)	 Which means: You can adjust the recording levels. * * 2000/01/18 - separated sb_card and sb_common - * Jeff Garzik <jgarzik@mandrakesoft.com> * * 2000/09/18 - got rid of attach_uart401 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include "sound_config.h"#include "sound_firmware.h"#include "mpu401.h"#include "sb_mixer.h"#include "sb.h"#include "sb_ess.h"/* * global module flag */int sb_be_quiet = 0;static sb_devc *detected_devc = NULL;	/* For communication from probe to init */static sb_devc *last_devc = NULL;	/* For MPU401 initialization */static unsigned char jazz_irq_bits[] = {	0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6};static unsigned char jazz_dma_bits[] = {	0, 1, 0, 2, 0, 3, 0, 4};void *smw_free = NULL;/* * Jazz16 chipset specific control variables */static int jazz16_base = 0;		/* Not detected */static unsigned char jazz16_bits = 0;	/* I/O relocation bits *//* * Logitech Soundman Wave specific initialization code */#ifdef SMW_MIDI0001_INCLUDED#include "smw-midi0001.h"#elsestatic unsigned char *smw_ucode = NULL;static int      smw_ucodeLen = 0;#endifsb_devc *last_sb = NULL;		/* Last sb loaded */int sb_dsp_command(sb_devc * devc, unsigned char val){	int i;	unsigned long limit;	limit = jiffies + HZ / 10;	/* Timeout */		/*	 * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes	 * called while interrupts are disabled. This means that the timer is	 * disabled also. However the timeout situation is a abnormal condition.	 * Normally the DSP should be ready to accept commands after just couple of	 * loops.	 */	for (i = 0; i < 500000 && (limit-jiffies)>0; i++)	{		if ((inb(DSP_STATUS) & 0x80) == 0)		{			outb((val), DSP_COMMAND);			return 1;		}	}	printk(KERN_WARNING "Sound Blaster:  DSP command(%x) timeout.\n", val);	return 0;}int sb_dsp_get_byte(sb_devc * devc){	int i;	for (i = 1000; i; i--)	{		if (inb(DSP_DATA_AVAIL) & 0x80)			return inb(DSP_READ);	}	return 0xffff;}static void sb_intr (sb_devc *devc){	int status;	unsigned char   src = 0xff;	if (devc->model == MDL_SB16)	{		src = sb_getmixer(devc, IRQ_STAT);	/* Interrupt source register */		if (src & 4)						/* MPU401 interrupt */			if(devc->midi_irq_cookie)				uart401intr(devc->irq, devc->midi_irq_cookie, NULL);		if (!(src & 3))			return;	/* Not a DSP interrupt */	}	if (devc->intr_active && (!devc->fullduplex || (src & 0x01)))	{		switch (devc->irq_mode)		{			case IMODE_OUTPUT:				DMAbuf_outputintr(devc->dev, 1);				break;			case IMODE_INPUT:				DMAbuf_inputintr(devc->dev);				break;			case IMODE_INIT:				break;			case IMODE_MIDI:				sb_midi_interrupt(devc);				break;			default:				/* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */				;		}	}	else if (devc->intr_active_16 && (src & 0x02))	{		switch (devc->irq_mode_16)		{			case IMODE_OUTPUT:				DMAbuf_outputintr(devc->dev, 1);				break;			case IMODE_INPUT:				DMAbuf_inputintr(devc->dev);				break;			case IMODE_INIT:				break;			default:				/* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */				;		}	}	/*	 * Acknowledge interrupts 	 */	if (src & 0x01)		status = inb(DSP_DATA_AVAIL);	if (devc->model == MDL_SB16 && src & 0x02)		status = inb(DSP_DATA_AVL16);}static void pci_intr(sb_devc *devc){	int src = inb(devc->pcibase+0x1A);	src&=3;	if(src)		sb_intr(devc);}static void sbintr(int irq, void *dev_id, struct pt_regs *dummy){	sb_devc *devc = dev_id;	devc->irq_ok = 1;	switch (devc->model) {	case MDL_ESSPCI:		pci_intr (devc);		break;			case MDL_ESS:		ess_intr (devc);		break;	default:		sb_intr (devc);		break;	}}int sb_dsp_reset(sb_devc * devc){	int loopc;	DEB(printk("Entered sb_dsp_reset()\n"));	if (devc->model == MDL_ESS) return ess_dsp_reset (devc);	/* This is only for non-ESS chips */	outb(1, DSP_RESET);	udelay(10);	outb(0, DSP_RESET);	udelay(30);	for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++);	if (inb(DSP_READ) != 0xAA)	{		DDB(printk("sb: No response to RESET\n"));		return 0;	/* Sorry */	}	DEB(printk("sb_dsp_reset() OK\n"));	return 1;}static void dsp_get_vers(sb_devc * devc){	int i;	unsigned long   flags;	DDB(printk("Entered dsp_get_vers()\n"));	save_flags(flags);	cli();	devc->major = devc->minor = 0;	sb_dsp_command(devc, 0xe1);	/* Get version */	for (i = 100000; i; i--)	{		if (inb(DSP_DATA_AVAIL) & 0x80)		{			if (devc->major == 0)				devc->major = inb(DSP_READ);			else			{				devc->minor = inb(DSP_READ);				break;			}		}	}	DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor));	restore_flags(flags);}static int sb16_set_dma_hw(sb_devc * devc){	int bits;	if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3)	{		printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8);		return 0;	}	bits = (1 << devc->dma8);	if (devc->dma16 >= 5 && devc->dma16 <= 7)		bits |= (1 << devc->dma16);	sb_setmixer(devc, DMA_NR, bits);	return 1;}static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config){	/*	 * This routine initializes new MIDI port setup register of SB Vibra (CT2502).	 */	unsigned char   bits = sb_getmixer(devc, 0x84) & ~0x06;	switch (hw_config->io_base)	{		case 0x300:			sb_setmixer(devc, 0x84, bits | 0x04);			break;		case 0x330:			sb_setmixer(devc, 0x84, bits | 0x00);			break;		default:			sb_setmixer(devc, 0x84, bits | 0x02);		/* Disable MPU */			printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);	}}static int sb16_set_irq_hw(sb_devc * devc, int level){	int ival;	switch (level)	{		case 5:			ival = 2;			break;		case 7:			ival = 4;			break;		case 9:			ival = 1;			break;		case 10:			ival = 8;			break;		default:			printk(KERN_ERR "SB16: Invalid IRQ%d\n", level);			return 0;	}	sb_setmixer(devc, IRQ_NR, ival);	return 1;}static void relocate_Jazz16(sb_devc * devc, struct address_info *hw_config){	unsigned char bits = 0;	unsigned long flags;	if (jazz16_base != 0 && jazz16_base != hw_config->io_base)		return;	switch (hw_config->io_base)	{		case 0x220:			bits = 1;			break;		case 0x240:			bits = 2;			break;		case 0x260:			bits = 3;			break;		default:			return;	}	bits = jazz16_bits = bits << 5;	jazz16_base = hw_config->io_base;	/*	 *	Magic wake up sequence by writing to 0x201 (aka Joystick port)	 */	save_flags(flags);	cli();	outb((0xAF), 0x201);	outb((0x50), 0x201);	outb((bits), 0x201);	restore_flags(flags);}static int init_Jazz16(sb_devc * devc, struct address_info *hw_config){	char name[100];	/*	 * First try to check that the card has Jazz16 chip. It identifies itself	 * by returning 0x12 as response to DSP command 0xfa.	 */	if (!sb_dsp_command(devc, 0xfa))		return 0;	if (sb_dsp_get_byte(devc) != 0x12)		return 0;	/*	 * OK so far. Now configure the IRQ and DMA channel used by the card.	 */	if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0)	{		printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq);		return 0;	}	if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0)	{		  printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma);		  return 0;	}	if (hw_config->dma2 < 0)	{		printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n");		return 0;	}	if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0)	{		printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2);		return 0;	}	devc->dma16 = hw_config->dma2;	if (!sb_dsp_command(devc, 0xfb))		return 0;	if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] |			(jazz_dma_bits[hw_config->dma2] << 4)))		return 0;	if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq]))		return 0;	/*	 * Now we have configured a standard Jazz16 device. 	 */	devc->model = MDL_JAZZ;	strcpy(name, "Jazz16");	hw_config->name = "Jazz16";	devc->caps |= SB_NO_MIDI;	return 1;}static void relocate_ess1688(sb_devc * devc){	unsigned char bits;	switch (devc->base)	{		case 0x220:			bits = 0x04;			break;		case 0x230:			bits = 0x05;			break;		case 0x240:			bits = 0x06;			break;		case 0x250:			bits = 0x07;			break;		default:			return;	/* Wrong port */	}	DDB(printk("Doing ESS1688 address selection\n"));		/*	 * ES1688 supports two alternative ways for software address config.	 * First try the so called Read-Sequence-Key method.	 */	/* Reset the sequence logic */	inb(0x229);	inb(0x229);	inb(0x229);	/* Perform the read sequence */	inb(0x22b);	inb(0x229);	inb(0x22b);	inb(0x229);	inb(0x229);	inb(0x22b);	inb(0x229);	/* Select the base address by reading from it. Then probe using the port. */	inb(devc->base);	if (sb_dsp_reset(devc))	/* Bingo */		return;#if 0				/* This causes system lockups (Nokia 386/25 at least) */	/*	 * The last resort is the system control register method.	 */	outb((0x00), 0xfb);	/* 0xFB is the unlock register */	outb((0x00), 0xe0);	/* Select index 0 */	outb((bits), 0xe1);	/* Write the config bits */	outb((0x00), 0xf9);	/* 0xFB is the lock register */#endif}int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo){	sb_devc sb_info;	sb_devc *devc = &sb_info;	memset((char *) &sb_info, 0, sizeof(sb_info));	/* Zero everything */	/* Copy module options in place */	if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options));	sb_info.my_mididev = -1;	sb_info.my_mixerdev = -1;	sb_info.dev = -1;	/*	 * Initialize variables 	 */		DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base));	if (check_region(hw_config->io_base, 16))	{#ifdef MODULE		printk(KERN_INFO "sb: I/O region in use.\n");#endif		return 0;	}	devc->type = hw_config->card_subtype;	devc->base = hw_config->io_base;	devc->irq = hw_config->irq;	devc->dma8 = hw_config->dma;	devc->dma16 = -1;	devc->pcibase = pciio;		if(pci == SB_PCI_ESSMAESTRO)	{		devc->model = MDL_ESSPCI;		devc->caps |= SB_PCI_IRQ;		hw_config->driver_use_1 |= SB_PCI_IRQ;		hw_config->card_subtype	= MDL_ESSPCI;	}		if(pci == SB_PCI_YAMAHA)	{		devc->model = MDL_YMPCI;		devc->caps |= SB_PCI_IRQ;		hw_config->driver_use_1 |= SB_PCI_IRQ;		hw_config->card_subtype	= MDL_YMPCI;				printk("Yamaha PCI mode.\n");	}		if (devc->sbmo.acer)	{		cli();		inb(devc->base + 0x09);		inb(devc->base + 0x09);		inb(devc->base + 0x09);		inb(devc->base + 0x0b);		inb(devc->base + 0x09);		inb(devc->base + 0x0b);		inb(devc->base + 0x09);		inb(devc->base + 0x09);		inb(devc->base + 0x0b);		inb(devc->base + 0x09);		inb(devc->base + 0x00);		sti();	}	/*	 * Detect the device	 */	if (sb_dsp_reset(devc))		dsp_get_vers(devc);	else		devc->major = 0;	if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW)		if (devc->major == 0 || (devc->major == 3 && devc->minor == 1))			relocate_Jazz16(devc, hw_config);	if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0))		relocate_ess1688(devc);	if (!sb_dsp_reset(devc))	{		DDB(printk("SB reset failed\n"));#ifdef MODULE		printk(KERN_INFO "sb: dsp reset failed.\n");#endif		return 0;	}	if (devc->major == 0)		dsp_get_vers(devc);	if (devc->major == 3 && devc->minor == 1)	{		if (devc->type == MDL_AZTECH)		/* SG Washington? */		{			if (sb_dsp_command(devc, 0x09))				if (sb_dsp_command(devc, 0x00))	/* Enter WSS mode */				{					int i;					/* Have some delay */					for (i = 0; i < 10000; i++)						inb(DSP_DATA_AVAIL);					devc->caps = SB_NO_AUDIO | SB_NO_MIDI;	/* Mixer only */					devc->model = MDL_AZTECH;				}		}	}		if(devc->type == MDL_ESSPCI)		devc->model = MDL_ESSPCI;			if(devc->type == MDL_YMPCI)	{		printk("YMPCI selected\n");		devc->model = MDL_YMPCI;	}			/*	 * Save device information for sb_dsp_init()	 */	detected_devc = (sb_devc *)kmalloc(sizeof(sb_devc), GFP_KERNEL);	if (detected_devc == NULL)	{		printk(KERN_ERR "sb: Can't allocate memory for device information\n");		return 0;	}	memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc));	MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));	return 1;}int sb_dsp_init(struct address_info *hw_config, struct module *owner){	sb_devc *devc;	char name[100];	extern int sb_be_quiet;	int	mixer22, mixer30;	/* * Check if we had detected a SB device earlier

⌨️ 快捷键说明

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