aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ca0106
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/ca0106')
-rw-r--r--sound/pci/ca0106/Makefile2
-rw-r--r--sound/pci/ca0106/ca0106.h27
-rw-r--r--sound/pci/ca0106/ca0106_main.c123
-rw-r--r--sound/pci/ca0106/ca_midi.c306
-rw-r--r--sound/pci/ca0106/ca_midi.h69
5 files changed, 515 insertions, 12 deletions
diff --git a/sound/pci/ca0106/Makefile b/sound/pci/ca0106/Makefile
index 89c6ceee21f3..dcbae7b31546 100644
--- a/sound/pci/ca0106/Makefile
+++ b/sound/pci/ca0106/Makefile
@@ -1,3 +1,3 @@
1snd-ca0106-objs := ca0106_main.o ca0106_proc.o ca0106_mixer.o 1snd-ca0106-objs := ca0106_main.o ca0106_proc.o ca0106_mixer.o ca_midi.o
2 2
3obj-$(CONFIG_SND_CA0106) += snd-ca0106.o 3obj-$(CONFIG_SND_CA0106) += snd-ca0106.o
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index da09cab405a9..9a4b6406f7a5 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -399,10 +399,24 @@
399#define PLAYBACK_VOLUME2 0x6a /* Playback Analog volume per channel. Does not effect AC3 output */ 399#define PLAYBACK_VOLUME2 0x6a /* Playback Analog volume per channel. Does not effect AC3 output */
400 /* Similar to register 0x66, except that the destination is the I2S mixer instead of the SPDIF mixer. I.E. Outputs to the Analog outputs instead of SPDIF. */ 400 /* Similar to register 0x66, except that the destination is the I2S mixer instead of the SPDIF mixer. I.E. Outputs to the Analog outputs instead of SPDIF. */
401#define UNKNOWN6b 0x6b /* Unknown. Readonly. Default 00400000 00400000 00400000 00400000 */ 401#define UNKNOWN6b 0x6b /* Unknown. Readonly. Default 00400000 00400000 00400000 00400000 */
402#define UART_A_DATA 0x6c /* Uart, used in setting sample rates, bits per sample etc. */ 402#define MIDI_UART_A_DATA 0x6c /* Midi Uart A Data */
403#define UART_A_CMD 0x6d /* Uart, used in setting sample rates, bits per sample etc. */ 403#define MIDI_UART_A_CMD 0x6d /* Midi Uart A Command/Status */
404#define UART_B_DATA 0x6e /* Uart, Unknown. */ 404#define MIDI_UART_B_DATA 0x6e /* Midi Uart B Data (currently unused) */
405#define UART_B_CMD 0x6f /* Uart, Unknown. */ 405#define MIDI_UART_B_CMD 0x6f /* Midi Uart B Command/Status (currently unused) */
406
407/* unique channel identifier for midi->channel */
408
409#define CA0106_MIDI_CHAN_A 0x1
410#define CA0106_MIDI_CHAN_B 0x2
411
412/* from mpu401 */
413
414#define CA0106_MIDI_INPUT_AVAIL 0x80
415#define CA0106_MIDI_OUTPUT_READY 0x40
416#define CA0106_MPU401_RESET 0xff
417#define CA0106_MPU401_ENTER_UART 0x3f
418#define CA0106_MPU401_ACK 0xfe
419
406#define SAMPLE_RATE_TRACKER_STATUS 0x70 /* Readonly. Default 00108000 00108000 00500000 00500000 */ 420#define SAMPLE_RATE_TRACKER_STATUS 0x70 /* Readonly. Default 00108000 00108000 00500000 00500000 */
407 /* Estimated sample rate [19:0] Relative to 48kHz. 0x8000 = 1.0 421 /* Estimated sample rate [19:0] Relative to 48kHz. 0x8000 = 1.0
408 * Rate Locked [20] 422 * Rate Locked [20]
@@ -538,6 +552,8 @@
538#define CONTROL_CENTER_LFE_CHANNEL 1 552#define CONTROL_CENTER_LFE_CHANNEL 1
539#define CONTROL_UNKNOWN_CHANNEL 2 553#define CONTROL_UNKNOWN_CHANNEL 2
540 554
555#include "ca_midi.h"
556
541typedef struct snd_ca0106_channel ca0106_channel_t; 557typedef struct snd_ca0106_channel ca0106_channel_t;
542typedef struct snd_ca0106 ca0106_t; 558typedef struct snd_ca0106 ca0106_t;
543typedef struct snd_ca0106_pcm ca0106_pcm_t; 559typedef struct snd_ca0106_pcm ca0106_pcm_t;
@@ -592,6 +608,9 @@ struct snd_ca0106 {
592 int capture_mic_line_in; 608 int capture_mic_line_in;
593 609
594 struct snd_dma_buffer buffer; 610 struct snd_dma_buffer buffer;
611
612 ca_midi_t midi;
613 ca_midi_t midi2;
595}; 614};
596 615
597int __devinit snd_ca0106_mixer(ca0106_t *emu); 616int __devinit snd_ca0106_mixer(ca0106_t *emu);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index ba07960921d8..ee58d16002e5 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -281,7 +281,7 @@ int snd_ca0106_i2c_write(ca0106_t *emu,
281 int retry; 281 int retry;
282 if ((reg > 0x7f) || (value > 0x1ff)) 282 if ((reg > 0x7f) || (value > 0x1ff))
283 { 283 {
284 snd_printk("i2c_write: invalid values.\n"); 284 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
285 return -EINVAL; 285 return -EINVAL;
286 } 286 }
287 287
@@ -319,7 +319,7 @@ int snd_ca0106_i2c_write(ca0106_t *emu,
319 319
320 if(retry==10) 320 if(retry==10)
321 { 321 {
322 snd_printk("Writing to ADC failed!\n"); 322 snd_printk(KERN_ERR "Writing to ADC failed!\n");
323 return -EINVAL; 323 return -EINVAL;
324 } 324 }
325 325
@@ -338,6 +338,18 @@ static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb)
338 spin_unlock_irqrestore(&emu->emu_lock, flags); 338 spin_unlock_irqrestore(&emu->emu_lock, flags);
339} 339}
340 340
341static void snd_ca0106_intr_disable(ca0106_t *emu, unsigned int intrenb)
342{
343 unsigned long flags;
344 unsigned int enable;
345
346 spin_lock_irqsave(&emu->emu_lock, flags);
347 enable = inl(emu->port + INTE) & ~intrenb;
348 outl(enable, emu->port + INTE);
349 spin_unlock_irqrestore(&emu->emu_lock, flags);
350}
351
352
341static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) 353static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime)
342{ 354{
343 kfree(runtime->private_data); 355 kfree(runtime->private_data);
@@ -421,7 +433,7 @@ static int snd_ca0106_pcm_open_capture_channel(snd_pcm_substream_t *substream, i
421 433
422 epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 434 epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
423 if (epcm == NULL) { 435 if (epcm == NULL) {
424 snd_printk("open_capture_channel: failed epcm alloc\n"); 436 snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n");
425 return -ENOMEM; 437 return -ENOMEM;
426 } 438 }
427 epcm->emu = chip; 439 epcm->emu = chip;
@@ -969,10 +981,8 @@ static int snd_ca0106_free(ca0106_t *chip)
969#endif 981#endif
970 982
971 // release the i/o port 983 // release the i/o port
972 if (chip->res_port) { 984 release_and_free_resource(chip->res_port);
973 release_resource(chip->res_port); 985
974 kfree_nocheck(chip->res_port);
975 }
976 // release the irq 986 // release the irq
977 if (chip->irq >= 0) 987 if (chip->irq >= 0)
978 free_irq(chip->irq, (void *)chip); 988 free_irq(chip->irq, (void *)chip);
@@ -1042,6 +1052,15 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id,
1042 1052
1043 snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76); 1053 snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76);
1044 spin_lock(&chip->emu_lock); 1054 spin_lock(&chip->emu_lock);
1055
1056 if (chip->midi.dev_id &&
1057 (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) {
1058 if (chip->midi.interrupt)
1059 chip->midi.interrupt(&chip->midi, status);
1060 else
1061 chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable);
1062 }
1063
1045 // acknowledge the interrupt if necessary 1064 // acknowledge the interrupt if necessary
1046 outl(status, chip->port+IPR); 1065 outl(status, chip->port+IPR);
1047 1066
@@ -1311,6 +1330,88 @@ static int __devinit snd_ca0106_create(snd_card_t *card,
1311 return 0; 1330 return 0;
1312} 1331}
1313 1332
1333
1334static void ca0106_midi_interrupt_enable(ca_midi_t *midi, int intr)
1335{
1336 snd_ca0106_intr_enable((ca0106_t *)(midi->dev_id), intr);
1337}
1338
1339static void ca0106_midi_interrupt_disable(ca_midi_t *midi, int intr)
1340{
1341 snd_ca0106_intr_disable((ca0106_t *)(midi->dev_id), intr);
1342}
1343
1344static unsigned char ca0106_midi_read(ca_midi_t *midi, int idx)
1345{
1346 return (unsigned char)snd_ca0106_ptr_read((ca0106_t *)(midi->dev_id), midi->port + idx, 0);
1347}
1348
1349static void ca0106_midi_write(ca_midi_t *midi, int data, int idx)
1350{
1351 snd_ca0106_ptr_write((ca0106_t *)(midi->dev_id), midi->port + idx, 0, data);
1352}
1353
1354static snd_card_t *ca0106_dev_id_card(void *dev_id)
1355{
1356 return ((ca0106_t *)dev_id)->card;
1357}
1358
1359static int ca0106_dev_id_port(void *dev_id)
1360{
1361 return ((ca0106_t *)dev_id)->port;
1362}
1363
1364static int __devinit snd_ca0106_midi(ca0106_t *chip, unsigned int channel)
1365{
1366 ca_midi_t *midi;
1367 char *name;
1368 int err;
1369
1370 if(channel==CA0106_MIDI_CHAN_B) {
1371 name = "CA0106 MPU-401 (UART) B";
1372 midi = &chip->midi2;
1373 midi->tx_enable = INTE_MIDI_TX_B;
1374 midi->rx_enable = INTE_MIDI_RX_B;
1375 midi->ipr_tx = IPR_MIDI_TX_B;
1376 midi->ipr_rx = IPR_MIDI_RX_B;
1377 midi->port = MIDI_UART_B_DATA;
1378 } else {
1379 name = "CA0106 MPU-401 (UART)";
1380 midi = &chip->midi;
1381 midi->tx_enable = INTE_MIDI_TX_A;
1382 midi->rx_enable = INTE_MIDI_TX_B;
1383 midi->ipr_tx = IPR_MIDI_TX_A;
1384 midi->ipr_rx = IPR_MIDI_RX_A;
1385 midi->port = MIDI_UART_A_DATA;
1386 }
1387
1388 midi->reset = CA0106_MPU401_RESET;
1389 midi->enter_uart = CA0106_MPU401_ENTER_UART;
1390 midi->ack = CA0106_MPU401_ACK;
1391
1392 midi->input_avail = CA0106_MIDI_INPUT_AVAIL;
1393 midi->output_ready = CA0106_MIDI_OUTPUT_READY;
1394
1395 midi->channel = channel;
1396
1397 midi->interrupt_enable = ca0106_midi_interrupt_enable;
1398 midi->interrupt_disable = ca0106_midi_interrupt_disable;
1399
1400 midi->read = ca0106_midi_read;
1401 midi->write = ca0106_midi_write;
1402
1403 midi->get_dev_id_card = ca0106_dev_id_card;
1404 midi->get_dev_id_port = ca0106_dev_id_port;
1405
1406 midi->dev_id = chip;
1407
1408 if ((err = ca_midi_init(chip, midi, 0, name)) < 0)
1409 return err;
1410
1411 return 0;
1412}
1413
1414
1314static int __devinit snd_ca0106_probe(struct pci_dev *pci, 1415static int __devinit snd_ca0106_probe(struct pci_dev *pci,
1315 const struct pci_device_id *pci_id) 1416 const struct pci_device_id *pci_id)
1316{ 1417{
@@ -1362,6 +1463,14 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
1362 return err; 1463 return err;
1363 } 1464 }
1364 1465
1466 snd_printdd("ca0106: probe for MIDI channel A ...");
1467 if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) {
1468 snd_card_free(card);
1469 snd_printdd(" failed, err=0x%x\n",err);
1470 return err;
1471 }
1472 snd_printdd(" done.\n");
1473
1365 snd_ca0106_proc_init(chip); 1474 snd_ca0106_proc_init(chip);
1366 1475
1367 if ((err = snd_card_register(card)) < 0) { 1476 if ((err = snd_card_register(card)) < 0) {
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
new file mode 100644
index 000000000000..2e08b27b8349
--- /dev/null
+++ b/sound/pci/ca0106/ca_midi.c
@@ -0,0 +1,306 @@
1/*
2 * Copyright 10/16/2005 Tilman Kranz <tilde@tk-sls.de>
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 <perex@suse.cz>
10 * emu10k1x: Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
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/driver.h>
31#include <sound/core.h>
32#include <sound/rawmidi.h>
33
34#include "ca_midi.h"
35
36#define ca_midi_write_data(midi, data) midi->write(midi, data, 0)
37#define ca_midi_write_cmd(midi, data) midi->write(midi, data, 1)
38#define ca_midi_read_data(midi) midi->read(midi, 0)
39#define ca_midi_read_stat(midi) midi->read(midi, 1)
40#define ca_midi_input_avail(midi) (!(ca_midi_read_stat(midi) & midi->input_avail))
41#define ca_midi_output_ready(midi) (!(ca_midi_read_stat(midi) & midi->output_ready))
42
43static void ca_midi_clear_rx(ca_midi_t *midi)
44{
45 int timeout = 100000;
46 for (; timeout > 0 && ca_midi_input_avail(midi); timeout--)
47 ca_midi_read_data(midi);
48#ifdef CONFIG_SND_DEBUG
49 if (timeout <= 0)
50 snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n", ca_midi_read_stat(midi));
51#endif
52}
53
54static void ca_midi_interrupt(ca_midi_t *midi, unsigned int status) {
55 unsigned char byte;
56
57 if (midi->rmidi == NULL) {
58 midi->interrupt_disable(midi,midi->tx_enable | midi->rx_enable);
59 return;
60 }
61
62 spin_lock(&midi->input_lock);
63 if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) {
64 if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
65 ca_midi_clear_rx(midi);
66 } else {
67 byte = ca_midi_read_data(midi);
68 if(midi->substream_input)
69 snd_rawmidi_receive(midi->substream_input, &byte, 1);
70
71
72 }
73 }
74 spin_unlock(&midi->input_lock);
75
76 spin_lock(&midi->output_lock);
77 if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) {
78 if (midi->substream_output &&
79 snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
80 ca_midi_write_data(midi, byte);
81 } else {
82 midi->interrupt_disable(midi,midi->tx_enable);
83 }
84 }
85 spin_unlock(&midi->output_lock);
86
87}
88
89static void ca_midi_cmd(ca_midi_t *midi, unsigned char cmd, int ack)
90{
91 unsigned long flags;
92 int timeout, ok;
93
94 spin_lock_irqsave(&midi->input_lock, flags);
95 ca_midi_write_data(midi, 0x00);
96 /* ca_midi_clear_rx(midi); */
97
98 ca_midi_write_cmd(midi, cmd);
99 if (ack) {
100 ok = 0;
101 timeout = 10000;
102 while (!ok && timeout-- > 0) {
103 if (ca_midi_input_avail(midi)) {
104 if (ca_midi_read_data(midi) == midi->ack)
105 ok = 1;
106 }
107 }
108 if (!ok && ca_midi_read_data(midi) == midi->ack)
109 ok = 1;
110 } else {
111 ok = 1;
112 }
113 spin_unlock_irqrestore(&midi->input_lock, flags);
114 if (!ok)
115 snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
116 cmd,
117 midi->get_dev_id_port(midi->dev_id),
118 ca_midi_read_stat(midi),
119 ca_midi_read_data(midi));
120}
121
122static int ca_midi_input_open(snd_rawmidi_substream_t * substream)
123{
124 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
125 unsigned long flags;
126
127 snd_assert(midi->dev_id, return -ENXIO);
128 spin_lock_irqsave(&midi->open_lock, flags);
129 midi->midi_mode |= CA_MIDI_MODE_INPUT;
130 midi->substream_input = substream;
131 if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
132 spin_unlock_irqrestore(&midi->open_lock, flags);
133 ca_midi_cmd(midi, midi->reset, 1);
134 ca_midi_cmd(midi, midi->enter_uart, 1);
135 } else {
136 spin_unlock_irqrestore(&midi->open_lock, flags);
137 }
138 return 0;
139}
140
141static int ca_midi_output_open(snd_rawmidi_substream_t * substream)
142{
143 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
144 unsigned long flags;
145
146 snd_assert(midi->dev_id, return -ENXIO);
147 spin_lock_irqsave(&midi->open_lock, flags);
148 midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
149 midi->substream_output = substream;
150 if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
151 spin_unlock_irqrestore(&midi->open_lock, flags);
152 ca_midi_cmd(midi, midi->reset, 1);
153 ca_midi_cmd(midi, midi->enter_uart, 1);
154 } else {
155 spin_unlock_irqrestore(&midi->open_lock, flags);
156 }
157 return 0;
158}
159
160static int ca_midi_input_close(snd_rawmidi_substream_t * substream)
161{
162 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
163 unsigned long flags;
164
165 snd_assert(midi->dev_id, return -ENXIO);
166 spin_lock_irqsave(&midi->open_lock, flags);
167 midi->interrupt_disable(midi,midi->rx_enable);
168 midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
169 midi->substream_input = NULL;
170 if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
171 spin_unlock_irqrestore(&midi->open_lock, flags);
172 ca_midi_cmd(midi, midi->reset, 0);
173 } else {
174 spin_unlock_irqrestore(&midi->open_lock, flags);
175 }
176 return 0;
177}
178
179static int ca_midi_output_close(snd_rawmidi_substream_t * substream)
180{
181 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
182 unsigned long flags;
183 snd_assert(midi->dev_id, return -ENXIO);
184
185 spin_lock_irqsave(&midi->open_lock, flags);
186
187 midi->interrupt_disable(midi,midi->tx_enable);
188 midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT;
189 midi->substream_output = NULL;
190
191 if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
192 spin_unlock_irqrestore(&midi->open_lock, flags);
193 ca_midi_cmd(midi, midi->reset, 0);
194 } else {
195 spin_unlock_irqrestore(&midi->open_lock, flags);
196 }
197 return 0;
198}
199
200static void ca_midi_input_trigger(snd_rawmidi_substream_t * substream, int up)
201{
202 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
203 snd_assert(midi->dev_id, return);
204
205 if (up) {
206 midi->interrupt_enable(midi,midi->rx_enable);
207 } else {
208 midi->interrupt_disable(midi, midi->rx_enable);
209 }
210}
211
212static void ca_midi_output_trigger(snd_rawmidi_substream_t * substream, int up)
213{
214 ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data;
215 unsigned long flags;
216
217 snd_assert(midi->dev_id, return);
218
219 if (up) {
220 int max = 4;
221 unsigned char byte;
222
223 spin_lock_irqsave(&midi->output_lock, flags);
224
225 /* try to send some amount of bytes here before interrupts */
226 while (max > 0) {
227 if (ca_midi_output_ready(midi)) {
228 if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) ||
229 snd_rawmidi_transmit(substream, &byte, 1) != 1) {
230 /* no more data */
231 spin_unlock_irqrestore(&midi->output_lock, flags);
232 return;
233 }
234 ca_midi_write_data(midi, byte);
235 max--;
236 } else {
237 break;
238 }
239 }
240
241 spin_unlock_irqrestore(&midi->output_lock, flags);
242 midi->interrupt_enable(midi,midi->tx_enable);
243
244 } else {
245 midi->interrupt_disable(midi,midi->tx_enable);
246 }
247}
248
249static snd_rawmidi_ops_t ca_midi_output =
250{
251 .open = ca_midi_output_open,
252 .close = ca_midi_output_close,
253 .trigger = ca_midi_output_trigger,
254};
255
256static snd_rawmidi_ops_t ca_midi_input =
257{
258 .open = ca_midi_input_open,
259 .close = ca_midi_input_close,
260 .trigger = ca_midi_input_trigger,
261};
262
263static void ca_midi_free(ca_midi_t *midi) {
264 midi->interrupt = NULL;
265 midi->interrupt_enable = NULL;
266 midi->interrupt_disable = NULL;
267 midi->read = NULL;
268 midi->write = NULL;
269 midi->get_dev_id_card = NULL;
270 midi->get_dev_id_port = NULL;
271 midi->rmidi = NULL;
272}
273
274static void ca_rmidi_free(snd_rawmidi_t *rmidi)
275{
276 ca_midi_free((ca_midi_t *)rmidi->private_data);
277}
278
279int __devinit ca_midi_init(void *dev_id, ca_midi_t *midi, int device, char *name)
280{
281 snd_rawmidi_t *rmidi;
282 int err;
283
284 if ((err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi)) < 0)
285 return err;
286
287 midi->dev_id = dev_id;
288 midi->interrupt = ca_midi_interrupt;
289
290 spin_lock_init(&midi->open_lock);
291 spin_lock_init(&midi->input_lock);
292 spin_lock_init(&midi->output_lock);
293
294 strcpy(rmidi->name, name);
295 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output);
296 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input);
297 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
298 SNDRV_RAWMIDI_INFO_INPUT |
299 SNDRV_RAWMIDI_INFO_DUPLEX;
300 rmidi->private_data = midi;
301 rmidi->private_free = ca_rmidi_free;
302
303 midi->rmidi = rmidi;
304 return 0;
305}
306
diff --git a/sound/pci/ca0106/ca_midi.h b/sound/pci/ca0106/ca_midi.h
new file mode 100644
index 000000000000..b452cec2bf57
--- /dev/null
+++ b/sound/pci/ca0106/ca_midi.h
@@ -0,0 +1,69 @@
1/*
2 * Copyright 10/16/2005 Tilman Kranz <tilde@tk-sls.de>
3 * Creative Audio MIDI, for the CA0106 Driver
4 * Version: 0.0.1
5 *
6 * Changelog:
7 * See ca_midi.c
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include<linux/spinlock.h>
26#include<sound/rawmidi.h>
27#include<sound/mpu401.h>
28
29#define CA_MIDI_MODE_INPUT MPU401_MODE_INPUT
30#define CA_MIDI_MODE_OUTPUT MPU401_MODE_OUTPUT
31
32typedef struct ca_midi ca_midi_t;
33struct ca_midi {
34
35 snd_rawmidi_t *rmidi;
36 snd_rawmidi_substream_t *substream_input;
37 snd_rawmidi_substream_t *substream_output;
38
39 void *dev_id;
40
41 spinlock_t input_lock;
42 spinlock_t output_lock;
43 spinlock_t open_lock;
44
45 unsigned int channel;
46
47 unsigned int midi_mode;
48 int port;
49 int tx_enable, rx_enable;
50 int ipr_tx, ipr_rx;
51
52 int input_avail, output_ready;
53 int ack, reset, enter_uart;
54
55 void (*interrupt)(ca_midi_t *midi, unsigned int status);
56 void (*interrupt_enable)(ca_midi_t *midi, int intr);
57 void (*interrupt_disable)(ca_midi_t *midi, int intr);
58
59 unsigned char (*read)(ca_midi_t *midi, int idx);
60 void (*write)(ca_midi_t *midi, int data, int idx);
61
62 /* get info from dev_id */
63 snd_card_t *(*get_dev_id_card)(void *dev_id);
64 int (*get_dev_id_port)(void *dev_id);
65};
66
67int __devinit ca_midi_init(void *card, ca_midi_t *midi, int device, char *name);
68
69