mpu401.c

来自「linux 内核源代码」· C语言 代码 · 共 1,816 行 · 第 1/3 页

C
1,816
字号
	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)	{		spin_unlock_irqrestore(&devc->lock,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]))			{				spin_unlock_irqrestore(&devc->lock,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)			{				spin_unlock_irqrestore(&devc->lock,flags);				return -EIO;			}		}	}	spin_unlock_irqrestore(&devc->lock,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, void __user *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 __user *)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, void __user *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:			if (copy_to_user(arg, &mpu_synth_info[midi_dev],					sizeof(struct synth_info)))				return -EFAULT;			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 (!try_module_get(coprocessor->owner))			return -ENODEV;		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);		module_put(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;	spin_lock_irqsave(&devc->lock,flags);	if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)	{		spin_unlock_irqrestore(&devc->lock,flags);		return;	}	if ((tmp & 0xf0) > 0x20)	/* Why it's larger than 2.x ??? */	{		spin_unlock_irqrestore(&devc->lock,flags);		return;	}	devc->version = tmp;	if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)	{		devc->version = 0;		spin_unlock_irqrestore(&devc->lock,flags);		return;	}	devc->revision = tmp;	spin_unlock_irqrestore(&devc->lock,flags);}int attach_mpu401(struct address_info *hw_config, struct module *owner){	unsigned long flags;	char revision_char;	int m, ret;	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");		ret = -ENOMEM;		goto out_err;	}	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;	spin_lock_init(&devc->lock);	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");			ret = -ENODEV;			goto out_mididev;		}		if (!devc->shared_irq)		{			if (request_irq(devc->irq, mpuintr, 0, "mpu401",					hw_config) < 0)			{				printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);				ret = -ENOMEM;				goto out_mididev;			}		}		spin_lock_irqsave(&devc->lock,flags);		mpu401_chk_version(m, devc);		if (devc->version == 0)			mpu401_chk_version(m, devc);			spin_unlock_irqrestore(&devc->lock,flags);	}	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] = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);	if (mpu401_synth_operations[m] == NULL)	{		printk(KERN_ERR "mpu401: Can't allocate memory\n");		ret = -ENOMEM;		goto out_irq;	}	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();		return 0;out_irq:	free_irq(devc->irq, hw_config);out_mididev:	sound_unload_mididev(m);out_err:	release_region(hw_config->io_base, 2);	return ret;}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--)		{			spin_lock_irqsave(&devc->lock,flags);			if (input_avail(devc))				if (read_data(devc) == MPU_ACK)					ok = 1;			spin_unlock_irqrestore(&devc->lock,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, struct resource *ports){	int ok = 0;	struct mpu_config tmp_devc;	tmp_devc.base = hw_config->io_base;	tmp_devc.irq = hw_config->irq;	tmp_devc.initialized = 0;	tmp_devc.opened = 0;	tmp_devc.osp = hw_config->osp;	if (hw_config->always_detect)		return 1;	if (inb(hw_config->io_base + 1) == 0xff)	{		DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));		return 0;	/* Just bus float? */

⌨️ 快捷键说明

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