1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
4 | * Routines for control of MPU-401 in UART mode |
5 | * |
6 | * MPU-401 supports UART mode which is not capable generate transmit |
7 | * interrupts thus output is done via polling. Without interrupt, |
8 | * input is done also via polling. Do not expect good performance. |
9 | * |
10 | * 13-03-2003: |
11 | * Added support for different kind of hardware I/O. Build in choices |
12 | * are port and mmio. For other kind of I/O, set mpu->read and |
13 | * mpu->write to your own I/O functions. |
14 | */ |
15 | |
16 | #include <linux/io.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/init.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/ioport.h> |
21 | #include <linux/module.h> |
22 | #include <linux/interrupt.h> |
23 | #include <linux/errno.h> |
24 | #include <sound/core.h> |
25 | #include <sound/mpu401.h> |
26 | |
27 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>" ); |
28 | MODULE_DESCRIPTION("Routines for control of MPU-401 in UART mode" ); |
29 | MODULE_LICENSE("GPL" ); |
30 | |
31 | static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu); |
32 | static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu); |
33 | |
34 | /* |
35 | |
36 | */ |
37 | |
38 | #define snd_mpu401_input_avail(mpu) \ |
39 | (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_RX_EMPTY)) |
40 | #define snd_mpu401_output_ready(mpu) \ |
41 | (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_TX_FULL)) |
42 | |
43 | /* Build in lowlevel io */ |
44 | static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, |
45 | unsigned long addr) |
46 | { |
47 | outb(value: data, port: addr); |
48 | } |
49 | |
50 | static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, |
51 | unsigned long addr) |
52 | { |
53 | return inb(port: addr); |
54 | } |
55 | |
56 | static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, |
57 | unsigned long addr) |
58 | { |
59 | writeb(val: data, addr: (void __iomem *)addr); |
60 | } |
61 | |
62 | static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, |
63 | unsigned long addr) |
64 | { |
65 | return readb(addr: (void __iomem *)addr); |
66 | } |
67 | /* */ |
68 | |
69 | static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) |
70 | { |
71 | int timeout = 100000; |
72 | for (; timeout > 0 && snd_mpu401_input_avail(mpu); timeout--) |
73 | mpu->read(mpu, MPU401D(mpu)); |
74 | #ifdef CONFIG_SND_DEBUG |
75 | if (timeout <= 0) |
76 | snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n" , |
77 | mpu->read(mpu, MPU401C(mpu))); |
78 | #endif |
79 | } |
80 | |
81 | static void uart_interrupt_tx(struct snd_mpu401 *mpu) |
82 | { |
83 | unsigned long flags; |
84 | |
85 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && |
86 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { |
87 | spin_lock_irqsave(&mpu->output_lock, flags); |
88 | snd_mpu401_uart_output_write(mpu); |
89 | spin_unlock_irqrestore(lock: &mpu->output_lock, flags); |
90 | } |
91 | } |
92 | |
93 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) |
94 | { |
95 | unsigned long flags; |
96 | |
97 | if (mpu->info_flags & MPU401_INFO_INPUT) { |
98 | spin_lock_irqsave(&mpu->input_lock, flags); |
99 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) |
100 | snd_mpu401_uart_input_read(mpu); |
101 | else |
102 | snd_mpu401_uart_clear_rx(mpu); |
103 | spin_unlock_irqrestore(lock: &mpu->input_lock, flags); |
104 | } |
105 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
106 | /* ok. for better Tx performance try do some output |
107 | when input is done */ |
108 | uart_interrupt_tx(mpu); |
109 | } |
110 | |
111 | /** |
112 | * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler |
113 | * @irq: the irq number |
114 | * @dev_id: mpu401 instance |
115 | * |
116 | * Processes the interrupt for MPU401-UART i/o. |
117 | * |
118 | * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise. |
119 | */ |
120 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id) |
121 | { |
122 | struct snd_mpu401 *mpu = dev_id; |
123 | |
124 | if (!mpu) |
125 | return IRQ_NONE; |
126 | _snd_mpu401_uart_interrupt(mpu); |
127 | return IRQ_HANDLED; |
128 | } |
129 | |
130 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); |
131 | |
132 | /** |
133 | * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler |
134 | * @irq: the irq number |
135 | * @dev_id: mpu401 instance |
136 | * |
137 | * Processes the interrupt for MPU401-UART output. |
138 | * |
139 | * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise. |
140 | */ |
141 | irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id) |
142 | { |
143 | struct snd_mpu401 *mpu = dev_id; |
144 | |
145 | if (!mpu) |
146 | return IRQ_NONE; |
147 | uart_interrupt_tx(mpu); |
148 | return IRQ_HANDLED; |
149 | } |
150 | |
151 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); |
152 | |
153 | /* |
154 | * timer callback |
155 | * reprogram the timer and call the interrupt job |
156 | */ |
157 | static void snd_mpu401_uart_timer(struct timer_list *t) |
158 | { |
159 | struct snd_mpu401 *mpu = from_timer(mpu, t, timer); |
160 | unsigned long flags; |
161 | |
162 | spin_lock_irqsave(&mpu->timer_lock, flags); |
163 | /*mpu->mode |= MPU401_MODE_TIMER;*/ |
164 | mod_timer(timer: &mpu->timer, expires: 1 + jiffies); |
165 | spin_unlock_irqrestore(lock: &mpu->timer_lock, flags); |
166 | if (mpu->rmidi) |
167 | _snd_mpu401_uart_interrupt(mpu); |
168 | } |
169 | |
170 | /* |
171 | * initialize the timer callback if not programmed yet |
172 | */ |
173 | static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) |
174 | { |
175 | unsigned long flags; |
176 | |
177 | spin_lock_irqsave (&mpu->timer_lock, flags); |
178 | if (mpu->timer_invoked == 0) { |
179 | timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0); |
180 | mod_timer(timer: &mpu->timer, expires: 1 + jiffies); |
181 | } |
182 | mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : |
183 | MPU401_MODE_OUTPUT_TIMER; |
184 | spin_unlock_irqrestore (lock: &mpu->timer_lock, flags); |
185 | } |
186 | |
187 | /* |
188 | * remove the timer callback if still active |
189 | */ |
190 | static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) |
191 | { |
192 | unsigned long flags; |
193 | |
194 | spin_lock_irqsave (&mpu->timer_lock, flags); |
195 | if (mpu->timer_invoked) { |
196 | mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : |
197 | ~MPU401_MODE_OUTPUT_TIMER; |
198 | if (! mpu->timer_invoked) |
199 | del_timer(timer: &mpu->timer); |
200 | } |
201 | spin_unlock_irqrestore (lock: &mpu->timer_lock, flags); |
202 | } |
203 | |
204 | /* |
205 | * send a UART command |
206 | * return zero if successful, non-zero for some errors |
207 | */ |
208 | |
209 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, |
210 | int ack) |
211 | { |
212 | unsigned long flags; |
213 | int timeout, ok; |
214 | |
215 | spin_lock_irqsave(&mpu->input_lock, flags); |
216 | if (mpu->hardware != MPU401_HW_TRID4DWAVE) { |
217 | mpu->write(mpu, 0x00, MPU401D(mpu)); |
218 | /*snd_mpu401_uart_clear_rx(mpu);*/ |
219 | } |
220 | /* ok. standard MPU-401 initialization */ |
221 | if (mpu->hardware != MPU401_HW_SB) { |
222 | for (timeout = 1000; timeout > 0 && |
223 | !snd_mpu401_output_ready(mpu); timeout--) |
224 | udelay(10); |
225 | #ifdef CONFIG_SND_DEBUG |
226 | if (!timeout) |
227 | snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n" , |
228 | mpu->read(mpu, MPU401C(mpu))); |
229 | #endif |
230 | } |
231 | mpu->write(mpu, cmd, MPU401C(mpu)); |
232 | if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) { |
233 | ok = 0; |
234 | timeout = 10000; |
235 | while (!ok && timeout-- > 0) { |
236 | if (snd_mpu401_input_avail(mpu)) { |
237 | if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) |
238 | ok = 1; |
239 | } |
240 | } |
241 | if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) |
242 | ok = 1; |
243 | } else |
244 | ok = 1; |
245 | spin_unlock_irqrestore(lock: &mpu->input_lock, flags); |
246 | if (!ok) { |
247 | snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx " |
248 | "(status = 0x%x, data = 0x%x)\n" , cmd, mpu->port, |
249 | mpu->read(mpu, MPU401C(mpu)), |
250 | mpu->read(mpu, MPU401D(mpu))); |
251 | return 1; |
252 | } |
253 | return 0; |
254 | } |
255 | |
256 | static int snd_mpu401_do_reset(struct snd_mpu401 *mpu) |
257 | { |
258 | if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, ack: 1)) |
259 | return -EIO; |
260 | if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, ack: 0)) |
261 | return -EIO; |
262 | return 0; |
263 | } |
264 | |
265 | /* |
266 | * input/output open/close - protected by open_mutex in rawmidi.c |
267 | */ |
268 | static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream) |
269 | { |
270 | struct snd_mpu401 *mpu; |
271 | int err; |
272 | |
273 | mpu = substream->rmidi->private_data; |
274 | if (mpu->open_input) { |
275 | err = mpu->open_input(mpu); |
276 | if (err < 0) |
277 | return err; |
278 | } |
279 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { |
280 | if (snd_mpu401_do_reset(mpu) < 0) |
281 | goto error_out; |
282 | } |
283 | mpu->substream_input = substream; |
284 | set_bit(MPU401_MODE_BIT_INPUT, addr: &mpu->mode); |
285 | return 0; |
286 | |
287 | error_out: |
288 | if (mpu->open_input && mpu->close_input) |
289 | mpu->close_input(mpu); |
290 | return -EIO; |
291 | } |
292 | |
293 | static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream) |
294 | { |
295 | struct snd_mpu401 *mpu; |
296 | int err; |
297 | |
298 | mpu = substream->rmidi->private_data; |
299 | if (mpu->open_output) { |
300 | err = mpu->open_output(mpu); |
301 | if (err < 0) |
302 | return err; |
303 | } |
304 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { |
305 | if (snd_mpu401_do_reset(mpu) < 0) |
306 | goto error_out; |
307 | } |
308 | mpu->substream_output = substream; |
309 | set_bit(MPU401_MODE_BIT_OUTPUT, addr: &mpu->mode); |
310 | return 0; |
311 | |
312 | error_out: |
313 | if (mpu->open_output && mpu->close_output) |
314 | mpu->close_output(mpu); |
315 | return -EIO; |
316 | } |
317 | |
318 | static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream) |
319 | { |
320 | struct snd_mpu401 *mpu; |
321 | int err = 0; |
322 | |
323 | mpu = substream->rmidi->private_data; |
324 | clear_bit(MPU401_MODE_BIT_INPUT, addr: &mpu->mode); |
325 | mpu->substream_input = NULL; |
326 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) |
327 | err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, ack: 0); |
328 | if (mpu->close_input) |
329 | mpu->close_input(mpu); |
330 | if (err) |
331 | return -EIO; |
332 | return 0; |
333 | } |
334 | |
335 | static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) |
336 | { |
337 | struct snd_mpu401 *mpu; |
338 | int err = 0; |
339 | |
340 | mpu = substream->rmidi->private_data; |
341 | clear_bit(MPU401_MODE_BIT_OUTPUT, addr: &mpu->mode); |
342 | mpu->substream_output = NULL; |
343 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) |
344 | err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, ack: 0); |
345 | if (mpu->close_output) |
346 | mpu->close_output(mpu); |
347 | if (err) |
348 | return -EIO; |
349 | return 0; |
350 | } |
351 | |
352 | /* |
353 | * trigger input callback |
354 | */ |
355 | static void |
356 | snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) |
357 | { |
358 | unsigned long flags; |
359 | struct snd_mpu401 *mpu; |
360 | int max = 64; |
361 | |
362 | mpu = substream->rmidi->private_data; |
363 | if (up) { |
364 | if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, |
365 | addr: &mpu->mode)) { |
366 | /* first time - flush FIFO */ |
367 | while (max-- > 0) |
368 | mpu->read(mpu, MPU401D(mpu)); |
369 | if (mpu->info_flags & MPU401_INFO_USE_TIMER) |
370 | snd_mpu401_uart_add_timer(mpu, input: 1); |
371 | } |
372 | |
373 | /* read data in advance */ |
374 | spin_lock_irqsave(&mpu->input_lock, flags); |
375 | snd_mpu401_uart_input_read(mpu); |
376 | spin_unlock_irqrestore(lock: &mpu->input_lock, flags); |
377 | } else { |
378 | if (mpu->info_flags & MPU401_INFO_USE_TIMER) |
379 | snd_mpu401_uart_remove_timer(mpu, input: 1); |
380 | clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, addr: &mpu->mode); |
381 | } |
382 | |
383 | } |
384 | |
385 | /* |
386 | * transfer input pending data |
387 | * call with input_lock spinlock held |
388 | */ |
389 | static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu) |
390 | { |
391 | int max = 128; |
392 | unsigned char byte; |
393 | |
394 | while (max-- > 0) { |
395 | if (! snd_mpu401_input_avail(mpu)) |
396 | break; /* input not available */ |
397 | byte = mpu->read(mpu, MPU401D(mpu)); |
398 | if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) |
399 | snd_rawmidi_receive(substream: mpu->substream_input, buffer: &byte, count: 1); |
400 | } |
401 | } |
402 | |
403 | /* |
404 | * Tx FIFO sizes: |
405 | * CS4237B - 16 bytes |
406 | * AudioDrive ES1688 - 12 bytes |
407 | * S3 SonicVibes - 8 bytes |
408 | * SoundBlaster AWE 64 - 2 bytes (ugly hardware) |
409 | */ |
410 | |
411 | /* |
412 | * write output pending bytes |
413 | * call with output_lock spinlock held |
414 | */ |
415 | static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) |
416 | { |
417 | unsigned char byte; |
418 | int max = 256; |
419 | |
420 | do { |
421 | if (snd_rawmidi_transmit_peek(substream: mpu->substream_output, |
422 | buffer: &byte, count: 1) == 1) { |
423 | /* |
424 | * Try twice because there is hardware that insists on |
425 | * setting the output busy bit after each write. |
426 | */ |
427 | if (!snd_mpu401_output_ready(mpu) && |
428 | !snd_mpu401_output_ready(mpu)) |
429 | break; /* Tx FIFO full - try again later */ |
430 | mpu->write(mpu, byte, MPU401D(mpu)); |
431 | snd_rawmidi_transmit_ack(substream: mpu->substream_output, count: 1); |
432 | } else { |
433 | snd_mpu401_uart_remove_timer (mpu, input: 0); |
434 | break; /* no other data - leave the tx loop */ |
435 | } |
436 | } while (--max > 0); |
437 | } |
438 | |
439 | /* |
440 | * output trigger callback |
441 | */ |
442 | static void |
443 | snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) |
444 | { |
445 | unsigned long flags; |
446 | struct snd_mpu401 *mpu; |
447 | |
448 | mpu = substream->rmidi->private_data; |
449 | if (up) { |
450 | set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, addr: &mpu->mode); |
451 | |
452 | /* try to add the timer at each output trigger, |
453 | * since the output timer might have been removed in |
454 | * snd_mpu401_uart_output_write(). |
455 | */ |
456 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
457 | snd_mpu401_uart_add_timer(mpu, input: 0); |
458 | |
459 | /* output pending data */ |
460 | spin_lock_irqsave(&mpu->output_lock, flags); |
461 | snd_mpu401_uart_output_write(mpu); |
462 | spin_unlock_irqrestore(lock: &mpu->output_lock, flags); |
463 | } else { |
464 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
465 | snd_mpu401_uart_remove_timer(mpu, input: 0); |
466 | clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, addr: &mpu->mode); |
467 | } |
468 | } |
469 | |
470 | /* |
471 | |
472 | */ |
473 | |
474 | static const struct snd_rawmidi_ops snd_mpu401_uart_output = |
475 | { |
476 | .open = snd_mpu401_uart_output_open, |
477 | .close = snd_mpu401_uart_output_close, |
478 | .trigger = snd_mpu401_uart_output_trigger, |
479 | }; |
480 | |
481 | static const struct snd_rawmidi_ops snd_mpu401_uart_input = |
482 | { |
483 | .open = snd_mpu401_uart_input_open, |
484 | .close = snd_mpu401_uart_input_close, |
485 | .trigger = snd_mpu401_uart_input_trigger, |
486 | }; |
487 | |
488 | static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) |
489 | { |
490 | struct snd_mpu401 *mpu = rmidi->private_data; |
491 | if (mpu->irq >= 0) |
492 | free_irq(mpu->irq, (void *) mpu); |
493 | release_and_free_resource(res: mpu->res); |
494 | kfree(objp: mpu); |
495 | } |
496 | |
497 | /** |
498 | * snd_mpu401_uart_new - create an MPU401-UART instance |
499 | * @card: the card instance |
500 | * @device: the device index, zero-based |
501 | * @hardware: the hardware type, MPU401_HW_XXXX |
502 | * @port: the base address of MPU401 port |
503 | * @info_flags: bitflags MPU401_INFO_XXX |
504 | * @irq: the ISA irq number, -1 if not to be allocated |
505 | * @rrawmidi: the pointer to store the new rawmidi instance |
506 | * |
507 | * Creates a new MPU-401 instance. |
508 | * |
509 | * Note that the rawmidi instance is returned on the rrawmidi argument, |
510 | * not the mpu401 instance itself. To access to the mpu401 instance, |
511 | * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast). |
512 | * |
513 | * Return: Zero if successful, or a negative error code. |
514 | */ |
515 | int snd_mpu401_uart_new(struct snd_card *card, int device, |
516 | unsigned short hardware, |
517 | unsigned long port, |
518 | unsigned int info_flags, |
519 | int irq, |
520 | struct snd_rawmidi ** rrawmidi) |
521 | { |
522 | struct snd_mpu401 *mpu; |
523 | struct snd_rawmidi *rmidi; |
524 | int in_enable, out_enable; |
525 | int err; |
526 | |
527 | if (rrawmidi) |
528 | *rrawmidi = NULL; |
529 | if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT))) |
530 | info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT; |
531 | in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0; |
532 | out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0; |
533 | err = snd_rawmidi_new(card, id: "MPU-401U" , device, |
534 | output_count: out_enable, input_count: in_enable, rmidi: &rmidi); |
535 | if (err < 0) |
536 | return err; |
537 | mpu = kzalloc(size: sizeof(*mpu), GFP_KERNEL); |
538 | if (!mpu) { |
539 | err = -ENOMEM; |
540 | goto free_device; |
541 | } |
542 | rmidi->private_data = mpu; |
543 | rmidi->private_free = snd_mpu401_uart_free; |
544 | spin_lock_init(&mpu->input_lock); |
545 | spin_lock_init(&mpu->output_lock); |
546 | spin_lock_init(&mpu->timer_lock); |
547 | mpu->hardware = hardware; |
548 | mpu->irq = -1; |
549 | if (! (info_flags & MPU401_INFO_INTEGRATED)) { |
550 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; |
551 | mpu->res = request_region(port, res_size, "MPU401 UART" ); |
552 | if (!mpu->res) { |
553 | snd_printk(KERN_ERR "mpu401_uart: " |
554 | "unable to grab port 0x%lx size %d\n" , |
555 | port, res_size); |
556 | err = -EBUSY; |
557 | goto free_device; |
558 | } |
559 | } |
560 | if (info_flags & MPU401_INFO_MMIO) { |
561 | mpu->write = mpu401_write_mmio; |
562 | mpu->read = mpu401_read_mmio; |
563 | } else { |
564 | mpu->write = mpu401_write_port; |
565 | mpu->read = mpu401_read_port; |
566 | } |
567 | mpu->port = port; |
568 | if (hardware == MPU401_HW_PC98II) |
569 | mpu->cport = port + 2; |
570 | else |
571 | mpu->cport = port + 1; |
572 | if (irq >= 0) { |
573 | if (request_irq(irq, handler: snd_mpu401_uart_interrupt, flags: 0, |
574 | name: "MPU401 UART" , dev: (void *) mpu)) { |
575 | snd_printk(KERN_ERR "mpu401_uart: " |
576 | "unable to grab IRQ %d\n" , irq); |
577 | err = -EBUSY; |
578 | goto free_device; |
579 | } |
580 | } |
581 | if (irq < 0 && !(info_flags & MPU401_INFO_IRQ_HOOK)) |
582 | info_flags |= MPU401_INFO_USE_TIMER; |
583 | mpu->info_flags = info_flags; |
584 | mpu->irq = irq; |
585 | if (card->shortname[0]) |
586 | snprintf(buf: rmidi->name, size: sizeof(rmidi->name), fmt: "%s MIDI" , |
587 | card->shortname); |
588 | else |
589 | sprintf(buf: rmidi->name, fmt: "MPU-401 MIDI %d-%d" ,card->number, device); |
590 | if (out_enable) { |
591 | snd_rawmidi_set_ops(rmidi, stream: SNDRV_RAWMIDI_STREAM_OUTPUT, |
592 | ops: &snd_mpu401_uart_output); |
593 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; |
594 | } |
595 | if (in_enable) { |
596 | snd_rawmidi_set_ops(rmidi, stream: SNDRV_RAWMIDI_STREAM_INPUT, |
597 | ops: &snd_mpu401_uart_input); |
598 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; |
599 | if (out_enable) |
600 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; |
601 | } |
602 | mpu->rmidi = rmidi; |
603 | if (rrawmidi) |
604 | *rrawmidi = rmidi; |
605 | return 0; |
606 | free_device: |
607 | snd_device_free(card, device_data: rmidi); |
608 | return err; |
609 | } |
610 | |
611 | EXPORT_SYMBOL(snd_mpu401_uart_new); |
612 | |