diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/drivers/mpu401/mpu401_uart.c | 108 |
1 files changed, 66 insertions, 42 deletions
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index b49a45cbf67a..cd64d3eb9ec8 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
@@ -58,22 +58,26 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu); | |||
58 | #define MPU401_ACK 0xfe | 58 | #define MPU401_ACK 0xfe |
59 | 59 | ||
60 | /* Build in lowlevel io */ | 60 | /* Build in lowlevel io */ |
61 | static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr) | 61 | static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, |
62 | unsigned long addr) | ||
62 | { | 63 | { |
63 | outb(data, addr); | 64 | outb(data, addr); |
64 | } | 65 | } |
65 | 66 | ||
66 | static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, unsigned long addr) | 67 | static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, |
68 | unsigned long addr) | ||
67 | { | 69 | { |
68 | return inb(addr); | 70 | return inb(addr); |
69 | } | 71 | } |
70 | 72 | ||
71 | static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr) | 73 | static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, |
74 | unsigned long addr) | ||
72 | { | 75 | { |
73 | writeb(data, (void __iomem *)addr); | 76 | writeb(data, (void __iomem *)addr); |
74 | } | 77 | } |
75 | 78 | ||
76 | static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, unsigned long addr) | 79 | static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, |
80 | unsigned long addr) | ||
77 | { | 81 | { |
78 | return readb((void __iomem *)addr); | 82 | return readb((void __iomem *)addr); |
79 | } | 83 | } |
@@ -86,20 +90,22 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) | |||
86 | mpu->read(mpu, MPU401D(mpu)); | 90 | mpu->read(mpu, MPU401D(mpu)); |
87 | #ifdef CONFIG_SND_DEBUG | 91 | #ifdef CONFIG_SND_DEBUG |
88 | if (timeout <= 0) | 92 | if (timeout <= 0) |
89 | snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); | 93 | snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", |
94 | mpu->read(mpu, MPU401C(mpu))); | ||
90 | #endif | 95 | #endif |
91 | } | 96 | } |
92 | 97 | ||
93 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | 98 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) |
94 | { | 99 | { |
95 | spin_lock(&mpu->input_lock); | 100 | spin_lock(&mpu->input_lock); |
96 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { | 101 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) |
97 | snd_mpu401_uart_input_read(mpu); | 102 | snd_mpu401_uart_input_read(mpu); |
98 | } else { | 103 | else |
99 | snd_mpu401_uart_clear_rx(mpu); | 104 | snd_mpu401_uart_clear_rx(mpu); |
100 | } | ||
101 | spin_unlock(&mpu->input_lock); | 105 | spin_unlock(&mpu->input_lock); |
102 | /* ok. for better Tx performance try do some output when input is done */ | 106 | /* ok. for better Tx performance try do some output when |
107 | * input is done | ||
108 | */ | ||
103 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && | 109 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && |
104 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { | 110 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { |
105 | spin_lock(&mpu->output_lock); | 111 | spin_lock(&mpu->output_lock); |
@@ -116,7 +122,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | |||
116 | * | 122 | * |
117 | * Processes the interrupt for MPU401-UART i/o. | 123 | * Processes the interrupt for MPU401-UART i/o. |
118 | */ | 124 | */ |
119 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 125 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, |
126 | struct pt_regs *regs) | ||
120 | { | 127 | { |
121 | struct snd_mpu401 *mpu = dev_id; | 128 | struct snd_mpu401 *mpu = dev_id; |
122 | 129 | ||
@@ -126,6 +133,8 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg | |||
126 | return IRQ_HANDLED; | 133 | return IRQ_HANDLED; |
127 | } | 134 | } |
128 | 135 | ||
136 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); | ||
137 | |||
129 | /* | 138 | /* |
130 | * timer callback | 139 | * timer callback |
131 | * reprogram the timer and call the interrupt job | 140 | * reprogram the timer and call the interrupt job |
@@ -159,7 +168,8 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) | |||
159 | mpu->timer.expires = 1 + jiffies; | 168 | mpu->timer.expires = 1 + jiffies; |
160 | add_timer(&mpu->timer); | 169 | add_timer(&mpu->timer); |
161 | } | 170 | } |
162 | mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER; | 171 | mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : |
172 | MPU401_MODE_OUTPUT_TIMER; | ||
163 | spin_unlock_irqrestore (&mpu->timer_lock, flags); | 173 | spin_unlock_irqrestore (&mpu->timer_lock, flags); |
164 | } | 174 | } |
165 | 175 | ||
@@ -172,7 +182,8 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) | |||
172 | 182 | ||
173 | spin_lock_irqsave (&mpu->timer_lock, flags); | 183 | spin_lock_irqsave (&mpu->timer_lock, flags); |
174 | if (mpu->timer_invoked) { | 184 | if (mpu->timer_invoked) { |
175 | mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER; | 185 | mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : |
186 | ~MPU401_MODE_OUTPUT_TIMER; | ||
176 | if (! mpu->timer_invoked) | 187 | if (! mpu->timer_invoked) |
177 | del_timer(&mpu->timer); | 188 | del_timer(&mpu->timer); |
178 | } | 189 | } |
@@ -180,11 +191,12 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) | |||
180 | } | 191 | } |
181 | 192 | ||
182 | /* | 193 | /* |
183 | 194 | * send a UART command | |
195 | * return zero if successful, non-zero for some errors | ||
184 | */ | 196 | */ |
185 | 197 | ||
186 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | 198 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, |
187 | int ack) | 199 | int ack) |
188 | { | 200 | { |
189 | unsigned long flags; | 201 | unsigned long flags; |
190 | int timeout, ok; | 202 | int timeout, ok; |
@@ -196,11 +208,13 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | |||
196 | } | 208 | } |
197 | /* ok. standard MPU-401 initialization */ | 209 | /* ok. standard MPU-401 initialization */ |
198 | if (mpu->hardware != MPU401_HW_SB) { | 210 | if (mpu->hardware != MPU401_HW_SB) { |
199 | for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--) | 211 | for (timeout = 1000; timeout > 0 && |
212 | !snd_mpu401_output_ready(mpu); timeout--) | ||
200 | udelay(10); | 213 | udelay(10); |
201 | #ifdef CONFIG_SND_DEBUG | 214 | #ifdef CONFIG_SND_DEBUG |
202 | if (!timeout) | 215 | if (!timeout) |
203 | snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); | 216 | snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n", |
217 | mpu->read(mpu, MPU401C(mpu))); | ||
204 | #endif | 218 | #endif |
205 | } | 219 | } |
206 | mpu->write(mpu, cmd, MPU401C(mpu)); | 220 | mpu->write(mpu, cmd, MPU401C(mpu)); |
@@ -215,12 +229,14 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | |||
215 | } | 229 | } |
216 | if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) | 230 | if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) |
217 | ok = 1; | 231 | ok = 1; |
218 | } else { | 232 | } else |
219 | ok = 1; | 233 | ok = 1; |
220 | } | ||
221 | spin_unlock_irqrestore(&mpu->input_lock, flags); | 234 | spin_unlock_irqrestore(&mpu->input_lock, flags); |
222 | if (!ok) { | 235 | if (!ok) { |
223 | snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); | 236 | snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx " |
237 | "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port, | ||
238 | mpu->read(mpu, MPU401C(mpu)), | ||
239 | mpu->read(mpu, MPU401D(mpu))); | ||
224 | return 1; | 240 | return 1; |
225 | } | 241 | } |
226 | return 0; | 242 | return 0; |
@@ -314,7 +330,8 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) | |||
314 | /* | 330 | /* |
315 | * trigger input callback | 331 | * trigger input callback |
316 | */ | 332 | */ |
317 | static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) | 333 | static void |
334 | snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) | ||
318 | { | 335 | { |
319 | unsigned long flags; | 336 | unsigned long flags; |
320 | struct snd_mpu401 *mpu; | 337 | struct snd_mpu401 *mpu; |
@@ -322,7 +339,8 @@ static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substrea | |||
322 | 339 | ||
323 | mpu = substream->rmidi->private_data; | 340 | mpu = substream->rmidi->private_data; |
324 | if (up) { | 341 | if (up) { |
325 | if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { | 342 | if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, |
343 | &mpu->mode)) { | ||
326 | /* first time - flush FIFO */ | 344 | /* first time - flush FIFO */ |
327 | while (max-- > 0) | 345 | while (max-- > 0) |
328 | mpu->read(mpu, MPU401D(mpu)); | 346 | mpu->read(mpu, MPU401D(mpu)); |
@@ -352,13 +370,11 @@ static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu) | |||
352 | unsigned char byte; | 370 | unsigned char byte; |
353 | 371 | ||
354 | while (max-- > 0) { | 372 | while (max-- > 0) { |
355 | if (snd_mpu401_input_avail(mpu)) { | 373 | if (! snd_mpu401_input_avail(mpu)) |
356 | byte = mpu->read(mpu, MPU401D(mpu)); | ||
357 | if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) | ||
358 | snd_rawmidi_receive(mpu->substream_input, &byte, 1); | ||
359 | } else { | ||
360 | break; /* input not available */ | 374 | break; /* input not available */ |
361 | } | 375 | byte = mpu->read(mpu, MPU401D(mpu)); |
376 | if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) | ||
377 | snd_rawmidi_receive(mpu->substream_input, &byte, 1); | ||
362 | } | 378 | } |
363 | } | 379 | } |
364 | 380 | ||
@@ -380,16 +396,16 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) | |||
380 | int max = 256, timeout; | 396 | int max = 256, timeout; |
381 | 397 | ||
382 | do { | 398 | do { |
383 | if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) { | 399 | if (snd_rawmidi_transmit_peek(mpu->substream_output, |
400 | &byte, 1) == 1) { | ||
384 | for (timeout = 100; timeout > 0; timeout--) { | 401 | for (timeout = 100; timeout > 0; timeout--) { |
385 | if (snd_mpu401_output_ready(mpu)) { | 402 | if (snd_mpu401_output_ready(mpu)) |
386 | mpu->write(mpu, byte, MPU401D(mpu)); | ||
387 | snd_rawmidi_transmit_ack(mpu->substream_output, 1); | ||
388 | break; | 403 | break; |
389 | } | ||
390 | } | 404 | } |
391 | if (timeout == 0) | 405 | if (timeout == 0) |
392 | break; /* Tx FIFO full - try again later */ | 406 | break; /* Tx FIFO full - try again later */ |
407 | mpu->write(mpu, byte, MPU401D(mpu)); | ||
408 | snd_rawmidi_transmit_ack(mpu->substream_output, 1); | ||
393 | } else { | 409 | } else { |
394 | snd_mpu401_uart_remove_timer (mpu, 0); | 410 | snd_mpu401_uart_remove_timer (mpu, 0); |
395 | break; /* no other data - leave the tx loop */ | 411 | break; /* no other data - leave the tx loop */ |
@@ -400,7 +416,8 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) | |||
400 | /* | 416 | /* |
401 | * output trigger callback | 417 | * output trigger callback |
402 | */ | 418 | */ |
403 | static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) | 419 | static void |
420 | snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) | ||
404 | { | 421 | { |
405 | unsigned long flags; | 422 | unsigned long flags; |
406 | struct snd_mpu401 *mpu; | 423 | struct snd_mpu401 *mpu; |
@@ -499,8 +516,11 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
499 | mpu->hardware = hardware; | 516 | mpu->hardware = hardware; |
500 | if (!integrated) { | 517 | if (!integrated) { |
501 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; | 518 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; |
502 | if ((mpu->res = request_region(port, res_size, "MPU401 UART")) == NULL) { | 519 | mpu->res = request_region(port, res_size, "MPU401 UART"); |
503 | snd_printk(KERN_ERR "mpu401_uart: unable to grab port 0x%lx size %d\n", port, res_size); | 520 | if (mpu->res == NULL) { |
521 | snd_printk(KERN_ERR "mpu401_uart: " | ||
522 | "unable to grab port 0x%lx size %d\n", | ||
523 | port, res_size); | ||
504 | snd_device_free(card, rmidi); | 524 | snd_device_free(card, rmidi); |
505 | return -EBUSY; | 525 | return -EBUSY; |
506 | } | 526 | } |
@@ -521,8 +541,10 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
521 | else | 541 | else |
522 | mpu->cport = port + 1; | 542 | mpu->cport = port + 1; |
523 | if (irq >= 0 && irq_flags) { | 543 | if (irq >= 0 && irq_flags) { |
524 | if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) { | 544 | if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, |
525 | snd_printk(KERN_ERR "mpu401_uart: unable to grab IRQ %d\n", irq); | 545 | "MPU401 UART", (void *) mpu)) { |
546 | snd_printk(KERN_ERR "mpu401_uart: " | ||
547 | "unable to grab IRQ %d\n", irq); | ||
526 | snd_device_free(card, rmidi); | 548 | snd_device_free(card, rmidi); |
527 | return -EBUSY; | 549 | return -EBUSY; |
528 | } | 550 | } |
@@ -530,11 +552,14 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
530 | mpu->irq = irq; | 552 | mpu->irq = irq; |
531 | mpu->irq_flags = irq_flags; | 553 | mpu->irq_flags = irq_flags; |
532 | if (card->shortname[0]) | 554 | if (card->shortname[0]) |
533 | snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname); | 555 | snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", |
556 | card->shortname); | ||
534 | else | 557 | else |
535 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device); | 558 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device); |
536 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output); | 559 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
537 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input); | 560 | &snd_mpu401_uart_output); |
561 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
562 | &snd_mpu401_uart_input); | ||
538 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | 563 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | |
539 | SNDRV_RAWMIDI_INFO_INPUT | | 564 | SNDRV_RAWMIDI_INFO_INPUT | |
540 | SNDRV_RAWMIDI_INFO_DUPLEX; | 565 | SNDRV_RAWMIDI_INFO_DUPLEX; |
@@ -544,7 +569,6 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
544 | return 0; | 569 | return 0; |
545 | } | 570 | } |
546 | 571 | ||
547 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); | ||
548 | EXPORT_SYMBOL(snd_mpu401_uart_new); | 572 | EXPORT_SYMBOL(snd_mpu401_uart_new); |
549 | 573 | ||
550 | /* | 574 | /* |