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

📄 sscape.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/sscape.c * * Low level driver for Ensoniq SoundScape * * * 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. * * * Thomas Sailer   	: ioctl code reworked (vmalloc/vfree removed) * Sergey Smitienko	: ensoniq p'n'p support * Christoph Hellwig	: adapted to module_init/module_exit * Bartlomiej Zolnierkiewicz : added __init to attach_sscape() * Chris Rankin		: Specify that this module owns the coprocessor * Arnaldo C. de Melo	: added missing restore_flags in sscape_pnp_upload_file */#include <linux/init.h>#include <linux/module.h>#include "sound_config.h"#include "sound_firmware.h"#include <linux/types.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/fcntl.h>#include <linux/ctype.h>#include <linux/stddef.h>#include <linux/kmod.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/segment.h>#include <linux/wait.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/wrapper.h>#include "coproc.h"#include "ad1848.h"#include "mpu401.h"/* *    I/O ports */#define MIDI_DATA       0#define MIDI_CTRL       1#define HOST_CTRL       2#define TX_READY	0x02#define RX_READY	0x01#define HOST_DATA       3#define ODIE_ADDR       4#define ODIE_DATA       5/* *    Indirect registers */#define GA_INTSTAT_REG	0#define GA_INTENA_REG	1#define GA_DMAA_REG	2#define GA_DMAB_REG	3#define GA_INTCFG_REG	4#define GA_DMACFG_REG	5#define GA_CDCFG_REG	6#define GA_SMCFGA_REG	7#define GA_SMCFGB_REG	8#define GA_HMCTL_REG	9/* * DMA channel identifiers (A and B) */#define SSCAPE_DMA_A	0#define SSCAPE_DMA_B	1#define PORT(name)	(devc->base+name)/* * Host commands recognized by the OBP microcode */ #define CMD_GEN_HOST_ACK	0x80#define CMD_GEN_MPU_ACK		0x81#define CMD_GET_BOARD_TYPE	0x82#define CMD_SET_CONTROL		0x88	/* Old firmware only */#define CMD_GET_CONTROL		0x89	/* Old firmware only */#define CTL_MASTER_VOL		0#define CTL_MIC_MODE		2#define CTL_SYNTH_VOL		4#define CTL_WAVE_VOL		7#define CMD_SET_EXTMIDI		0x8a#define CMD_GET_EXTMIDI		0x8b#define CMD_SET_MT32		0x8c#define CMD_GET_MT32		0x8d#define CMD_ACK			0x80#define	IC_ODIE			1#define	IC_OPUS			2typedef struct sscape_info{	int	base, irq, dma;		int	codec, codec_irq;	/* required to setup pnp cards*/	int	codec_type;	int	ic_type;	char*	raw_buf;	unsigned long	raw_buf_phys;	int	buffsize;		/* -------------------------- */		int	ok;	/* Properly detected */	int	failed;	int	dma_allocated;	int	codec_audiodev;	int	opened;	int	*osp;	int	my_audiodev;} sscape_info;static struct sscape_info adev_info = {	0};static struct sscape_info *devc = &adev_info;static int sscape_mididev = -1;/* Some older cards have assigned interrupt bits differently than new ones */static char valid_interrupts_old[] = {	9, 7, 5, 15};static char valid_interrupts_new[] = {	9, 5, 7, 10};static char *valid_interrupts = valid_interrupts_new;/* *	See the bottom of the driver. This can be set by spea =0/1. */ #ifdef REVEAL_SPEAstatic char old_hardware = 1;#elsestatic char old_hardware = 0;#endifstatic void sleep(unsigned howlong){	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(howlong);}static unsigned char sscape_read(struct sscape_info *devc, int reg){	unsigned long flags;	unsigned char val;	save_flags(flags);	cli();	outb(reg, PORT(ODIE_ADDR));	val = inb(PORT(ODIE_DATA));	restore_flags(flags);	return val;}static void sscape_write(struct sscape_info *devc, int reg, int data){	unsigned long flags;	save_flags(flags);	cli();	outb(reg, PORT(ODIE_ADDR));	outb(data, PORT(ODIE_DATA));	restore_flags(flags);}static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg){	unsigned char res;	unsigned long flags;	save_flags(flags);	cli();		outb( reg, devc -> codec);	res = inb (devc -> codec + 1);	restore_flags(flags);	return res;}static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data){	unsigned long flags;		save_flags(flags);	cli();	outb( reg, devc -> codec);	outb( data, devc -> codec + 1);	restore_flags(flags);}static void host_open(struct sscape_info *devc){	outb((0x00), PORT(HOST_CTRL));	/* Put the board to the host mode */}static void host_close(struct sscape_info *devc){	outb((0x03), PORT(HOST_CTRL));	/* Put the board to the MIDI mode */}static int host_write(struct sscape_info *devc, unsigned char *data, int count){	unsigned long flags;	int i, timeout_val;	save_flags(flags);	cli();	/*	 * Send the command and data bytes	 */	for (i = 0; i < count; i++)	{		for (timeout_val = 10000; timeout_val > 0; timeout_val--)			if (inb(PORT(HOST_CTRL)) & TX_READY)				break;		if (timeout_val <= 0)		{			    restore_flags(flags);			    return 0;		}		outb(data[i], PORT(HOST_DATA));	}	restore_flags(flags);	return 1;}static int host_read(struct sscape_info *devc){	unsigned long flags;	int timeout_val;	unsigned char data;	save_flags(flags);	cli();	/*	 * Read a byte	 */	for (timeout_val = 10000; timeout_val > 0; timeout_val--)		if (inb(PORT(HOST_CTRL)) & RX_READY)			break;	if (timeout_val <= 0)	{		restore_flags(flags);		return -1;	}	data = inb(PORT(HOST_DATA));	restore_flags(flags);	return data;}#if 0 /* unused */static int host_command1(struct sscape_info *devc, int cmd){	unsigned char buf[10];	buf[0] = (unsigned char) (cmd & 0xff);	return host_write(devc, buf, 1);}#endif /* unused */static int host_command2(struct sscape_info *devc, int cmd, int parm1){	unsigned char buf[10];	buf[0] = (unsigned char) (cmd & 0xff);	buf[1] = (unsigned char) (parm1 & 0xff);	return host_write(devc, buf, 2);}static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2){	unsigned char buf[10];	buf[0] = (unsigned char) (cmd & 0xff);	buf[1] = (unsigned char) (parm1 & 0xff);	buf[2] = (unsigned char) (parm2 & 0xff);	return host_write(devc, buf, 3);}static void set_mt32(struct sscape_info *devc, int value){	host_open(devc);	host_command2(devc, CMD_SET_MT32, value ? 1 : 0);	if (host_read(devc) != CMD_ACK)	{		/* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */	}	host_close(devc);}static void set_control(struct sscape_info *devc, int ctrl, int value){	host_open(devc);	host_command3(devc, CMD_SET_CONTROL, ctrl, value);	if (host_read(devc) != CMD_ACK)	{		/* printk( "SNDSCAPE: Setting control (%d) failed\n",  ctrl); */	}	host_close(devc);}static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode){	unsigned char temp;	if (dma_chan != SSCAPE_DMA_A)	{		printk(KERN_WARNING "soundscape: Tried to use DMA channel  != A. Why?\n");		return;	}	audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE;	DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode);	audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE;	temp = devc->dma << 4;	/* Setup DMA channel select bits */	if (devc->dma <= 3)		temp |= 0x80;	/* 8 bit DMA channel */	temp |= 1;		/* Trigger DMA */	sscape_write(devc, GA_DMAA_REG, temp);	temp &= 0xfe;		/* Clear DMA trigger */	sscape_write(devc, GA_DMAA_REG, temp);}static int verify_mpu(struct sscape_info *devc){	/*	 * The SoundScape board could be in three modes (MPU, 8250 and host).	 * If the card is not in the MPU mode, enabling the MPU driver will	 * cause infinite loop (the driver believes that there is always some	 * received data in the buffer.	 *	 * Detect this by looking if there are more than 10 received MIDI bytes	 * (0x00) in the buffer.	 */	int i;	for (i = 0; i < 10; i++)	{		if (inb(devc->base + HOST_CTRL) & 0x80)			return 1;		if (inb(devc->base) != 0x00)			return 1;	}	printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n");	return 0;}static int sscape_coproc_open(void *dev_info, int sub_device){	if (sub_device == COPR_MIDI)	{		set_mt32(devc, 0);		if (!verify_mpu(devc))			return -EIO;	}	return 0;}static void sscape_coproc_close(void *dev_info, int sub_device){	struct sscape_info *devc = dev_info;	unsigned long   flags;	save_flags(flags);	cli();	if (devc->dma_allocated)	{		sscape_write(devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */		devc->dma_allocated = 0;	}	restore_flags(flags);	return;}static void sscape_coproc_reset(void *dev_info){}static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag){	unsigned long flags;	unsigned char temp;	volatile int done, timeout_val;	static unsigned char codec_dma_bits = 0;	if (flag & CPF_FIRST)	{		/*		 * First block. Have to allocate DMA and to reset the board		 * before continuing.		 */		save_flags(flags);		cli();		codec_dma_bits = sscape_read(devc, GA_CDCFG_REG);		if (devc->dma_allocated == 0)			devc->dma_allocated = 1;		restore_flags(flags);		sscape_write(devc, GA_HMCTL_REG, 			(temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f);	/*Reset */		for (timeout_val = 10000; timeout_val > 0; timeout_val--)			sscape_read(devc, GA_HMCTL_REG);	/* Delay */		/* Take board out of reset */		sscape_write(devc, GA_HMCTL_REG,			(temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80);	}	/*	 * Transfer one code block using DMA	 */	if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL)	{		printk(KERN_WARNING "soundscape: DMA buffer not available\n");		return 0;	}	memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size);	save_flags(flags);	cli();		/******** INTERRUPTS DISABLED NOW ********/		do_dma(devc, SSCAPE_DMA_A,	       audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys,	       size, DMA_MODE_WRITE);	/*	 * Wait until transfer completes.	 */		done = 0;	timeout_val = 30;	while (!done && timeout_val-- > 0)	{		int resid;		if (HZ / 50)			sleep(HZ / 50);		clear_dma_ff(devc->dma);		if ((resid = get_dma_residue(devc->dma)) == 0)			done = 1;	}	restore_flags(flags);	if (!done)		return 0;	if (flag & CPF_LAST)	{		/*		 * Take the board out of reset		 */		outb((0x00), PORT(HOST_CTRL));		outb((0x00), PORT(MIDI_CTRL));		temp = sscape_read(devc, GA_HMCTL_REG);		temp |= 0x40;		sscape_write(devc, GA_HMCTL_REG, temp);	/* Kickstart the board */		/*		 * Wait until the ODB wakes up		 */		save_flags(flags);		cli();		done = 0;		timeout_val = 5 * HZ;		while (!done && timeout_val-- > 0)		{			unsigned char x;						sleep(1);			x = inb(PORT(HOST_DATA));			if (x == 0xff || x == 0xfe)		/* OBP startup acknowledge */			{				DDB(printk("Soundscape: Acknowledge = %x\n", x));

⌨️ 快捷键说明

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