Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ca_midi.c
Go to the documentation of this file.
1 /*
2  * Copyright 10/16/2005 Tilman Kranz <[email protected]>
3  * Creative Audio MIDI, for the CA0106 Driver
4  * Version: 0.0.1
5  *
6  * Changelog:
7  * Implementation is based on mpu401 and emu10k1x and
8  * tested with ca0106.
9  * mpu401: Copyright (c) by Jaroslav Kysela <[email protected]>
10  * emu10k1x: Copyright (c) by Francisco Moraes <[email protected]>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  *
26  *
27  */
28 
29 #include <linux/spinlock.h>
30 #include <sound/core.h>
31 #include <sound/rawmidi.h>
32 
33 #include "ca_midi.h"
34 
35 #define ca_midi_write_data(midi, data) midi->write(midi, data, 0)
36 #define ca_midi_write_cmd(midi, data) midi->write(midi, data, 1)
37 #define ca_midi_read_data(midi) midi->read(midi, 0)
38 #define ca_midi_read_stat(midi) midi->read(midi, 1)
39 #define ca_midi_input_avail(midi) (!(ca_midi_read_stat(midi) & midi->input_avail))
40 #define ca_midi_output_ready(midi) (!(ca_midi_read_stat(midi) & midi->output_ready))
41 
42 static void ca_midi_clear_rx(struct snd_ca_midi *midi)
43 {
44  int timeout = 100000;
45  for (; timeout > 0 && ca_midi_input_avail(midi); timeout--)
46  ca_midi_read_data(midi);
47 #ifdef CONFIG_SND_DEBUG
48  if (timeout <= 0)
49  snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n",
50  ca_midi_read_stat(midi));
51 #endif
52 }
53 
54 static void ca_midi_interrupt(struct snd_ca_midi *midi, unsigned int status)
55 {
56  unsigned char byte;
57 
58  if (midi->rmidi == NULL) {
59  midi->interrupt_disable(midi,midi->tx_enable | midi->rx_enable);
60  return;
61  }
62 
63  spin_lock(&midi->input_lock);
64  if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) {
65  if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
66  ca_midi_clear_rx(midi);
67  } else {
68  byte = ca_midi_read_data(midi);
69  if(midi->substream_input)
70  snd_rawmidi_receive(midi->substream_input, &byte, 1);
71 
72 
73  }
74  }
75  spin_unlock(&midi->input_lock);
76 
77  spin_lock(&midi->output_lock);
78  if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) {
79  if (midi->substream_output &&
80  snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
81  ca_midi_write_data(midi, byte);
82  } else {
83  midi->interrupt_disable(midi,midi->tx_enable);
84  }
85  }
86  spin_unlock(&midi->output_lock);
87 
88 }
89 
90 static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
91 {
92  unsigned long flags;
93  int timeout, ok;
94 
95  spin_lock_irqsave(&midi->input_lock, flags);
96  ca_midi_write_data(midi, 0x00);
97  /* ca_midi_clear_rx(midi); */
98 
99  ca_midi_write_cmd(midi, cmd);
100  if (ack) {
101  ok = 0;
102  timeout = 10000;
103  while (!ok && timeout-- > 0) {
104  if (ca_midi_input_avail(midi)) {
105  if (ca_midi_read_data(midi) == midi->ack)
106  ok = 1;
107  }
108  }
109  if (!ok && ca_midi_read_data(midi) == midi->ack)
110  ok = 1;
111  } else {
112  ok = 1;
113  }
114  spin_unlock_irqrestore(&midi->input_lock, flags);
115  if (!ok)
116  snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
117  cmd,
118  midi->get_dev_id_port(midi->dev_id),
119  ca_midi_read_stat(midi),
120  ca_midi_read_data(midi));
121 }
122 
123 static int ca_midi_input_open(struct snd_rawmidi_substream *substream)
124 {
125  struct snd_ca_midi *midi = substream->rmidi->private_data;
126  unsigned long flags;
127 
128  if (snd_BUG_ON(!midi->dev_id))
129  return -ENXIO;
130  spin_lock_irqsave(&midi->open_lock, flags);
131  midi->midi_mode |= CA_MIDI_MODE_INPUT;
132  midi->substream_input = substream;
133  if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
134  spin_unlock_irqrestore(&midi->open_lock, flags);
135  ca_midi_cmd(midi, midi->reset, 1);
136  ca_midi_cmd(midi, midi->enter_uart, 1);
137  } else {
138  spin_unlock_irqrestore(&midi->open_lock, flags);
139  }
140  return 0;
141 }
142 
143 static int ca_midi_output_open(struct snd_rawmidi_substream *substream)
144 {
145  struct snd_ca_midi *midi = substream->rmidi->private_data;
146  unsigned long flags;
147 
148  if (snd_BUG_ON(!midi->dev_id))
149  return -ENXIO;
150  spin_lock_irqsave(&midi->open_lock, flags);
152  midi->substream_output = substream;
153  if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
154  spin_unlock_irqrestore(&midi->open_lock, flags);
155  ca_midi_cmd(midi, midi->reset, 1);
156  ca_midi_cmd(midi, midi->enter_uart, 1);
157  } else {
158  spin_unlock_irqrestore(&midi->open_lock, flags);
159  }
160  return 0;
161 }
162 
163 static int ca_midi_input_close(struct snd_rawmidi_substream *substream)
164 {
165  struct snd_ca_midi *midi = substream->rmidi->private_data;
166  unsigned long flags;
167 
168  if (snd_BUG_ON(!midi->dev_id))
169  return -ENXIO;
170  spin_lock_irqsave(&midi->open_lock, flags);
171  midi->interrupt_disable(midi,midi->rx_enable);
172  midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
173  midi->substream_input = NULL;
174  if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
175  spin_unlock_irqrestore(&midi->open_lock, flags);
176  ca_midi_cmd(midi, midi->reset, 0);
177  } else {
178  spin_unlock_irqrestore(&midi->open_lock, flags);
179  }
180  return 0;
181 }
182 
183 static int ca_midi_output_close(struct snd_rawmidi_substream *substream)
184 {
185  struct snd_ca_midi *midi = substream->rmidi->private_data;
186  unsigned long flags;
187 
188  if (snd_BUG_ON(!midi->dev_id))
189  return -ENXIO;
190 
191  spin_lock_irqsave(&midi->open_lock, flags);
192 
193  midi->interrupt_disable(midi,midi->tx_enable);
194  midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT;
195  midi->substream_output = NULL;
196 
197  if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
198  spin_unlock_irqrestore(&midi->open_lock, flags);
199  ca_midi_cmd(midi, midi->reset, 0);
200  } else {
201  spin_unlock_irqrestore(&midi->open_lock, flags);
202  }
203  return 0;
204 }
205 
206 static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
207 {
208  struct snd_ca_midi *midi = substream->rmidi->private_data;
209 
210  if (snd_BUG_ON(!midi->dev_id))
211  return;
212 
213  if (up) {
214  midi->interrupt_enable(midi,midi->rx_enable);
215  } else {
216  midi->interrupt_disable(midi, midi->rx_enable);
217  }
218 }
219 
220 static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
221 {
222  struct snd_ca_midi *midi = substream->rmidi->private_data;
223  unsigned long flags;
224 
225  if (snd_BUG_ON(!midi->dev_id))
226  return;
227 
228  if (up) {
229  int max = 4;
230  unsigned char byte;
231 
232  spin_lock_irqsave(&midi->output_lock, flags);
233 
234  /* try to send some amount of bytes here before interrupts */
235  while (max > 0) {
236  if (ca_midi_output_ready(midi)) {
237  if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) ||
238  snd_rawmidi_transmit(substream, &byte, 1) != 1) {
239  /* no more data */
240  spin_unlock_irqrestore(&midi->output_lock, flags);
241  return;
242  }
243  ca_midi_write_data(midi, byte);
244  max--;
245  } else {
246  break;
247  }
248  }
249 
250  spin_unlock_irqrestore(&midi->output_lock, flags);
251  midi->interrupt_enable(midi,midi->tx_enable);
252 
253  } else {
254  midi->interrupt_disable(midi,midi->tx_enable);
255  }
256 }
257 
258 static struct snd_rawmidi_ops ca_midi_output =
259 {
260  .open = ca_midi_output_open,
261  .close = ca_midi_output_close,
262  .trigger = ca_midi_output_trigger,
263 };
264 
265 static struct snd_rawmidi_ops ca_midi_input =
266 {
267  .open = ca_midi_input_open,
268  .close = ca_midi_input_close,
269  .trigger = ca_midi_input_trigger,
270 };
271 
272 static void ca_midi_free(struct snd_ca_midi *midi)
273 {
274  midi->interrupt = NULL;
275  midi->interrupt_enable = NULL;
276  midi->interrupt_disable = NULL;
277  midi->read = NULL;
278  midi->write = NULL;
279  midi->get_dev_id_card = NULL;
280  midi->get_dev_id_port = NULL;
281  midi->rmidi = NULL;
282 }
283 
284 static void ca_rmidi_free(struct snd_rawmidi *rmidi)
285 {
286  ca_midi_free(rmidi->private_data);
287 }
288 
289 int __devinit ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name)
290 {
291  struct snd_rawmidi *rmidi;
292  int err;
293 
294  if ((err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi)) < 0)
295  return err;
296 
297  midi->dev_id = dev_id;
298  midi->interrupt = ca_midi_interrupt;
299 
300  spin_lock_init(&midi->open_lock);
301  spin_lock_init(&midi->input_lock);
302  spin_lock_init(&midi->output_lock);
303 
304  strcpy(rmidi->name, name);
305  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output);
306  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input);
310  rmidi->private_data = midi;
311  rmidi->private_free = ca_rmidi_free;
312 
313  midi->rmidi = rmidi;
314  return 0;
315 }
316