Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pas2_midi.c
Go to the documentation of this file.
1 /*
2  * sound/oss/pas2_midi.c
3  *
4  * The low level driver for the PAS Midi Interface.
5  */
6 /*
7  * Copyright (C) by Hannu Savolainen 1993-1997
8  *
9  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10  * Version 2 (June 1991). See the "COPYING" file distributed with this software
11  * for more info.
12  *
13  * Bartlomiej Zolnierkiewicz : Added __init to pas_init_mixer()
14  */
15 
16 #include <linux/init.h>
17 #include <linux/spinlock.h>
18 #include "sound_config.h"
19 
20 #include "pas2.h"
21 
22 extern spinlock_t pas_lock;
23 
24 static int midi_busy, input_opened;
25 static int my_dev;
26 
27 int pas2_mididev=-1;
28 
29 static unsigned char tmp_queue[256];
30 static volatile int qlen;
31 static volatile unsigned char qhead, qtail;
32 
33 static void (*midi_input_intr) (int dev, unsigned char data);
34 
35 static int pas_midi_open(int dev, int mode,
36  void (*input) (int dev, unsigned char data),
37  void (*output) (int dev)
38 )
39 {
40  int err;
41  unsigned long flags;
42  unsigned char ctrl;
43 
44 
45  if (midi_busy)
46  return -EBUSY;
47 
48  /*
49  * Reset input and output FIFO pointers
50  */
51  pas_write(0x20 | 0x40,
52  0x178b);
53 
54  spin_lock_irqsave(&pas_lock, flags);
55 
56  if ((err = pas_set_intr(0x10)) < 0)
57  {
58  spin_unlock_irqrestore(&pas_lock, flags);
59  return err;
60  }
61  /*
62  * Enable input available and output FIFO empty interrupts
63  */
64 
65  ctrl = 0;
66  input_opened = 0;
67  midi_input_intr = input;
68 
69  if (mode == OPEN_READ || mode == OPEN_READWRITE)
70  {
71  ctrl |= 0x04; /* Enable input */
72  input_opened = 1;
73  }
74  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
75  {
76  ctrl |= 0x08 | 0x10; /* Enable output */
77  }
78  pas_write(ctrl, 0x178b);
79 
80  /*
81  * Acknowledge any pending interrupts
82  */
83 
84  pas_write(0xff, 0x1B88);
85 
86  spin_unlock_irqrestore(&pas_lock, flags);
87 
88  midi_busy = 1;
89  qlen = qhead = qtail = 0;
90  return 0;
91 }
92 
93 static void pas_midi_close(int dev)
94 {
95 
96  /*
97  * Reset FIFO pointers, disable intrs
98  */
99  pas_write(0x20 | 0x40, 0x178b);
100 
101  pas_remove_intr(0x10);
102  midi_busy = 0;
103 }
104 
105 static int dump_to_midi(unsigned char midi_byte)
106 {
107  int fifo_space, x;
108 
109  fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f;
110 
111  /*
112  * The MIDI FIFO space register and it's documentation is nonunderstandable.
113  * There seem to be no way to differentiate between buffer full and buffer
114  * empty situations. For this reason we don't never write the buffer
115  * completely full. In this way we can assume that 0 (or is it 15)
116  * means that the buffer is empty.
117  */
118 
119  if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */
120  return 0; /* Ask upper layers to retry after some time */
121 
122  pas_write(midi_byte, 0x178A);
123 
124  return 1;
125 }
126 
127 static int pas_midi_out(int dev, unsigned char midi_byte)
128 {
129 
130  unsigned long flags;
131 
132  /*
133  * Drain the local queue first
134  */
135 
136  spin_lock_irqsave(&pas_lock, flags);
137 
138  while (qlen && dump_to_midi(tmp_queue[qhead]))
139  {
140  qlen--;
141  qhead++;
142  }
143 
144  spin_unlock_irqrestore(&pas_lock, flags);
145 
146  /*
147  * Output the byte if the local queue is empty.
148  */
149 
150  if (!qlen)
151  if (dump_to_midi(midi_byte))
152  return 1;
153 
154  /*
155  * Put to the local queue
156  */
157 
158  if (qlen >= 256)
159  return 0; /* Local queue full */
160 
161  spin_lock_irqsave(&pas_lock, flags);
162 
163  tmp_queue[qtail] = midi_byte;
164  qlen++;
165  qtail++;
166 
167  spin_unlock_irqrestore(&pas_lock, flags);
168 
169  return 1;
170 }
171 
172 static int pas_midi_start_read(int dev)
173 {
174  return 0;
175 }
176 
177 static int pas_midi_end_read(int dev)
178 {
179  return 0;
180 }
181 
182 static void pas_midi_kick(int dev)
183 {
184 }
185 
186 static int pas_buffer_status(int dev)
187 {
188  return qlen;
189 }
190 
191 #define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi"
192 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
193 #include "midi_synth.h"
194 
195 static struct midi_operations pas_midi_operations =
196 {
197  .owner = THIS_MODULE,
198  .info = {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
199  .converter = &std_midi_synth,
200  .in_info = {0},
201  .open = pas_midi_open,
202  .close = pas_midi_close,
203  .outputc = pas_midi_out,
204  .start_read = pas_midi_start_read,
205  .end_read = pas_midi_end_read,
206  .kick = pas_midi_kick,
207  .buffer_status = pas_buffer_status,
208 };
209 
211 {
212  int dev = sound_alloc_mididev();
213 
214  if (dev == -1)
215  {
216  printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n");
217  return;
218  }
219  std_midi_synth.midi_dev = my_dev = dev;
220  midi_devs[dev] = &pas_midi_operations;
221  pas2_mididev = dev;
222  sequencer_init();
223 }
224 
226 {
227  unsigned char stat;
228  int i, incount;
229 
230  stat = pas_read(0x1B88);
231 
232  if (stat & 0x04) /* Input data available */
233  {
234  incount = pas_read(0x1B89) & 0x0f; /* Input FIFO size */
235  if (!incount)
236  incount = 16;
237 
238  for (i = 0; i < incount; i++)
239  if (input_opened)
240  {
241  midi_input_intr(my_dev, pas_read(0x178A));
242  } else
243  pas_read(0x178A); /* Flush */
244  }
245  if (stat & (0x08 | 0x10))
246  {
247  spin_lock(&pas_lock);/* called in irq context */
248 
249  while (qlen && dump_to_midi(tmp_queue[qhead]))
250  {
251  qlen--;
252  qhead++;
253  }
254 
255  spin_unlock(&pas_lock);
256  }
257  if (stat & 0x40)
258  {
259  printk(KERN_WARNING "MIDI output overrun %x,%x\n", pas_read(0x1B89), stat);
260  }
261  pas_write(stat, 0x1B88); /* Acknowledge interrupts */
262 }