source: GPL/alsa-kernel/drivers/mtpav.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

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