| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 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 | */ | 
|  | 69 | MODULE_AUTHOR("Michael T. Mayers"); | 
|  | 70 | MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI"); | 
|  | 71 | MODULE_LICENSE("GPL"); | 
|  | 72 | MODULE_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 |  | 
|  | 79 | static int index = SNDRV_DEFAULT_IDX1; | 
|  | 80 | static char *id = SNDRV_DEFAULT_STR1; | 
|  | 81 | static long port = MTPAV_IOBASE;	/* 0x378, 0x278 */ | 
|  | 82 | static int irq = MTPAV_IRQ;		/* 7, 5 */ | 
|  | 83 | static int hwports = MTPAV_MAX_PORTS;	/* use hardware ports 1-8 */ | 
|  | 84 |  | 
|  | 85 | module_param(index, int, 0444); | 
|  | 86 | MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI."); | 
|  | 87 | module_param(id, charp, 0444); | 
|  | 88 | MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI."); | 
|  | 89 | module_param_hw(port, long, ioport, 0444); | 
|  | 90 | MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI."); | 
|  | 91 | module_param_hw(irq, int, irq, 0444); | 
|  | 92 | MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI."); | 
|  | 93 | module_param(hwports, int, 0444); | 
|  | 94 | MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI."); | 
|  | 95 |  | 
|  | 96 | static 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 |  | 
|  | 130 | struct 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 |  | 
|  | 139 | struct 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 |  | 
|  | 182 | static 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 |  | 
|  | 197 | static 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 |  | 
|  | 222 | static 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 |  | 
|  | 240 | static 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 |  | 
|  | 249 | static 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 |  | 
|  | 261 | static 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 */ | 
|  | 287 | static 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 |  | 
|  | 323 | static 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 |  | 
|  | 339 | static 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 |  | 
|  | 353 | static 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 |  | 
|  | 371 | static 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 |  | 
|  | 389 | static 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 |  | 
|  | 409 | static void snd_mtpav_output_timer(struct timer_list *t) | 
|  | 410 | { | 
|  | 411 | unsigned long flags; | 
|  | 412 | struct mtpav *chip = from_timer(chip, t, timer); | 
|  | 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! */ | 
|  | 428 | static void snd_mtpav_add_output_timer(struct mtpav *chip) | 
|  | 429 | { | 
|  | 430 | mod_timer(&chip->timer, 1 + jiffies); | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | /* spinlock held! */ | 
|  | 434 | static void snd_mtpav_remove_output_timer(struct mtpav *chip) | 
|  | 435 | { | 
|  | 436 | del_timer(&chip->timer); | 
|  | 437 | } | 
|  | 438 |  | 
|  | 439 | /* | 
|  | 440 | */ | 
|  | 441 |  | 
|  | 442 | static 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 |  | 
|  | 458 | static 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 |  | 
|  | 474 | static 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 |  | 
|  | 502 | static 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 |  | 
|  | 514 | static 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 |  | 
|  | 533 | static 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 |  | 
|  | 571 | static 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 | */ | 
|  | 584 | static 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 |  | 
|  | 603 | static const 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 |  | 
|  | 609 | static const 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 |  | 
|  | 620 | static 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 |  | 
|  | 635 | static 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 |  | 
|  | 676 | static 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 | */ | 
|  | 692 | static 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 | timer_setup(&mtp_card->timer, snd_mtpav_output_timer, 0); | 
|  | 711 |  | 
|  | 712 | card->private_free = snd_mtpav_free; | 
|  | 713 |  | 
|  | 714 | err = snd_mtpav_get_RAWMIDI(mtp_card); | 
|  | 715 | if (err < 0) | 
|  | 716 | goto __error; | 
|  | 717 |  | 
|  | 718 | mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST; | 
|  | 719 |  | 
|  | 720 | err = snd_mtpav_get_ISA(mtp_card); | 
|  | 721 | if (err < 0) | 
|  | 722 | goto __error; | 
|  | 723 |  | 
|  | 724 | strcpy(card->driver, "MTPAV"); | 
|  | 725 | strcpy(card->shortname, "MTPAV on parallel port"); | 
|  | 726 | snprintf(card->longname, sizeof(card->longname), | 
|  | 727 | "MTPAV on parallel port at 0x%lx", port); | 
|  | 728 |  | 
|  | 729 | snd_mtpav_portscan(mtp_card); | 
|  | 730 |  | 
|  | 731 | err = snd_card_register(mtp_card->card); | 
|  | 732 | if (err < 0) | 
|  | 733 | goto __error; | 
|  | 734 |  | 
|  | 735 | platform_set_drvdata(dev, card); | 
|  | 736 | printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", irq, port); | 
|  | 737 | return 0; | 
|  | 738 |  | 
|  | 739 | __error: | 
|  | 740 | snd_card_free(card); | 
|  | 741 | return err; | 
|  | 742 | } | 
|  | 743 |  | 
|  | 744 | static int snd_mtpav_remove(struct platform_device *devptr) | 
|  | 745 | { | 
|  | 746 | snd_card_free(platform_get_drvdata(devptr)); | 
|  | 747 | return 0; | 
|  | 748 | } | 
|  | 749 |  | 
|  | 750 | #define SND_MTPAV_DRIVER	"snd_mtpav" | 
|  | 751 |  | 
|  | 752 | static struct platform_driver snd_mtpav_driver = { | 
|  | 753 | .probe		= snd_mtpav_probe, | 
|  | 754 | .remove		= snd_mtpav_remove, | 
|  | 755 | .driver		= { | 
|  | 756 | .name	= SND_MTPAV_DRIVER, | 
|  | 757 | }, | 
|  | 758 | }; | 
|  | 759 |  | 
|  | 760 | static int __init alsa_card_mtpav_init(void) | 
|  | 761 | { | 
|  | 762 | int err; | 
|  | 763 |  | 
|  | 764 | if ((err = platform_driver_register(&snd_mtpav_driver)) < 0) | 
|  | 765 | return err; | 
|  | 766 |  | 
|  | 767 | device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0); | 
|  | 768 | if (!IS_ERR(device)) { | 
|  | 769 | if (platform_get_drvdata(device)) | 
|  | 770 | return 0; | 
|  | 771 | platform_device_unregister(device); | 
|  | 772 | err = -ENODEV; | 
|  | 773 | } else | 
|  | 774 | err = PTR_ERR(device); | 
|  | 775 | platform_driver_unregister(&snd_mtpav_driver); | 
|  | 776 | return err; | 
|  | 777 | } | 
|  | 778 |  | 
|  | 779 | static void __exit alsa_card_mtpav_exit(void) | 
|  | 780 | { | 
|  | 781 | platform_device_unregister(device); | 
|  | 782 | platform_driver_unregister(&snd_mtpav_driver); | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | module_init(alsa_card_mtpav_init) | 
|  | 786 | module_exit(alsa_card_mtpav_exit) |