Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *  Routines for the GF1 MIDI interface - like UART 6850
0005  */
0006 
0007 #include <linux/delay.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/time.h>
0010 #include <sound/core.h>
0011 #include <sound/gus.h>
0012 
0013 static void snd_gf1_interrupt_midi_in(struct snd_gus_card * gus)
0014 {
0015     int count;
0016     unsigned char stat, byte;
0017     __always_unused unsigned char data;
0018     unsigned long flags;
0019 
0020     count = 10;
0021     while (count) {
0022         spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0023         stat = snd_gf1_uart_stat(gus);
0024         if (!(stat & 0x01)) {   /* data in Rx FIFO? */
0025             spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0026             count--;
0027             continue;
0028         }
0029         count = 100;    /* arm counter to new value */
0030         data = snd_gf1_uart_get(gus);
0031         if (!(gus->gf1.uart_cmd & 0x80)) {
0032             spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0033             continue;
0034         }           
0035         if (stat & 0x10) {  /* framing error */
0036             gus->gf1.uart_framing++;
0037             spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0038             continue;
0039         }
0040         byte = snd_gf1_uart_get(gus);
0041         spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0042         snd_rawmidi_receive(gus->midi_substream_input, &byte, 1);
0043         if (stat & 0x20) {
0044             gus->gf1.uart_overrun++;
0045         }
0046     }
0047 }
0048 
0049 static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus)
0050 {
0051     char byte;
0052     unsigned long flags;
0053 
0054     /* try unlock output */
0055     if (snd_gf1_uart_stat(gus) & 0x01)
0056         snd_gf1_interrupt_midi_in(gus);
0057 
0058     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0059     if (snd_gf1_uart_stat(gus) & 0x02) {    /* Tx FIFO free? */
0060         if (snd_rawmidi_transmit(gus->midi_substream_output, &byte, 1) != 1) {  /* no other bytes or error */
0061             snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); /* disable Tx interrupt */
0062         } else {
0063             snd_gf1_uart_put(gus, byte);
0064         }
0065     }
0066     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0067 }
0068 
0069 static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close)
0070 {
0071     snd_gf1_uart_cmd(gus, 0x03);    /* reset */
0072     if (!close && gus->uart_enable) {
0073         udelay(160);
0074         snd_gf1_uart_cmd(gus, 0x00);    /* normal operations */
0075     }
0076 }
0077 
0078 static int snd_gf1_uart_output_open(struct snd_rawmidi_substream *substream)
0079 {
0080     unsigned long flags;
0081     struct snd_gus_card *gus;
0082 
0083     gus = substream->rmidi->private_data;
0084     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0085     if (!(gus->gf1.uart_cmd & 0x80)) {  /* input active? */
0086         snd_gf1_uart_reset(gus, 0);
0087     }
0088     gus->gf1.interrupt_handler_midi_out = snd_gf1_interrupt_midi_out;
0089     gus->midi_substream_output = substream;
0090     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0091 #if 0
0092     snd_printk(KERN_DEBUG "write init - cmd = 0x%x, stat = 0x%x\n", gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
0093 #endif
0094     return 0;
0095 }
0096 
0097 static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
0098 {
0099     unsigned long flags;
0100     struct snd_gus_card *gus;
0101     int i;
0102 
0103     gus = substream->rmidi->private_data;
0104     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0105     if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) {
0106         snd_gf1_uart_reset(gus, 0);
0107     }
0108     gus->gf1.interrupt_handler_midi_in = snd_gf1_interrupt_midi_in;
0109     gus->midi_substream_input = substream;
0110     if (gus->uart_enable) {
0111         for (i = 0; i < 1000 && (snd_gf1_uart_stat(gus) & 0x01); i++)
0112             snd_gf1_uart_get(gus);  /* clean Rx */
0113         if (i >= 1000)
0114             snd_printk(KERN_ERR "gus midi uart init read - cleanup error\n");
0115     }
0116     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0117 #if 0
0118     snd_printk(KERN_DEBUG
0119            "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
0120            gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
0121     snd_printk(KERN_DEBUG
0122            "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
0123            "(page = 0x%x)\n",
0124            gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
0125            inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
0126 #endif
0127     return 0;
0128 }
0129 
0130 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream *substream)
0131 {
0132     unsigned long flags;
0133     struct snd_gus_card *gus;
0134 
0135     gus = substream->rmidi->private_data;
0136     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0137     if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in)
0138         snd_gf1_uart_reset(gus, 1);
0139     snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_OUT);
0140     gus->midi_substream_output = NULL;
0141     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0142     return 0;
0143 }
0144 
0145 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream *substream)
0146 {
0147     unsigned long flags;
0148     struct snd_gus_card *gus;
0149 
0150     gus = substream->rmidi->private_data;
0151     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0152     if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out)
0153         snd_gf1_uart_reset(gus, 1);
0154     snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_IN);
0155     gus->midi_substream_input = NULL;
0156     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0157     return 0;
0158 }
0159 
0160 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
0161 {
0162     struct snd_gus_card *gus;
0163     unsigned long flags;
0164 
0165     gus = substream->rmidi->private_data;
0166 
0167     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0168     if (up) {
0169         if ((gus->gf1.uart_cmd & 0x80) == 0)
0170             snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x80); /* enable Rx interrupts */
0171     } else {
0172         if (gus->gf1.uart_cmd & 0x80)
0173             snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x80); /* disable Rx interrupts */
0174     }
0175     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0176 }
0177 
0178 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
0179 {
0180     unsigned long flags;
0181     struct snd_gus_card *gus;
0182     char byte;
0183     int timeout;
0184 
0185     gus = substream->rmidi->private_data;
0186 
0187     spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0188     if (up) {
0189         if ((gus->gf1.uart_cmd & 0x20) == 0) {
0190             spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0191             /* wait for empty Rx - Tx is probably unlocked */
0192             timeout = 10000;
0193             while (timeout-- > 0 && snd_gf1_uart_stat(gus) & 0x01);
0194             /* Tx FIFO free? */
0195             spin_lock_irqsave(&gus->uart_cmd_lock, flags);
0196             if (gus->gf1.uart_cmd & 0x20) {
0197                 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0198                 return;
0199             }
0200             if (snd_gf1_uart_stat(gus) & 0x02) {
0201                 if (snd_rawmidi_transmit(substream, &byte, 1) != 1) {
0202                     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0203                     return;
0204                 }
0205                 snd_gf1_uart_put(gus, byte);
0206             }
0207             snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x20);    /* enable Tx interrupt */
0208         }
0209     } else {
0210         if (gus->gf1.uart_cmd & 0x20)
0211             snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20);
0212     }
0213     spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
0214 }
0215 
0216 static const struct snd_rawmidi_ops snd_gf1_uart_output =
0217 {
0218     .open =     snd_gf1_uart_output_open,
0219     .close =    snd_gf1_uart_output_close,
0220     .trigger =  snd_gf1_uart_output_trigger,
0221 };
0222 
0223 static const struct snd_rawmidi_ops snd_gf1_uart_input =
0224 {
0225     .open =     snd_gf1_uart_input_open,
0226     .close =    snd_gf1_uart_input_close,
0227     .trigger =  snd_gf1_uart_input_trigger,
0228 };
0229 
0230 int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device)
0231 {
0232     struct snd_rawmidi *rmidi;
0233     int err;
0234 
0235     err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi);
0236     if (err < 0)
0237         return err;
0238     strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
0239     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output);
0240     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_gf1_uart_input);
0241     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
0242     rmidi->private_data = gus;
0243     gus->midi_uart = rmidi;
0244     return err;
0245 }