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