aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ice1712/ice1724.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/ice1712/ice1724.c')
-rw-r--r--sound/pci/ice1712/ice1724.c213
1 files changed, 167 insertions, 46 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 67350901772c..e596d777d9dd 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -32,7 +32,7 @@
32#include <linux/mutex.h> 32#include <linux/mutex.h>
33#include <sound/core.h> 33#include <sound/core.h>
34#include <sound/info.h> 34#include <sound/info.h>
35#include <sound/mpu401.h> 35#include <sound/rawmidi.h>
36#include <sound/initval.h> 36#include <sound/initval.h>
37 37
38#include <sound/asoundef.h> 38#include <sound/asoundef.h>
@@ -223,30 +223,153 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice)
223} 223}
224 224
225/* 225/*
226 * MPU401 accessor 226 * MIDI
227 */ 227 */
228static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, 228
229 unsigned long addr) 229static void vt1724_midi_clear_rx(struct snd_ice1712 *ice)
230{
231 unsigned int count;
232
233 for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count)
234 inb(ICEREG1724(ice, MPU_DATA));
235}
236
237static inline struct snd_rawmidi_substream *
238get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream)
230{ 239{
231 /* fix status bits to the standard position */ 240 return list_first_entry(&ice->rmidi[0]->streams[stream].substreams,
232 /* only RX_EMPTY and TX_FULL are checked */ 241 struct snd_rawmidi_substream, list);
233 if (addr == MPU401C(mpu)) 242}
234 return (inb(addr) & 0x0c) << 4; 243
244static void vt1724_midi_write(struct snd_ice1712 *ice)
245{
246 struct snd_rawmidi_substream *s;
247 int count, i;
248 u8 buffer[32];
249
250 s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT);
251 count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO));
252 if (count > 0) {
253 count = snd_rawmidi_transmit(s, buffer, count);
254 for (i = 0; i < count; ++i)
255 outb(buffer[i], ICEREG1724(ice, MPU_DATA));
256 }
257}
258
259static void vt1724_midi_read(struct snd_ice1712 *ice)
260{
261 struct snd_rawmidi_substream *s;
262 int count, i;
263 u8 buffer[32];
264
265 s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT);
266 count = inb(ICEREG1724(ice, MPU_RXFIFO));
267 if (count > 0) {
268 count = min(count, 32);
269 for (i = 0; i < count; ++i)
270 buffer[i] = inb(ICEREG1724(ice, MPU_DATA));
271 snd_rawmidi_receive(s, buffer, count);
272 }
273}
274
275static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
276 u8 flag, int enable)
277{
278 struct snd_ice1712 *ice = substream->rmidi->private_data;
279 u8 mask;
280
281 spin_lock_irq(&ice->reg_lock);
282 mask = inb(ICEREG1724(ice, IRQMASK));
283 if (enable)
284 mask &= ~flag;
235 else 285 else
236 return inb(addr); 286 mask |= flag;
287 outb(mask, ICEREG1724(ice, IRQMASK));
288 spin_unlock_irq(&ice->reg_lock);
237} 289}
238 290
239static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, 291static int vt1724_midi_output_open(struct snd_rawmidi_substream *s)
240 unsigned char data, unsigned long addr)
241{ 292{
242 if (addr == MPU401C(mpu)) { 293 vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1);
243 if (data == MPU401_ENTER_UART) 294 return 0;
244 outb(0x01, addr); 295}
245 /* what else? */ 296
246 } else 297static int vt1724_midi_output_close(struct snd_rawmidi_substream *s)
247 outb(data, addr); 298{
299 vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
300 return 0;
248} 301}
249 302
303static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
304{
305 struct snd_ice1712 *ice = s->rmidi->private_data;
306 unsigned long flags;
307
308 spin_lock_irqsave(&ice->reg_lock, flags);
309 if (up) {
310 ice->midi_output = 1;
311 vt1724_midi_write(ice);
312 } else {
313 ice->midi_output = 0;
314 }
315 spin_unlock_irqrestore(&ice->reg_lock, flags);
316}
317
318static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
319{
320 struct snd_ice1712 *ice = s->rmidi->private_data;
321 unsigned long timeout;
322
323 /* 32 bytes should be transmitted in less than about 12 ms */
324 timeout = jiffies + msecs_to_jiffies(15);
325 do {
326 if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY)
327 break;
328 schedule_timeout_uninterruptible(1);
329 } while (time_after(timeout, jiffies));
330}
331
332static struct snd_rawmidi_ops vt1724_midi_output_ops = {
333 .open = vt1724_midi_output_open,
334 .close = vt1724_midi_output_close,
335 .trigger = vt1724_midi_output_trigger,
336 .drain = vt1724_midi_output_drain,
337};
338
339static int vt1724_midi_input_open(struct snd_rawmidi_substream *s)
340{
341 vt1724_midi_clear_rx(s->rmidi->private_data);
342 vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1);
343 return 0;
344}
345
346static int vt1724_midi_input_close(struct snd_rawmidi_substream *s)
347{
348 vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0);
349 return 0;
350}
351
352static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
353{
354 struct snd_ice1712 *ice = s->rmidi->private_data;
355 unsigned long flags;
356
357 spin_lock_irqsave(&ice->reg_lock, flags);
358 if (up) {
359 ice->midi_input = 1;
360 vt1724_midi_read(ice);
361 } else {
362 ice->midi_input = 0;
363 }
364 spin_unlock_irqrestore(&ice->reg_lock, flags);
365}
366
367static struct snd_rawmidi_ops vt1724_midi_input_ops = {
368 .open = vt1724_midi_input_open,
369 .close = vt1724_midi_input_close,
370 .trigger = vt1724_midi_input_trigger,
371};
372
250 373
251/* 374/*
252 * Interrupt handler 375 * Interrupt handler
@@ -278,13 +401,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
278#endif 401#endif
279 handled = 1; 402 handled = 1;
280 if (status & VT1724_IRQ_MPU_TX) { 403 if (status & VT1724_IRQ_MPU_TX) {
281 if (ice->rmidi[0]) 404 spin_lock(&ice->reg_lock);
282 snd_mpu401_uart_interrupt_tx(irq, 405 if (ice->midi_output)
283 ice->rmidi[0]->private_data); 406 vt1724_midi_write(ice);
284 else /* disable TX to be sure */ 407 spin_unlock(&ice->reg_lock);
285 outb(inb(ICEREG1724(ice, IRQMASK)) |
286 VT1724_IRQ_MPU_TX,
287 ICEREG1724(ice, IRQMASK));
288 /* Due to mysterical reasons, MPU_TX is always 408 /* Due to mysterical reasons, MPU_TX is always
289 * generated (and can't be cleared) when a PCM 409 * generated (and can't be cleared) when a PCM
290 * playback is going. So let's ignore at the 410 * playback is going. So let's ignore at the
@@ -293,13 +413,12 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
293 status_mask &= ~VT1724_IRQ_MPU_TX; 413 status_mask &= ~VT1724_IRQ_MPU_TX;
294 } 414 }
295 if (status & VT1724_IRQ_MPU_RX) { 415 if (status & VT1724_IRQ_MPU_RX) {
296 if (ice->rmidi[0]) 416 spin_lock(&ice->reg_lock);
297 snd_mpu401_uart_interrupt(irq, 417 if (ice->midi_input)
298 ice->rmidi[0]->private_data); 418 vt1724_midi_read(ice);
299 else /* disable RX to be sure */ 419 else
300 outb(inb(ICEREG1724(ice, IRQMASK)) | 420 vt1724_midi_clear_rx(ice);
301 VT1724_IRQ_MPU_RX, 421 spin_unlock(&ice->reg_lock);
302 ICEREG1724(ice, IRQMASK));
303 } 422 }
304 /* ack MPU irq */ 423 /* ack MPU irq */
305 outb(status, ICEREG1724(ice, IRQSTAT)); 424 outb(status, ICEREG1724(ice, IRQSTAT));
@@ -2425,28 +2544,30 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
2425 2544
2426 if (! c->no_mpu401) { 2545 if (! c->no_mpu401) {
2427 if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { 2546 if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
2428 struct snd_mpu401 *mpu; 2547 struct snd_rawmidi *rmidi;
2429 if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, 2548
2430 ICEREG1724(ice, MPU_CTRL), 2549 err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi);
2431 (MPU401_INFO_INTEGRATED | 2550 if (err < 0) {
2432 MPU401_INFO_NO_ACK |
2433 MPU401_INFO_TX_IRQ),
2434 ice->irq, 0,
2435 &ice->rmidi[0])) < 0) {
2436 snd_card_free(card); 2551 snd_card_free(card);
2437 return err; 2552 return err;
2438 } 2553 }
2439 mpu = ice->rmidi[0]->private_data; 2554 ice->rmidi[0] = rmidi;
2440 mpu->read = snd_vt1724_mpu401_read; 2555 rmidi->private_data = ice;
2441 mpu->write = snd_vt1724_mpu401_write; 2556 strcpy(rmidi->name, "ICE1724 MIDI");
2442 /* unmask MPU RX/TX irqs */ 2557 rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
2443 outb(inb(ICEREG1724(ice, IRQMASK)) & 2558 SNDRV_RAWMIDI_INFO_INPUT |
2444 ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), 2559 SNDRV_RAWMIDI_INFO_DUPLEX;
2445 ICEREG1724(ice, IRQMASK)); 2560 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
2561 &vt1724_midi_output_ops);
2562 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
2563 &vt1724_midi_input_ops);
2564
2446 /* set watermarks */ 2565 /* set watermarks */
2447 outb(VT1724_MPU_RX_FIFO | 0x1, 2566 outb(VT1724_MPU_RX_FIFO | 0x1,
2448 ICEREG1724(ice, MPU_FIFO_WM)); 2567 ICEREG1724(ice, MPU_FIFO_WM));
2449 outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); 2568 outb(0x1, ICEREG1724(ice, MPU_FIFO_WM));
2569 /* set UART mode */
2570 outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL));
2450 } 2571 }
2451 } 2572 }
2452 2573