diff options
Diffstat (limited to 'sound/oss/uart6850.c')
-rw-r--r-- | sound/oss/uart6850.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c new file mode 100644 index 000000000000..be00cf128651 --- /dev/null +++ b/sound/oss/uart6850.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * sound/uart6850.c | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) by Hannu Savolainen 1993-1997 | ||
6 | * | ||
7 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
8 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
9 | * for more info. | ||
10 | * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. | ||
11 | * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. | ||
12 | * | ||
13 | * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now | ||
14 | * uses native linux resources | ||
15 | * Christoph Hellwig: Adapted to module_init/module_exit | ||
16 | * Jeff Garzik: Made it work again, in theory | ||
17 | * FIXME: If the request_irq() succeeds, the probe succeeds. Ug. | ||
18 | * | ||
19 | * Status: Testing required (no shit -jgarzik) | ||
20 | * | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: | ||
29 | * added 6850 support, used with COVOX SoundMaster II and custom cards. | ||
30 | */ | ||
31 | |||
32 | #include "sound_config.h" | ||
33 | |||
34 | static int uart6850_base = 0x330; | ||
35 | |||
36 | static int *uart6850_osp; | ||
37 | |||
38 | #define DATAPORT (uart6850_base) | ||
39 | #define COMDPORT (uart6850_base+1) | ||
40 | #define STATPORT (uart6850_base+1) | ||
41 | |||
42 | static int uart6850_status(void) | ||
43 | { | ||
44 | return inb(STATPORT); | ||
45 | } | ||
46 | |||
47 | #define input_avail() (uart6850_status()&INPUT_AVAIL) | ||
48 | #define output_ready() (uart6850_status()&OUTPUT_READY) | ||
49 | |||
50 | static void uart6850_cmd(unsigned char cmd) | ||
51 | { | ||
52 | outb(cmd, COMDPORT); | ||
53 | } | ||
54 | |||
55 | static int uart6850_read(void) | ||
56 | { | ||
57 | return inb(DATAPORT); | ||
58 | } | ||
59 | |||
60 | static void uart6850_write(unsigned char byte) | ||
61 | { | ||
62 | outb(byte, DATAPORT); | ||
63 | } | ||
64 | |||
65 | #define OUTPUT_READY 0x02 /* Mask for data ready Bit */ | ||
66 | #define INPUT_AVAIL 0x01 /* Mask for Data Send Ready Bit */ | ||
67 | |||
68 | #define UART_RESET 0x95 | ||
69 | #define UART_MODE_ON 0x03 | ||
70 | |||
71 | static int uart6850_opened; | ||
72 | static int uart6850_irq; | ||
73 | static int uart6850_detected; | ||
74 | static int my_dev; | ||
75 | static DEFINE_SPINLOCK(lock); | ||
76 | |||
77 | static void (*midi_input_intr) (int dev, unsigned char data); | ||
78 | static void poll_uart6850(unsigned long dummy); | ||
79 | |||
80 | |||
81 | static struct timer_list uart6850_timer = | ||
82 | TIMER_INITIALIZER(poll_uart6850, 0, 0); | ||
83 | |||
84 | static void uart6850_input_loop(void) | ||
85 | { | ||
86 | int count = 10; | ||
87 | |||
88 | while (count) | ||
89 | { | ||
90 | /* | ||
91 | * Not timed out | ||
92 | */ | ||
93 | if (input_avail()) | ||
94 | { | ||
95 | unsigned char c = uart6850_read(); | ||
96 | count = 100; | ||
97 | if (uart6850_opened & OPEN_READ) | ||
98 | midi_input_intr(my_dev, c); | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | while (!input_avail() && count) | ||
103 | count--; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static irqreturn_t m6850intr(int irq, void *dev_id, struct pt_regs *dummy) | ||
109 | { | ||
110 | if (input_avail()) | ||
111 | uart6850_input_loop(); | ||
112 | return IRQ_HANDLED; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * It looks like there is no input interrupts in the UART mode. Let's try | ||
117 | * polling. | ||
118 | */ | ||
119 | |||
120 | static void poll_uart6850(unsigned long dummy) | ||
121 | { | ||
122 | unsigned long flags; | ||
123 | |||
124 | if (!(uart6850_opened & OPEN_READ)) | ||
125 | return; /* Device has been closed */ | ||
126 | |||
127 | spin_lock_irqsave(&lock,flags); | ||
128 | if (input_avail()) | ||
129 | uart6850_input_loop(); | ||
130 | |||
131 | uart6850_timer.expires = 1 + jiffies; | ||
132 | add_timer(&uart6850_timer); | ||
133 | |||
134 | /* | ||
135 | * Come back later | ||
136 | */ | ||
137 | |||
138 | spin_unlock_irqrestore(&lock,flags); | ||
139 | } | ||
140 | |||
141 | static int uart6850_open(int dev, int mode, | ||
142 | void (*input) (int dev, unsigned char data), | ||
143 | void (*output) (int dev) | ||
144 | ) | ||
145 | { | ||
146 | if (uart6850_opened) | ||
147 | { | ||
148 | /* printk("Midi6850: Midi busy\n");*/ | ||
149 | return -EBUSY; | ||
150 | }; | ||
151 | |||
152 | uart6850_cmd(UART_RESET); | ||
153 | uart6850_input_loop(); | ||
154 | midi_input_intr = input; | ||
155 | uart6850_opened = mode; | ||
156 | poll_uart6850(0); /* | ||
157 | * Enable input polling | ||
158 | */ | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void uart6850_close(int dev) | ||
164 | { | ||
165 | uart6850_cmd(UART_MODE_ON); | ||
166 | del_timer(&uart6850_timer); | ||
167 | uart6850_opened = 0; | ||
168 | } | ||
169 | |||
170 | static int uart6850_out(int dev, unsigned char midi_byte) | ||
171 | { | ||
172 | int timeout; | ||
173 | unsigned long flags; | ||
174 | |||
175 | /* | ||
176 | * Test for input since pending input seems to block the output. | ||
177 | */ | ||
178 | |||
179 | spin_lock_irqsave(&lock,flags); | ||
180 | |||
181 | if (input_avail()) | ||
182 | uart6850_input_loop(); | ||
183 | |||
184 | spin_unlock_irqrestore(&lock,flags); | ||
185 | |||
186 | /* | ||
187 | * Sometimes it takes about 13000 loops before the output becomes ready | ||
188 | * (After reset). Normally it takes just about 10 loops. | ||
189 | */ | ||
190 | |||
191 | for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* | ||
192 | * Wait | ||
193 | */ | ||
194 | if (!output_ready()) | ||
195 | { | ||
196 | printk(KERN_WARNING "Midi6850: Timeout\n"); | ||
197 | return 0; | ||
198 | } | ||
199 | uart6850_write(midi_byte); | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | static inline int uart6850_command(int dev, unsigned char *midi_byte) | ||
204 | { | ||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | static inline int uart6850_start_read(int dev) | ||
209 | { | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static inline int uart6850_end_read(int dev) | ||
214 | { | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static inline void uart6850_kick(int dev) | ||
219 | { | ||
220 | } | ||
221 | |||
222 | static inline int uart6850_buffer_status(int dev) | ||
223 | { | ||
224 | return 0; /* | ||
225 | * No data in buffers | ||
226 | */ | ||
227 | } | ||
228 | |||
229 | #define MIDI_SYNTH_NAME "6850 UART Midi" | ||
230 | #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT | ||
231 | #include "midi_synth.h" | ||
232 | |||
233 | static struct midi_operations uart6850_operations = | ||
234 | { | ||
235 | .owner = THIS_MODULE, | ||
236 | .info = {"6850 UART", 0, 0, SNDCARD_UART6850}, | ||
237 | .converter = &std_midi_synth, | ||
238 | .in_info = {0}, | ||
239 | .open = uart6850_open, | ||
240 | .close = uart6850_close, | ||
241 | .outputc = uart6850_out, | ||
242 | .start_read = uart6850_start_read, | ||
243 | .end_read = uart6850_end_read, | ||
244 | .kick = uart6850_kick, | ||
245 | .command = uart6850_command, | ||
246 | .buffer_status = uart6850_buffer_status | ||
247 | }; | ||
248 | |||
249 | |||
250 | static void __init attach_uart6850(struct address_info *hw_config) | ||
251 | { | ||
252 | int ok, timeout; | ||
253 | unsigned long flags; | ||
254 | |||
255 | if (!uart6850_detected) | ||
256 | return; | ||
257 | |||
258 | if ((my_dev = sound_alloc_mididev()) == -1) | ||
259 | { | ||
260 | printk(KERN_INFO "uart6850: Too many midi devices detected\n"); | ||
261 | return; | ||
262 | } | ||
263 | uart6850_base = hw_config->io_base; | ||
264 | uart6850_osp = hw_config->osp; | ||
265 | uart6850_irq = hw_config->irq; | ||
266 | |||
267 | spin_lock_irqsave(&lock,flags); | ||
268 | |||
269 | for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* | ||
270 | * Wait | ||
271 | */ | ||
272 | uart6850_cmd(UART_MODE_ON); | ||
273 | ok = 1; | ||
274 | spin_unlock_irqrestore(&lock,flags); | ||
275 | |||
276 | conf_printf("6850 Midi Interface", hw_config); | ||
277 | |||
278 | std_midi_synth.midi_dev = my_dev; | ||
279 | hw_config->slots[4] = my_dev; | ||
280 | midi_devs[my_dev] = &uart6850_operations; | ||
281 | sequencer_init(); | ||
282 | } | ||
283 | |||
284 | static inline int reset_uart6850(void) | ||
285 | { | ||
286 | uart6850_read(); | ||
287 | return 1; /* | ||
288 | * OK | ||
289 | */ | ||
290 | } | ||
291 | |||
292 | static int __init probe_uart6850(struct address_info *hw_config) | ||
293 | { | ||
294 | int ok; | ||
295 | |||
296 | uart6850_osp = hw_config->osp; | ||
297 | uart6850_base = hw_config->io_base; | ||
298 | uart6850_irq = hw_config->irq; | ||
299 | |||
300 | if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0) | ||
301 | return 0; | ||
302 | |||
303 | ok = reset_uart6850(); | ||
304 | uart6850_detected = ok; | ||
305 | return ok; | ||
306 | } | ||
307 | |||
308 | static void __exit unload_uart6850(struct address_info *hw_config) | ||
309 | { | ||
310 | free_irq(hw_config->irq, NULL); | ||
311 | sound_unload_mididev(hw_config->slots[4]); | ||
312 | } | ||
313 | |||
314 | static struct address_info cfg_mpu; | ||
315 | |||
316 | static int __initdata io = -1; | ||
317 | static int __initdata irq = -1; | ||
318 | |||
319 | module_param(io, int, 0); | ||
320 | module_param(irq, int, 0); | ||
321 | |||
322 | static int __init init_uart6850(void) | ||
323 | { | ||
324 | cfg_mpu.io_base = io; | ||
325 | cfg_mpu.irq = irq; | ||
326 | |||
327 | if (cfg_mpu.io_base == -1 || cfg_mpu.irq == -1) { | ||
328 | printk(KERN_INFO "uart6850: irq and io must be set.\n"); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | if (probe_uart6850(&cfg_mpu)) | ||
333 | return -ENODEV; | ||
334 | attach_uart6850(&cfg_mpu); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static void __exit cleanup_uart6850(void) | ||
340 | { | ||
341 | unload_uart6850(&cfg_mpu); | ||
342 | } | ||
343 | |||
344 | module_init(init_uart6850); | ||
345 | module_exit(cleanup_uart6850); | ||
346 | |||
347 | #ifndef MODULE | ||
348 | static int __init setup_uart6850(char *str) | ||
349 | { | ||
350 | /* io, irq */ | ||
351 | int ints[3]; | ||
352 | |||
353 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
354 | |||
355 | io = ints[1]; | ||
356 | irq = ints[2]; | ||
357 | |||
358 | return 1; | ||
359 | } | ||
360 | __setup("uart6850=", setup_uart6850); | ||
361 | #endif | ||
362 | MODULE_LICENSE("GPL"); | ||