Put the sound stuff in alpabetic order.
[unix-history] / sys / i386 / isa / sound / pas2_midi.c
CommitLineData
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
18static int midi_busy = 0, input_opened = 0;
19static int my_dev;
20static volatile int ofifo_bytes = 0;
21
22static unsigned char tmp_queue[256];
23static volatile int qlen;
24static volatile unsigned char qhead, qtail;
25
26static int
27pas_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
81static void
82pas_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
92static int
93dump_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
111static int
112pas_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
157static int
158pas_midi_start_read (int dev)
159{
160 return 0;
161}
162
163static int
164pas_midi_end_read (int dev)
165{
166 return 0;
167}
168
169static int
170pas_midi_ioctl (int dev, unsigned cmd, unsigned arg)
171{
172 return RET_ERROR (EINVAL);
173}
174
175static void
176pas_midi_kick (int dev)
177{
178 ofifo_bytes = 0;
179}
180
181static int
182pas_buffer_status (int dev)
183{
184 return !qlen;
185}
186
187static 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
201long
202pas_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
209void
210pas_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