cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mtpav.c (19281B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *      MOTU Midi Timepiece ALSA Main routines
      4 *      Copyright by Michael T. Mayers (c) Jan 09, 2000
      5 *      mail: michael@tweakoz.com
      6 *      Thanks to John Galbraith
      7 *
      8 *      This driver is for the 'Mark Of The Unicorn' (MOTU)
      9 *      MidiTimePiece AV multiport MIDI interface 
     10 *
     11 *      IOPORTS
     12 *      -------
     13 *      8 MIDI Ins and 8 MIDI outs
     14 *      Video Sync In (BNC), Word Sync Out (BNC), 
     15 *      ADAT Sync Out (DB9)
     16 *      SMPTE in/out (1/4")
     17 *      2 programmable pedal/footswitch inputs and 4 programmable MIDI controller knobs.
     18 *      Macintosh RS422 serial port
     19 *      RS422 "network" port for ganging multiple MTP's
     20 *      PC Parallel Port ( which this driver currently uses )
     21 *
     22 *      MISC FEATURES
     23 *      -------------
     24 *      Hardware MIDI routing, merging, and filtering   
     25 *      MIDI Synchronization to Video, ADAT, SMPTE and other Clock sources
     26 *      128 'scene' memories, recallable from MIDI program change
     27 *
     28 * ChangeLog
     29 * Jun 11 2001	Takashi Iwai <tiwai@suse.de>
     30 *      - Recoded & debugged
     31 *      - Added timer interrupt for midi outputs
     32 *      - hwports is between 1 and 8, which specifies the number of hardware ports.
     33 *        The three global ports, computer, adat and broadcast ports, are created
     34 *        always after h/w and remote ports.
     35 */
     36
     37#include <linux/init.h>
     38#include <linux/interrupt.h>
     39#include <linux/module.h>
     40#include <linux/err.h>
     41#include <linux/platform_device.h>
     42#include <linux/ioport.h>
     43#include <linux/io.h>
     44#include <linux/moduleparam.h>
     45#include <sound/core.h>
     46#include <sound/initval.h>
     47#include <sound/rawmidi.h>
     48#include <linux/delay.h>
     49
     50/*
     51 *      globals
     52 */
     53MODULE_AUTHOR("Michael T. Mayers");
     54MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI");
     55MODULE_LICENSE("GPL");
     56
     57// io resources
     58#define MTPAV_IOBASE		0x378
     59#define MTPAV_IRQ		7
     60#define MTPAV_MAX_PORTS		8
     61
     62static int index = SNDRV_DEFAULT_IDX1;
     63static char *id = SNDRV_DEFAULT_STR1;
     64static long port = MTPAV_IOBASE;	/* 0x378, 0x278 */
     65static int irq = MTPAV_IRQ;		/* 7, 5 */
     66static int hwports = MTPAV_MAX_PORTS;	/* use hardware ports 1-8 */
     67
     68module_param(index, int, 0444);
     69MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI.");
     70module_param(id, charp, 0444);
     71MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI.");
     72module_param_hw(port, long, ioport, 0444);
     73MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI.");
     74module_param_hw(irq, int, irq, 0444);
     75MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI.");
     76module_param(hwports, int, 0444);
     77MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI.");
     78
     79static struct platform_device *device;
     80
     81/*
     82 *      defines
     83 */
     84//#define USE_FAKE_MTP //       don't actually read/write to MTP device (for debugging without an actual unit) (does not work yet)
     85
     86// parallel port usage masks
     87#define SIGS_BYTE 0x08
     88#define SIGS_RFD 0x80
     89#define SIGS_IRQ 0x40
     90#define SIGS_IN0 0x10
     91#define SIGS_IN1 0x20
     92
     93#define SIGC_WRITE 0x04
     94#define SIGC_READ 0x08
     95#define SIGC_INTEN 0x10
     96
     97#define DREG 0
     98#define SREG 1
     99#define CREG 2
    100
    101//
    102#define MTPAV_MODE_INPUT_OPENED		0x01
    103#define MTPAV_MODE_OUTPUT_OPENED	0x02
    104#define MTPAV_MODE_INPUT_TRIGGERED	0x04
    105#define MTPAV_MODE_OUTPUT_TRIGGERED	0x08
    106
    107#define NUMPORTS (0x12+1)
    108
    109
    110/*
    111 */
    112
    113struct mtpav_port {
    114	u8 number;
    115	u8 hwport;
    116	u8 mode;
    117	u8 running_status;
    118	struct snd_rawmidi_substream *input;
    119	struct snd_rawmidi_substream *output;
    120};
    121
    122struct mtpav {
    123	struct snd_card *card;
    124	unsigned long port;
    125	struct resource *res_port;
    126	int irq;			/* interrupt (for inputs) */
    127	spinlock_t spinlock;
    128	int share_irq;			/* number of accesses to input interrupts */
    129	int istimer;			/* number of accesses to timer interrupts */
    130	struct timer_list timer;	/* timer interrupts for outputs */
    131	struct snd_rawmidi *rmidi;
    132	int num_ports;		/* number of hw ports (1-8) */
    133	struct mtpav_port ports[NUMPORTS];	/* all ports including computer, adat and bc */
    134
    135	u32 inmidiport;		/* selected input midi port */
    136	u32 inmidistate;	/* during midi command 0xf5 */
    137
    138	u32 outmidihwport;	/* selected output midi hw port */
    139};
    140
    141
    142/*
    143 * possible hardware ports (selected by 0xf5 port message)
    144 *      0x00		all ports
    145 *      0x01 .. 0x08    this MTP's ports 1..8
    146 *      0x09 .. 0x10    networked MTP's ports (9..16)
    147 *      0x11            networked MTP's computer port
    148 *      0x63            to ADAT
    149 *
    150 * mappig:
    151 *  subdevice 0 - (X-1)    ports
    152 *            X - (2*X-1)  networked ports
    153 *            X            computer
    154 *            X+1          ADAT
    155 *            X+2          all ports
    156 *
    157 *  where X = chip->num_ports
    158 */
    159
    160#define MTPAV_PIDX_COMPUTER	0
    161#define MTPAV_PIDX_ADAT		1
    162#define MTPAV_PIDX_BROADCAST	2
    163
    164
    165static int translate_subdevice_to_hwport(struct mtpav *chip, int subdev)
    166{
    167	if (subdev < 0)
    168		return 0x01; /* invalid - use port 0 as default */
    169	else if (subdev < chip->num_ports)
    170		return subdev + 1; /* single mtp port */
    171	else if (subdev < chip->num_ports * 2)
    172		return subdev - chip->num_ports + 0x09; /* remote port */
    173	else if (subdev == chip->num_ports * 2 + MTPAV_PIDX_COMPUTER)
    174		return 0x11; /* computer port */
    175	else if (subdev == chip->num_ports + MTPAV_PIDX_ADAT)
    176		return 0x63;		/* ADAT */
    177	return 0; /* all ports */
    178}
    179
    180static int translate_hwport_to_subdevice(struct mtpav *chip, int hwport)
    181{
    182	int p;
    183	if (hwport <= 0x00) /* all ports */
    184		return chip->num_ports + MTPAV_PIDX_BROADCAST;
    185	else if (hwport <= 0x08) { /* single port */
    186		p = hwport - 1;
    187		if (p >= chip->num_ports)
    188			p = 0;
    189		return p;
    190	} else if (hwport <= 0x10) { /* remote port */
    191		p = hwport - 0x09 + chip->num_ports;
    192		if (p >= chip->num_ports * 2)
    193			p = chip->num_ports;
    194		return p;
    195	} else if (hwport == 0x11)  /* computer port */
    196		return chip->num_ports + MTPAV_PIDX_COMPUTER;
    197	else  /* ADAT */
    198		return chip->num_ports + MTPAV_PIDX_ADAT;
    199}
    200
    201
    202/*
    203 */
    204
    205static u8 snd_mtpav_getreg(struct mtpav *chip, u16 reg)
    206{
    207	u8 rval = 0;
    208
    209	if (reg == SREG) {
    210		rval = inb(chip->port + SREG);
    211		rval = (rval & 0xf8);
    212	} else if (reg == CREG) {
    213		rval = inb(chip->port + CREG);
    214		rval = (rval & 0x1c);
    215	}
    216
    217	return rval;
    218}
    219
    220/*
    221 */
    222
    223static inline void snd_mtpav_mputreg(struct mtpav *chip, u16 reg, u8 val)
    224{
    225	if (reg == DREG || reg == CREG)
    226		outb(val, chip->port + reg);
    227}
    228
    229/*
    230 */
    231
    232static void snd_mtpav_wait_rfdhi(struct mtpav *chip)
    233{
    234	int counts = 10000;
    235	u8 sbyte;
    236
    237	sbyte = snd_mtpav_getreg(chip, SREG);
    238	while (!(sbyte & SIGS_RFD) && counts--) {
    239		sbyte = snd_mtpav_getreg(chip, SREG);
    240		udelay(10);
    241	}
    242}
    243
    244static void snd_mtpav_send_byte(struct mtpav *chip, u8 byte)
    245{
    246	u8 tcbyt;
    247	u8 clrwrite;
    248	u8 setwrite;
    249
    250	snd_mtpav_wait_rfdhi(chip);
    251
    252	/////////////////
    253
    254	tcbyt = snd_mtpav_getreg(chip, CREG);
    255	clrwrite = tcbyt & (SIGC_WRITE ^ 0xff);
    256	setwrite = tcbyt | SIGC_WRITE;
    257
    258	snd_mtpav_mputreg(chip, DREG, byte);
    259	snd_mtpav_mputreg(chip, CREG, clrwrite);	// clear write bit
    260
    261	snd_mtpav_mputreg(chip, CREG, setwrite);	// set write bit
    262
    263}
    264
    265
    266/*
    267 */
    268
    269/* call this with spin lock held */
    270static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
    271					struct mtpav_port *portp,
    272					struct snd_rawmidi_substream *substream)
    273{
    274	u8 outbyte;
    275
    276	// Get the outbyte first, so we can emulate running status if
    277	// necessary
    278	if (snd_rawmidi_transmit(substream, &outbyte, 1) != 1)
    279		return;
    280
    281	// send port change command if necessary
    282
    283	if (portp->hwport != mtp_card->outmidihwport) {
    284		mtp_card->outmidihwport = portp->hwport;
    285
    286		snd_mtpav_send_byte(mtp_card, 0xf5);
    287		snd_mtpav_send_byte(mtp_card, portp->hwport);
    288		/*
    289		snd_printk(KERN_DEBUG "new outport: 0x%x\n",
    290			   (unsigned int) portp->hwport);
    291		*/
    292		if (!(outbyte & 0x80) && portp->running_status)
    293			snd_mtpav_send_byte(mtp_card, portp->running_status);
    294	}
    295
    296	// send data
    297
    298	do {
    299		if (outbyte & 0x80)
    300			portp->running_status = outbyte;
    301		
    302		snd_mtpav_send_byte(mtp_card, outbyte);
    303	} while (snd_rawmidi_transmit(substream, &outbyte, 1) == 1);
    304}
    305
    306static void snd_mtpav_output_write(struct snd_rawmidi_substream *substream)
    307{
    308	struct mtpav *mtp_card = substream->rmidi->private_data;
    309	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    310	unsigned long flags;
    311
    312	spin_lock_irqsave(&mtp_card->spinlock, flags);
    313	snd_mtpav_output_port_write(mtp_card, portp, substream);
    314	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    315}
    316
    317
    318/*
    319 *      mtpav control
    320 */
    321
    322static void snd_mtpav_portscan(struct mtpav *chip)	// put mtp into smart routing mode
    323{
    324	u8 p;
    325
    326	for (p = 0; p < 8; p++) {
    327		snd_mtpav_send_byte(chip, 0xf5);
    328		snd_mtpav_send_byte(chip, p);
    329		snd_mtpav_send_byte(chip, 0xfe);
    330	}
    331}
    332
    333/*
    334 */
    335
    336static int snd_mtpav_input_open(struct snd_rawmidi_substream *substream)
    337{
    338	struct mtpav *mtp_card = substream->rmidi->private_data;
    339	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    340	unsigned long flags;
    341
    342	spin_lock_irqsave(&mtp_card->spinlock, flags);
    343	portp->mode |= MTPAV_MODE_INPUT_OPENED;
    344	portp->input = substream;
    345	if (mtp_card->share_irq++ == 0)
    346		snd_mtpav_mputreg(mtp_card, CREG, (SIGC_INTEN | SIGC_WRITE));	// enable pport interrupts
    347	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    348	return 0;
    349}
    350
    351/*
    352 */
    353
    354static int snd_mtpav_input_close(struct snd_rawmidi_substream *substream)
    355{
    356	struct mtpav *mtp_card = substream->rmidi->private_data;
    357	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    358	unsigned long flags;
    359
    360	spin_lock_irqsave(&mtp_card->spinlock, flags);
    361	portp->mode &= ~MTPAV_MODE_INPUT_OPENED;
    362	portp->input = NULL;
    363	if (--mtp_card->share_irq == 0)
    364		snd_mtpav_mputreg(mtp_card, CREG, 0);	// disable pport interrupts
    365	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    366	return 0;
    367}
    368
    369/*
    370 */
    371
    372static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int up)
    373{
    374	struct mtpav *mtp_card = substream->rmidi->private_data;
    375	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    376	unsigned long flags;
    377
    378	spin_lock_irqsave(&mtp_card->spinlock, flags);
    379	if (up)
    380		portp->mode |= MTPAV_MODE_INPUT_TRIGGERED;
    381	else
    382		portp->mode &= ~MTPAV_MODE_INPUT_TRIGGERED;
    383	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    384
    385}
    386
    387
    388/*
    389 * timer interrupt for outputs
    390 */
    391
    392static void snd_mtpav_output_timer(struct timer_list *t)
    393{
    394	unsigned long flags;
    395	struct mtpav *chip = from_timer(chip, t, timer);
    396	int p;
    397
    398	spin_lock_irqsave(&chip->spinlock, flags);
    399	/* reprogram timer */
    400	mod_timer(&chip->timer, 1 + jiffies);
    401	/* process each port */
    402	for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
    403		struct mtpav_port *portp = &chip->ports[p];
    404		if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output)
    405			snd_mtpav_output_port_write(chip, portp, portp->output);
    406	}
    407	spin_unlock_irqrestore(&chip->spinlock, flags);
    408}
    409
    410/* spinlock held! */
    411static void snd_mtpav_add_output_timer(struct mtpav *chip)
    412{
    413	mod_timer(&chip->timer, 1 + jiffies);
    414}
    415
    416/* spinlock held! */
    417static void snd_mtpav_remove_output_timer(struct mtpav *chip)
    418{
    419	del_timer(&chip->timer);
    420}
    421
    422/*
    423 */
    424
    425static int snd_mtpav_output_open(struct snd_rawmidi_substream *substream)
    426{
    427	struct mtpav *mtp_card = substream->rmidi->private_data;
    428	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    429	unsigned long flags;
    430
    431	spin_lock_irqsave(&mtp_card->spinlock, flags);
    432	portp->mode |= MTPAV_MODE_OUTPUT_OPENED;
    433	portp->output = substream;
    434	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    435	return 0;
    436};
    437
    438/*
    439 */
    440
    441static int snd_mtpav_output_close(struct snd_rawmidi_substream *substream)
    442{
    443	struct mtpav *mtp_card = substream->rmidi->private_data;
    444	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    445	unsigned long flags;
    446
    447	spin_lock_irqsave(&mtp_card->spinlock, flags);
    448	portp->mode &= ~MTPAV_MODE_OUTPUT_OPENED;
    449	portp->output = NULL;
    450	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    451	return 0;
    452};
    453
    454/*
    455 */
    456
    457static void snd_mtpav_output_trigger(struct snd_rawmidi_substream *substream, int up)
    458{
    459	struct mtpav *mtp_card = substream->rmidi->private_data;
    460	struct mtpav_port *portp = &mtp_card->ports[substream->number];
    461	unsigned long flags;
    462
    463	spin_lock_irqsave(&mtp_card->spinlock, flags);
    464	if (up) {
    465		if (! (portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) {
    466			if (mtp_card->istimer++ == 0)
    467				snd_mtpav_add_output_timer(mtp_card);
    468			portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED;
    469		}
    470	} else {
    471		portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED;
    472		if (--mtp_card->istimer == 0)
    473			snd_mtpav_remove_output_timer(mtp_card);
    474	}
    475	spin_unlock_irqrestore(&mtp_card->spinlock, flags);
    476
    477	if (up)
    478		snd_mtpav_output_write(substream);
    479}
    480
    481/*
    482 * midi interrupt for inputs
    483 */
    484
    485static void snd_mtpav_inmidi_process(struct mtpav *mcrd, u8 inbyte)
    486{
    487	struct mtpav_port *portp;
    488
    489	if ((int)mcrd->inmidiport > mcrd->num_ports * 2 + MTPAV_PIDX_BROADCAST)
    490		return;
    491
    492	portp = &mcrd->ports[mcrd->inmidiport];
    493	if (portp->mode & MTPAV_MODE_INPUT_TRIGGERED)
    494		snd_rawmidi_receive(portp->input, &inbyte, 1);
    495}
    496
    497static void snd_mtpav_inmidi_h(struct mtpav *mcrd, u8 inbyte)
    498{
    499	if (inbyte >= 0xf8) {
    500		/* real-time midi code */
    501		snd_mtpav_inmidi_process(mcrd, inbyte);
    502		return;
    503	}
    504
    505	if (mcrd->inmidistate == 0) {	// awaiting command
    506		if (inbyte == 0xf5)	// MTP port #
    507			mcrd->inmidistate = 1;
    508		else
    509			snd_mtpav_inmidi_process(mcrd, inbyte);
    510	} else if (mcrd->inmidistate) {
    511		mcrd->inmidiport = translate_hwport_to_subdevice(mcrd, inbyte);
    512		mcrd->inmidistate = 0;
    513	}
    514}
    515
    516static void snd_mtpav_read_bytes(struct mtpav *mcrd)
    517{
    518	u8 clrread, setread;
    519	u8 mtp_read_byte;
    520	u8 sr, cbyt;
    521	int i;
    522
    523	u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
    524
    525	/* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
    526
    527	if (!(sbyt & SIGS_BYTE))
    528		return;
    529
    530	cbyt = snd_mtpav_getreg(mcrd, CREG);
    531	clrread = cbyt & (SIGC_READ ^ 0xff);
    532	setread = cbyt | SIGC_READ;
    533
    534	do {
    535
    536		mtp_read_byte = 0;
    537		for (i = 0; i < 4; i++) {
    538			snd_mtpav_mputreg(mcrd, CREG, setread);
    539			sr = snd_mtpav_getreg(mcrd, SREG);
    540			snd_mtpav_mputreg(mcrd, CREG, clrread);
    541
    542			sr &= SIGS_IN0 | SIGS_IN1;
    543			sr >>= 4;
    544			mtp_read_byte |= sr << (i * 2);
    545		}
    546
    547		snd_mtpav_inmidi_h(mcrd, mtp_read_byte);
    548
    549		sbyt = snd_mtpav_getreg(mcrd, SREG);
    550
    551	} while (sbyt & SIGS_BYTE);
    552}
    553
    554static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
    555{
    556	struct mtpav *mcard = dev_id;
    557
    558	spin_lock(&mcard->spinlock);
    559	snd_mtpav_read_bytes(mcard);
    560	spin_unlock(&mcard->spinlock);
    561	return IRQ_HANDLED;
    562}
    563
    564/*
    565 * get ISA resources
    566 */
    567static int snd_mtpav_get_ISA(struct mtpav *mcard)
    568{
    569	mcard->res_port = devm_request_region(mcard->card->dev, port, 3,
    570					      "MotuMTPAV MIDI");
    571	if (!mcard->res_port) {
    572		snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
    573		return -EBUSY;
    574	}
    575	mcard->port = port;
    576	if (devm_request_irq(mcard->card->dev, irq, snd_mtpav_irqh, 0,
    577			     "MOTU MTPAV", mcard)) {
    578		snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
    579		return -EBUSY;
    580	}
    581	mcard->irq = irq;
    582	return 0;
    583}
    584
    585
    586/*
    587 */
    588
    589static const struct snd_rawmidi_ops snd_mtpav_output = {
    590	.open =		snd_mtpav_output_open,
    591	.close =	snd_mtpav_output_close,
    592	.trigger =	snd_mtpav_output_trigger,
    593};
    594
    595static const struct snd_rawmidi_ops snd_mtpav_input = {
    596	.open =		snd_mtpav_input_open,
    597	.close =	snd_mtpav_input_close,
    598	.trigger =	snd_mtpav_input_trigger,
    599};
    600
    601
    602/*
    603 * get RAWMIDI resources
    604 */
    605
    606static void snd_mtpav_set_name(struct mtpav *chip,
    607			       struct snd_rawmidi_substream *substream)
    608{
    609	if (substream->number >= 0 && substream->number < chip->num_ports)
    610		sprintf(substream->name, "MTP direct %d", (substream->number % chip->num_ports) + 1);
    611	else if (substream->number >= 8 && substream->number < chip->num_ports * 2)
    612		sprintf(substream->name, "MTP remote %d", (substream->number % chip->num_ports) + 1);
    613	else if (substream->number == chip->num_ports * 2)
    614		strcpy(substream->name, "MTP computer");
    615	else if (substream->number == chip->num_ports * 2 + 1)
    616		strcpy(substream->name, "MTP ADAT");
    617	else
    618		strcpy(substream->name, "MTP broadcast");
    619}
    620
    621static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
    622{
    623	int rval;
    624	struct snd_rawmidi *rawmidi;
    625	struct snd_rawmidi_substream *substream;
    626	struct list_head *list;
    627
    628	if (hwports < 1)
    629		hwports = 1;
    630	else if (hwports > 8)
    631		hwports = 8;
    632	mcard->num_ports = hwports;
    633
    634	rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
    635			       mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
    636			       mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
    637			       &mcard->rmidi);
    638	if (rval < 0)
    639		return rval;
    640	rawmidi = mcard->rmidi;
    641	rawmidi->private_data = mcard;
    642
    643	list_for_each(list, &rawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
    644		substream = list_entry(list, struct snd_rawmidi_substream, list);
    645		snd_mtpav_set_name(mcard, substream);
    646		substream->ops = &snd_mtpav_input;
    647	}
    648	list_for_each(list, &rawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
    649		substream = list_entry(list, struct snd_rawmidi_substream, list);
    650		snd_mtpav_set_name(mcard, substream);
    651		substream->ops = &snd_mtpav_output;
    652		mcard->ports[substream->number].hwport = translate_subdevice_to_hwport(mcard, substream->number);
    653	}
    654	rawmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
    655			       SNDRV_RAWMIDI_INFO_DUPLEX;
    656	sprintf(rawmidi->name, "MTP AV MIDI");
    657	return 0;
    658}
    659
    660/*
    661 */
    662
    663static void snd_mtpav_free(struct snd_card *card)
    664{
    665	struct mtpav *crd = card->private_data;
    666	unsigned long flags;
    667
    668	spin_lock_irqsave(&crd->spinlock, flags);
    669	if (crd->istimer > 0)
    670		snd_mtpav_remove_output_timer(crd);
    671	spin_unlock_irqrestore(&crd->spinlock, flags);
    672}
    673
    674/*
    675 */
    676static int snd_mtpav_probe(struct platform_device *dev)
    677{
    678	struct snd_card *card;
    679	int err;
    680	struct mtpav *mtp_card;
    681
    682	err = snd_devm_card_new(&dev->dev, index, id, THIS_MODULE,
    683				sizeof(*mtp_card), &card);
    684	if (err < 0)
    685		return err;
    686
    687	mtp_card = card->private_data;
    688	spin_lock_init(&mtp_card->spinlock);
    689	mtp_card->card = card;
    690	mtp_card->irq = -1;
    691	mtp_card->share_irq = 0;
    692	mtp_card->inmidistate = 0;
    693	mtp_card->outmidihwport = 0xffffffff;
    694	timer_setup(&mtp_card->timer, snd_mtpav_output_timer, 0);
    695
    696	err = snd_mtpav_get_RAWMIDI(mtp_card);
    697	if (err < 0)
    698		return err;
    699
    700	mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST;
    701
    702	err = snd_mtpav_get_ISA(mtp_card);
    703	if (err < 0)
    704		return err;
    705
    706	strcpy(card->driver, "MTPAV");
    707	strcpy(card->shortname, "MTPAV on parallel port");
    708	snprintf(card->longname, sizeof(card->longname),
    709		 "MTPAV on parallel port at 0x%lx", port);
    710
    711	snd_mtpav_portscan(mtp_card);
    712
    713	err = snd_card_register(mtp_card->card);
    714	if (err < 0)
    715		return err;
    716
    717	card->private_free = snd_mtpav_free;
    718
    719	platform_set_drvdata(dev, card);
    720	printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", irq, port);
    721	return 0;
    722}
    723
    724#define SND_MTPAV_DRIVER	"snd_mtpav"
    725
    726static struct platform_driver snd_mtpav_driver = {
    727	.probe		= snd_mtpav_probe,
    728	.driver		= {
    729		.name	= SND_MTPAV_DRIVER,
    730	},
    731};
    732
    733static int __init alsa_card_mtpav_init(void)
    734{
    735	int err;
    736
    737	err = platform_driver_register(&snd_mtpav_driver);
    738	if (err < 0)
    739		return err;
    740
    741	device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);
    742	if (!IS_ERR(device)) {
    743		if (platform_get_drvdata(device))
    744			return 0;
    745		platform_device_unregister(device);
    746		err = -ENODEV;
    747	} else
    748		err = PTR_ERR(device);
    749	platform_driver_unregister(&snd_mtpav_driver);
    750	return err;
    751}
    752
    753static void __exit alsa_card_mtpav_exit(void)
    754{
    755	platform_device_unregister(device);
    756	platform_driver_unregister(&snd_mtpav_driver);
    757}
    758
    759module_init(alsa_card_mtpav_init)
    760module_exit(alsa_card_mtpav_exit)