0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <linux/init.h>
0038 #include <linux/interrupt.h>
0039 #include <linux/module.h>
0040 #include <linux/err.h>
0041 #include <linux/platform_device.h>
0042 #include <linux/ioport.h>
0043 #include <linux/io.h>
0044 #include <linux/moduleparam.h>
0045 #include <sound/core.h>
0046 #include <sound/initval.h>
0047 #include <sound/rawmidi.h>
0048 #include <linux/delay.h>
0049
0050
0051
0052
0053 MODULE_AUTHOR("Michael T. Mayers");
0054 MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI");
0055 MODULE_LICENSE("GPL");
0056
0057
0058 #define MTPAV_IOBASE 0x378
0059 #define MTPAV_IRQ 7
0060 #define MTPAV_MAX_PORTS 8
0061
0062 static int index = SNDRV_DEFAULT_IDX1;
0063 static char *id = SNDRV_DEFAULT_STR1;
0064 static long port = MTPAV_IOBASE;
0065 static int irq = MTPAV_IRQ;
0066 static int hwports = MTPAV_MAX_PORTS;
0067
0068 module_param(index, int, 0444);
0069 MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI.");
0070 module_param(id, charp, 0444);
0071 MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI.");
0072 module_param_hw(port, long, ioport, 0444);
0073 MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI.");
0074 module_param_hw(irq, int, irq, 0444);
0075 MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI.");
0076 module_param(hwports, int, 0444);
0077 MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI.");
0078
0079 static struct platform_device *device;
0080
0081
0082
0083
0084
0085
0086
0087 #define SIGS_BYTE 0x08
0088 #define SIGS_RFD 0x80
0089 #define SIGS_IRQ 0x40
0090 #define SIGS_IN0 0x10
0091 #define SIGS_IN1 0x20
0092
0093 #define SIGC_WRITE 0x04
0094 #define SIGC_READ 0x08
0095 #define SIGC_INTEN 0x10
0096
0097 #define DREG 0
0098 #define SREG 1
0099 #define CREG 2
0100
0101
0102 #define MTPAV_MODE_INPUT_OPENED 0x01
0103 #define MTPAV_MODE_OUTPUT_OPENED 0x02
0104 #define MTPAV_MODE_INPUT_TRIGGERED 0x04
0105 #define MTPAV_MODE_OUTPUT_TRIGGERED 0x08
0106
0107 #define NUMPORTS (0x12+1)
0108
0109
0110
0111
0112
0113 struct mtpav_port {
0114 u8 number;
0115 u8 hwport;
0116 u8 mode;
0117 u8 running_status;
0118 struct snd_rawmidi_substream *input;
0119 struct snd_rawmidi_substream *output;
0120 };
0121
0122 struct mtpav {
0123 struct snd_card *card;
0124 unsigned long port;
0125 struct resource *res_port;
0126 int irq;
0127 spinlock_t spinlock;
0128 int share_irq;
0129 int istimer;
0130 struct timer_list timer;
0131 struct snd_rawmidi *rmidi;
0132 int num_ports;
0133 struct mtpav_port ports[NUMPORTS];
0134
0135 u32 inmidiport;
0136 u32 inmidistate;
0137
0138 u32 outmidihwport;
0139 };
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 #define MTPAV_PIDX_COMPUTER 0
0161 #define MTPAV_PIDX_ADAT 1
0162 #define MTPAV_PIDX_BROADCAST 2
0163
0164
0165 static int translate_subdevice_to_hwport(struct mtpav *chip, int subdev)
0166 {
0167 if (subdev < 0)
0168 return 0x01;
0169 else if (subdev < chip->num_ports)
0170 return subdev + 1;
0171 else if (subdev < chip->num_ports * 2)
0172 return subdev - chip->num_ports + 0x09;
0173 else if (subdev == chip->num_ports * 2 + MTPAV_PIDX_COMPUTER)
0174 return 0x11;
0175 else if (subdev == chip->num_ports + MTPAV_PIDX_ADAT)
0176 return 0x63;
0177 return 0;
0178 }
0179
0180 static int translate_hwport_to_subdevice(struct mtpav *chip, int hwport)
0181 {
0182 int p;
0183 if (hwport <= 0x00)
0184 return chip->num_ports + MTPAV_PIDX_BROADCAST;
0185 else if (hwport <= 0x08) {
0186 p = hwport - 1;
0187 if (p >= chip->num_ports)
0188 p = 0;
0189 return p;
0190 } else if (hwport <= 0x10) {
0191 p = hwport - 0x09 + chip->num_ports;
0192 if (p >= chip->num_ports * 2)
0193 p = chip->num_ports;
0194 return p;
0195 } else if (hwport == 0x11)
0196 return chip->num_ports + MTPAV_PIDX_COMPUTER;
0197 else
0198 return chip->num_ports + MTPAV_PIDX_ADAT;
0199 }
0200
0201
0202
0203
0204
0205 static u8 snd_mtpav_getreg(struct mtpav *chip, u16 reg)
0206 {
0207 u8 rval = 0;
0208
0209 if (reg == SREG) {
0210 rval = inb(chip->port + SREG);
0211 rval = (rval & 0xf8);
0212 } else if (reg == CREG) {
0213 rval = inb(chip->port + CREG);
0214 rval = (rval & 0x1c);
0215 }
0216
0217 return rval;
0218 }
0219
0220
0221
0222
0223 static inline void snd_mtpav_mputreg(struct mtpav *chip, u16 reg, u8 val)
0224 {
0225 if (reg == DREG || reg == CREG)
0226 outb(val, chip->port + reg);
0227 }
0228
0229
0230
0231
0232 static void snd_mtpav_wait_rfdhi(struct mtpav *chip)
0233 {
0234 int counts = 10000;
0235 u8 sbyte;
0236
0237 sbyte = snd_mtpav_getreg(chip, SREG);
0238 while (!(sbyte & SIGS_RFD) && counts--) {
0239 sbyte = snd_mtpav_getreg(chip, SREG);
0240 udelay(10);
0241 }
0242 }
0243
0244 static void snd_mtpav_send_byte(struct mtpav *chip, u8 byte)
0245 {
0246 u8 tcbyt;
0247 u8 clrwrite;
0248 u8 setwrite;
0249
0250 snd_mtpav_wait_rfdhi(chip);
0251
0252
0253
0254 tcbyt = snd_mtpav_getreg(chip, CREG);
0255 clrwrite = tcbyt & (SIGC_WRITE ^ 0xff);
0256 setwrite = tcbyt | SIGC_WRITE;
0257
0258 snd_mtpav_mputreg(chip, DREG, byte);
0259 snd_mtpav_mputreg(chip, CREG, clrwrite);
0260
0261 snd_mtpav_mputreg(chip, CREG, setwrite);
0262
0263 }
0264
0265
0266
0267
0268
0269
0270 static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
0271 struct mtpav_port *portp,
0272 struct snd_rawmidi_substream *substream)
0273 {
0274 u8 outbyte;
0275
0276
0277
0278 if (snd_rawmidi_transmit(substream, &outbyte, 1) != 1)
0279 return;
0280
0281
0282
0283 if (portp->hwport != mtp_card->outmidihwport) {
0284 mtp_card->outmidihwport = portp->hwport;
0285
0286 snd_mtpav_send_byte(mtp_card, 0xf5);
0287 snd_mtpav_send_byte(mtp_card, portp->hwport);
0288
0289
0290
0291
0292 if (!(outbyte & 0x80) && portp->running_status)
0293 snd_mtpav_send_byte(mtp_card, portp->running_status);
0294 }
0295
0296
0297
0298 do {
0299 if (outbyte & 0x80)
0300 portp->running_status = outbyte;
0301
0302 snd_mtpav_send_byte(mtp_card, outbyte);
0303 } while (snd_rawmidi_transmit(substream, &outbyte, 1) == 1);
0304 }
0305
0306 static void snd_mtpav_output_write(struct snd_rawmidi_substream *substream)
0307 {
0308 struct mtpav *mtp_card = substream->rmidi->private_data;
0309 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0310 unsigned long flags;
0311
0312 spin_lock_irqsave(&mtp_card->spinlock, flags);
0313 snd_mtpav_output_port_write(mtp_card, portp, substream);
0314 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0315 }
0316
0317
0318
0319
0320
0321
0322 static void snd_mtpav_portscan(struct mtpav *chip)
0323 {
0324 u8 p;
0325
0326 for (p = 0; p < 8; p++) {
0327 snd_mtpav_send_byte(chip, 0xf5);
0328 snd_mtpav_send_byte(chip, p);
0329 snd_mtpav_send_byte(chip, 0xfe);
0330 }
0331 }
0332
0333
0334
0335
0336 static int snd_mtpav_input_open(struct snd_rawmidi_substream *substream)
0337 {
0338 struct mtpav *mtp_card = substream->rmidi->private_data;
0339 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0340 unsigned long flags;
0341
0342 spin_lock_irqsave(&mtp_card->spinlock, flags);
0343 portp->mode |= MTPAV_MODE_INPUT_OPENED;
0344 portp->input = substream;
0345 if (mtp_card->share_irq++ == 0)
0346 snd_mtpav_mputreg(mtp_card, CREG, (SIGC_INTEN | SIGC_WRITE));
0347 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0348 return 0;
0349 }
0350
0351
0352
0353
0354 static int snd_mtpav_input_close(struct snd_rawmidi_substream *substream)
0355 {
0356 struct mtpav *mtp_card = substream->rmidi->private_data;
0357 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0358 unsigned long flags;
0359
0360 spin_lock_irqsave(&mtp_card->spinlock, flags);
0361 portp->mode &= ~MTPAV_MODE_INPUT_OPENED;
0362 portp->input = NULL;
0363 if (--mtp_card->share_irq == 0)
0364 snd_mtpav_mputreg(mtp_card, CREG, 0);
0365 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0366 return 0;
0367 }
0368
0369
0370
0371
0372 static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int up)
0373 {
0374 struct mtpav *mtp_card = substream->rmidi->private_data;
0375 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0376 unsigned long flags;
0377
0378 spin_lock_irqsave(&mtp_card->spinlock, flags);
0379 if (up)
0380 portp->mode |= MTPAV_MODE_INPUT_TRIGGERED;
0381 else
0382 portp->mode &= ~MTPAV_MODE_INPUT_TRIGGERED;
0383 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0384
0385 }
0386
0387
0388
0389
0390
0391
0392 static void snd_mtpav_output_timer(struct timer_list *t)
0393 {
0394 unsigned long flags;
0395 struct mtpav *chip = from_timer(chip, t, timer);
0396 int p;
0397
0398 spin_lock_irqsave(&chip->spinlock, flags);
0399
0400 mod_timer(&chip->timer, 1 + jiffies);
0401
0402 for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
0403 struct mtpav_port *portp = &chip->ports[p];
0404 if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output)
0405 snd_mtpav_output_port_write(chip, portp, portp->output);
0406 }
0407 spin_unlock_irqrestore(&chip->spinlock, flags);
0408 }
0409
0410
0411 static void snd_mtpav_add_output_timer(struct mtpav *chip)
0412 {
0413 mod_timer(&chip->timer, 1 + jiffies);
0414 }
0415
0416
0417 static void snd_mtpav_remove_output_timer(struct mtpav *chip)
0418 {
0419 del_timer(&chip->timer);
0420 }
0421
0422
0423
0424
0425 static int snd_mtpav_output_open(struct snd_rawmidi_substream *substream)
0426 {
0427 struct mtpav *mtp_card = substream->rmidi->private_data;
0428 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0429 unsigned long flags;
0430
0431 spin_lock_irqsave(&mtp_card->spinlock, flags);
0432 portp->mode |= MTPAV_MODE_OUTPUT_OPENED;
0433 portp->output = substream;
0434 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0435 return 0;
0436 };
0437
0438
0439
0440
0441 static int snd_mtpav_output_close(struct snd_rawmidi_substream *substream)
0442 {
0443 struct mtpav *mtp_card = substream->rmidi->private_data;
0444 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0445 unsigned long flags;
0446
0447 spin_lock_irqsave(&mtp_card->spinlock, flags);
0448 portp->mode &= ~MTPAV_MODE_OUTPUT_OPENED;
0449 portp->output = NULL;
0450 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0451 return 0;
0452 };
0453
0454
0455
0456
0457 static void snd_mtpav_output_trigger(struct snd_rawmidi_substream *substream, int up)
0458 {
0459 struct mtpav *mtp_card = substream->rmidi->private_data;
0460 struct mtpav_port *portp = &mtp_card->ports[substream->number];
0461 unsigned long flags;
0462
0463 spin_lock_irqsave(&mtp_card->spinlock, flags);
0464 if (up) {
0465 if (! (portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) {
0466 if (mtp_card->istimer++ == 0)
0467 snd_mtpav_add_output_timer(mtp_card);
0468 portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED;
0469 }
0470 } else {
0471 portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED;
0472 if (--mtp_card->istimer == 0)
0473 snd_mtpav_remove_output_timer(mtp_card);
0474 }
0475 spin_unlock_irqrestore(&mtp_card->spinlock, flags);
0476
0477 if (up)
0478 snd_mtpav_output_write(substream);
0479 }
0480
0481
0482
0483
0484
0485 static void snd_mtpav_inmidi_process(struct mtpav *mcrd, u8 inbyte)
0486 {
0487 struct mtpav_port *portp;
0488
0489 if ((int)mcrd->inmidiport > mcrd->num_ports * 2 + MTPAV_PIDX_BROADCAST)
0490 return;
0491
0492 portp = &mcrd->ports[mcrd->inmidiport];
0493 if (portp->mode & MTPAV_MODE_INPUT_TRIGGERED)
0494 snd_rawmidi_receive(portp->input, &inbyte, 1);
0495 }
0496
0497 static void snd_mtpav_inmidi_h(struct mtpav *mcrd, u8 inbyte)
0498 {
0499 if (inbyte >= 0xf8) {
0500
0501 snd_mtpav_inmidi_process(mcrd, inbyte);
0502 return;
0503 }
0504
0505 if (mcrd->inmidistate == 0) {
0506 if (inbyte == 0xf5)
0507 mcrd->inmidistate = 1;
0508 else
0509 snd_mtpav_inmidi_process(mcrd, inbyte);
0510 } else if (mcrd->inmidistate) {
0511 mcrd->inmidiport = translate_hwport_to_subdevice(mcrd, inbyte);
0512 mcrd->inmidistate = 0;
0513 }
0514 }
0515
0516 static void snd_mtpav_read_bytes(struct mtpav *mcrd)
0517 {
0518 u8 clrread, setread;
0519 u8 mtp_read_byte;
0520 u8 sr, cbyt;
0521 int i;
0522
0523 u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
0524
0525
0526
0527 if (!(sbyt & SIGS_BYTE))
0528 return;
0529
0530 cbyt = snd_mtpav_getreg(mcrd, CREG);
0531 clrread = cbyt & (SIGC_READ ^ 0xff);
0532 setread = cbyt | SIGC_READ;
0533
0534 do {
0535
0536 mtp_read_byte = 0;
0537 for (i = 0; i < 4; i++) {
0538 snd_mtpav_mputreg(mcrd, CREG, setread);
0539 sr = snd_mtpav_getreg(mcrd, SREG);
0540 snd_mtpav_mputreg(mcrd, CREG, clrread);
0541
0542 sr &= SIGS_IN0 | SIGS_IN1;
0543 sr >>= 4;
0544 mtp_read_byte |= sr << (i * 2);
0545 }
0546
0547 snd_mtpav_inmidi_h(mcrd, mtp_read_byte);
0548
0549 sbyt = snd_mtpav_getreg(mcrd, SREG);
0550
0551 } while (sbyt & SIGS_BYTE);
0552 }
0553
0554 static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
0555 {
0556 struct mtpav *mcard = dev_id;
0557
0558 spin_lock(&mcard->spinlock);
0559 snd_mtpav_read_bytes(mcard);
0560 spin_unlock(&mcard->spinlock);
0561 return IRQ_HANDLED;
0562 }
0563
0564
0565
0566
0567 static int snd_mtpav_get_ISA(struct mtpav *mcard)
0568 {
0569 mcard->res_port = devm_request_region(mcard->card->dev, port, 3,
0570 "MotuMTPAV MIDI");
0571 if (!mcard->res_port) {
0572 snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
0573 return -EBUSY;
0574 }
0575 mcard->port = port;
0576 if (devm_request_irq(mcard->card->dev, irq, snd_mtpav_irqh, 0,
0577 "MOTU MTPAV", mcard)) {
0578 snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
0579 return -EBUSY;
0580 }
0581 mcard->irq = irq;
0582 return 0;
0583 }
0584
0585
0586
0587
0588
0589 static const struct snd_rawmidi_ops snd_mtpav_output = {
0590 .open = snd_mtpav_output_open,
0591 .close = snd_mtpav_output_close,
0592 .trigger = snd_mtpav_output_trigger,
0593 };
0594
0595 static const struct snd_rawmidi_ops snd_mtpav_input = {
0596 .open = snd_mtpav_input_open,
0597 .close = snd_mtpav_input_close,
0598 .trigger = snd_mtpav_input_trigger,
0599 };
0600
0601
0602
0603
0604
0605
0606 static void snd_mtpav_set_name(struct mtpav *chip,
0607 struct snd_rawmidi_substream *substream)
0608 {
0609 if (substream->number >= 0 && substream->number < chip->num_ports)
0610 sprintf(substream->name, "MTP direct %d", (substream->number % chip->num_ports) + 1);
0611 else if (substream->number >= 8 && substream->number < chip->num_ports * 2)
0612 sprintf(substream->name, "MTP remote %d", (substream->number % chip->num_ports) + 1);
0613 else if (substream->number == chip->num_ports * 2)
0614 strcpy(substream->name, "MTP computer");
0615 else if (substream->number == chip->num_ports * 2 + 1)
0616 strcpy(substream->name, "MTP ADAT");
0617 else
0618 strcpy(substream->name, "MTP broadcast");
0619 }
0620
0621 static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
0622 {
0623 int rval;
0624 struct snd_rawmidi *rawmidi;
0625 struct snd_rawmidi_substream *substream;
0626 struct list_head *list;
0627
0628 if (hwports < 1)
0629 hwports = 1;
0630 else if (hwports > 8)
0631 hwports = 8;
0632 mcard->num_ports = hwports;
0633
0634 rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
0635 mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
0636 mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
0637 &mcard->rmidi);
0638 if (rval < 0)
0639 return rval;
0640 rawmidi = mcard->rmidi;
0641 rawmidi->private_data = mcard;
0642
0643 list_for_each(list, &rawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
0644 substream = list_entry(list, struct snd_rawmidi_substream, list);
0645 snd_mtpav_set_name(mcard, substream);
0646 substream->ops = &snd_mtpav_input;
0647 }
0648 list_for_each(list, &rawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
0649 substream = list_entry(list, struct snd_rawmidi_substream, list);
0650 snd_mtpav_set_name(mcard, substream);
0651 substream->ops = &snd_mtpav_output;
0652 mcard->ports[substream->number].hwport = translate_subdevice_to_hwport(mcard, substream->number);
0653 }
0654 rawmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
0655 SNDRV_RAWMIDI_INFO_DUPLEX;
0656 sprintf(rawmidi->name, "MTP AV MIDI");
0657 return 0;
0658 }
0659
0660
0661
0662
0663 static void snd_mtpav_free(struct snd_card *card)
0664 {
0665 struct mtpav *crd = card->private_data;
0666 unsigned long flags;
0667
0668 spin_lock_irqsave(&crd->spinlock, flags);
0669 if (crd->istimer > 0)
0670 snd_mtpav_remove_output_timer(crd);
0671 spin_unlock_irqrestore(&crd->spinlock, flags);
0672 }
0673
0674
0675
0676 static int snd_mtpav_probe(struct platform_device *dev)
0677 {
0678 struct snd_card *card;
0679 int err;
0680 struct mtpav *mtp_card;
0681
0682 err = snd_devm_card_new(&dev->dev, index, id, THIS_MODULE,
0683 sizeof(*mtp_card), &card);
0684 if (err < 0)
0685 return err;
0686
0687 mtp_card = card->private_data;
0688 spin_lock_init(&mtp_card->spinlock);
0689 mtp_card->card = card;
0690 mtp_card->irq = -1;
0691 mtp_card->share_irq = 0;
0692 mtp_card->inmidistate = 0;
0693 mtp_card->outmidihwport = 0xffffffff;
0694 timer_setup(&mtp_card->timer, snd_mtpav_output_timer, 0);
0695
0696 err = snd_mtpav_get_RAWMIDI(mtp_card);
0697 if (err < 0)
0698 return err;
0699
0700 mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST;
0701
0702 err = snd_mtpav_get_ISA(mtp_card);
0703 if (err < 0)
0704 return err;
0705
0706 strcpy(card->driver, "MTPAV");
0707 strcpy(card->shortname, "MTPAV on parallel port");
0708 snprintf(card->longname, sizeof(card->longname),
0709 "MTPAV on parallel port at 0x%lx", port);
0710
0711 snd_mtpav_portscan(mtp_card);
0712
0713 err = snd_card_register(mtp_card->card);
0714 if (err < 0)
0715 return err;
0716
0717 card->private_free = snd_mtpav_free;
0718
0719 platform_set_drvdata(dev, card);
0720 printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", irq, port);
0721 return 0;
0722 }
0723
0724 #define SND_MTPAV_DRIVER "snd_mtpav"
0725
0726 static struct platform_driver snd_mtpav_driver = {
0727 .probe = snd_mtpav_probe,
0728 .driver = {
0729 .name = SND_MTPAV_DRIVER,
0730 },
0731 };
0732
0733 static int __init alsa_card_mtpav_init(void)
0734 {
0735 int err;
0736
0737 err = platform_driver_register(&snd_mtpav_driver);
0738 if (err < 0)
0739 return err;
0740
0741 device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);
0742 if (!IS_ERR(device)) {
0743 if (platform_get_drvdata(device))
0744 return 0;
0745 platform_device_unregister(device);
0746 err = -ENODEV;
0747 } else
0748 err = PTR_ERR(device);
0749 platform_driver_unregister(&snd_mtpav_driver);
0750 return err;
0751 }
0752
0753 static void __exit alsa_card_mtpav_exit(void)
0754 {
0755 platform_device_unregister(device);
0756 platform_driver_unregister(&snd_mtpav_driver);
0757 }
0758
0759 module_init(alsa_card_mtpav_init)
0760 module_exit(alsa_card_mtpav_exit)