Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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