linux/sound/pci/emu10k1/emumpu401.c
<<
>>
Prefs
   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
  15static 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
  24static 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
  45static 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
  62static 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
  95static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
  96{
  97        do_emu10k1_midi_interrupt(emu, &emu->midi, status);
  98}
  99
 100static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
 101{
 102        do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
 103}
 104
 105static 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
 141static 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
 164error_out:
 165        return -EIO;
 166}
 167
 168static 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
 191error_out:
 192        return -EIO;
 193}
 194
 195static 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
 218static 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
 241static 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
 255static 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
 296static 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
 303static 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
 310static 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
 317static 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        err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi);
 323        if (err < 0)
 324                return err;
 325        midi->emu = emu;
 326        spin_lock_init(&midi->open_lock);
 327        spin_lock_init(&midi->input_lock);
 328        spin_lock_init(&midi->output_lock);
 329        strcpy(rmidi->name, name);
 330        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
 331        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
 332        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
 333                             SNDRV_RAWMIDI_INFO_INPUT |
 334                             SNDRV_RAWMIDI_INFO_DUPLEX;
 335        rmidi->private_data = midi;
 336        rmidi->private_free = snd_emu10k1_midi_free;
 337        midi->rmidi = rmidi;
 338        return 0;
 339}
 340
 341int snd_emu10k1_midi(struct snd_emu10k1 *emu)
 342{
 343        struct snd_emu10k1_midi *midi = &emu->midi;
 344        int err;
 345
 346        err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)");
 347        if (err < 0)
 348                return err;
 349
 350        midi->tx_enable = INTE_MIDITXENABLE;
 351        midi->rx_enable = INTE_MIDIRXENABLE;
 352        midi->port = MUDATA;
 353        midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
 354        midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
 355        midi->interrupt = snd_emu10k1_midi_interrupt;
 356        return 0;
 357}
 358
 359int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
 360{
 361        struct snd_emu10k1_midi *midi;
 362        int err;
 363
 364        midi = &emu->midi;
 365        err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)");
 366        if (err < 0)
 367                return err;
 368
 369        midi->tx_enable = INTE_MIDITXENABLE;
 370        midi->rx_enable = INTE_MIDIRXENABLE;
 371        midi->port = A_MUDATA1;
 372        midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
 373        midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
 374        midi->interrupt = snd_emu10k1_midi_interrupt;
 375
 376        midi = &emu->midi2;
 377        err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2");
 378        if (err < 0)
 379                return err;
 380
 381        midi->tx_enable = INTE_A_MIDITXENABLE2;
 382        midi->rx_enable = INTE_A_MIDIRXENABLE2;
 383        midi->port = A_MUDATA2;
 384        midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2;
 385        midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2;
 386        midi->interrupt = snd_emu10k1_midi_interrupt2;
 387        return 0;
 388}
 389