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

📄 mtpav.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      MOTU Midi Timepiece ALSA Main routines *      Copyright by Michael T. Mayers (c) Jan 09, 2000 *      mail: michael@tweakoz.com *      Thanks to John Galbraith * *      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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * * *      This driver is for the 'Mark Of The Unicorn' (MOTU) *      MidiTimePiece AV multiport MIDI interface  * *      IOPORTS *      ------- *      8 MIDI Ins and 8 MIDI outs *      Video Sync In (BNC), Word Sync Out (BNC),  *      ADAT Sync Out (DB9) *      SMPTE in/out (1/4") *      2 programmable pedal/footswitch inputs and 4 programmable MIDI controller knobs. *      Macintosh RS422 serial port *      RS422 "network" port for ganging multiple MTP's *      PC Parallel Port ( which this driver currently uses ) * *      MISC FEATURES *      ------------- *      Hardware MIDI routing, merging, and filtering    *      MIDI Synchronization to Video, ADAT, SMPTE and other Clock sources *      128 'scene' memories, recallable from MIDI program change * * * ChangeLog * Jun 11 2001	Takashi Iwai <tiwai@suse.de> *      - Recoded & debugged *      - Added timer interrupt for midi outputs *      - hwports is between 1 and 8, which specifies the number of hardware ports. *        The three global ports, computer, adat and broadcast ports, are created *        always after h/w and remote ports. * */#include <sound/driver.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/err.h>#include <linux/platform_device.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/initval.h>#include <sound/rawmidi.h>#include <linux/delay.h>#include <asm/io.h>/* *      globals */MODULE_AUTHOR("Michael T. Mayers");MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{MOTU,MidiTimePiece AV multiport MIDI}}");// io resources#define MTPAV_IOBASE		0x378#define MTPAV_IRQ		7#define MTPAV_MAX_PORTS		8static int index = SNDRV_DEFAULT_IDX1;static char *id = SNDRV_DEFAULT_STR1;static long port = MTPAV_IOBASE;	/* 0x378, 0x278 */static int irq = MTPAV_IRQ;		/* 7, 5 */static int hwports = MTPAV_MAX_PORTS;	/* use hardware ports 1-8 */module_param(index, int, 0444);MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI.");module_param(id, charp, 0444);MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI.");module_param(port, long, 0444);MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI.");module_param(irq, int, 0444);MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI.");module_param(hwports, int, 0444);MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI.");static struct platform_device *device;/* *      defines *///#define USE_FAKE_MTP //       don't actually read/write to MTP device (for debugging without an actual unit) (does not work yet)// parallel port usage masks#define SIGS_BYTE 0x08#define SIGS_RFD 0x80#define SIGS_IRQ 0x40#define SIGS_IN0 0x10#define SIGS_IN1 0x20#define SIGC_WRITE 0x04#define SIGC_READ 0x08#define SIGC_INTEN 0x10#define DREG 0#define SREG 1#define CREG 2//#define MTPAV_MODE_INPUT_OPENED		0x01#define MTPAV_MODE_OUTPUT_OPENED	0x02#define MTPAV_MODE_INPUT_TRIGGERED	0x04#define MTPAV_MODE_OUTPUT_TRIGGERED	0x08#define NUMPORTS (0x12+1)/* */struct mtpav_port {	u8 number;	u8 hwport;	u8 mode;	u8 running_status;	struct snd_rawmidi_substream *input;	struct snd_rawmidi_substream *output;};struct mtpav {	struct snd_card *card;	unsigned long port;	struct resource *res_port;	int irq;			/* interrupt (for inputs) */	spinlock_t spinlock;	int share_irq;			/* number of accesses to input interrupts */	int istimer;			/* number of accesses to timer interrupts */	struct timer_list timer;	/* timer interrupts for outputs */	struct snd_rawmidi *rmidi;	int num_ports;		/* number of hw ports (1-8) */	struct mtpav_port ports[NUMPORTS];	/* all ports including computer, adat and bc */	u32 inmidiport;		/* selected input midi port */	u32 inmidistate;	/* during midi command 0xf5 */	u32 outmidihwport;	/* selected output midi hw port */};/* * possible hardware ports (selected by 0xf5 port message) *      0x00		all ports *      0x01 .. 0x08    this MTP's ports 1..8 *      0x09 .. 0x10    networked MTP's ports (9..16) *      0x11            networked MTP's computer port *      0x63            to ADAT * * mappig: *  subdevice 0 - (X-1)    ports *            X - (2*X-1)  networked ports *            X            computer *            X+1          ADAT *            X+2          all ports * *  where X = chip->num_ports */#define MTPAV_PIDX_COMPUTER	0#define MTPAV_PIDX_ADAT		1#define MTPAV_PIDX_BROADCAST	2static int translate_subdevice_to_hwport(struct mtpav *chip, int subdev){	if (subdev < 0)		return 0x01; /* invalid - use port 0 as default */	else if (subdev < chip->num_ports)		return subdev + 1; /* single mtp port */	else if (subdev < chip->num_ports * 2)		return subdev - chip->num_ports + 0x09; /* remote port */	else if (subdev == chip->num_ports * 2 + MTPAV_PIDX_COMPUTER)		return 0x11; /* computer port */	else if (subdev == chip->num_ports + MTPAV_PIDX_ADAT)		return 0x63;		/* ADAT */	return 0; /* all ports */}static int translate_hwport_to_subdevice(struct mtpav *chip, int hwport){	int p;	if (hwport <= 0x00) /* all ports */		return chip->num_ports + MTPAV_PIDX_BROADCAST;	else if (hwport <= 0x08) { /* single port */		p = hwport - 1;		if (p >= chip->num_ports)			p = 0;		return p;	} else if (hwport <= 0x10) { /* remote port */		p = hwport - 0x09 + chip->num_ports;		if (p >= chip->num_ports * 2)			p = chip->num_ports;		return p;	} else if (hwport == 0x11)  /* computer port */		return chip->num_ports + MTPAV_PIDX_COMPUTER;	else  /* ADAT */		return chip->num_ports + MTPAV_PIDX_ADAT;}/* */static u8 snd_mtpav_getreg(struct mtpav *chip, u16 reg){	u8 rval = 0;	if (reg == SREG) {		rval = inb(chip->port + SREG);		rval = (rval & 0xf8);	} else if (reg == CREG) {		rval = inb(chip->port + CREG);		rval = (rval & 0x1c);	}	return rval;}/* */static inline void snd_mtpav_mputreg(struct mtpav *chip, u16 reg, u8 val){	if (reg == DREG || reg == CREG)		outb(val, chip->port + reg);}/* */static void snd_mtpav_wait_rfdhi(struct mtpav *chip){	int counts = 10000;	u8 sbyte;	sbyte = snd_mtpav_getreg(chip, SREG);	while (!(sbyte & SIGS_RFD) && counts--) {		sbyte = snd_mtpav_getreg(chip, SREG);		udelay(10);	}}static void snd_mtpav_send_byte(struct mtpav *chip, u8 byte){	u8 tcbyt;	u8 clrwrite;	u8 setwrite;	snd_mtpav_wait_rfdhi(chip);	/////////////////	tcbyt = snd_mtpav_getreg(chip, CREG);	clrwrite = tcbyt & (SIGC_WRITE ^ 0xff);	setwrite = tcbyt | SIGC_WRITE;	snd_mtpav_mputreg(chip, DREG, byte);	snd_mtpav_mputreg(chip, CREG, clrwrite);	// clear write bit	snd_mtpav_mputreg(chip, CREG, setwrite);	// set write bit}/* *//* call this with spin lock held */static void snd_mtpav_output_port_write(struct mtpav *mtp_card,					struct mtpav_port *portp,					struct snd_rawmidi_substream *substream){	u8 outbyte;	// Get the outbyte first, so we can emulate running status if	// necessary	if (snd_rawmidi_transmit(substream, &outbyte, 1) != 1)		return;	// send port change command if necessary	if (portp->hwport != mtp_card->outmidihwport) {		mtp_card->outmidihwport = portp->hwport;		snd_mtpav_send_byte(mtp_card, 0xf5);		snd_mtpav_send_byte(mtp_card, portp->hwport);		//snd_printk("new outport: 0x%x\n", (unsigned int) portp->hwport);		if (!(outbyte & 0x80) && portp->running_status)			snd_mtpav_send_byte(mtp_card, portp->running_status);	}	// send data	do {		if (outbyte & 0x80)			portp->running_status = outbyte;				snd_mtpav_send_byte(mtp_card, outbyte);	} while (snd_rawmidi_transmit(substream, &outbyte, 1) == 1);}static void snd_mtpav_output_write(struct snd_rawmidi_substream *substream){	struct mtpav *mtp_card = substream->rmidi->private_data;	struct mtpav_port *portp = &mtp_card->ports[substream->number];	unsigned long flags;	spin_lock_irqsave(&mtp_card->spinlock, flags);	snd_mtpav_output_port_write(mtp_card, portp, substream);	spin_unlock_irqrestore(&mtp_card->spinlock, flags);}/* *      mtpav control */static void snd_mtpav_portscan(struct mtpav *chip)	// put mtp into smart routing mode{	u8 p;	for (p = 0; p < 8; p++) {		snd_mtpav_send_byte(chip, 0xf5);		snd_mtpav_send_byte(chip, p);		snd_mtpav_send_byte(chip, 0xfe);	}}/* */static int snd_mtpav_input_open(struct snd_rawmidi_substream *substream){	struct mtpav *mtp_card = substream->rmidi->private_data;	struct mtpav_port *portp = &mtp_card->ports[substream->number];	unsigned long flags;	spin_lock_irqsave(&mtp_card->spinlock, flags);	portp->mode |= MTPAV_MODE_INPUT_OPENED;	portp->input = substream;	if (mtp_card->share_irq++ == 0)		snd_mtpav_mputreg(mtp_card, CREG, (SIGC_INTEN | SIGC_WRITE));	// enable pport interrupts	spin_unlock_irqrestore(&mtp_card->spinlock, flags);	return 0;}/* */static int snd_mtpav_input_close(struct snd_rawmidi_substream *substream){	struct mtpav *mtp_card = substream->rmidi->private_data;	struct mtpav_port *portp = &mtp_card->ports[substream->number];	unsigned long flags;	spin_lock_irqsave(&mtp_card->spinlock, flags);	portp->mode &= ~MTPAV_MODE_INPUT_OPENED;	portp->input = NULL;	if (--mtp_card->share_irq == 0)		snd_mtpav_mputreg(mtp_card, CREG, 0);	// disable pport interrupts	spin_unlock_irqrestore(&mtp_card->spinlock, flags);	return 0;}/* */static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int up){	struct mtpav *mtp_card = substream->rmidi->private_data;	struct mtpav_port *portp = &mtp_card->ports[substream->number];	unsigned long flags;	spin_lock_irqsave(&mtp_card->spinlock, flags);	if (up)

⌨️ 快捷键说明

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