18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 48c2ecf20Sopenharmony_ci * Routines for control of EMU10K1 MPU-401 in UART mode 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/time.h> 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <sound/core.h> 108c2ecf20Sopenharmony_ci#include <sound/emu10k1.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define EMU10K1_MIDI_MODE_INPUT (1<<0) 138c2ecf20Sopenharmony_ci#define EMU10K1_MIDI_MODE_OUTPUT (1<<1) 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic inline unsigned char mpu401_read(struct snd_emu10k1 *emu, 168c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *mpu, int idx) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci if (emu->audigy) 198c2ecf20Sopenharmony_ci return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0); 208c2ecf20Sopenharmony_ci else 218c2ecf20Sopenharmony_ci return inb(emu->port + mpu->port + idx); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline void mpu401_write(struct snd_emu10k1 *emu, 258c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *mpu, int data, int idx) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (emu->audigy) 288c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, mpu->port + idx, 0, data); 298c2ecf20Sopenharmony_ci else 308c2ecf20Sopenharmony_ci outb(data, emu->port + mpu->port + idx); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0) 348c2ecf20Sopenharmony_ci#define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1) 358c2ecf20Sopenharmony_ci#define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0) 368c2ecf20Sopenharmony_ci#define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80)) 398c2ecf20Sopenharmony_ci#define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40)) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define MPU401_RESET 0xff 428c2ecf20Sopenharmony_ci#define MPU401_ENTER_UART 0x3f 438c2ecf20Sopenharmony_ci#define MPU401_ACK 0xfe 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mpu) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int timeout = 100000; 488c2ecf20Sopenharmony_ci for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--) 498c2ecf20Sopenharmony_ci mpu401_read_data(emu, mpu); 508c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 518c2ecf20Sopenharmony_ci if (timeout <= 0) 528c2ecf20Sopenharmony_ci dev_err(emu->card->dev, 538c2ecf20Sopenharmony_ci "cmd: clear rx timeout (status = 0x%x)\n", 548c2ecf20Sopenharmony_ci mpu401_read_stat(emu, mpu)); 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned char byte; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (midi->rmidi == NULL) { 678c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable); 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci spin_lock(&midi->input_lock); 728c2ecf20Sopenharmony_ci if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { 738c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { 748c2ecf20Sopenharmony_ci mpu401_clear_rx(emu, midi); 758c2ecf20Sopenharmony_ci } else { 768c2ecf20Sopenharmony_ci byte = mpu401_read_data(emu, midi); 778c2ecf20Sopenharmony_ci if (midi->substream_input) 788c2ecf20Sopenharmony_ci snd_rawmidi_receive(midi->substream_input, &byte, 1); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci spin_unlock(&midi->input_lock); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci spin_lock(&midi->output_lock); 848c2ecf20Sopenharmony_ci if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { 858c2ecf20Sopenharmony_ci if (midi->substream_output && 868c2ecf20Sopenharmony_ci snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { 878c2ecf20Sopenharmony_ci mpu401_write_data(emu, midi, byte); 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->tx_enable); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci spin_unlock(&midi->output_lock); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci do_emu10k1_midi_interrupt(emu, &emu->midi, status); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci do_emu10k1_midi_interrupt(emu, &emu->midi2, status); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci unsigned long flags; 1088c2ecf20Sopenharmony_ci int timeout, ok; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->input_lock, flags); 1118c2ecf20Sopenharmony_ci mpu401_write_data(emu, midi, 0x00); 1128c2ecf20Sopenharmony_ci /* mpu401_clear_rx(emu, midi); */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci mpu401_write_cmd(emu, midi, cmd); 1158c2ecf20Sopenharmony_ci if (ack) { 1168c2ecf20Sopenharmony_ci ok = 0; 1178c2ecf20Sopenharmony_ci timeout = 10000; 1188c2ecf20Sopenharmony_ci while (!ok && timeout-- > 0) { 1198c2ecf20Sopenharmony_ci if (mpu401_input_avail(emu, midi)) { 1208c2ecf20Sopenharmony_ci if (mpu401_read_data(emu, midi) == MPU401_ACK) 1218c2ecf20Sopenharmony_ci ok = 1; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) 1258c2ecf20Sopenharmony_ci ok = 1; 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci ok = 1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->input_lock, flags); 1308c2ecf20Sopenharmony_ci if (!ok) { 1318c2ecf20Sopenharmony_ci dev_err(emu->card->dev, 1328c2ecf20Sopenharmony_ci "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", 1338c2ecf20Sopenharmony_ci cmd, emu->port, 1348c2ecf20Sopenharmony_ci mpu401_read_stat(emu, midi), 1358c2ecf20Sopenharmony_ci mpu401_read_data(emu, midi)); 1368c2ecf20Sopenharmony_ci return 1; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 1448c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci emu = midi->emu; 1488c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 1498c2ecf20Sopenharmony_ci return -ENXIO; 1508c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->open_lock, flags); 1518c2ecf20Sopenharmony_ci midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; 1528c2ecf20Sopenharmony_ci midi->substream_input = substream; 1538c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { 1548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 1558c2ecf20Sopenharmony_ci if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) 1568c2ecf20Sopenharmony_ci goto error_out; 1578c2ecf20Sopenharmony_ci if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) 1588c2ecf20Sopenharmony_ci goto error_out; 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cierror_out: 1658c2ecf20Sopenharmony_ci return -EIO; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 1718c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 1728c2ecf20Sopenharmony_ci unsigned long flags; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci emu = midi->emu; 1758c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 1768c2ecf20Sopenharmony_ci return -ENXIO; 1778c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->open_lock, flags); 1788c2ecf20Sopenharmony_ci midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; 1798c2ecf20Sopenharmony_ci midi->substream_output = substream; 1808c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { 1818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 1828c2ecf20Sopenharmony_ci if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) 1838c2ecf20Sopenharmony_ci goto error_out; 1848c2ecf20Sopenharmony_ci if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) 1858c2ecf20Sopenharmony_ci goto error_out; 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cierror_out: 1928c2ecf20Sopenharmony_ci return -EIO; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 1988c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 1998c2ecf20Sopenharmony_ci unsigned long flags; 2008c2ecf20Sopenharmony_ci int err = 0; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci emu = midi->emu; 2038c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2048c2ecf20Sopenharmony_ci return -ENXIO; 2058c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->open_lock, flags); 2068c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->rx_enable); 2078c2ecf20Sopenharmony_ci midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; 2088c2ecf20Sopenharmony_ci midi->substream_input = NULL; 2098c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { 2108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 2118c2ecf20Sopenharmony_ci err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci return err; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 2218c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 2228c2ecf20Sopenharmony_ci unsigned long flags; 2238c2ecf20Sopenharmony_ci int err = 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci emu = midi->emu; 2268c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2278c2ecf20Sopenharmony_ci return -ENXIO; 2288c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->open_lock, flags); 2298c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->tx_enable); 2308c2ecf20Sopenharmony_ci midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; 2318c2ecf20Sopenharmony_ci midi->substream_output = NULL; 2328c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { 2338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 2348c2ecf20Sopenharmony_ci err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->open_lock, flags); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci return err; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 2448c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 2458c2ecf20Sopenharmony_ci emu = midi->emu; 2468c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (up) 2508c2ecf20Sopenharmony_ci snd_emu10k1_intr_enable(emu, midi->rx_enable); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->rx_enable); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu; 2588c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; 2598c2ecf20Sopenharmony_ci unsigned long flags; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci emu = midi->emu; 2628c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (up) { 2668c2ecf20Sopenharmony_ci int max = 4; 2678c2ecf20Sopenharmony_ci unsigned char byte; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* try to send some amount of bytes here before interrupts */ 2708c2ecf20Sopenharmony_ci spin_lock_irqsave(&midi->output_lock, flags); 2718c2ecf20Sopenharmony_ci while (max > 0) { 2728c2ecf20Sopenharmony_ci if (mpu401_output_ready(emu, midi)) { 2738c2ecf20Sopenharmony_ci if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || 2748c2ecf20Sopenharmony_ci snd_rawmidi_transmit(substream, &byte, 1) != 1) { 2758c2ecf20Sopenharmony_ci /* no more data */ 2768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->output_lock, flags); 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci mpu401_write_data(emu, midi, byte); 2808c2ecf20Sopenharmony_ci max--; 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&midi->output_lock, flags); 2868c2ecf20Sopenharmony_ci snd_emu10k1_intr_enable(emu, midi->tx_enable); 2878c2ecf20Sopenharmony_ci } else { 2888c2ecf20Sopenharmony_ci snd_emu10k1_intr_disable(emu, midi->tx_enable); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_emu10k1_midi_output = 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci .open = snd_emu10k1_midi_output_open, 2998c2ecf20Sopenharmony_ci .close = snd_emu10k1_midi_output_close, 3008c2ecf20Sopenharmony_ci .trigger = snd_emu10k1_midi_output_trigger, 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_emu10k1_midi_input = 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci .open = snd_emu10k1_midi_input_open, 3068c2ecf20Sopenharmony_ci .close = snd_emu10k1_midi_input_close, 3078c2ecf20Sopenharmony_ci .trigger = snd_emu10k1_midi_input_trigger, 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = rmidi->private_data; 3138c2ecf20Sopenharmony_ci midi->interrupt = NULL; 3148c2ecf20Sopenharmony_ci midi->rmidi = NULL; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct snd_rawmidi *rmidi; 3208c2ecf20Sopenharmony_ci int err; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci midi->emu = emu; 3258c2ecf20Sopenharmony_ci spin_lock_init(&midi->open_lock); 3268c2ecf20Sopenharmony_ci spin_lock_init(&midi->input_lock); 3278c2ecf20Sopenharmony_ci spin_lock_init(&midi->output_lock); 3288c2ecf20Sopenharmony_ci strcpy(rmidi->name, name); 3298c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output); 3308c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input); 3318c2ecf20Sopenharmony_ci rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | 3328c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_INPUT | 3338c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_DUPLEX; 3348c2ecf20Sopenharmony_ci rmidi->private_data = midi; 3358c2ecf20Sopenharmony_ci rmidi->private_free = snd_emu10k1_midi_free; 3368c2ecf20Sopenharmony_ci midi->rmidi = rmidi; 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint snd_emu10k1_midi(struct snd_emu10k1 *emu) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi = &emu->midi; 3438c2ecf20Sopenharmony_ci int err; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0) 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci midi->tx_enable = INTE_MIDITXENABLE; 3498c2ecf20Sopenharmony_ci midi->rx_enable = INTE_MIDIRXENABLE; 3508c2ecf20Sopenharmony_ci midi->port = MUDATA; 3518c2ecf20Sopenharmony_ci midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; 3528c2ecf20Sopenharmony_ci midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; 3538c2ecf20Sopenharmony_ci midi->interrupt = snd_emu10k1_midi_interrupt; 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ciint snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct snd_emu10k1_midi *midi; 3608c2ecf20Sopenharmony_ci int err; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci midi = &emu->midi; 3638c2ecf20Sopenharmony_ci if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0) 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci midi->tx_enable = INTE_MIDITXENABLE; 3678c2ecf20Sopenharmony_ci midi->rx_enable = INTE_MIDIRXENABLE; 3688c2ecf20Sopenharmony_ci midi->port = A_MUDATA1; 3698c2ecf20Sopenharmony_ci midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; 3708c2ecf20Sopenharmony_ci midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; 3718c2ecf20Sopenharmony_ci midi->interrupt = snd_emu10k1_midi_interrupt; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci midi = &emu->midi2; 3748c2ecf20Sopenharmony_ci if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0) 3758c2ecf20Sopenharmony_ci return err; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci midi->tx_enable = INTE_A_MIDITXENABLE2; 3788c2ecf20Sopenharmony_ci midi->rx_enable = INTE_A_MIDIRXENABLE2; 3798c2ecf20Sopenharmony_ci midi->port = A_MUDATA2; 3808c2ecf20Sopenharmony_ci midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2; 3818c2ecf20Sopenharmony_ci midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2; 3828c2ecf20Sopenharmony_ci midi->interrupt = snd_emu10k1_midi_interrupt2; 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 385