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