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

📄 mpu401.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 3 页
字号:
	timeout = 50000;retry:	if (timeout-- <= 0)	{		printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd);		return -EIO;	}	save_flags(flags);	cli();	if (!output_ready(devc))	{		  restore_flags(flags);		  goto retry;	}	write_command(devc, cmd->cmd);	ok = 0;	for (timeout = 50000; timeout > 0 && !ok; timeout--)	{		if (input_avail(devc))		{			if (devc->opened && devc->mode == MODE_SYNTH)			{				if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)					ok = 1;			}			else			{				/* Device is not currently open. Use simpler method */				if (read_data(devc) == MPU_ACK)					ok = 1;			}		}	}	if (!ok)	{		restore_flags(flags);		return -EIO;	}	if (cmd->nr_args)	{		for (i = 0; i < cmd->nr_args; i++)		{			for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);			if (!mpu401_out(dev, cmd->data[i]))			{				restore_flags(flags);				printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd);				return -EIO;			}		}	}	ret = 0;	cmd->data[0] = 0;	if (cmd->nr_returns)	{		for (i = 0; i < cmd->nr_returns; i++)		{			ok = 0;			for (timeout = 5000; timeout > 0 && !ok; timeout--)				if (input_avail(devc))				{					cmd->data[i] = read_data(devc);					ok = 1;				}			if (!ok)			{				restore_flags(flags);				return -EIO;			}		}	}	restore_flags(flags);	return ret;}static int mpu_cmd(int dev, int cmd, int data){	int ret;	static mpu_command_rec rec;	rec.cmd = cmd & 0xff;	rec.nr_args = ((cmd & 0xf0) == 0xE0);	rec.nr_returns = ((cmd & 0xf0) == 0xA0);	rec.data[0] = data & 0xff;	if ((ret = mpu401_command(dev, &rec)) < 0)		return ret;	return (unsigned char) rec.data[0];}static int mpu401_prefix_cmd(int dev, unsigned char status){	struct mpu_config *devc = &dev_conf[dev];	if (devc->uart_mode)		return 1;	if (status < 0xf0)	{		if (mpu_cmd(dev, 0xD0, 0) < 0)			return 0;		return 1;	}	switch (status)	{		case 0xF0:			if (mpu_cmd(dev, 0xDF, 0) < 0)				return 0;			return 1;		default:			return 0;	}}static int mpu401_start_read(int dev){	return 0;}static int mpu401_end_read(int dev){	return 0;}static int mpu401_ioctl(int dev, unsigned cmd, caddr_t arg){	struct mpu_config *devc;	mpu_command_rec rec;	int val, ret;	devc = &dev_conf[dev];	switch (cmd) 	{		case SNDCTL_MIDI_MPUMODE:			if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */				printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n");				return -EINVAL;			}			if (get_user(val, (int *)arg))				return -EFAULT;			set_uart_mode(dev, devc, !val);			return 0;		case SNDCTL_MIDI_MPUCMD:			if (copy_from_user(&rec, arg, sizeof(rec)))				return -EFAULT;			if ((ret = mpu401_command(dev, &rec)) < 0)				return ret;			if (copy_to_user(arg, &rec, sizeof(rec)))				return -EFAULT;			return 0;		default:			return -EINVAL;	}}static void mpu401_kick(int dev){}static int mpu401_buffer_status(int dev){	return 0;		/*				 * No data in buffers				 */}static int mpu_synth_ioctl(int dev,		unsigned int cmd, caddr_t arg){	int midi_dev;	struct mpu_config *devc;	midi_dev = synth_devs[dev]->midi_dev;	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)		return -ENXIO;	devc = &dev_conf[midi_dev];	switch (cmd)	{		case SNDCTL_SYNTH_INFO:			memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info));			return 0;		case SNDCTL_SYNTH_MEMAVL:			return 0x7fffffff;		default:			return -EINVAL;	}}static int mpu_synth_open(int dev, int mode){	int midi_dev, err;	struct mpu_config *devc;	struct coproc_operations *coprocessor;	midi_dev = synth_devs[dev]->midi_dev;	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)		return -ENXIO;	devc = &dev_conf[midi_dev];	/*	 *  Verify that the device is really running.	 *  Some devices (such as Ensoniq SoundScape don't	 *  work before the on board processor (OBP) is initialized	 *  by downloading its microcode.	 */	if (!devc->initialized)	{		if (mpu401_status(devc) == 0xff)	/* Bus float */		{			printk(KERN_ERR "mpu401: Device not initialized properly\n");			return -EIO;		}		reset_mpu401(devc);	}	if (devc->opened)		return -EBUSY;	devc->mode = MODE_SYNTH;	devc->synthno = dev;	devc->inputintr = NULL;	coprocessor = midi_devs[midi_dev]->coproc;	if (coprocessor) {		if (coprocessor->owner)			__MOD_INC_USE_COUNT(coprocessor->owner);		if ((err = coprocessor->open(coprocessor->devc, COPR_MIDI)) < 0)		{			printk(KERN_WARNING "mpu401: Can't access coprocessor device\n");			return err;		}	}	devc->opened = mode;	reset_mpu401(devc);	if (mode & OPEN_READ)	{		mpu_cmd(midi_dev, 0x8B, 0);	/* Enable data in stop mode */		mpu_cmd(midi_dev, 0x34, 0);	/* Return timing bytes in stop mode */		mpu_cmd(midi_dev, 0x87, 0);	/* Enable pitch & controller */	}	return 0;}static void mpu_synth_close(int dev){ 	int midi_dev;	struct mpu_config *devc;	struct coproc_operations *coprocessor;	midi_dev = synth_devs[dev]->midi_dev;	devc = &dev_conf[midi_dev];	mpu_cmd(midi_dev, 0x15, 0);	/* Stop recording, playback and MIDI */	mpu_cmd(midi_dev, 0x8a, 0);	/* Disable data in stopped mode */	devc->inputintr = NULL;	coprocessor = midi_devs[midi_dev]->coproc;	if (coprocessor) {		coprocessor->close(coprocessor->devc, COPR_MIDI);		if (coprocessor->owner)			__MOD_DEC_USE_COUNT(coprocessor->owner);	}	devc->opened = 0;	devc->mode = 0;}#define MIDI_SYNTH_NAME	"MPU-401 UART Midi"#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT#include "midi_synth.h"static struct synth_operations mpu401_synth_proto ={	owner:		THIS_MODULE,	id:		"MPU401",	info:		NULL,	midi_dev:	0,	synth_type:	SYNTH_TYPE_MIDI,	synth_subtype:	0,	open:		mpu_synth_open,	close:		mpu_synth_close,	ioctl:		mpu_synth_ioctl,	kill_note:	midi_synth_kill_note,	start_note:	midi_synth_start_note,	set_instr:	midi_synth_set_instr,	reset:		midi_synth_reset,	hw_control:	midi_synth_hw_control,	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,	send_sysex:	midi_synth_send_sysex};static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV];static struct midi_operations mpu401_midi_proto ={	owner:		THIS_MODULE,	info:		{"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},	in_info:	{0},	open:		mpu401_open,	close:		mpu401_close,	ioctl:		mpu401_ioctl,	outputc:	mpu401_out,	start_read:	mpu401_start_read,	end_read:	mpu401_end_read,	kick:		mpu401_kick,	buffer_status:	mpu401_buffer_status,	prefix_cmd:	mpu401_prefix_cmd};static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];static void mpu401_chk_version(int n, struct mpu_config *devc){	int tmp;	unsigned long flags;	devc->version = devc->revision = 0;	save_flags(flags);	cli();	if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)	{		restore_flags(flags);		return;	}	if ((tmp & 0xf0) > 0x20)	/* Why it's larger than 2.x ??? */	{		restore_flags(flags);		return;	}	devc->version = tmp;	if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)	{		devc->version = 0;		restore_flags(flags);		return;	}	devc->revision = tmp;	restore_flags(flags);}void attach_mpu401(struct address_info *hw_config, struct module *owner){	unsigned long flags;	char revision_char;	int m;	struct mpu_config *devc;	hw_config->slots[1] = -1;	m = sound_alloc_mididev();	if (m == -1)	{		printk(KERN_WARNING "MPU-401: Too many midi devices detected\n");		return;	}	devc = &dev_conf[m];	devc->base = hw_config->io_base;	devc->osp = hw_config->osp;	devc->irq = hw_config->irq;	devc->opened = 0;	devc->uart_mode = 0;	devc->initialized = 0;	devc->version = 0;	devc->revision = 0;	devc->capabilities = 0;	devc->timer_flag = 0;	devc->m_busy = 0;	devc->m_state = ST_INIT;	devc->shared_irq = hw_config->always_detect;	devc->irq = hw_config->irq;	if (devc->irq < 0)	{		devc->irq *= -1;		devc->shared_irq = 1;	}	if (!hw_config->always_detect)	{		/* Verify the hardware again */		if (!reset_mpu401(devc))		{			printk(KERN_WARNING "mpu401: Device didn't respond\n");			sound_unload_mididev(m);			return;		}		if (!devc->shared_irq)		{			if (request_irq(devc->irq, mpuintr, 0, "mpu401", (void *)m) < 0)			{				printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);				sound_unload_mididev(m);				return;			}		}		save_flags(flags);		cli();		mpu401_chk_version(m, devc);		if (devc->version == 0)			mpu401_chk_version(m, devc);		restore_flags(flags);	}	request_region(hw_config->io_base, 2, "mpu401");	if (devc->version != 0)		if (mpu_cmd(m, 0xC5, 0) >= 0)	/* Set timebase OK */			if (mpu_cmd(m, 0xE0, 120) >= 0)		/* Set tempo OK */				devc->capabilities |= MPU_CAP_INTLG;	/* Supports intelligent mode */	mpu401_synth_operations[m] = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);	if (mpu401_synth_operations[m] == NULL)	{		sound_unload_mididev(m);		printk(KERN_ERR "mpu401: Can't allocate memory\n");		return;	}	if (!(devc->capabilities & MPU_CAP_INTLG))	/* No intelligent mode */	{		memcpy((char *) mpu401_synth_operations[m],			(char *) &std_midi_synth,			 sizeof(struct synth_operations));	}	else	{		memcpy((char *) mpu401_synth_operations[m],			(char *) &mpu401_synth_proto,			 sizeof(struct synth_operations));	}	if (owner)		mpu401_synth_operations[m]->owner = owner;	memcpy((char *) &mpu401_midi_operations[m],	       (char *) &mpu401_midi_proto,	       sizeof(struct midi_operations));	mpu401_midi_operations[m].converter = mpu401_synth_operations[m];	memcpy((char *) &mpu_synth_info[m],	       (char *) &mpu_synth_info_proto,	       sizeof(struct synth_info));	n_mpu_devs++;	if (devc->version == 0x20 && devc->revision >= 0x07)	/* MusicQuest interface */	{		int ports = (devc->revision & 0x08) ? 32 : 16;		devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |				MPU_CAP_CLS | MPU_CAP_2PORT;		revision_char = (devc->revision == 0x7f) ? 'M' : ' ';		sprintf(mpu_synth_info[m].name, "MQX-%d%c MIDI Interface #%d",				ports,				revision_char,				n_mpu_devs);	}	else	{		revision_char = devc->revision ? devc->revision + '@' : ' ';		if ((int) devc->revision > ('Z' - '@'))			revision_char = '+';		devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;		if (hw_config->name)			sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);		else			sprintf(mpu_synth_info[m].name,				"MPU-401 %d.%d%c Midi interface #%d",				(int) (devc->version & 0xf0) >> 4,				devc->version & 0x0f,				revision_char,				n_mpu_devs);	}	strcpy(mpu401_midi_operations[m].info.name,	       mpu_synth_info[m].name);	conf_printf(mpu_synth_info[m].name, hw_config);	mpu401_synth_operations[m]->midi_dev = devc->devno = m;	mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno];	if (devc->capabilities & MPU_CAP_INTLG)		/* Intelligent mode */		hw_config->slots[2] = mpu_timer_init(m);	midi_devs[m] = &mpu401_midi_operations[devc->devno];		if (owner)		midi_devs[m]->owner = owner;	hw_config->slots[1] = m;	sequencer_init();}static int reset_mpu401(struct mpu_config *devc){	unsigned long flags;	int ok, timeout, n;	int timeout_limit;	/*	 * Send the RESET command. Try again if no success at the first time.	 * (If the device is in the UART mode, it will not ack the reset cmd).	 */	ok = 0;	timeout_limit = devc->initialized ? 30000 : 100000;	devc->initialized = 1;	for (n = 0; n < 2 && !ok; n++)	{		for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)			  ok = output_ready(devc);		write_command(devc, MPU_RESET);	/*							   * Send MPU-401 RESET Command							 */		/*		 * Wait at least 25 msec. This method is not accurate so let's make the		 * loop bit longer. Cannot sleep since this is called during boot.		 */		for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)		{			save_flags(flags);			cli();			if (input_avail(devc))				if (read_data(devc) == MPU_ACK)					ok = 1;			restore_flags(flags);		}	}	devc->m_state = ST_INIT;	devc->m_ptr = 0;	devc->m_left = 0;	devc->last_status = 0;	devc->uart_mode = 0;	return ok;}static void set_uart_mode(int dev, struct mpu_config *devc, int arg){	if (!arg && (devc->capabilities & MPU_CAP_INTLG))		return;	if ((devc->uart_mode == 0) == (arg == 0))		return;		/* Already set */	reset_mpu401(devc);	/* This exits the uart mode */	if (arg)	{		if (mpu_cmd(dev, UART_MODE_ON, 0) < 0)		{			printk(KERN_ERR "mpu401: Can't enter UART mode\n");			devc->uart_mode = 0;			return;		}	}	devc->uart_mode = arg;}int probe_mpu401(struct address_info *hw_config){	int ok = 0;	struct mpu_config tmp_devc;

⌨️ 快捷键说明

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