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

📄 wavfront.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	case SNDCTL_SEQ_PERCMODE:		return 0; /* don't force an error */		break;	case SNDCTL_SYNTH_MEMAVL:		if ((dev.freemem = wavefront_freemem ()) < 0) {			printk (KERN_ERR LOGNAME "cannot get memory size\n");			return -EIO;		} else {			return dev.freemem;		}		break;	case SNDCTL_SYNTH_CONTROL:		copy_from_user (&wc, arg, sizeof (wc));		if ((err = wavefront_synth_control (cmd, &wc)) == 0) {			copy_to_user (arg, &wc, sizeof (wc));		}		return err;	default:		return -(EINVAL);	}}intwavefront_oss_load_patch (int devno, int format, const char *addr,			  int offs, int count, int pmgr_flag){	if (format == SYSEX_PATCH) {	/* Handled by midi_synth.c */		if (midi_load_patch == NULL) {			printk (KERN_ERR LOGNAME				"SYSEX not loadable: "				"no midi patch loader!\n");			return -(EINVAL);		}		return midi_load_patch (devno, format, addr,					offs, count, pmgr_flag);	} else if (format == GUS_PATCH) {		return wavefront_load_gus_patch (devno, format,						 addr, offs, count, pmgr_flag);	} else if (format != WAVEFRONT_PATCH) {		printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);		return -(EINVAL);	}	if (count < sizeof (wavefront_patch_info)) {		printk (KERN_ERR LOGNAME "sample header too short\n");		return -(EINVAL);	}	/* "addr" points to a user-space wavefront_patch_info */	return wavefront_load_patch (addr);}	static struct synth_operations wavefront_operations ={	owner:		THIS_MODULE,	id:		"WaveFront",	info:		&wavefront_info,	midi_dev:	0,	synth_type:	SYNTH_TYPE_SAMPLE,	synth_subtype:	SAMPLE_TYPE_WAVEFRONT,	open:		wavefront_oss_open,	close:		wavefront_oss_close,	ioctl:		wavefront_oss_ioctl,	kill_note:	midi_synth_kill_note,	start_note:	midi_synth_start_note,	set_instr:	midi_synth_set_instr,	reset:		midi_synth_reset,	load_patch:	midi_synth_load_patch,	aftertouch:	midi_synth_aftertouch,	controller:	midi_synth_controller,	panning:	midi_synth_panning,	bender:		midi_synth_bender,	setup_voice:	midi_synth_setup_voice};#endif OSS_SUPPORT_SEQ#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALLstatic void __init attach_wavefront (struct address_info *hw_config){    (void) install_wavefront ();}static int __init probe_wavefront (struct address_info *hw_config){    return !detect_wavefront (hw_config->irq, hw_config->io_base);}static void __exit unload_wavefront (struct address_info *hw_config) {    (void) uninstall_wavefront ();}#endif OSS_SUPPORT_STATIC_INSTALL/***********************************************************************//* WaveFront: Linux modular sound kernel installation interface        *//***********************************************************************/voidwavefrontintr (int irq, void *dev_id, struct pt_regs *dummy){	struct wf_config *hw = dev_id;	/*	   Some comments on interrupts. I attempted a version of this	   driver that used interrupts throughout the code instead of	   doing busy and/or sleep-waiting. Alas, it appears that once	   the Motorola firmware is downloaded, the card *never*	   generates an RX interrupt. These are successfully generated	   during firmware loading, and after that wavefront_status()	   reports that an interrupt is pending on the card from time	   to time, but it never seems to be delivered to this	   driver. Note also that wavefront_status() continues to	   report that RX interrupts are enabled, suggesting that I	   didn't goof up and disable them by mistake.	   Thus, I stepped back to a prior version of	   wavefront_wait(), the only place where this really	   matters. Its sad, but I've looked through the code to check	   on things, and I really feel certain that the Motorola	   firmware prevents RX-ready interrupts.	*/	if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {		return;	}	hw->irq_ok = 1;	hw->irq_cnt++;	wake_up_interruptible (&hw->interrupt_sleeper);}/* STATUS REGISTER 0 Host Rx Interrupt Enable (1=Enabled)1 Host Rx Register Full (1=Full)2 Host Rx Interrupt Pending (1=Interrupt)3 Unused4 Host Tx Interrupt (1=Enabled)5 Host Tx Register empty (1=Empty)6 Host Tx Interrupt Pending (1=Interrupt)7 Unused*/intwavefront_interrupt_bits (int irq){	int bits;	switch (irq) {	case 9:		bits = 0x00;		break;	case 5:		bits = 0x08;		break;	case 12:		bits = 0x10;		break;	case 15:		bits = 0x18;		break;		default:		printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);		bits = -1;	}	return bits;}voidwavefront_should_cause_interrupt (int val, int port, int timeout){	unsigned long flags;	save_flags (flags);	cli();	dev.irq_ok = 0;	outb (val,port);	interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);	restore_flags (flags);}static int __init wavefront_hw_reset (void){	int bits;	int hwv[2];	unsigned long irq_mask;	short reported_irq;	/* IRQ already checked in init_module() */	bits = wavefront_interrupt_bits (dev.irq);	printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");	sti ();	irq_mask = probe_irq_on ();	outb (0x0, dev.control_port); 	outb (0x80 | 0x40 | bits, dev.data_port);		wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,					 dev.control_port,					 (reset_time*HZ)/100);	reported_irq = probe_irq_off (irq_mask);	if (reported_irq != dev.irq) {		if (reported_irq == 0) {			printk (KERN_ERR LOGNAME				"No unassigned interrupts detected "				"after h/w reset\n");		} else if (reported_irq < 0) {			printk (KERN_ERR LOGNAME				"Multiple unassigned interrupts detected "				"after h/w reset\n");		} else {			printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "				"value provided (%d)\n", reported_irq,				dev.irq);		}		dev.irq = -1;		return 1;	} else {		printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",			reported_irq);	}	if (request_irq (dev.irq, wavefrontintr,			 SA_INTERRUPT|SA_SHIRQ,			 "wavefront synth", &dev) < 0) {		printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",			dev.irq);		return 1;	}	/* try reset of port */      	outb (0x0, dev.control_port);   	/* At this point, the board is in reset, and the H/W initialization	   register is accessed at the same address as the data port.     	   Bit 7 - Enable IRQ Driver		   0 - Tri-state the Wave-Board drivers for the PC Bus IRQs	   1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus.     	   Bit 6 - MIDI Interface Select	   0 - Use the MIDI Input from the 26-pin WaveBlaster	   compatible header as the serial MIDI source	   1 - Use the MIDI Input from the 9-pin D connector as the	   serial MIDI source.     	   Bits 5:3 - IRQ Selection	   0 0 0 - IRQ 2/9	   0 0 1 - IRQ 5	   0 1 0 - IRQ 12	   0 1 1 - IRQ 15	   1 0 0 - Reserved	   1 0 1 - Reserved	   1 1 0 - Reserved	   1 1 1 - Reserved     	   Bits 2:1 - Reserved	   Bit 0 - Disable Boot ROM	   0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM	   1 - memory accesses to 03FC30-03FFFFH are directed to external 	   storage.     	*/	/* configure hardware: IRQ, enable interrupts, 	   plus external 9-pin MIDI interface selected	*/	outb (0x80 | 0x40 | bits, dev.data_port);	  	/* CONTROL REGISTER	   0 Host Rx Interrupt Enable (1=Enabled)      0x1	   1 Unused                                    0x2	   2 Unused                                    0x4	   3 Unused                                    0x8	   4 Host Tx Interrupt Enable                 0x10	   5 Mute (0=Mute; 1=Play)                    0x20	   6 Master Interrupt Enable (1=Enabled)      0x40	   7 Master Reset (0=Reset; 1=Run)            0x80	   Take us out of reset, mute output, master + TX + RX interrupts on.	   	   We'll get an interrupt presumably to tell us that the TX	   register is clear.	*/	wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,					 dev.control_port,					 (reset_time*HZ)/100);	/* Note: data port is now the data port, not the h/w initialization	   port.	 */	if (!dev.irq_ok) {		printk (KERN_WARNING LOGNAME			"intr not received after h/w un-reset.\n");		goto gone_bad;	} 	dev.interrupts_on = 1;		/* Note: data port is now the data port, not the h/w initialization	   port.	   At this point, only "HW VERSION" or "DOWNLOAD OS" commands	   will work. So, issue one of them, and wait for TX	   interrupt. This can take a *long* time after a cold boot,	   while the ISC ROM does its RAM test. The SDK says up to 4	   seconds - with 12MB of RAM on a Tropez+, it takes a lot	   longer than that (~16secs). Note that the card understands	   the difference between a warm and a cold boot, so	   subsequent ISC2115 reboots (say, caused by module	   reloading) will get through this much faster.	   XXX Interesting question: why is no RX interrupt received first ?	*/	wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, 					 dev.data_port, ramcheck_time*HZ);	if (!dev.irq_ok) {		printk (KERN_WARNING LOGNAME			"post-RAM-check interrupt not received.\n");		goto gone_bad;	} 	if (!wavefront_wait (STAT_CAN_READ)) {		printk (KERN_WARNING LOGNAME			"no response to HW version cmd.\n");		goto gone_bad;	}		if ((hwv[0] = wavefront_read ()) == -1) {		printk (KERN_WARNING LOGNAME			"board not responding correctly.\n");		goto gone_bad;	}	if (hwv[0] == 0xFF) { /* NAK */		/* Board's RAM test failed. Try to read error code,		   and tell us about it either way.		*/				if ((hwv[0] = wavefront_read ()) == -1) {			printk (KERN_WARNING LOGNAME "on-board RAM test failed "				"(bad error code).\n");		} else {			printk (KERN_WARNING LOGNAME "on-board RAM test failed "				"(error code: 0x%x).\n",				hwv[0]);		}		goto gone_bad;	}	/* We're OK, just get the next byte of the HW version response */	if ((hwv[1] = wavefront_read ()) == -1) {		printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");		goto gone_bad;	}	printk (KERN_INFO LOGNAME "hardware version %d.%d\n",		hwv[0], hwv[1]);	return 0;     gone_bad:	if (dev.irq >= 0) {		free_irq (dev.irq, &dev);		dev.irq = -1;	}	return (1);}static int __init detect_wavefront (int irq, int io_base){	unsigned char   rbuf[4], wbuf[4];	/* TB docs say the device takes up 8 ports, but we know that	   if there is an FX device present (i.e. a Tropez+) it really	   consumes 16.	*/	if (check_region (io_base, 16)) {		printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "			"already in use - ignored\n", dev.base,			dev.base+15);		return -1;	}  	dev.irq = irq;	dev.base = io_base;	dev.israw = 0;	dev.debug = debug_default;	dev.interrupts_on = 0;	dev.irq_cnt = 0;	dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */	if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {		dev.fw_version[0] = rbuf[0];		dev.fw_version[1] = rbuf[1];		printk (KERN_INFO LOGNAME			"firmware %d.%d already loaded.\n",			rbuf[0], rbuf[1]);		/* check that a command actually works */      		if (wavefront_cmd (WFC_HARDWARE_VERSION,				   rbuf, wbuf) == 0) {			dev.hw_version[0] = rbuf[0];			dev.hw_version[1] = rbuf[1];		} else {			printk (KERN_WARNING LOGNAME "not raw, but no "				"hardware version!\n");			return 0;		}		if (!wf_raw) {			return 1;		} else {			printk (KERN_INFO LOGNAME				"reloading firmware anyway.\n");			dev.israw = 1;		}	} else {		dev.israw = 1;		printk (KERN_INFO LOGNAME			"no response to firmware probe, assume raw.\n");	}	init_waitqueue_head (&dev.interrupt_sleeper);	if (wavefront_hw_reset ()) {		printk (KERN_WARNING LOGNAME "hardware reset failed\n");		return 0;	}	/* Check for FX device, present only on Tropez+ */	dev.has_fx = (detect_wffx () == 0);	return 1;}#include "os.h"#define __KERNEL_SYSCALLS__#include <linux/fs.h>#include <linux/mm.h>#include <linux/malloc.h>#include <linux/unistd.h>#include <asm/uaccess.h>static int errno; static intwavefront_download_firmware (char *path){	unsigned char section[WF_SECTION_MAX];	char section_length; /* yes, just a char; max value is WF_SECTION_MAX */	int section_cnt_downloaded = 0;	int fd;	int c;	int i;	mm_segment_t fs;	/* This tries to be a bit cleverer than the stuff Alan Cox did for	   the generic sound firmware, in that it actually knows	   something about the structure of the Motorola firmware. In	   particular, it uses a version that has been stripped of the	   20K of useless header information, and had section lengths	   added, making it possible to load the entire OS without any	   [kv]malloc() activity, since the longest entity we ever read is	   42 bytes (well, WF_SECTION_MAX) long.	*/	fs = get_fs();	set_fs (get_ds());	if ((fd = open (path, 0, 0)) < 0) {		printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",			path)

⌨️ 快捷键说明

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