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

📄 sbc.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *      sbc.c  --  Linux soundcard HF FSK driver,  *                 Soundblaster specific functions. * *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch) *        Swiss Federal Institute of Technology (ETH), Electronics Lab * *      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., 675 Mass Ave, Cambridge, MA 02139, USA. * * *//*****************************************************************************/     #include <linux/types.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/hfmodem.h>#include <asm/io.h>#include <asm/dma.h>/* --------------------------------------------------------------------- *//*  * the sbc converter's registers  */#define DSP_RESET(iobase)        (iobase+0x6)#define DSP_READ_DATA(iobase)    (iobase+0xa)#define DSP_WRITE_DATA(iobase)   (iobase+0xc)#define DSP_WRITE_STATUS(iobase) (iobase+0xc)#define DSP_DATA_AVAIL(iobase)   (iobase+0xe)#define DSP_MIXER_ADDR(iobase)   (iobase+0x4)#define DSP_MIXER_DATA(iobase)   (iobase+0x5)#define DSP_INTACK_16BIT(iobase) (iobase+0xf)#define SBC_EXTENT               16/* --------------------------------------------------------------------- *//* * SBC commands */#define SBC_OUTPUT             0x14#define SBC_INPUT              0x24#define SBC_BLOCKSIZE          0x48#define SBC_HI_OUTPUT          0x91 #define SBC_HI_INPUT           0x99 #define SBC_LO_OUTPUT_AUTOINIT 0x1c#define SBC_LO_INPUT_AUTOINIT  0x2c#define SBC_HI_OUTPUT_AUTOINIT 0x90 #define SBC_HI_INPUT_AUTOINIT  0x98#define SBC_IMMED_INT          0xf2#define SBC_GET_REVISION       0xe1#define ESS_GET_REVISION       0xe7#define ESS_EXTENDED_MODE      0xc6#define SBC_SPEAKER_ON         0xd1#define SBC_SPEAKER_OFF        0xd3#define SBC_DMA_ON             0xd0#define SBC_DMA_OFF            0xd4#define SBC_SAMPLE_RATE        0x40#define SBC_SAMPLE_RATE_OUT    0x41#define SBC_SAMPLE_RATE_IN     0x42#define SBC_MONO_8BIT          0xa0#define SBC_MONO_16BIT         0xa4#define SBC_STEREO_8BIT        0xa8#define SBC_STEREO_16BIT       0xac#define SBC4_OUT8_AI           0xc6#define SBC4_IN8_AI            0xce#define SBC4_MODE_UNS_MONO     0x00#define SBC4_MODE_SIGN_MONO    0x10#define SBC4_OUT16_AI          0xb6#define SBC4_IN16_AI           0xbe#define SBC4_OUT16_AI_NO_FIFO  0xb4#define SBC4_IN16_AI_NO_FIFO   0xbc/* --------------------------------------------------------------------- */extern const struct hfmodem_scops sbc4_scops;extern const struct hfmodem_scops ess_scops;/* --------------------------------------------------------------------- */static int reset_dsp(struct hfmodem_state *dev){        int i;        outb(1, DSP_RESET(dev->io.base_addr));	udelay(3);        outb(0, DSP_RESET(dev->io.base_addr));        for (i = 0; i < 0xffff; i++)                if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)                        if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa)                                return 1;        return 0;}/* --------------------------------------------------------------------- */static void write_dsp(struct hfmodem_state *dev, unsigned char data){        int i;                for (i = 0; i < 0xffff; i++)                if (!(inb(DSP_WRITE_STATUS(dev->io.base_addr)) & 0x80)) {                        outb(data, DSP_WRITE_DATA(dev->io.base_addr));                        return;                }}/* --------------------------------------------------------------------- */static int read_dsp(struct hfmodem_state *dev, unsigned char *data){        int i;        if (!data)                return 0;        for (i = 0; i < 0xffff; i++)                 if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80) {                        *data = inb(DSP_READ_DATA(dev->io.base_addr));                        return 1;                }        return 0;}/* --------------------------------------------------------------------- */static void write_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char data){	write_dsp(dev, reg);	write_dsp(dev, data);}/* --------------------------------------------------------------------- */static int read_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char *data){	write_dsp(dev, 0xc0);	write_dsp(dev, reg);	return read_dsp(dev, data);}/* --------------------------------------------------------------------- */static int reset_ess(struct hfmodem_state *dev){        int i;        outb(3, DSP_RESET(dev->io.base_addr)); /* reset FIFOs too */	udelay(3);        outb(0, DSP_RESET(dev->io.base_addr));        for (i = 0; i < 0xffff; i++)                if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)                        if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa) {				write_dsp(dev, ESS_EXTENDED_MODE);                                return 1;			}        return 0;}/* --------------------------------------------------------------------- */static int config_resources(struct hfmodem_state *dev){        unsigned char irqreg = 0, dmareg = 0, realirq, realdma;        unsigned long flags;        switch (dev->io.irq) {        case 2:        case 9:                irqreg |= 0x01;                break;        case 5:                irqreg |= 0x02;                break;        case 7:                irqreg |= 0x04;                break;        case 10:                irqreg |= 0x08;                break;                        default:                return -ENODEV;        }        switch (dev->io.dma) {        case 0:                dmareg |= 0x01;                break;        case 1:                dmareg |= 0x02;                break;        case 3:                dmareg |= 0x08;                break;	case 5:		dmareg |= 0x20;		break;			case 6:		dmareg |= 0x40;		break;			case 7:		dmareg |= 0x80;		break;		         default:                return -ENODEV;        }        save_flags(flags);        cli();        outb(0x80, DSP_MIXER_ADDR(dev->io.base_addr));        outb(irqreg, DSP_MIXER_DATA(dev->io.base_addr));        realirq = inb(DSP_MIXER_DATA(dev->io.base_addr));        outb(0x81, DSP_MIXER_ADDR(dev->io.base_addr));        outb(dmareg, DSP_MIXER_DATA(dev->io.base_addr));        realdma = inb(DSP_MIXER_DATA(dev->io.base_addr));        restore_flags(flags);        if ((~realirq) & irqreg || (~realdma) & dmareg) {                printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device "                       "and IRQ/DMA specified wrongly?\n", hfmodem_drvname);                return -EINVAL;        }        return 0;}/* --------------------------------------------------------------------- */extern __inline__ void sbc_int_ack_8bit(struct hfmodem_state *dev){        inb(DSP_DATA_AVAIL(dev->io.base_addr));}/* --------------------------------------------------------------------- */extern __inline__ void sbc_int_ack_16bit(struct hfmodem_state *dev){        inb(DSP_INTACK_16BIT(dev->io.base_addr));}/* --------------------------------------------------------------------- */static void set_mixer(struct hfmodem_state *dev, unsigned char reg, unsigned char data){	outb(reg, DSP_MIXER_ADDR(dev->io.base_addr));	outb(data, DSP_MIXER_DATA(dev->io.base_addr));}	/* --------------------------------------------------------------------- */int hfmodem_sbcprobe(struct hfmodem_state *dev){	unsigned char revhi, revlo, essrevhi, essrevlo, tmp;	int ret;	if (dev->io.base_addr <= 0 || dev->io.base_addr > 0x1000-SBC_EXTENT ||             dev->io.irq < 2 || dev->io.irq > 15 || dev->io.dma > 7 || dev->io.dma == 2)                return -ENXIO;        if (check_region(dev->io.base_addr, SBC_EXTENT))                return -EACCES;        /*         * check if a card is available         */        if (!reset_dsp(dev)) {                printk(KERN_ERR "%s: sbc: no card at io address 0x%x\n", 		       hfmodem_drvname, dev->io.base_addr);                return -ENODEV;        }	set_mixer(dev, 0, 0); /* reset mixer */        write_dsp(dev, SBC_GET_REVISION);        if (!read_dsp(dev, &revhi) || !read_dsp(dev, &revlo))                return -ENODEV;        printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%02d\n", hfmodem_drvname, revhi, revlo);	if (revhi == 3 && revlo == 1) {		write_dsp(dev, ESS_GET_REVISION);		if (!read_dsp(dev, &essrevhi) || !read_dsp(dev, &essrevlo))			return -ENODEV;		if (essrevhi == 0x48 && (essrevlo & 0xf0) == 0x80) {			printk(KERN_INFO "%s: ESS ES488 AudioDrive (rev %d): unsupported.\n",			       hfmodem_drvname, essrevlo & 0x0f);			return -ENODEV;		}		if (essrevhi == 0x68 && (essrevlo & 0xf0) == 0x80) {			printk(KERN_INFO "%s: ESS ES%s688 AudioDrive (rev %d)\n",			       hfmodem_drvname, ((essrevlo & 0x0f) >= 8) ? "1" : "", essrevlo & 0x0f);			if (dev->io.dma > 3) {				printk(KERN_INFO "%s: DMA number out of range\n", hfmodem_drvname);				return -ENXIO;			}			printk(KERN_INFO "%s: ess: irq: ", hfmodem_drvname);			read_ess(dev, 0xb1, &tmp);			switch (tmp & 0xf) {			case 0:				printk("2, 9, \"all others\"");				break;			       			case 5:				printk("5");				break;			case 10:				printk("7");				break;			case 15:				printk("10");				break;			default:				printk("unknown (%d)", tmp & 0xf);				break;			}			printk(" dma: ");			read_ess(dev, 0xb2, &tmp);			switch (tmp & 0xf) {			case 0:				printk("\"all others\"");				break;			       			case 5:				printk("0");				break;			case 10:				printk("1");				break;			case 15:				printk("3");				break;			default:				printk("unknown (%d)", tmp & 0xf);				break;			}			printk("\n");			dev->scops = &ess_scops;			return 0;		}	}	if (revhi < 4) {		printk(KERN_INFO "%s: at least SB16 required\n", hfmodem_drvname);		return -ENODEV;	}	if (dev->io.dma < 4) {

⌨️ 快捷键说明

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