Commit | Line | Data |
---|---|---|
1b261ae5 JH |
1 | /* |
2 | * linux/kernel/chr_drv/sound/pas2_midi.c | |
3 | * | |
4 | * The low level driver for the PAS Midi Interface. | |
5 | * | |
6 | * (C) 1992 Hannu Savolainen (hsavolai@cs.helsinki.fi) See COPYING for further | |
7 | * details. Should be distributed with this file. | |
8 | */ | |
9 | ||
10 | #include "sound_config.h" | |
11 | ||
12 | #ifdef CONFIGURE_SOUNDCARD | |
13 | ||
14 | #include "pas.h" | |
15 | ||
16 | #if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) && defined(EXCLUDE_PRO_MIDI) | |
17 | ||
18 | static int midi_busy = 0, input_opened = 0; | |
19 | static int my_dev; | |
20 | static volatile int ofifo_bytes = 0; | |
21 | ||
22 | static unsigned char tmp_queue[256]; | |
23 | static volatile int qlen; | |
24 | static volatile unsigned char qhead, qtail; | |
25 | ||
26 | static int | |
27 | pas_midi_open (int dev, int mode) | |
28 | { | |
29 | int err; | |
30 | unsigned long flags; | |
31 | unsigned char ctrl; | |
32 | ||
33 | ||
34 | if (midi_busy) | |
35 | { | |
36 | printk ("PAS2: Midi busy\n"); | |
37 | return RET_ERROR (EBUSY); | |
38 | } | |
39 | ||
40 | /* Reset input and output FIFO pointers */ | |
41 | pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, | |
42 | MIDI_CONTROL); | |
43 | ||
44 | DISABLE_INTR (flags); | |
45 | ||
46 | if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0) | |
47 | return err; | |
48 | ||
49 | /* Enable input available and output FIFO empty interrupts */ | |
50 | ||
51 | ctrl = 0; | |
52 | input_opened = 0; | |
53 | ||
54 | if (mode == OPEN_READ || mode == OPEN_READWRITE) | |
55 | { | |
56 | ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */ | |
57 | input_opened = 1; | |
58 | } | |
59 | ||
60 | if (mode == OPEN_WRITE || mode == OPEN_READWRITE) | |
61 | { | |
62 | ctrl |= M_C_ENA_OUTPUT_IRQ | /* Enable output */ | |
63 | M_C_ENA_OUTPUT_HALF_IRQ; | |
64 | } | |
65 | ||
66 | pas_write (ctrl, | |
67 | MIDI_CONTROL); | |
68 | ||
69 | /* Acknowledge any pending interrupts */ | |
70 | ||
71 | pas_write (0xff, MIDI_STATUS); | |
72 | ofifo_bytes = 0; | |
73 | ||
74 | RESTORE_INTR (flags); | |
75 | ||
76 | midi_busy = 1; | |
77 | qlen = qhead = qtail = 0; | |
78 | return 0; | |
79 | } | |
80 | ||
81 | static void | |
82 | pas_midi_close (int dev) | |
83 | { | |
84 | ||
85 | /* Reset FIFO pointers, disable intrs */ | |
86 | pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); | |
87 | ||
88 | pas_remove_intr (I_M_MIDI_IRQ_ENABLE); | |
89 | midi_busy = 0; | |
90 | } | |
91 | ||
92 | static int | |
93 | dump_to_midi (unsigned char midi_byte) | |
94 | { | |
95 | int fifo_space, x; | |
96 | ||
97 | fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; | |
98 | ||
99 | if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* Fifo full */ | |
100 | { | |
101 | return 0; /* Upper layer will call again */ | |
102 | } | |
103 | ||
104 | ofifo_bytes++; | |
105 | ||
106 | pas_write (midi_byte, MIDI_DATA); | |
107 | ||
108 | return 1; | |
109 | } | |
110 | ||
111 | static int | |
112 | pas_midi_out (int dev, unsigned char midi_byte) | |
113 | { | |
114 | ||
115 | unsigned long flags; | |
116 | ||
117 | /* | |
118 | * Drain the local queue first | |
119 | */ | |
120 | ||
121 | DISABLE_INTR (flags); | |
122 | ||
123 | while (qlen && dump_to_midi (tmp_queue[qhead])) | |
124 | { | |
125 | qlen--; | |
126 | qhead++; | |
127 | } | |
128 | ||
129 | RESTORE_INTR (flags); | |
130 | ||
131 | /* | |
132 | * Output the byte if the local queue is empty. | |
133 | */ | |
134 | ||
135 | if (!qlen) | |
136 | if (dump_to_midi (midi_byte)) | |
137 | return 1; /* OK */ | |
138 | ||
139 | /* | |
140 | * Put to the local queue | |
141 | */ | |
142 | ||
143 | if (qlen >= 256) | |
144 | return 0; /* Local queue full */ | |
145 | ||
146 | DISABLE_INTR (flags); | |
147 | ||
148 | tmp_queue[qtail] = midi_byte; | |
149 | qlen++; | |
150 | qtail++; | |
151 | ||
152 | RESTORE_INTR (flags); | |
153 | ||
154 | return 1; | |
155 | } | |
156 | ||
157 | static int | |
158 | pas_midi_start_read (int dev) | |
159 | { | |
160 | return 0; | |
161 | } | |
162 | ||
163 | static int | |
164 | pas_midi_end_read (int dev) | |
165 | { | |
166 | return 0; | |
167 | } | |
168 | ||
169 | static int | |
170 | pas_midi_ioctl (int dev, unsigned cmd, unsigned arg) | |
171 | { | |
172 | return RET_ERROR (EINVAL); | |
173 | } | |
174 | ||
175 | static void | |
176 | pas_midi_kick (int dev) | |
177 | { | |
178 | ofifo_bytes = 0; | |
179 | } | |
180 | ||
181 | static int | |
182 | pas_buffer_status (int dev) | |
183 | { | |
184 | return !qlen; | |
185 | } | |
186 | ||
187 | static struct midi_operations pas_midi_operations = | |
188 | { | |
189 | {"Pro Audio Spectrum", 0}, | |
190 | pas_midi_open, | |
191 | pas_midi_close, | |
192 | pas_midi_ioctl, | |
193 | pas_midi_out, | |
194 | pas_midi_start_read, | |
195 | pas_midi_end_read, | |
196 | pas_midi_kick, | |
197 | NULL, /* command */ | |
198 | pas_buffer_status | |
199 | }; | |
200 | ||
201 | long | |
202 | pas_midi_init (long mem_start) | |
203 | { | |
204 | my_dev = num_midis; | |
205 | midi_devs[num_midis++] = &pas_midi_operations; | |
206 | return mem_start; | |
207 | } | |
208 | ||
209 | void | |
210 | pas_midi_interrupt (void) | |
211 | { | |
212 | unsigned char stat; | |
213 | int i, incount; | |
214 | unsigned long flags; | |
215 | ||
216 | stat = pas_read (MIDI_STATUS); | |
217 | ||
218 | if (stat & M_S_INPUT_AVAIL) /* Input byte available */ | |
219 | { | |
220 | incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* Input FIFO count */ | |
221 | if (!incount) | |
222 | incount = 16; | |
223 | ||
224 | for (i = 0; i < incount; i++) | |
225 | if (input_opened) | |
226 | { | |
227 | sequencer_midi_input (my_dev, pas_read (MIDI_DATA)); | |
228 | } | |
229 | else | |
230 | pas_read (MIDI_DATA); /* Flush */ | |
231 | } | |
232 | ||
233 | if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) | |
234 | { | |
235 | if (!(stat & M_S_OUTPUT_EMPTY)) | |
236 | { | |
237 | ofifo_bytes = 8; | |
238 | } | |
239 | else | |
240 | { | |
241 | ofifo_bytes = 0; | |
242 | } | |
243 | ||
244 | DISABLE_INTR (flags); | |
245 | ||
246 | while (qlen && dump_to_midi (tmp_queue[qhead])) | |
247 | { | |
248 | qlen--; | |
249 | qhead++; | |
250 | } | |
251 | ||
252 | RESTORE_INTR (flags); | |
253 | } | |
254 | ||
255 | if (stat & M_S_FRAMING_ERROR) | |
256 | printk ("MIDI framing error\n"); | |
257 | ||
258 | if (stat & M_S_OUTPUT_OVERRUN) | |
259 | { | |
260 | printk ("MIDI output overrun %02x,%02x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); | |
261 | ofifo_bytes = 100; | |
262 | } | |
263 | ||
264 | pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */ | |
265 | } | |
266 | ||
267 | #endif | |
268 | ||
269 | #endif |