root/sound/pci/emu10k1/emumpu401.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mpu401_read
  2. mpu401_write
  3. mpu401_clear_rx
  4. do_emu10k1_midi_interrupt
  5. snd_emu10k1_midi_interrupt
  6. snd_emu10k1_midi_interrupt2
  7. snd_emu10k1_midi_cmd
  8. snd_emu10k1_midi_input_open
  9. snd_emu10k1_midi_output_open
  10. snd_emu10k1_midi_input_close
  11. snd_emu10k1_midi_output_close
  12. snd_emu10k1_midi_input_trigger
  13. snd_emu10k1_midi_output_trigger
  14. snd_emu10k1_midi_free
  15. emu10k1_midi_init
  16. snd_emu10k1_midi
  17. snd_emu10k1_audigy_midi

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   4  *  Routines for control of EMU10K1 MPU-401 in UART mode
   5  */
   6 
   7 #include <linux/time.h>
   8 #include <linux/init.h>
   9 #include <sound/core.h>
  10 #include <sound/emu10k1.h>
  11 
  12 #define EMU10K1_MIDI_MODE_INPUT         (1<<0)
  13 #define EMU10K1_MIDI_MODE_OUTPUT        (1<<1)
  14 
  15 static inline unsigned char mpu401_read(struct snd_emu10k1 *emu,
  16                                         struct snd_emu10k1_midi *mpu, int idx)
  17 {
  18         if (emu->audigy)
  19                 return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0);
  20         else
  21                 return inb(emu->port + mpu->port + idx);
  22 }
  23 
  24 static inline void mpu401_write(struct snd_emu10k1 *emu,
  25                                 struct snd_emu10k1_midi *mpu, int data, int idx)
  26 {
  27         if (emu->audigy)
  28                 snd_emu10k1_ptr_write(emu, mpu->port + idx, 0, data);
  29         else
  30                 outb(data, emu->port + mpu->port + idx);
  31 }
  32 
  33 #define mpu401_write_data(emu, mpu, data)       mpu401_write(emu, mpu, data, 0)
  34 #define mpu401_write_cmd(emu, mpu, data)        mpu401_write(emu, mpu, data, 1)
  35 #define mpu401_read_data(emu, mpu)              mpu401_read(emu, mpu, 0)
  36 #define mpu401_read_stat(emu, mpu)              mpu401_read(emu, mpu, 1)
  37 
  38 #define mpu401_input_avail(emu,mpu)     (!(mpu401_read_stat(emu,mpu) & 0x80))
  39 #define mpu401_output_ready(emu,mpu)    (!(mpu401_read_stat(emu,mpu) & 0x40))
  40 
  41 #define MPU401_RESET            0xff
  42 #define MPU401_ENTER_UART       0x3f
  43 #define MPU401_ACK              0xfe
  44 
  45 static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mpu)
  46 {
  47         int timeout = 100000;
  48         for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--)
  49                 mpu401_read_data(emu, mpu);
  50 #ifdef CONFIG_SND_DEBUG
  51         if (timeout <= 0)
  52                 dev_err(emu->card->dev,
  53                         "cmd: clear rx timeout (status = 0x%x)\n",
  54                         mpu401_read_stat(emu, mpu));
  55 #endif
  56 }
  57 
  58 /*
  59 
  60  */
  61 
  62 static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status)
  63 {
  64         unsigned char byte;
  65 
  66         if (midi->rmidi == NULL) {
  67                 snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable);
  68                 return;
  69         }
  70 
  71         spin_lock(&midi->input_lock);
  72         if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
  73                 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
  74                         mpu401_clear_rx(emu, midi);
  75                 } else {
  76                         byte = mpu401_read_data(emu, midi);
  77                         if (midi->substream_input)
  78                                 snd_rawmidi_receive(midi->substream_input, &byte, 1);
  79                 }
  80         }
  81         spin_unlock(&midi->input_lock);
  82 
  83         spin_lock(&midi->output_lock);
  84         if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
  85                 if (midi->substream_output &&
  86                     snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
  87                         mpu401_write_data(emu, midi, byte);
  88                 } else {
  89                         snd_emu10k1_intr_disable(emu, midi->tx_enable);
  90                 }
  91         }
  92         spin_unlock(&midi->output_lock);
  93 }
  94 
  95 static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
  96 {
  97         do_emu10k1_midi_interrupt(emu, &emu->midi, status);
  98 }
  99 
 100 static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
 101 {
 102         do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
 103 }
 104 
 105 static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
 106 {
 107         unsigned long flags;
 108         int timeout, ok;
 109 
 110         spin_lock_irqsave(&midi->input_lock, flags);
 111         mpu401_write_data(emu, midi, 0x00);
 112         /* mpu401_clear_rx(emu, midi); */
 113 
 114         mpu401_write_cmd(emu, midi, cmd);
 115         if (ack) {
 116                 ok = 0;
 117                 timeout = 10000;
 118                 while (!ok && timeout-- > 0) {
 119                         if (mpu401_input_avail(emu, midi)) {
 120                                 if (mpu401_read_data(emu, midi) == MPU401_ACK)
 121                                         ok = 1;
 122                         }
 123                 }
 124                 if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
 125                         ok = 1;
 126         } else {
 127                 ok = 1;
 128         }
 129         spin_unlock_irqrestore(&midi->input_lock, flags);
 130         if (!ok) {
 131                 dev_err(emu->card->dev,
 132                         "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
 133                            cmd, emu->port,
 134                            mpu401_read_stat(emu, midi),
 135                            mpu401_read_data(emu, midi));
 136                 return 1;
 137         }
 138         return 0;
 139 }
 140 
 141 static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
 142 {
 143         struct snd_emu10k1 *emu;
 144         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 145         unsigned long flags;
 146 
 147         emu = midi->emu;
 148         if (snd_BUG_ON(!emu))
 149                 return -ENXIO;
 150         spin_lock_irqsave(&midi->open_lock, flags);
 151         midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
 152         midi->substream_input = substream;
 153         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
 154                 spin_unlock_irqrestore(&midi->open_lock, flags);
 155                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
 156                         goto error_out;
 157                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
 158                         goto error_out;
 159         } else {
 160                 spin_unlock_irqrestore(&midi->open_lock, flags);
 161         }
 162         return 0;
 163 
 164 error_out:
 165         return -EIO;
 166 }
 167 
 168 static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
 169 {
 170         struct snd_emu10k1 *emu;
 171         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 172         unsigned long flags;
 173 
 174         emu = midi->emu;
 175         if (snd_BUG_ON(!emu))
 176                 return -ENXIO;
 177         spin_lock_irqsave(&midi->open_lock, flags);
 178         midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
 179         midi->substream_output = substream;
 180         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
 181                 spin_unlock_irqrestore(&midi->open_lock, flags);
 182                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
 183                         goto error_out;
 184                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
 185                         goto error_out;
 186         } else {
 187                 spin_unlock_irqrestore(&midi->open_lock, flags);
 188         }
 189         return 0;
 190 
 191 error_out:
 192         return -EIO;
 193 }
 194 
 195 static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
 196 {
 197         struct snd_emu10k1 *emu;
 198         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 199         unsigned long flags;
 200         int err = 0;
 201 
 202         emu = midi->emu;
 203         if (snd_BUG_ON(!emu))
 204                 return -ENXIO;
 205         spin_lock_irqsave(&midi->open_lock, flags);
 206         snd_emu10k1_intr_disable(emu, midi->rx_enable);
 207         midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
 208         midi->substream_input = NULL;
 209         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
 210                 spin_unlock_irqrestore(&midi->open_lock, flags);
 211                 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
 212         } else {
 213                 spin_unlock_irqrestore(&midi->open_lock, flags);
 214         }
 215         return err;
 216 }
 217 
 218 static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
 219 {
 220         struct snd_emu10k1 *emu;
 221         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 222         unsigned long flags;
 223         int err = 0;
 224 
 225         emu = midi->emu;
 226         if (snd_BUG_ON(!emu))
 227                 return -ENXIO;
 228         spin_lock_irqsave(&midi->open_lock, flags);
 229         snd_emu10k1_intr_disable(emu, midi->tx_enable);
 230         midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
 231         midi->substream_output = NULL;
 232         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
 233                 spin_unlock_irqrestore(&midi->open_lock, flags);
 234                 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
 235         } else {
 236                 spin_unlock_irqrestore(&midi->open_lock, flags);
 237         }
 238         return err;
 239 }
 240 
 241 static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 242 {
 243         struct snd_emu10k1 *emu;
 244         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 245         emu = midi->emu;
 246         if (snd_BUG_ON(!emu))
 247                 return;
 248 
 249         if (up)
 250                 snd_emu10k1_intr_enable(emu, midi->rx_enable);
 251         else
 252                 snd_emu10k1_intr_disable(emu, midi->rx_enable);
 253 }
 254 
 255 static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 256 {
 257         struct snd_emu10k1 *emu;
 258         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 259         unsigned long flags;
 260 
 261         emu = midi->emu;
 262         if (snd_BUG_ON(!emu))
 263                 return;
 264 
 265         if (up) {
 266                 int max = 4;
 267                 unsigned char byte;
 268         
 269                 /* try to send some amount of bytes here before interrupts */
 270                 spin_lock_irqsave(&midi->output_lock, flags);
 271                 while (max > 0) {
 272                         if (mpu401_output_ready(emu, midi)) {
 273                                 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
 274                                     snd_rawmidi_transmit(substream, &byte, 1) != 1) {
 275                                         /* no more data */
 276                                         spin_unlock_irqrestore(&midi->output_lock, flags);
 277                                         return;
 278                                 }
 279                                 mpu401_write_data(emu, midi, byte);
 280                                 max--;
 281                         } else {
 282                                 break;
 283                         }
 284                 }
 285                 spin_unlock_irqrestore(&midi->output_lock, flags);
 286                 snd_emu10k1_intr_enable(emu, midi->tx_enable);
 287         } else {
 288                 snd_emu10k1_intr_disable(emu, midi->tx_enable);
 289         }
 290 }
 291 
 292 /*
 293 
 294  */
 295 
 296 static const struct snd_rawmidi_ops snd_emu10k1_midi_output =
 297 {
 298         .open =         snd_emu10k1_midi_output_open,
 299         .close =        snd_emu10k1_midi_output_close,
 300         .trigger =      snd_emu10k1_midi_output_trigger,
 301 };
 302 
 303 static const struct snd_rawmidi_ops snd_emu10k1_midi_input =
 304 {
 305         .open =         snd_emu10k1_midi_input_open,
 306         .close =        snd_emu10k1_midi_input_close,
 307         .trigger =      snd_emu10k1_midi_input_trigger,
 308 };
 309 
 310 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 311 {
 312         struct snd_emu10k1_midi *midi = rmidi->private_data;
 313         midi->interrupt = NULL;
 314         midi->rmidi = NULL;
 315 }
 316 
 317 static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name)
 318 {
 319         struct snd_rawmidi *rmidi;
 320         int err;
 321 
 322         if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0)
 323                 return err;
 324         midi->emu = emu;
 325         spin_lock_init(&midi->open_lock);
 326         spin_lock_init(&midi->input_lock);
 327         spin_lock_init(&midi->output_lock);
 328         strcpy(rmidi->name, name);
 329         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
 330         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
 331         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
 332                              SNDRV_RAWMIDI_INFO_INPUT |
 333                              SNDRV_RAWMIDI_INFO_DUPLEX;
 334         rmidi->private_data = midi;
 335         rmidi->private_free = snd_emu10k1_midi_free;
 336         midi->rmidi = rmidi;
 337         return 0;
 338 }
 339 
 340 int snd_emu10k1_midi(struct snd_emu10k1 *emu)
 341 {
 342         struct snd_emu10k1_midi *midi = &emu->midi;
 343         int err;
 344 
 345         if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0)
 346                 return err;
 347 
 348         midi->tx_enable = INTE_MIDITXENABLE;
 349         midi->rx_enable = INTE_MIDIRXENABLE;
 350         midi->port = MUDATA;
 351         midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
 352         midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
 353         midi->interrupt = snd_emu10k1_midi_interrupt;
 354         return 0;
 355 }
 356 
 357 int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
 358 {
 359         struct snd_emu10k1_midi *midi;
 360         int err;
 361 
 362         midi = &emu->midi;
 363         if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0)
 364                 return err;
 365 
 366         midi->tx_enable = INTE_MIDITXENABLE;
 367         midi->rx_enable = INTE_MIDIRXENABLE;
 368         midi->port = A_MUDATA1;
 369         midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
 370         midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
 371         midi->interrupt = snd_emu10k1_midi_interrupt;
 372 
 373         midi = &emu->midi2;
 374         if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0)
 375                 return err;
 376 
 377         midi->tx_enable = INTE_A_MIDITXENABLE2;
 378         midi->rx_enable = INTE_A_MIDIRXENABLE2;
 379         midi->port = A_MUDATA2;
 380         midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2;
 381         midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2;
 382         midi->interrupt = snd_emu10k1_midi_interrupt2;
 383         return 0;
 384 }

/* [<][>][^][v][top][bottom][index][help] */