11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
41da177e4SLinus Torvalds * Driver EMU10K1X chips
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Parts of this code were adapted from audigyls.c driver which is
71da177e4SLinus Torvalds * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * BUGS:
101da177e4SLinus Torvalds * --
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds * TODO:
131da177e4SLinus Torvalds *
141da177e4SLinus Torvalds * Chips (SB0200 model):
151da177e4SLinus Torvalds * - EMU10K1X-DBQ
161da177e4SLinus Torvalds * - STAC 9708T
171da177e4SLinus Torvalds */
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/interrupt.h>
201da177e4SLinus Torvalds #include <linux/pci.h>
219d2f928dSTobias Klauser #include <linux/dma-mapping.h>
221da177e4SLinus Torvalds #include <linux/slab.h>
2365a77217SPaul Gortmaker #include <linux/module.h>
241da177e4SLinus Torvalds #include <sound/core.h>
251da177e4SLinus Torvalds #include <sound/initval.h>
261da177e4SLinus Torvalds #include <sound/pcm.h>
271da177e4SLinus Torvalds #include <sound/ac97_codec.h>
281da177e4SLinus Torvalds #include <sound/info.h>
291da177e4SLinus Torvalds #include <sound/rawmidi.h>
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>");
321da177e4SLinus Torvalds MODULE_DESCRIPTION("EMU10K1X");
331da177e4SLinus Torvalds MODULE_LICENSE("GPL");
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds // module parameters (see "Module Parameters")
361da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
371da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
38a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444);
411da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for the EMU10K1X soundcard.");
421da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444);
431da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for the EMU10K1X soundcard.");
441da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444);
451da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds // some definitions were borrowed from emu10k1 driver as they seem to be the same
491da177e4SLinus Torvalds /************************************************************************************************/
501da177e4SLinus Torvalds /* PCI function 0 registers, address = <val> + PCIBASE0 */
511da177e4SLinus Torvalds /************************************************************************************************/
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds #define PTR 0x00 /* Indexed register set pointer register */
541da177e4SLinus Torvalds /* NOTE: The CHANNELNUM and ADDRESS words can */
551da177e4SLinus Torvalds /* be modified independently of each other. */
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds #define DATA 0x04 /* Indexed register set data register */
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds #define IPR 0x08 /* Global interrupt pending register */
601da177e4SLinus Torvalds /* Clear pending interrupts by writing a 1 to */
611da177e4SLinus Torvalds /* the relevant bits and zero to the other bits */
621da177e4SLinus Torvalds #define IPR_MIDITRANSBUFEMPTY 0x00000001 /* MIDI UART transmit buffer empty */
631da177e4SLinus Torvalds #define IPR_MIDIRECVBUFEMPTY 0x00000002 /* MIDI UART receive buffer empty */
641da177e4SLinus Torvalds #define IPR_CH_0_LOOP 0x00000800 /* Channel 0 loop */
651da177e4SLinus Torvalds #define IPR_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
661da177e4SLinus Torvalds #define IPR_CAP_0_LOOP 0x00080000 /* Channel capture loop */
671da177e4SLinus Torvalds #define IPR_CAP_0_HALF_LOOP 0x00010000 /* Channel capture half loop */
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds #define INTE 0x0c /* Interrupt enable register */
701da177e4SLinus Torvalds #define INTE_MIDITXENABLE 0x00000001 /* Enable MIDI transmit-buffer-empty interrupts */
711da177e4SLinus Torvalds #define INTE_MIDIRXENABLE 0x00000002 /* Enable MIDI receive-buffer-empty interrupts */
721da177e4SLinus Torvalds #define INTE_CH_0_LOOP 0x00000800 /* Channel 0 loop */
731da177e4SLinus Torvalds #define INTE_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
741da177e4SLinus Torvalds #define INTE_CAP_0_LOOP 0x00080000 /* Channel capture loop */
751da177e4SLinus Torvalds #define INTE_CAP_0_HALF_LOOP 0x00010000 /* Channel capture half loop */
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds #define HCFG 0x14 /* Hardware config register */
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
801da177e4SLinus Torvalds /* NOTE: This should generally never be used. */
811da177e4SLinus Torvalds #define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */
821da177e4SLinus Torvalds /* Should be set to 1 when the EMU10K1 is */
831da177e4SLinus Torvalds /* completely initialized. */
841da177e4SLinus Torvalds #define GPIO 0x18 /* Defaults: 00001080-Analog, 00001000-SPDIF. */
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds #define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds #define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */
901da177e4SLinus Torvalds
911da177e4SLinus Torvalds /********************************************************************************************************/
921da177e4SLinus Torvalds /* Emu10k1x pointer-offset register set, accessed through the PTR and DATA registers */
931da177e4SLinus Torvalds /********************************************************************************************************/
941da177e4SLinus Torvalds #define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */
951da177e4SLinus Torvalds /* One list entry: 4 bytes for DMA address,
961da177e4SLinus Torvalds * 4 bytes for period_size << 16.
971da177e4SLinus Torvalds * One list entry is 8 bytes long.
981da177e4SLinus Torvalds * One list entry for each period in the buffer.
991da177e4SLinus Torvalds */
1001da177e4SLinus Torvalds #define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */
1011da177e4SLinus Torvalds #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */
102b595076aSUwe Kleine-König #define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */
1031da177e4SLinus Torvalds #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size */
1041da177e4SLinus Torvalds #define PLAYBACK_POINTER 0x06 /* Playback period pointer. Sample currently in DAC */
1051da177e4SLinus Torvalds #define PLAYBACK_UNKNOWN1 0x07
1061da177e4SLinus Torvalds #define PLAYBACK_UNKNOWN2 0x08
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds /* Only one capture channel supported */
1091da177e4SLinus Torvalds #define CAPTURE_DMA_ADDR 0x10 /* Capture DMA address */
1101da177e4SLinus Torvalds #define CAPTURE_BUFFER_SIZE 0x11 /* Capture buffer size */
1111da177e4SLinus Torvalds #define CAPTURE_POINTER 0x12 /* Capture buffer pointer. Sample currently in ADC */
1121da177e4SLinus Torvalds #define CAPTURE_UNKNOWN 0x13
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds /* From 0x20 - 0x3f, last samples played on each channel */
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds #define TRIGGER_CHANNEL 0x40 /* Trigger channel playback */
1171da177e4SLinus Torvalds #define TRIGGER_CHANNEL_0 0x00000001 /* Trigger channel 0 */
1181da177e4SLinus Torvalds #define TRIGGER_CHANNEL_1 0x00000002 /* Trigger channel 1 */
1191da177e4SLinus Torvalds #define TRIGGER_CHANNEL_2 0x00000004 /* Trigger channel 2 */
1201da177e4SLinus Torvalds #define TRIGGER_CAPTURE 0x00000100 /* Trigger capture channel */
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds #define ROUTING 0x41 /* Setup sound routing ? */
1231da177e4SLinus Torvalds #define ROUTING_FRONT_LEFT 0x00000001
1241da177e4SLinus Torvalds #define ROUTING_FRONT_RIGHT 0x00000002
1251da177e4SLinus Torvalds #define ROUTING_REAR_LEFT 0x00000004
1261da177e4SLinus Torvalds #define ROUTING_REAR_RIGHT 0x00000008
1271da177e4SLinus Torvalds #define ROUTING_CENTER_LFE 0x00010000
1281da177e4SLinus Torvalds
1291da177e4SLinus Torvalds #define SPCS0 0x42 /* SPDIF output Channel Status 0 register */
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds #define SPCS1 0x43 /* SPDIF output Channel Status 1 register */
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds #define SPCS2 0x44 /* SPDIF output Channel Status 2 register */
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds #define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */
1361da177e4SLinus Torvalds #define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */
1371da177e4SLinus Torvalds #define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */
1381da177e4SLinus Torvalds #define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */
1391da177e4SLinus Torvalds #define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */
1401da177e4SLinus Torvalds #define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */
1411da177e4SLinus Torvalds #define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */
1421da177e4SLinus Torvalds #define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */
1431da177e4SLinus Torvalds #define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */
1441da177e4SLinus Torvalds #define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */
1451da177e4SLinus Torvalds #define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */
1461da177e4SLinus Torvalds #define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */
1471da177e4SLinus Torvalds #define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */
1481da177e4SLinus Torvalds #define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */
1491da177e4SLinus Torvalds #define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */
1501da177e4SLinus Torvalds #define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */
1511da177e4SLinus Torvalds #define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */
1521da177e4SLinus Torvalds #define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */
1531da177e4SLinus Torvalds #define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */
1541da177e4SLinus Torvalds #define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */
1551da177e4SLinus Torvalds #define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */
1561da177e4SLinus Torvalds #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
1571da177e4SLinus Torvalds #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds #define SPDIF_SELECT 0x45 /* Enables SPDIF or Analogue outputs 0-Analogue, 0x700-SPDIF */
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds /* This is the MPU port on the card */
1621da177e4SLinus Torvalds #define MUDATA 0x47
1631da177e4SLinus Torvalds #define MUCMD 0x48
1641da177e4SLinus Torvalds #define MUSTAT MUCMD
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds /* From 0x50 - 0x5f, last samples captured */
1671da177e4SLinus Torvalds
168ddcecf6bSTakashi Iwai /*
1691da177e4SLinus Torvalds * The hardware has 3 channels for playback and 1 for capture.
1701da177e4SLinus Torvalds * - channel 0 is the front channel
1711da177e4SLinus Torvalds * - channel 1 is the rear channel
172af901ca1SAndré Goddard Rosa * - channel 2 is the center/lfe channel
1731da177e4SLinus Torvalds * Volume is controlled by the AC97 for the front and rear channels by
1741da177e4SLinus Torvalds * the PCM Playback Volume, Sigmatel Surround Playback Volume and
1751da177e4SLinus Torvalds * Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects
1761da177e4SLinus Torvalds * the front/rear channel mixing in the REAR OUT jack. When using the
1771da177e4SLinus Torvalds * 4-Speaker Stereo, both front and rear channels will be mixed in the
1781da177e4SLinus Torvalds * REAR OUT.
1791da177e4SLinus Torvalds * The center/lfe channel has no volume control and cannot be muted during
1801da177e4SLinus Torvalds * playback.
1811da177e4SLinus Torvalds */
1821da177e4SLinus Torvalds
1834b32f1aaSTakashi Iwai struct emu10k1x_voice {
1844b32f1aaSTakashi Iwai struct emu10k1x *emu;
1851da177e4SLinus Torvalds int number;
1861da177e4SLinus Torvalds int use;
1871da177e4SLinus Torvalds
1884b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
1891da177e4SLinus Torvalds };
1901da177e4SLinus Torvalds
1914b32f1aaSTakashi Iwai struct emu10k1x_pcm {
1924b32f1aaSTakashi Iwai struct emu10k1x *emu;
1934b32f1aaSTakashi Iwai struct snd_pcm_substream *substream;
1944b32f1aaSTakashi Iwai struct emu10k1x_voice *voice;
1951da177e4SLinus Torvalds unsigned short running;
1961da177e4SLinus Torvalds };
1971da177e4SLinus Torvalds
1984b32f1aaSTakashi Iwai struct emu10k1x_midi {
1994b32f1aaSTakashi Iwai struct emu10k1x *emu;
2004b32f1aaSTakashi Iwai struct snd_rawmidi *rmidi;
2014b32f1aaSTakashi Iwai struct snd_rawmidi_substream *substream_input;
2024b32f1aaSTakashi Iwai struct snd_rawmidi_substream *substream_output;
2031da177e4SLinus Torvalds unsigned int midi_mode;
2041da177e4SLinus Torvalds spinlock_t input_lock;
2051da177e4SLinus Torvalds spinlock_t output_lock;
2061da177e4SLinus Torvalds spinlock_t open_lock;
2071da177e4SLinus Torvalds int tx_enable, rx_enable;
2081da177e4SLinus Torvalds int port;
2091da177e4SLinus Torvalds int ipr_tx, ipr_rx;
2104b32f1aaSTakashi Iwai void (*interrupt)(struct emu10k1x *emu, unsigned int status);
2114b32f1aaSTakashi Iwai };
2121da177e4SLinus Torvalds
2131da177e4SLinus Torvalds // definition of the chip-specific record
2144b32f1aaSTakashi Iwai struct emu10k1x {
2154b32f1aaSTakashi Iwai struct snd_card *card;
2161da177e4SLinus Torvalds struct pci_dev *pci;
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds unsigned long port;
2191da177e4SLinus Torvalds int irq;
2201da177e4SLinus Torvalds
22101f681daSTakashi Iwai unsigned char revision; /* chip revision */
2221da177e4SLinus Torvalds unsigned int serial; /* serial number */
2231da177e4SLinus Torvalds unsigned short model; /* subsystem id */
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds spinlock_t emu_lock;
2261da177e4SLinus Torvalds spinlock_t voice_lock;
2271da177e4SLinus Torvalds
2284b32f1aaSTakashi Iwai struct snd_ac97 *ac97;
2294b32f1aaSTakashi Iwai struct snd_pcm *pcm;
2301da177e4SLinus Torvalds
2314b32f1aaSTakashi Iwai struct emu10k1x_voice voices[3];
2324b32f1aaSTakashi Iwai struct emu10k1x_voice capture_voice;
2331da177e4SLinus Torvalds u32 spdif_bits[3]; // SPDIF out setup
2341da177e4SLinus Torvalds
2352b377c6bSTakashi Iwai struct snd_dma_buffer *dma_buffer;
2361da177e4SLinus Torvalds
2374b32f1aaSTakashi Iwai struct emu10k1x_midi midi;
2381da177e4SLinus Torvalds };
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds /* hardware definition */
2417c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1x_playback_hw = {
2421da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP |
2431da177e4SLinus Torvalds SNDRV_PCM_INFO_INTERLEAVED |
2441da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER |
2451da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID),
2461da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_S16_LE,
2471da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_48000,
2481da177e4SLinus Torvalds .rate_min = 48000,
2491da177e4SLinus Torvalds .rate_max = 48000,
2501da177e4SLinus Torvalds .channels_min = 2,
2511da177e4SLinus Torvalds .channels_max = 2,
2521da177e4SLinus Torvalds .buffer_bytes_max = (32*1024),
2531da177e4SLinus Torvalds .period_bytes_min = 64,
2541da177e4SLinus Torvalds .period_bytes_max = (16*1024),
2551da177e4SLinus Torvalds .periods_min = 2,
2561da177e4SLinus Torvalds .periods_max = 8,
2571da177e4SLinus Torvalds .fifo_size = 0,
2581da177e4SLinus Torvalds };
2591da177e4SLinus Torvalds
2607c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1x_capture_hw = {
2611da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP |
2621da177e4SLinus Torvalds SNDRV_PCM_INFO_INTERLEAVED |
2631da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER |
2641da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID),
2651da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_S16_LE,
2661da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_48000,
2671da177e4SLinus Torvalds .rate_min = 48000,
2681da177e4SLinus Torvalds .rate_max = 48000,
2691da177e4SLinus Torvalds .channels_min = 2,
2701da177e4SLinus Torvalds .channels_max = 2,
2711da177e4SLinus Torvalds .buffer_bytes_max = (32*1024),
2721da177e4SLinus Torvalds .period_bytes_min = 64,
2731da177e4SLinus Torvalds .period_bytes_max = (16*1024),
2741da177e4SLinus Torvalds .periods_min = 2,
2751da177e4SLinus Torvalds .periods_max = 2,
2761da177e4SLinus Torvalds .fifo_size = 0,
2771da177e4SLinus Torvalds };
2781da177e4SLinus Torvalds
snd_emu10k1x_ptr_read(struct emu10k1x * emu,unsigned int reg,unsigned int chn)2794b32f1aaSTakashi Iwai static unsigned int snd_emu10k1x_ptr_read(struct emu10k1x * emu,
2801da177e4SLinus Torvalds unsigned int reg,
2811da177e4SLinus Torvalds unsigned int chn)
2821da177e4SLinus Torvalds {
2831da177e4SLinus Torvalds unsigned long flags;
2841da177e4SLinus Torvalds unsigned int regptr, val;
2851da177e4SLinus Torvalds
2861da177e4SLinus Torvalds regptr = (reg << 16) | chn;
2871da177e4SLinus Torvalds
2881da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
2891da177e4SLinus Torvalds outl(regptr, emu->port + PTR);
2901da177e4SLinus Torvalds val = inl(emu->port + DATA);
2911da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
2921da177e4SLinus Torvalds return val;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds
snd_emu10k1x_ptr_write(struct emu10k1x * emu,unsigned int reg,unsigned int chn,unsigned int data)2954b32f1aaSTakashi Iwai static void snd_emu10k1x_ptr_write(struct emu10k1x *emu,
2961da177e4SLinus Torvalds unsigned int reg,
2971da177e4SLinus Torvalds unsigned int chn,
2981da177e4SLinus Torvalds unsigned int data)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds unsigned int regptr;
3011da177e4SLinus Torvalds unsigned long flags;
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds regptr = (reg << 16) | chn;
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
3061da177e4SLinus Torvalds outl(regptr, emu->port + PTR);
3071da177e4SLinus Torvalds outl(data, emu->port + DATA);
3081da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds
snd_emu10k1x_intr_enable(struct emu10k1x * emu,unsigned int intrenb)3114b32f1aaSTakashi Iwai static void snd_emu10k1x_intr_enable(struct emu10k1x *emu, unsigned int intrenb)
3121da177e4SLinus Torvalds {
3131da177e4SLinus Torvalds unsigned long flags;
314f2948fc2SHarvey Harrison unsigned int intr_enable;
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
317f2948fc2SHarvey Harrison intr_enable = inl(emu->port + INTE) | intrenb;
318f2948fc2SHarvey Harrison outl(intr_enable, emu->port + INTE);
3191da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
snd_emu10k1x_intr_disable(struct emu10k1x * emu,unsigned int intrenb)3224b32f1aaSTakashi Iwai static void snd_emu10k1x_intr_disable(struct emu10k1x *emu, unsigned int intrenb)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds unsigned long flags;
325f2948fc2SHarvey Harrison unsigned int intr_enable;
3261da177e4SLinus Torvalds
3271da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
328f2948fc2SHarvey Harrison intr_enable = inl(emu->port + INTE) & ~intrenb;
329f2948fc2SHarvey Harrison outl(intr_enable, emu->port + INTE);
3301da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds
snd_emu10k1x_gpio_write(struct emu10k1x * emu,unsigned int value)3334b32f1aaSTakashi Iwai static void snd_emu10k1x_gpio_write(struct emu10k1x *emu, unsigned int value)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds unsigned long flags;
3361da177e4SLinus Torvalds
3371da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
3381da177e4SLinus Torvalds outl(value, emu->port + GPIO);
3391da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds
snd_emu10k1x_pcm_free_substream(struct snd_pcm_runtime * runtime)3424b32f1aaSTakashi Iwai static void snd_emu10k1x_pcm_free_substream(struct snd_pcm_runtime *runtime)
3431da177e4SLinus Torvalds {
3444d572776SJesper Juhl kfree(runtime->private_data);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds
snd_emu10k1x_pcm_interrupt(struct emu10k1x * emu,struct emu10k1x_voice * voice)3474b32f1aaSTakashi Iwai static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voice *voice)
3481da177e4SLinus Torvalds {
3494b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
3501da177e4SLinus Torvalds
3519031f938STakashi Iwai epcm = voice->epcm;
3529031f938STakashi Iwai if (!epcm)
3531da177e4SLinus Torvalds return;
3541da177e4SLinus Torvalds if (epcm->substream == NULL)
3551da177e4SLinus Torvalds return;
3561da177e4SLinus Torvalds #if 0
35726bc6964STakashi Iwai dev_info(emu->card->dev,
35826bc6964STakashi Iwai "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
3591da177e4SLinus Torvalds epcm->substream->ops->pointer(epcm->substream),
3601da177e4SLinus Torvalds snd_pcm_lib_period_bytes(epcm->substream),
3611da177e4SLinus Torvalds snd_pcm_lib_buffer_bytes(epcm->substream));
3621da177e4SLinus Torvalds #endif
3631da177e4SLinus Torvalds snd_pcm_period_elapsed(epcm->substream);
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds
3661da177e4SLinus Torvalds /* open callback */
snd_emu10k1x_playback_open(struct snd_pcm_substream * substream)3674b32f1aaSTakashi Iwai static int snd_emu10k1x_playback_open(struct snd_pcm_substream *substream)
3681da177e4SLinus Torvalds {
3694b32f1aaSTakashi Iwai struct emu10k1x *chip = snd_pcm_substream_chip(substream);
3704b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
3714b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
3721da177e4SLinus Torvalds int err;
3731da177e4SLinus Torvalds
3749031f938STakashi Iwai err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
3759031f938STakashi Iwai if (err < 0)
3761da177e4SLinus Torvalds return err;
3779031f938STakashi Iwai err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
3789031f938STakashi Iwai if (err < 0)
3791da177e4SLinus Torvalds return err;
3801da177e4SLinus Torvalds
381e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
3821da177e4SLinus Torvalds if (epcm == NULL)
3831da177e4SLinus Torvalds return -ENOMEM;
3841da177e4SLinus Torvalds epcm->emu = chip;
3851da177e4SLinus Torvalds epcm->substream = substream;
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds runtime->private_data = epcm;
3881da177e4SLinus Torvalds runtime->private_free = snd_emu10k1x_pcm_free_substream;
3891da177e4SLinus Torvalds
3901da177e4SLinus Torvalds runtime->hw = snd_emu10k1x_playback_hw;
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds return 0;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds /* close callback */
snd_emu10k1x_playback_close(struct snd_pcm_substream * substream)3964b32f1aaSTakashi Iwai static int snd_emu10k1x_playback_close(struct snd_pcm_substream *substream)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds return 0;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds /* hw_params callback */
snd_emu10k1x_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)4024b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_hw_params(struct snd_pcm_substream *substream,
4034b32f1aaSTakashi Iwai struct snd_pcm_hw_params *hw_params)
4041da177e4SLinus Torvalds {
4054b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
4064b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds if (! epcm->voice) {
4091da177e4SLinus Torvalds epcm->voice = &epcm->emu->voices[substream->pcm->device];
4101da177e4SLinus Torvalds epcm->voice->use = 1;
4111da177e4SLinus Torvalds epcm->voice->epcm = epcm;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds
41463832bd9STakashi Iwai return 0;
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds /* hw_free callback */
snd_emu10k1x_pcm_hw_free(struct snd_pcm_substream * substream)4184b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_hw_free(struct snd_pcm_substream *substream)
4191da177e4SLinus Torvalds {
4204b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
4214b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
4221da177e4SLinus Torvalds
4231da177e4SLinus Torvalds if (runtime->private_data == NULL)
4241da177e4SLinus Torvalds return 0;
4251da177e4SLinus Torvalds
4261da177e4SLinus Torvalds epcm = runtime->private_data;
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds if (epcm->voice) {
4291da177e4SLinus Torvalds epcm->voice->use = 0;
4301da177e4SLinus Torvalds epcm->voice->epcm = NULL;
4311da177e4SLinus Torvalds epcm->voice = NULL;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds
43463832bd9STakashi Iwai return 0;
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds /* prepare callback */
snd_emu10k1x_pcm_prepare(struct snd_pcm_substream * substream)4384b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream)
4391da177e4SLinus Torvalds {
4404b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
4414b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
4424b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
4431da177e4SLinus Torvalds int voice = epcm->voice->number;
4442b377c6bSTakashi Iwai u32 *table_base = (u32 *)(emu->dma_buffer->area+1024*voice);
4451da177e4SLinus Torvalds u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
4461da177e4SLinus Torvalds int i;
4471da177e4SLinus Torvalds
4481da177e4SLinus Torvalds for(i = 0; i < runtime->periods; i++) {
4491da177e4SLinus Torvalds *table_base++=runtime->dma_addr+(i*period_size_bytes);
4501da177e4SLinus Torvalds *table_base++=period_size_bytes<<16;
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds
4532b377c6bSTakashi Iwai snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_ADDR, voice, emu->dma_buffer->addr+1024*voice);
4541da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_SIZE, voice, (runtime->periods - 1) << 19);
4551da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_PTR, voice, 0);
4561da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_POINTER, voice, 0);
4571da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN1, voice, 0);
4581da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN2, voice, 0);
4591da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_DMA_ADDR, voice, runtime->dma_addr);
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, PLAYBACK_PERIOD_SIZE, voice, frames_to_bytes(runtime, runtime->period_size)<<16);
4621da177e4SLinus Torvalds
4631da177e4SLinus Torvalds return 0;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds
4661da177e4SLinus Torvalds /* trigger callback */
snd_emu10k1x_pcm_trigger(struct snd_pcm_substream * substream,int cmd)4674b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_trigger(struct snd_pcm_substream *substream,
4681da177e4SLinus Torvalds int cmd)
4691da177e4SLinus Torvalds {
4704b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
4714b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
4724b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
4731da177e4SLinus Torvalds int channel = epcm->voice->number;
4741da177e4SLinus Torvalds int result = 0;
4751da177e4SLinus Torvalds
47626bc6964STakashi Iwai /*
47726bc6964STakashi Iwai dev_dbg(emu->card->dev,
47826bc6964STakashi Iwai "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n",
47926bc6964STakashi Iwai (int)emu, cmd, (int)substream->ops->pointer(substream));
48026bc6964STakashi Iwai */
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds switch (cmd) {
4831da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START:
4841da177e4SLinus Torvalds if(runtime->periods == 2)
4851da177e4SLinus Torvalds snd_emu10k1x_intr_enable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel);
4861da177e4SLinus Torvalds else
4871da177e4SLinus Torvalds snd_emu10k1x_intr_enable(emu, INTE_CH_0_LOOP << channel);
4881da177e4SLinus Torvalds epcm->running = 1;
4891da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|(TRIGGER_CHANNEL_0<<channel));
4901da177e4SLinus Torvalds break;
4911da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP:
4921da177e4SLinus Torvalds epcm->running = 0;
4931da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel);
4941da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CHANNEL_0<<channel));
4951da177e4SLinus Torvalds break;
4961da177e4SLinus Torvalds default:
4971da177e4SLinus Torvalds result = -EINVAL;
4981da177e4SLinus Torvalds break;
4991da177e4SLinus Torvalds }
5001da177e4SLinus Torvalds return result;
5011da177e4SLinus Torvalds }
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds /* pointer callback */
5041da177e4SLinus Torvalds static snd_pcm_uframes_t
snd_emu10k1x_pcm_pointer(struct snd_pcm_substream * substream)5054b32f1aaSTakashi Iwai snd_emu10k1x_pcm_pointer(struct snd_pcm_substream *substream)
5061da177e4SLinus Torvalds {
5074b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
5084b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
5094b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
5101da177e4SLinus Torvalds int channel = epcm->voice->number;
5111da177e4SLinus Torvalds snd_pcm_uframes_t ptr = 0, ptr1 = 0, ptr2= 0,ptr3 = 0,ptr4 = 0;
5121da177e4SLinus Torvalds
5131da177e4SLinus Torvalds if (!epcm->running)
5141da177e4SLinus Torvalds return 0;
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds ptr3 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
5171da177e4SLinus Torvalds ptr1 = snd_emu10k1x_ptr_read(emu, PLAYBACK_POINTER, channel);
5181da177e4SLinus Torvalds ptr4 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
5191da177e4SLinus Torvalds
5201da177e4SLinus Torvalds if(ptr4 == 0 && ptr1 == frames_to_bytes(runtime, runtime->buffer_size))
5211da177e4SLinus Torvalds return 0;
5221da177e4SLinus Torvalds
5231da177e4SLinus Torvalds if (ptr3 != ptr4)
5241da177e4SLinus Torvalds ptr1 = snd_emu10k1x_ptr_read(emu, PLAYBACK_POINTER, channel);
5251da177e4SLinus Torvalds ptr2 = bytes_to_frames(runtime, ptr1);
5261da177e4SLinus Torvalds ptr2 += (ptr4 >> 3) * runtime->period_size;
5271da177e4SLinus Torvalds ptr = ptr2;
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds if (ptr >= runtime->buffer_size)
5301da177e4SLinus Torvalds ptr -= runtime->buffer_size;
5311da177e4SLinus Torvalds
5321da177e4SLinus Torvalds return ptr;
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvalds /* operators */
5366769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1x_playback_ops = {
5371da177e4SLinus Torvalds .open = snd_emu10k1x_playback_open,
5381da177e4SLinus Torvalds .close = snd_emu10k1x_playback_close,
5391da177e4SLinus Torvalds .hw_params = snd_emu10k1x_pcm_hw_params,
5401da177e4SLinus Torvalds .hw_free = snd_emu10k1x_pcm_hw_free,
5411da177e4SLinus Torvalds .prepare = snd_emu10k1x_pcm_prepare,
5421da177e4SLinus Torvalds .trigger = snd_emu10k1x_pcm_trigger,
5431da177e4SLinus Torvalds .pointer = snd_emu10k1x_pcm_pointer,
5441da177e4SLinus Torvalds };
5451da177e4SLinus Torvalds
5461da177e4SLinus Torvalds /* open_capture callback */
snd_emu10k1x_pcm_open_capture(struct snd_pcm_substream * substream)5474b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_open_capture(struct snd_pcm_substream *substream)
5481da177e4SLinus Torvalds {
5494b32f1aaSTakashi Iwai struct emu10k1x *chip = snd_pcm_substream_chip(substream);
5504b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
5514b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
5521da177e4SLinus Torvalds int err;
5531da177e4SLinus Torvalds
5549031f938STakashi Iwai err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
5559031f938STakashi Iwai if (err < 0)
5561da177e4SLinus Torvalds return err;
5579031f938STakashi Iwai err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
5589031f938STakashi Iwai if (err < 0)
5591da177e4SLinus Torvalds return err;
5601da177e4SLinus Torvalds
561e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
5621da177e4SLinus Torvalds if (epcm == NULL)
5631da177e4SLinus Torvalds return -ENOMEM;
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds epcm->emu = chip;
5661da177e4SLinus Torvalds epcm->substream = substream;
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds runtime->private_data = epcm;
5691da177e4SLinus Torvalds runtime->private_free = snd_emu10k1x_pcm_free_substream;
5701da177e4SLinus Torvalds
5711da177e4SLinus Torvalds runtime->hw = snd_emu10k1x_capture_hw;
5721da177e4SLinus Torvalds
5731da177e4SLinus Torvalds return 0;
5741da177e4SLinus Torvalds }
5751da177e4SLinus Torvalds
5761da177e4SLinus Torvalds /* close callback */
snd_emu10k1x_pcm_close_capture(struct snd_pcm_substream * substream)5774b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_close_capture(struct snd_pcm_substream *substream)
5781da177e4SLinus Torvalds {
5791da177e4SLinus Torvalds return 0;
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds
5821da177e4SLinus Torvalds /* hw_params callback */
snd_emu10k1x_pcm_hw_params_capture(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)5834b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_hw_params_capture(struct snd_pcm_substream *substream,
5844b32f1aaSTakashi Iwai struct snd_pcm_hw_params *hw_params)
5851da177e4SLinus Torvalds {
5864b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
5874b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
5881da177e4SLinus Torvalds
5891da177e4SLinus Torvalds if (! epcm->voice) {
5901da177e4SLinus Torvalds if (epcm->emu->capture_voice.use)
5911da177e4SLinus Torvalds return -EBUSY;
5921da177e4SLinus Torvalds epcm->voice = &epcm->emu->capture_voice;
5931da177e4SLinus Torvalds epcm->voice->epcm = epcm;
5941da177e4SLinus Torvalds epcm->voice->use = 1;
5951da177e4SLinus Torvalds }
5961da177e4SLinus Torvalds
59763832bd9STakashi Iwai return 0;
5981da177e4SLinus Torvalds }
5991da177e4SLinus Torvalds
6001da177e4SLinus Torvalds /* hw_free callback */
snd_emu10k1x_pcm_hw_free_capture(struct snd_pcm_substream * substream)6014b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_hw_free_capture(struct snd_pcm_substream *substream)
6021da177e4SLinus Torvalds {
6034b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
6041da177e4SLinus Torvalds
6054b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm;
6061da177e4SLinus Torvalds
6071da177e4SLinus Torvalds if (runtime->private_data == NULL)
6081da177e4SLinus Torvalds return 0;
6091da177e4SLinus Torvalds epcm = runtime->private_data;
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds if (epcm->voice) {
6121da177e4SLinus Torvalds epcm->voice->use = 0;
6131da177e4SLinus Torvalds epcm->voice->epcm = NULL;
6141da177e4SLinus Torvalds epcm->voice = NULL;
6151da177e4SLinus Torvalds }
6161da177e4SLinus Torvalds
61763832bd9STakashi Iwai return 0;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds
6201da177e4SLinus Torvalds /* prepare capture callback */
snd_emu10k1x_pcm_prepare_capture(struct snd_pcm_substream * substream)6214b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_prepare_capture(struct snd_pcm_substream *substream)
6221da177e4SLinus Torvalds {
6234b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
6244b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
6251da177e4SLinus Torvalds
6261da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, CAPTURE_DMA_ADDR, 0, runtime->dma_addr);
6271da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, CAPTURE_BUFFER_SIZE, 0, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
6281da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, CAPTURE_POINTER, 0, 0);
6291da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, CAPTURE_UNKNOWN, 0, 0);
6301da177e4SLinus Torvalds
6311da177e4SLinus Torvalds return 0;
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds
6341da177e4SLinus Torvalds /* trigger_capture callback */
snd_emu10k1x_pcm_trigger_capture(struct snd_pcm_substream * substream,int cmd)6354b32f1aaSTakashi Iwai static int snd_emu10k1x_pcm_trigger_capture(struct snd_pcm_substream *substream,
6361da177e4SLinus Torvalds int cmd)
6371da177e4SLinus Torvalds {
6384b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
6394b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
6404b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
6411da177e4SLinus Torvalds int result = 0;
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds switch (cmd) {
6441da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START:
6451da177e4SLinus Torvalds snd_emu10k1x_intr_enable(emu, INTE_CAP_0_LOOP |
6461da177e4SLinus Torvalds INTE_CAP_0_HALF_LOOP);
6471da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|TRIGGER_CAPTURE);
6481da177e4SLinus Torvalds epcm->running = 1;
6491da177e4SLinus Torvalds break;
6501da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP:
6511da177e4SLinus Torvalds epcm->running = 0;
6521da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, INTE_CAP_0_LOOP |
6531da177e4SLinus Torvalds INTE_CAP_0_HALF_LOOP);
6541da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CAPTURE));
6551da177e4SLinus Torvalds break;
6561da177e4SLinus Torvalds default:
6571da177e4SLinus Torvalds result = -EINVAL;
6581da177e4SLinus Torvalds break;
6591da177e4SLinus Torvalds }
6601da177e4SLinus Torvalds return result;
6611da177e4SLinus Torvalds }
6621da177e4SLinus Torvalds
6631da177e4SLinus Torvalds /* pointer_capture callback */
6641da177e4SLinus Torvalds static snd_pcm_uframes_t
snd_emu10k1x_pcm_pointer_capture(struct snd_pcm_substream * substream)6654b32f1aaSTakashi Iwai snd_emu10k1x_pcm_pointer_capture(struct snd_pcm_substream *substream)
6661da177e4SLinus Torvalds {
6674b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_pcm_substream_chip(substream);
6684b32f1aaSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
6694b32f1aaSTakashi Iwai struct emu10k1x_pcm *epcm = runtime->private_data;
6701da177e4SLinus Torvalds snd_pcm_uframes_t ptr;
6711da177e4SLinus Torvalds
6721da177e4SLinus Torvalds if (!epcm->running)
6731da177e4SLinus Torvalds return 0;
6741da177e4SLinus Torvalds
6751da177e4SLinus Torvalds ptr = bytes_to_frames(runtime, snd_emu10k1x_ptr_read(emu, CAPTURE_POINTER, 0));
6761da177e4SLinus Torvalds if (ptr >= runtime->buffer_size)
6771da177e4SLinus Torvalds ptr -= runtime->buffer_size;
6781da177e4SLinus Torvalds
6791da177e4SLinus Torvalds return ptr;
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds
6826769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1x_capture_ops = {
6831da177e4SLinus Torvalds .open = snd_emu10k1x_pcm_open_capture,
6841da177e4SLinus Torvalds .close = snd_emu10k1x_pcm_close_capture,
6851da177e4SLinus Torvalds .hw_params = snd_emu10k1x_pcm_hw_params_capture,
6861da177e4SLinus Torvalds .hw_free = snd_emu10k1x_pcm_hw_free_capture,
6871da177e4SLinus Torvalds .prepare = snd_emu10k1x_pcm_prepare_capture,
6881da177e4SLinus Torvalds .trigger = snd_emu10k1x_pcm_trigger_capture,
6891da177e4SLinus Torvalds .pointer = snd_emu10k1x_pcm_pointer_capture,
6901da177e4SLinus Torvalds };
6911da177e4SLinus Torvalds
snd_emu10k1x_ac97_read(struct snd_ac97 * ac97,unsigned short reg)6924b32f1aaSTakashi Iwai static unsigned short snd_emu10k1x_ac97_read(struct snd_ac97 *ac97,
6931da177e4SLinus Torvalds unsigned short reg)
6941da177e4SLinus Torvalds {
6954b32f1aaSTakashi Iwai struct emu10k1x *emu = ac97->private_data;
6961da177e4SLinus Torvalds unsigned long flags;
6971da177e4SLinus Torvalds unsigned short val;
6981da177e4SLinus Torvalds
6991da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
7001da177e4SLinus Torvalds outb(reg, emu->port + AC97ADDRESS);
7011da177e4SLinus Torvalds val = inw(emu->port + AC97DATA);
7021da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
7031da177e4SLinus Torvalds return val;
7041da177e4SLinus Torvalds }
7051da177e4SLinus Torvalds
snd_emu10k1x_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)7064b32f1aaSTakashi Iwai static void snd_emu10k1x_ac97_write(struct snd_ac97 *ac97,
7071da177e4SLinus Torvalds unsigned short reg, unsigned short val)
7081da177e4SLinus Torvalds {
7094b32f1aaSTakashi Iwai struct emu10k1x *emu = ac97->private_data;
7101da177e4SLinus Torvalds unsigned long flags;
7111da177e4SLinus Torvalds
7121da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
7131da177e4SLinus Torvalds outb(reg, emu->port + AC97ADDRESS);
7141da177e4SLinus Torvalds outw(val, emu->port + AC97DATA);
7151da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
7161da177e4SLinus Torvalds }
7171da177e4SLinus Torvalds
snd_emu10k1x_ac97(struct emu10k1x * chip)7184b32f1aaSTakashi Iwai static int snd_emu10k1x_ac97(struct emu10k1x *chip)
7191da177e4SLinus Torvalds {
7204b32f1aaSTakashi Iwai struct snd_ac97_bus *pbus;
7214b32f1aaSTakashi Iwai struct snd_ac97_template ac97;
7221da177e4SLinus Torvalds int err;
72351055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = {
7241da177e4SLinus Torvalds .write = snd_emu10k1x_ac97_write,
7251da177e4SLinus Torvalds .read = snd_emu10k1x_ac97_read,
7261da177e4SLinus Torvalds };
7271da177e4SLinus Torvalds
7289031f938STakashi Iwai err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus);
7299031f938STakashi Iwai if (err < 0)
7301da177e4SLinus Torvalds return err;
7311da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */
7321da177e4SLinus Torvalds
7331da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97));
7341da177e4SLinus Torvalds ac97.private_data = chip;
7351da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF;
7361da177e4SLinus Torvalds return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds
snd_emu10k1x_free(struct snd_card * card)7392b377c6bSTakashi Iwai static void snd_emu10k1x_free(struct snd_card *card)
7401da177e4SLinus Torvalds {
7412b377c6bSTakashi Iwai struct emu10k1x *chip = card->private_data;
7422b377c6bSTakashi Iwai
7431da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, TRIGGER_CHANNEL, 0, 0);
7441da177e4SLinus Torvalds // disable interrupts
7451da177e4SLinus Torvalds outl(0, chip->port + INTE);
7461da177e4SLinus Torvalds // disable audio
7471da177e4SLinus Torvalds outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
7481da177e4SLinus Torvalds }
7491da177e4SLinus Torvalds
snd_emu10k1x_interrupt(int irq,void * dev_id)7507d12e780SDavid Howells static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
7511da177e4SLinus Torvalds {
7521da177e4SLinus Torvalds unsigned int status;
7531da177e4SLinus Torvalds
7544b32f1aaSTakashi Iwai struct emu10k1x *chip = dev_id;
7554b32f1aaSTakashi Iwai struct emu10k1x_voice *pvoice = chip->voices;
7561da177e4SLinus Torvalds int i;
7571da177e4SLinus Torvalds int mask;
7581da177e4SLinus Torvalds
7591da177e4SLinus Torvalds status = inl(chip->port + IPR);
7601da177e4SLinus Torvalds
76189173bd4STakashi Iwai if (! status)
76289173bd4STakashi Iwai return IRQ_NONE;
76389173bd4STakashi Iwai
7641da177e4SLinus Torvalds // capture interrupt
7651da177e4SLinus Torvalds if (status & (IPR_CAP_0_LOOP | IPR_CAP_0_HALF_LOOP)) {
766f2948fc2SHarvey Harrison struct emu10k1x_voice *cap_voice = &chip->capture_voice;
767f2948fc2SHarvey Harrison if (cap_voice->use)
768f2948fc2SHarvey Harrison snd_emu10k1x_pcm_interrupt(chip, cap_voice);
7691da177e4SLinus Torvalds else
7701da177e4SLinus Torvalds snd_emu10k1x_intr_disable(chip,
7711da177e4SLinus Torvalds INTE_CAP_0_LOOP |
7721da177e4SLinus Torvalds INTE_CAP_0_HALF_LOOP);
7731da177e4SLinus Torvalds }
7741da177e4SLinus Torvalds
7751da177e4SLinus Torvalds mask = IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP;
7761da177e4SLinus Torvalds for (i = 0; i < 3; i++) {
7771da177e4SLinus Torvalds if (status & mask) {
7781da177e4SLinus Torvalds if (pvoice->use)
7791da177e4SLinus Torvalds snd_emu10k1x_pcm_interrupt(chip, pvoice);
7801da177e4SLinus Torvalds else
7811da177e4SLinus Torvalds snd_emu10k1x_intr_disable(chip, mask);
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds pvoice++;
7841da177e4SLinus Torvalds mask <<= 1;
7851da177e4SLinus Torvalds }
7861da177e4SLinus Torvalds
7871da177e4SLinus Torvalds if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
7881da177e4SLinus Torvalds if (chip->midi.interrupt)
7891da177e4SLinus Torvalds chip->midi.interrupt(chip, status);
7901da177e4SLinus Torvalds else
7911da177e4SLinus Torvalds snd_emu10k1x_intr_disable(chip, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
7921da177e4SLinus Torvalds }
7931da177e4SLinus Torvalds
7941da177e4SLinus Torvalds // acknowledge the interrupt if necessary
7951da177e4SLinus Torvalds outl(status, chip->port + IPR);
7961da177e4SLinus Torvalds
79726bc6964STakashi Iwai /* dev_dbg(chip->card->dev, "interrupt %08x\n", status); */
7981da177e4SLinus Torvalds return IRQ_HANDLED;
7991da177e4SLinus Torvalds }
8001da177e4SLinus Torvalds
8013adc497fSTakashi Iwai static const struct snd_pcm_chmap_elem surround_map[] = {
8023adc497fSTakashi Iwai { .channels = 2,
8033adc497fSTakashi Iwai .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
8043adc497fSTakashi Iwai { }
8053adc497fSTakashi Iwai };
8063adc497fSTakashi Iwai
8073adc497fSTakashi Iwai static const struct snd_pcm_chmap_elem clfe_map[] = {
8083adc497fSTakashi Iwai { .channels = 2,
8093adc497fSTakashi Iwai .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
8103adc497fSTakashi Iwai { }
8113adc497fSTakashi Iwai };
8123adc497fSTakashi Iwai
snd_emu10k1x_pcm(struct emu10k1x * emu,int device)813bb814c39SLars-Peter Clausen static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
8141da177e4SLinus Torvalds {
8154b32f1aaSTakashi Iwai struct snd_pcm *pcm;
8163adc497fSTakashi Iwai const struct snd_pcm_chmap_elem *map = NULL;
8171da177e4SLinus Torvalds int err;
8181da177e4SLinus Torvalds int capture = 0;
8191da177e4SLinus Torvalds
8201da177e4SLinus Torvalds if (device == 0)
8211da177e4SLinus Torvalds capture = 1;
8221da177e4SLinus Torvalds
8239031f938STakashi Iwai err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm);
8249031f938STakashi Iwai if (err < 0)
8251da177e4SLinus Torvalds return err;
8261da177e4SLinus Torvalds
8271da177e4SLinus Torvalds pcm->private_data = emu;
8281da177e4SLinus Torvalds
8291da177e4SLinus Torvalds switch(device) {
8301da177e4SLinus Torvalds case 0:
8311da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops);
8321da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1x_capture_ops);
8331da177e4SLinus Torvalds break;
8341da177e4SLinus Torvalds case 1:
8351da177e4SLinus Torvalds case 2:
8361da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops);
8371da177e4SLinus Torvalds break;
8381da177e4SLinus Torvalds }
8391da177e4SLinus Torvalds
8401da177e4SLinus Torvalds pcm->info_flags = 0;
8411da177e4SLinus Torvalds switch(device) {
8421da177e4SLinus Torvalds case 0:
8431da177e4SLinus Torvalds strcpy(pcm->name, "EMU10K1X Front");
8443adc497fSTakashi Iwai map = snd_pcm_std_chmaps;
8451da177e4SLinus Torvalds break;
8461da177e4SLinus Torvalds case 1:
8471da177e4SLinus Torvalds strcpy(pcm->name, "EMU10K1X Rear");
8483adc497fSTakashi Iwai map = surround_map;
8491da177e4SLinus Torvalds break;
8501da177e4SLinus Torvalds case 2:
8511da177e4SLinus Torvalds strcpy(pcm->name, "EMU10K1X Center/LFE");
8523adc497fSTakashi Iwai map = clfe_map;
8531da177e4SLinus Torvalds break;
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds emu->pcm = pcm;
8561da177e4SLinus Torvalds
85763832bd9STakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
85863832bd9STakashi Iwai &emu->pci->dev, 32*1024, 32*1024);
8591da177e4SLinus Torvalds
860bb814c39SLars-Peter Clausen return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
8613adc497fSTakashi Iwai 1 << 2, NULL);
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds
snd_emu10k1x_create(struct snd_card * card,struct pci_dev * pci)864e23e7a14SBill Pemberton static int snd_emu10k1x_create(struct snd_card *card,
8652b377c6bSTakashi Iwai struct pci_dev *pci)
8661da177e4SLinus Torvalds {
8672b377c6bSTakashi Iwai struct emu10k1x *chip = card->private_data;
8681da177e4SLinus Torvalds int err;
8691da177e4SLinus Torvalds int ch;
8701da177e4SLinus Torvalds
8712b377c6bSTakashi Iwai err = pcim_enable_device(pci);
8729031f938STakashi Iwai if (err < 0)
8731da177e4SLinus Torvalds return err;
8749ac05523SChristophe JAILLET
8759ac05523SChristophe JAILLET if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28)) < 0) {
87626bc6964STakashi Iwai dev_err(card->dev, "error to set 28bit mask DMA\n");
8771da177e4SLinus Torvalds return -ENXIO;
8781da177e4SLinus Torvalds }
8791da177e4SLinus Torvalds
8801da177e4SLinus Torvalds chip->card = card;
8811da177e4SLinus Torvalds chip->pci = pci;
8821da177e4SLinus Torvalds chip->irq = -1;
8831da177e4SLinus Torvalds
8841da177e4SLinus Torvalds spin_lock_init(&chip->emu_lock);
8851da177e4SLinus Torvalds spin_lock_init(&chip->voice_lock);
8861da177e4SLinus Torvalds
8872b377c6bSTakashi Iwai err = pci_request_regions(pci, "EMU10K1X");
8882b377c6bSTakashi Iwai if (err < 0)
8892b377c6bSTakashi Iwai return err;
8901da177e4SLinus Torvalds chip->port = pci_resource_start(pci, 0);
8911da177e4SLinus Torvalds
8922b377c6bSTakashi Iwai if (devm_request_irq(&pci->dev, pci->irq, snd_emu10k1x_interrupt,
893934c2b6dSTakashi Iwai IRQF_SHARED, KBUILD_MODNAME, chip)) {
89426bc6964STakashi Iwai dev_err(card->dev, "cannot grab irq %d\n", pci->irq);
8951da177e4SLinus Torvalds return -EBUSY;
8961da177e4SLinus Torvalds }
8971da177e4SLinus Torvalds chip->irq = pci->irq;
89866471aa7STakashi Iwai card->sync_irq = chip->irq;
8992b377c6bSTakashi Iwai card->private_free = snd_emu10k1x_free;
9001da177e4SLinus Torvalds
9012b377c6bSTakashi Iwai chip->dma_buffer = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV,
9022b377c6bSTakashi Iwai 4 * 1024);
9032b377c6bSTakashi Iwai if (!chip->dma_buffer)
9041da177e4SLinus Torvalds return -ENOMEM;
9051da177e4SLinus Torvalds
9061da177e4SLinus Torvalds pci_set_master(pci);
9071da177e4SLinus Torvalds /* read revision & serial */
90844c10138SAuke Kok chip->revision = pci->revision;
9091da177e4SLinus Torvalds pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
9101da177e4SLinus Torvalds pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
91126bc6964STakashi Iwai dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model,
9121da177e4SLinus Torvalds chip->revision, chip->serial);
9131da177e4SLinus Torvalds
9141da177e4SLinus Torvalds outl(0, chip->port + INTE);
9151da177e4SLinus Torvalds
9161da177e4SLinus Torvalds for(ch = 0; ch < 3; ch++) {
9171da177e4SLinus Torvalds chip->voices[ch].emu = chip;
9181da177e4SLinus Torvalds chip->voices[ch].number = ch;
9191da177e4SLinus Torvalds }
9201da177e4SLinus Torvalds
9211da177e4SLinus Torvalds /*
9221da177e4SLinus Torvalds * Init to 0x02109204 :
9231da177e4SLinus Torvalds * Clock accuracy = 0 (1000ppm)
9241da177e4SLinus Torvalds * Sample Rate = 2 (48kHz)
9251da177e4SLinus Torvalds * Audio Channel = 1 (Left of 2)
9261da177e4SLinus Torvalds * Source Number = 0 (Unspecified)
9271da177e4SLinus Torvalds * Generation Status = 1 (Original for Cat Code 12)
9281da177e4SLinus Torvalds * Cat Code = 12 (Digital Signal Mixer)
9291da177e4SLinus Torvalds * Mode = 0 (Mode 0)
9301da177e4SLinus Torvalds * Emphasis = 0 (None)
9311da177e4SLinus Torvalds * CP = 1 (Copyright unasserted)
9321da177e4SLinus Torvalds * AN = 0 (Audio data)
9331da177e4SLinus Torvalds * P = 0 (Consumer)
9341da177e4SLinus Torvalds */
9351da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, SPCS0, 0,
9361da177e4SLinus Torvalds chip->spdif_bits[0] =
9371da177e4SLinus Torvalds SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
9381da177e4SLinus Torvalds SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
9391da177e4SLinus Torvalds SPCS_GENERATIONSTATUS | 0x00001200 |
9401da177e4SLinus Torvalds 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
9411da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, SPCS1, 0,
9421da177e4SLinus Torvalds chip->spdif_bits[1] =
9431da177e4SLinus Torvalds SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
9441da177e4SLinus Torvalds SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
9451da177e4SLinus Torvalds SPCS_GENERATIONSTATUS | 0x00001200 |
9461da177e4SLinus Torvalds 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
9471da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, SPCS2, 0,
9481da177e4SLinus Torvalds chip->spdif_bits[2] =
9491da177e4SLinus Torvalds SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
9501da177e4SLinus Torvalds SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
9511da177e4SLinus Torvalds SPCS_GENERATIONSTATUS | 0x00001200 |
9521da177e4SLinus Torvalds 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
9531da177e4SLinus Torvalds
9541da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, SPDIF_SELECT, 0, 0x700); // disable SPDIF
9551da177e4SLinus Torvalds snd_emu10k1x_ptr_write(chip, ROUTING, 0, 0x1003F); // routing
9561da177e4SLinus Torvalds snd_emu10k1x_gpio_write(chip, 0x1080); // analog mode
9571da177e4SLinus Torvalds
9581da177e4SLinus Torvalds outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG);
9591da177e4SLinus Torvalds
9601da177e4SLinus Torvalds return 0;
9611da177e4SLinus Torvalds }
9621da177e4SLinus Torvalds
snd_emu10k1x_proc_reg_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)9634b32f1aaSTakashi Iwai static void snd_emu10k1x_proc_reg_read(struct snd_info_entry *entry,
9644b32f1aaSTakashi Iwai struct snd_info_buffer *buffer)
9651da177e4SLinus Torvalds {
9664b32f1aaSTakashi Iwai struct emu10k1x *emu = entry->private_data;
9671da177e4SLinus Torvalds unsigned long value,value1,value2;
9681da177e4SLinus Torvalds unsigned long flags;
9691da177e4SLinus Torvalds int i;
9701da177e4SLinus Torvalds
9711da177e4SLinus Torvalds snd_iprintf(buffer, "Registers:\n\n");
9721da177e4SLinus Torvalds for(i = 0; i < 0x20; i+=4) {
9731da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags);
9741da177e4SLinus Torvalds value = inl(emu->port + i);
9751da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags);
9761da177e4SLinus Torvalds snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
9771da177e4SLinus Torvalds }
9781da177e4SLinus Torvalds snd_iprintf(buffer, "\nRegisters\n\n");
9791da177e4SLinus Torvalds for(i = 0; i <= 0x48; i++) {
9801da177e4SLinus Torvalds value = snd_emu10k1x_ptr_read(emu, i, 0);
9811da177e4SLinus Torvalds if(i < 0x10 || (i >= 0x20 && i < 0x40)) {
9821da177e4SLinus Torvalds value1 = snd_emu10k1x_ptr_read(emu, i, 1);
9831da177e4SLinus Torvalds value2 = snd_emu10k1x_ptr_read(emu, i, 2);
9841da177e4SLinus Torvalds snd_iprintf(buffer, "%02X: %08lX %08lX %08lX\n", i, value, value1, value2);
9851da177e4SLinus Torvalds } else {
9861da177e4SLinus Torvalds snd_iprintf(buffer, "%02X: %08lX\n", i, value);
9871da177e4SLinus Torvalds }
9881da177e4SLinus Torvalds }
9891da177e4SLinus Torvalds }
9901da177e4SLinus Torvalds
snd_emu10k1x_proc_reg_write(struct snd_info_entry * entry,struct snd_info_buffer * buffer)9914b32f1aaSTakashi Iwai static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
9924b32f1aaSTakashi Iwai struct snd_info_buffer *buffer)
9931da177e4SLinus Torvalds {
9944b32f1aaSTakashi Iwai struct emu10k1x *emu = entry->private_data;
9951da177e4SLinus Torvalds char line[64];
9961da177e4SLinus Torvalds unsigned int reg, channel_id , val;
9971da177e4SLinus Torvalds
9981da177e4SLinus Torvalds while (!snd_info_get_line(buffer, line, sizeof(line))) {
9991da177e4SLinus Torvalds if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3)
10001da177e4SLinus Torvalds continue;
10011da177e4SLinus Torvalds
100291231e52SDan Carpenter if (reg < 0x49 && channel_id <= 2)
10031da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds
snd_emu10k1x_proc_init(struct emu10k1x * emu)1007e23e7a14SBill Pemberton static int snd_emu10k1x_proc_init(struct emu10k1x *emu)
10081da177e4SLinus Torvalds {
100947f2769bSTakashi Iwai snd_card_rw_proc_new(emu->card, "emu10k1x_regs", emu,
101047f2769bSTakashi Iwai snd_emu10k1x_proc_reg_read,
101147f2769bSTakashi Iwai snd_emu10k1x_proc_reg_write);
10121da177e4SLinus Torvalds return 0;
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds
1015a5ce8890STakashi Iwai #define snd_emu10k1x_shared_spdif_info snd_ctl_boolean_mono_info
10161da177e4SLinus Torvalds
snd_emu10k1x_shared_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)10174b32f1aaSTakashi Iwai static int snd_emu10k1x_shared_spdif_get(struct snd_kcontrol *kcontrol,
10184b32f1aaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
10191da177e4SLinus Torvalds {
10204b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
10211da177e4SLinus Torvalds
10221da177e4SLinus Torvalds ucontrol->value.integer.value[0] = (snd_emu10k1x_ptr_read(emu, SPDIF_SELECT, 0) == 0x700) ? 0 : 1;
10231da177e4SLinus Torvalds
10241da177e4SLinus Torvalds return 0;
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds
snd_emu10k1x_shared_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)10274b32f1aaSTakashi Iwai static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
10284b32f1aaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
10291da177e4SLinus Torvalds {
10304b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
10311da177e4SLinus Torvalds unsigned int val;
10321da177e4SLinus Torvalds
10331da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ;
10341da177e4SLinus Torvalds
10351da177e4SLinus Torvalds if (val) {
10361da177e4SLinus Torvalds // enable spdif output
10371da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x000);
10381da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x700);
10391da177e4SLinus Torvalds snd_emu10k1x_gpio_write(emu, 0x1000);
10401da177e4SLinus Torvalds } else {
10411da177e4SLinus Torvalds // disable spdif output
10421da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x700);
10431da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F);
10441da177e4SLinus Torvalds snd_emu10k1x_gpio_write(emu, 0x1080);
10451da177e4SLinus Torvalds }
1046b7cad26dSHariprasad Kelam return 0;
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds
1049f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
10501da177e4SLinus Torvalds {
10511da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10521da177e4SLinus Torvalds .name = "Analog/Digital Output Jack",
10531da177e4SLinus Torvalds .info = snd_emu10k1x_shared_spdif_info,
10541da177e4SLinus Torvalds .get = snd_emu10k1x_shared_spdif_get,
10551da177e4SLinus Torvalds .put = snd_emu10k1x_shared_spdif_put
10561da177e4SLinus Torvalds };
10571da177e4SLinus Torvalds
snd_emu10k1x_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)10584b32f1aaSTakashi Iwai static int snd_emu10k1x_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10591da177e4SLinus Torvalds {
10601da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
10611da177e4SLinus Torvalds uinfo->count = 1;
10621da177e4SLinus Torvalds return 0;
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds
snd_emu10k1x_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)10654b32f1aaSTakashi Iwai static int snd_emu10k1x_spdif_get(struct snd_kcontrol *kcontrol,
10664b32f1aaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
10671da177e4SLinus Torvalds {
10684b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
10691da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10701da177e4SLinus Torvalds
10711da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
10721da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
10731da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
10741da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
10751da177e4SLinus Torvalds return 0;
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds
snd_emu10k1x_spdif_get_mask(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)10784b32f1aaSTakashi Iwai static int snd_emu10k1x_spdif_get_mask(struct snd_kcontrol *kcontrol,
10794b32f1aaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
10801da177e4SLinus Torvalds {
10811da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff;
10821da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff;
10831da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff;
10841da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff;
10851da177e4SLinus Torvalds return 0;
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds
snd_emu10k1x_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)10884b32f1aaSTakashi Iwai static int snd_emu10k1x_spdif_put(struct snd_kcontrol *kcontrol,
10894b32f1aaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
10901da177e4SLinus Torvalds {
10914b32f1aaSTakashi Iwai struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
10921da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10931da177e4SLinus Torvalds int change;
10941da177e4SLinus Torvalds unsigned int val;
10951da177e4SLinus Torvalds
10961da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) |
10971da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) |
10981da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) |
10991da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24);
11001da177e4SLinus Torvalds change = val != emu->spdif_bits[idx];
11011da177e4SLinus Torvalds if (change) {
11021da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, SPCS0 + idx, 0, val);
11031da177e4SLinus Torvalds emu->spdif_bits[idx] = val;
11041da177e4SLinus Torvalds }
11051da177e4SLinus Torvalds return change;
11061da177e4SLinus Torvalds }
11071da177e4SLinus Torvalds
1108f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control =
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ,
11115549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM,
11121da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11131da177e4SLinus Torvalds .count = 3,
11141da177e4SLinus Torvalds .info = snd_emu10k1x_spdif_info,
11151da177e4SLinus Torvalds .get = snd_emu10k1x_spdif_get_mask
11161da177e4SLinus Torvalds };
11171da177e4SLinus Torvalds
1118f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1x_spdif_control =
11191da177e4SLinus Torvalds {
11205549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM,
11211da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11221da177e4SLinus Torvalds .count = 3,
11231da177e4SLinus Torvalds .info = snd_emu10k1x_spdif_info,
11241da177e4SLinus Torvalds .get = snd_emu10k1x_spdif_get,
11251da177e4SLinus Torvalds .put = snd_emu10k1x_spdif_put
11261da177e4SLinus Torvalds };
11271da177e4SLinus Torvalds
snd_emu10k1x_mixer(struct emu10k1x * emu)1128e23e7a14SBill Pemberton static int snd_emu10k1x_mixer(struct emu10k1x *emu)
11291da177e4SLinus Torvalds {
11301da177e4SLinus Torvalds int err;
11314b32f1aaSTakashi Iwai struct snd_kcontrol *kctl;
11324b32f1aaSTakashi Iwai struct snd_card *card = emu->card;
11331da177e4SLinus Torvalds
11349031f938STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu);
11359031f938STakashi Iwai if (!kctl)
11361da177e4SLinus Torvalds return -ENOMEM;
11379031f938STakashi Iwai err = snd_ctl_add(card, kctl);
11389031f938STakashi Iwai if (err)
11391da177e4SLinus Torvalds return err;
11409031f938STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu);
11419031f938STakashi Iwai if (!kctl)
11421da177e4SLinus Torvalds return -ENOMEM;
11439031f938STakashi Iwai err = snd_ctl_add(card, kctl);
11449031f938STakashi Iwai if (err)
11451da177e4SLinus Torvalds return err;
11469031f938STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu);
11479031f938STakashi Iwai if (!kctl)
11481da177e4SLinus Torvalds return -ENOMEM;
11499031f938STakashi Iwai err = snd_ctl_add(card, kctl);
11509031f938STakashi Iwai if (err)
11511da177e4SLinus Torvalds return err;
11521da177e4SLinus Torvalds
11531da177e4SLinus Torvalds return 0;
11541da177e4SLinus Torvalds }
11551da177e4SLinus Torvalds
11561da177e4SLinus Torvalds #define EMU10K1X_MIDI_MODE_INPUT (1<<0)
11571da177e4SLinus Torvalds #define EMU10K1X_MIDI_MODE_OUTPUT (1<<1)
11581da177e4SLinus Torvalds
mpu401_read(struct emu10k1x * emu,struct emu10k1x_midi * mpu,int idx)11594b32f1aaSTakashi Iwai static inline unsigned char mpu401_read(struct emu10k1x *emu, struct emu10k1x_midi *mpu, int idx)
11601da177e4SLinus Torvalds {
11611da177e4SLinus Torvalds return (unsigned char)snd_emu10k1x_ptr_read(emu, mpu->port + idx, 0);
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds
mpu401_write(struct emu10k1x * emu,struct emu10k1x_midi * mpu,int data,int idx)11644b32f1aaSTakashi Iwai static inline void mpu401_write(struct emu10k1x *emu, struct emu10k1x_midi *mpu, int data, int idx)
11651da177e4SLinus Torvalds {
11661da177e4SLinus Torvalds snd_emu10k1x_ptr_write(emu, mpu->port + idx, 0, data);
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds
11691da177e4SLinus Torvalds #define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0)
11701da177e4SLinus Torvalds #define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1)
11711da177e4SLinus Torvalds #define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0)
11721da177e4SLinus Torvalds #define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1)
11731da177e4SLinus Torvalds
11741da177e4SLinus Torvalds #define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80))
11751da177e4SLinus Torvalds #define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40))
11761da177e4SLinus Torvalds
11771da177e4SLinus Torvalds #define MPU401_RESET 0xff
11781da177e4SLinus Torvalds #define MPU401_ENTER_UART 0x3f
11791da177e4SLinus Torvalds #define MPU401_ACK 0xfe
11801da177e4SLinus Torvalds
mpu401_clear_rx(struct emu10k1x * emu,struct emu10k1x_midi * mpu)11814b32f1aaSTakashi Iwai static void mpu401_clear_rx(struct emu10k1x *emu, struct emu10k1x_midi *mpu)
11821da177e4SLinus Torvalds {
11831da177e4SLinus Torvalds int timeout = 100000;
11841da177e4SLinus Torvalds for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--)
11851da177e4SLinus Torvalds mpu401_read_data(emu, mpu);
11861da177e4SLinus Torvalds #ifdef CONFIG_SND_DEBUG
11871da177e4SLinus Torvalds if (timeout <= 0)
118826bc6964STakashi Iwai dev_err(emu->card->dev,
118926bc6964STakashi Iwai "cmd: clear rx timeout (status = 0x%x)\n",
119026bc6964STakashi Iwai mpu401_read_stat(emu, mpu));
11911da177e4SLinus Torvalds #endif
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds
11941da177e4SLinus Torvalds /*
11951da177e4SLinus Torvalds
11961da177e4SLinus Torvalds */
11971da177e4SLinus Torvalds
do_emu10k1x_midi_interrupt(struct emu10k1x * emu,struct emu10k1x_midi * midi,unsigned int status)11984b32f1aaSTakashi Iwai static void do_emu10k1x_midi_interrupt(struct emu10k1x *emu,
11994b32f1aaSTakashi Iwai struct emu10k1x_midi *midi, unsigned int status)
12001da177e4SLinus Torvalds {
12011da177e4SLinus Torvalds unsigned char byte;
12021da177e4SLinus Torvalds
12031da177e4SLinus Torvalds if (midi->rmidi == NULL) {
12041da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->tx_enable | midi->rx_enable);
12051da177e4SLinus Torvalds return;
12061da177e4SLinus Torvalds }
12071da177e4SLinus Torvalds
12081da177e4SLinus Torvalds spin_lock(&midi->input_lock);
12091da177e4SLinus Torvalds if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
12101da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
12111da177e4SLinus Torvalds mpu401_clear_rx(emu, midi);
12121da177e4SLinus Torvalds } else {
12131da177e4SLinus Torvalds byte = mpu401_read_data(emu, midi);
12141da177e4SLinus Torvalds if (midi->substream_input)
12151da177e4SLinus Torvalds snd_rawmidi_receive(midi->substream_input, &byte, 1);
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds spin_unlock(&midi->input_lock);
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds spin_lock(&midi->output_lock);
12211da177e4SLinus Torvalds if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
12221da177e4SLinus Torvalds if (midi->substream_output &&
12231da177e4SLinus Torvalds snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
12241da177e4SLinus Torvalds mpu401_write_data(emu, midi, byte);
12251da177e4SLinus Torvalds } else {
12261da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->tx_enable);
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds spin_unlock(&midi->output_lock);
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds
snd_emu10k1x_midi_interrupt(struct emu10k1x * emu,unsigned int status)12324b32f1aaSTakashi Iwai static void snd_emu10k1x_midi_interrupt(struct emu10k1x *emu, unsigned int status)
12331da177e4SLinus Torvalds {
12341da177e4SLinus Torvalds do_emu10k1x_midi_interrupt(emu, &emu->midi, status);
12351da177e4SLinus Torvalds }
12361da177e4SLinus Torvalds
snd_emu10k1x_midi_cmd(struct emu10k1x * emu,struct emu10k1x_midi * midi,unsigned char cmd,int ack)1237b130807dSRandy Dunlap static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu,
12384b32f1aaSTakashi Iwai struct emu10k1x_midi *midi, unsigned char cmd, int ack)
12391da177e4SLinus Torvalds {
12401da177e4SLinus Torvalds unsigned long flags;
12411da177e4SLinus Torvalds int timeout, ok;
12421da177e4SLinus Torvalds
12431da177e4SLinus Torvalds spin_lock_irqsave(&midi->input_lock, flags);
12441da177e4SLinus Torvalds mpu401_write_data(emu, midi, 0x00);
12451da177e4SLinus Torvalds /* mpu401_clear_rx(emu, midi); */
12461da177e4SLinus Torvalds
12471da177e4SLinus Torvalds mpu401_write_cmd(emu, midi, cmd);
12481da177e4SLinus Torvalds if (ack) {
12491da177e4SLinus Torvalds ok = 0;
12501da177e4SLinus Torvalds timeout = 10000;
12511da177e4SLinus Torvalds while (!ok && timeout-- > 0) {
12521da177e4SLinus Torvalds if (mpu401_input_avail(emu, midi)) {
12531da177e4SLinus Torvalds if (mpu401_read_data(emu, midi) == MPU401_ACK)
12541da177e4SLinus Torvalds ok = 1;
12551da177e4SLinus Torvalds }
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
12581da177e4SLinus Torvalds ok = 1;
12591da177e4SLinus Torvalds } else {
12601da177e4SLinus Torvalds ok = 1;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->input_lock, flags);
1263b130807dSRandy Dunlap if (!ok) {
126426bc6964STakashi Iwai dev_err(emu->card->dev,
126526bc6964STakashi Iwai "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
12661da177e4SLinus Torvalds cmd, emu->port,
12671da177e4SLinus Torvalds mpu401_read_stat(emu, midi),
12681da177e4SLinus Torvalds mpu401_read_data(emu, midi));
1269b130807dSRandy Dunlap return 1;
1270b130807dSRandy Dunlap }
1271b130807dSRandy Dunlap return 0;
12721da177e4SLinus Torvalds }
12731da177e4SLinus Torvalds
snd_emu10k1x_midi_input_open(struct snd_rawmidi_substream * substream)12744b32f1aaSTakashi Iwai static int snd_emu10k1x_midi_input_open(struct snd_rawmidi_substream *substream)
12751da177e4SLinus Torvalds {
12764b32f1aaSTakashi Iwai struct emu10k1x *emu;
12774b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
12781da177e4SLinus Torvalds unsigned long flags;
12791da177e4SLinus Torvalds
12801da177e4SLinus Torvalds emu = midi->emu;
1281da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1282da3cec35STakashi Iwai return -ENXIO;
12831da177e4SLinus Torvalds spin_lock_irqsave(&midi->open_lock, flags);
12841da177e4SLinus Torvalds midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT;
12851da177e4SLinus Torvalds midi->substream_input = substream;
12861da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) {
12871da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
1288b130807dSRandy Dunlap if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
1289b130807dSRandy Dunlap goto error_out;
1290b130807dSRandy Dunlap if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
1291b130807dSRandy Dunlap goto error_out;
12921da177e4SLinus Torvalds } else {
12931da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
12941da177e4SLinus Torvalds }
12951da177e4SLinus Torvalds return 0;
1296b130807dSRandy Dunlap
1297b130807dSRandy Dunlap error_out:
1298b130807dSRandy Dunlap return -EIO;
12991da177e4SLinus Torvalds }
13001da177e4SLinus Torvalds
snd_emu10k1x_midi_output_open(struct snd_rawmidi_substream * substream)13014b32f1aaSTakashi Iwai static int snd_emu10k1x_midi_output_open(struct snd_rawmidi_substream *substream)
13021da177e4SLinus Torvalds {
13034b32f1aaSTakashi Iwai struct emu10k1x *emu;
13044b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
13051da177e4SLinus Torvalds unsigned long flags;
13061da177e4SLinus Torvalds
13071da177e4SLinus Torvalds emu = midi->emu;
1308da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1309da3cec35STakashi Iwai return -ENXIO;
13101da177e4SLinus Torvalds spin_lock_irqsave(&midi->open_lock, flags);
13111da177e4SLinus Torvalds midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT;
13121da177e4SLinus Torvalds midi->substream_output = substream;
13131da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
13141da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
1315b130807dSRandy Dunlap if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
1316b130807dSRandy Dunlap goto error_out;
1317b130807dSRandy Dunlap if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
1318b130807dSRandy Dunlap goto error_out;
13191da177e4SLinus Torvalds } else {
13201da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
13211da177e4SLinus Torvalds }
13221da177e4SLinus Torvalds return 0;
1323b130807dSRandy Dunlap
1324b130807dSRandy Dunlap error_out:
1325b130807dSRandy Dunlap return -EIO;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds
snd_emu10k1x_midi_input_close(struct snd_rawmidi_substream * substream)13284b32f1aaSTakashi Iwai static int snd_emu10k1x_midi_input_close(struct snd_rawmidi_substream *substream)
13291da177e4SLinus Torvalds {
13304b32f1aaSTakashi Iwai struct emu10k1x *emu;
13314b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
13321da177e4SLinus Torvalds unsigned long flags;
1333b130807dSRandy Dunlap int err = 0;
13341da177e4SLinus Torvalds
13351da177e4SLinus Torvalds emu = midi->emu;
1336da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1337da3cec35STakashi Iwai return -ENXIO;
13381da177e4SLinus Torvalds spin_lock_irqsave(&midi->open_lock, flags);
13391da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->rx_enable);
13401da177e4SLinus Torvalds midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT;
13411da177e4SLinus Torvalds midi->substream_input = NULL;
13421da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) {
13431da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
1344b130807dSRandy Dunlap err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
13451da177e4SLinus Torvalds } else {
13461da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
13471da177e4SLinus Torvalds }
1348b130807dSRandy Dunlap return err;
13491da177e4SLinus Torvalds }
13501da177e4SLinus Torvalds
snd_emu10k1x_midi_output_close(struct snd_rawmidi_substream * substream)13514b32f1aaSTakashi Iwai static int snd_emu10k1x_midi_output_close(struct snd_rawmidi_substream *substream)
13521da177e4SLinus Torvalds {
13534b32f1aaSTakashi Iwai struct emu10k1x *emu;
13544b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
13551da177e4SLinus Torvalds unsigned long flags;
1356b130807dSRandy Dunlap int err = 0;
13571da177e4SLinus Torvalds
13581da177e4SLinus Torvalds emu = midi->emu;
1359da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1360da3cec35STakashi Iwai return -ENXIO;
13611da177e4SLinus Torvalds spin_lock_irqsave(&midi->open_lock, flags);
13621da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->tx_enable);
13631da177e4SLinus Torvalds midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT;
13641da177e4SLinus Torvalds midi->substream_output = NULL;
13651da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
13661da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
1367b130807dSRandy Dunlap err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
13681da177e4SLinus Torvalds } else {
13691da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->open_lock, flags);
13701da177e4SLinus Torvalds }
1371b130807dSRandy Dunlap return err;
13721da177e4SLinus Torvalds }
13731da177e4SLinus Torvalds
snd_emu10k1x_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)13744b32f1aaSTakashi Iwai static void snd_emu10k1x_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
13751da177e4SLinus Torvalds {
13764b32f1aaSTakashi Iwai struct emu10k1x *emu;
13774b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
13781da177e4SLinus Torvalds emu = midi->emu;
1379da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1380da3cec35STakashi Iwai return;
13811da177e4SLinus Torvalds
13821da177e4SLinus Torvalds if (up)
13831da177e4SLinus Torvalds snd_emu10k1x_intr_enable(emu, midi->rx_enable);
13841da177e4SLinus Torvalds else
13851da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->rx_enable);
13861da177e4SLinus Torvalds }
13871da177e4SLinus Torvalds
snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)13884b32f1aaSTakashi Iwai static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
13891da177e4SLinus Torvalds {
13904b32f1aaSTakashi Iwai struct emu10k1x *emu;
13914b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = substream->rmidi->private_data;
13921da177e4SLinus Torvalds unsigned long flags;
13931da177e4SLinus Torvalds
13941da177e4SLinus Torvalds emu = midi->emu;
1395da3cec35STakashi Iwai if (snd_BUG_ON(!emu))
1396da3cec35STakashi Iwai return;
13971da177e4SLinus Torvalds
13981da177e4SLinus Torvalds if (up) {
13991da177e4SLinus Torvalds int max = 4;
14001da177e4SLinus Torvalds unsigned char byte;
14011da177e4SLinus Torvalds
14021da177e4SLinus Torvalds /* try to send some amount of bytes here before interrupts */
14031da177e4SLinus Torvalds spin_lock_irqsave(&midi->output_lock, flags);
14041da177e4SLinus Torvalds while (max > 0) {
14051da177e4SLinus Torvalds if (mpu401_output_ready(emu, midi)) {
14061da177e4SLinus Torvalds if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) ||
14071da177e4SLinus Torvalds snd_rawmidi_transmit(substream, &byte, 1) != 1) {
14081da177e4SLinus Torvalds /* no more data */
14091da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->output_lock, flags);
14101da177e4SLinus Torvalds return;
14111da177e4SLinus Torvalds }
14121da177e4SLinus Torvalds mpu401_write_data(emu, midi, byte);
14131da177e4SLinus Torvalds max--;
14141da177e4SLinus Torvalds } else {
14151da177e4SLinus Torvalds break;
14161da177e4SLinus Torvalds }
14171da177e4SLinus Torvalds }
14181da177e4SLinus Torvalds spin_unlock_irqrestore(&midi->output_lock, flags);
14191da177e4SLinus Torvalds snd_emu10k1x_intr_enable(emu, midi->tx_enable);
14201da177e4SLinus Torvalds } else {
14211da177e4SLinus Torvalds snd_emu10k1x_intr_disable(emu, midi->tx_enable);
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds }
14241da177e4SLinus Torvalds
14251da177e4SLinus Torvalds /*
14261da177e4SLinus Torvalds
14271da177e4SLinus Torvalds */
14281da177e4SLinus Torvalds
1429485885b9STakashi Iwai static const struct snd_rawmidi_ops snd_emu10k1x_midi_output =
14301da177e4SLinus Torvalds {
14311da177e4SLinus Torvalds .open = snd_emu10k1x_midi_output_open,
14321da177e4SLinus Torvalds .close = snd_emu10k1x_midi_output_close,
14331da177e4SLinus Torvalds .trigger = snd_emu10k1x_midi_output_trigger,
14341da177e4SLinus Torvalds };
14351da177e4SLinus Torvalds
1436485885b9STakashi Iwai static const struct snd_rawmidi_ops snd_emu10k1x_midi_input =
14371da177e4SLinus Torvalds {
14381da177e4SLinus Torvalds .open = snd_emu10k1x_midi_input_open,
14391da177e4SLinus Torvalds .close = snd_emu10k1x_midi_input_close,
14401da177e4SLinus Torvalds .trigger = snd_emu10k1x_midi_input_trigger,
14411da177e4SLinus Torvalds };
14421da177e4SLinus Torvalds
snd_emu10k1x_midi_free(struct snd_rawmidi * rmidi)14434b32f1aaSTakashi Iwai static void snd_emu10k1x_midi_free(struct snd_rawmidi *rmidi)
14441da177e4SLinus Torvalds {
14454b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = rmidi->private_data;
14461da177e4SLinus Torvalds midi->interrupt = NULL;
14471da177e4SLinus Torvalds midi->rmidi = NULL;
14481da177e4SLinus Torvalds }
14491da177e4SLinus Torvalds
emu10k1x_midi_init(struct emu10k1x * emu,struct emu10k1x_midi * midi,int device,char * name)1450e23e7a14SBill Pemberton static int emu10k1x_midi_init(struct emu10k1x *emu,
1451e23e7a14SBill Pemberton struct emu10k1x_midi *midi, int device,
1452e23e7a14SBill Pemberton char *name)
14531da177e4SLinus Torvalds {
14544b32f1aaSTakashi Iwai struct snd_rawmidi *rmidi;
14551da177e4SLinus Torvalds int err;
14561da177e4SLinus Torvalds
14579031f938STakashi Iwai err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi);
14589031f938STakashi Iwai if (err < 0)
14591da177e4SLinus Torvalds return err;
14601da177e4SLinus Torvalds midi->emu = emu;
14611da177e4SLinus Torvalds spin_lock_init(&midi->open_lock);
14621da177e4SLinus Torvalds spin_lock_init(&midi->input_lock);
14631da177e4SLinus Torvalds spin_lock_init(&midi->output_lock);
14641da177e4SLinus Torvalds strcpy(rmidi->name, name);
14651da177e4SLinus Torvalds snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1x_midi_output);
14661da177e4SLinus Torvalds snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1x_midi_input);
14671da177e4SLinus Torvalds rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
14681da177e4SLinus Torvalds SNDRV_RAWMIDI_INFO_INPUT |
14691da177e4SLinus Torvalds SNDRV_RAWMIDI_INFO_DUPLEX;
14701da177e4SLinus Torvalds rmidi->private_data = midi;
14711da177e4SLinus Torvalds rmidi->private_free = snd_emu10k1x_midi_free;
14721da177e4SLinus Torvalds midi->rmidi = rmidi;
14731da177e4SLinus Torvalds return 0;
14741da177e4SLinus Torvalds }
14751da177e4SLinus Torvalds
snd_emu10k1x_midi(struct emu10k1x * emu)1476e23e7a14SBill Pemberton static int snd_emu10k1x_midi(struct emu10k1x *emu)
14771da177e4SLinus Torvalds {
14784b32f1aaSTakashi Iwai struct emu10k1x_midi *midi = &emu->midi;
14791da177e4SLinus Torvalds int err;
14801da177e4SLinus Torvalds
14819031f938STakashi Iwai err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)");
14829031f938STakashi Iwai if (err < 0)
14831da177e4SLinus Torvalds return err;
14841da177e4SLinus Torvalds
14851da177e4SLinus Torvalds midi->tx_enable = INTE_MIDITXENABLE;
14861da177e4SLinus Torvalds midi->rx_enable = INTE_MIDIRXENABLE;
14871da177e4SLinus Torvalds midi->port = MUDATA;
14881da177e4SLinus Torvalds midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
14891da177e4SLinus Torvalds midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
14901da177e4SLinus Torvalds midi->interrupt = snd_emu10k1x_midi_interrupt;
14911da177e4SLinus Torvalds return 0;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds
__snd_emu10k1x_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)1494f37019b6STakashi Iwai static int __snd_emu10k1x_probe(struct pci_dev *pci,
14951da177e4SLinus Torvalds const struct pci_device_id *pci_id)
14961da177e4SLinus Torvalds {
14971da177e4SLinus Torvalds static int dev;
14984b32f1aaSTakashi Iwai struct snd_card *card;
14994b32f1aaSTakashi Iwai struct emu10k1x *chip;
15001da177e4SLinus Torvalds int err;
15011da177e4SLinus Torvalds
15021da177e4SLinus Torvalds if (dev >= SNDRV_CARDS)
15031da177e4SLinus Torvalds return -ENODEV;
15041da177e4SLinus Torvalds if (!enable[dev]) {
15051da177e4SLinus Torvalds dev++;
15061da177e4SLinus Torvalds return -ENOENT;
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds
15092b377c6bSTakashi Iwai err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
15102b377c6bSTakashi Iwai sizeof(*chip), &card);
15112b377c6bSTakashi Iwai if (err < 0)
15122b377c6bSTakashi Iwai return err;
15132b377c6bSTakashi Iwai chip = card->private_data;
15142b377c6bSTakashi Iwai
15152b377c6bSTakashi Iwai err = snd_emu10k1x_create(card, pci);
1516e58de7baSTakashi Iwai if (err < 0)
1517e58de7baSTakashi Iwai return err;
15181da177e4SLinus Torvalds
15199031f938STakashi Iwai err = snd_emu10k1x_pcm(chip, 0);
15202b377c6bSTakashi Iwai if (err < 0)
15211da177e4SLinus Torvalds return err;
15229031f938STakashi Iwai err = snd_emu10k1x_pcm(chip, 1);
15232b377c6bSTakashi Iwai if (err < 0)
15241da177e4SLinus Torvalds return err;
15259031f938STakashi Iwai err = snd_emu10k1x_pcm(chip, 2);
15262b377c6bSTakashi Iwai if (err < 0)
15271da177e4SLinus Torvalds return err;
15281da177e4SLinus Torvalds
15299031f938STakashi Iwai err = snd_emu10k1x_ac97(chip);
15302b377c6bSTakashi Iwai if (err < 0)
15311da177e4SLinus Torvalds return err;
15321da177e4SLinus Torvalds
15339031f938STakashi Iwai err = snd_emu10k1x_mixer(chip);
15342b377c6bSTakashi Iwai if (err < 0)
15351da177e4SLinus Torvalds return err;
15361da177e4SLinus Torvalds
15379031f938STakashi Iwai err = snd_emu10k1x_midi(chip);
15382b377c6bSTakashi Iwai if (err < 0)
15391da177e4SLinus Torvalds return err;
15401da177e4SLinus Torvalds
15411da177e4SLinus Torvalds snd_emu10k1x_proc_init(chip);
15421da177e4SLinus Torvalds
15431da177e4SLinus Torvalds strcpy(card->driver, "EMU10K1X");
15441da177e4SLinus Torvalds strcpy(card->shortname, "Dell Sound Blaster Live!");
15451da177e4SLinus Torvalds sprintf(card->longname, "%s at 0x%lx irq %i",
15461da177e4SLinus Torvalds card->shortname, chip->port, chip->irq);
15471da177e4SLinus Torvalds
15489031f938STakashi Iwai err = snd_card_register(card);
15492b377c6bSTakashi Iwai if (err < 0)
15501da177e4SLinus Torvalds return err;
15511da177e4SLinus Torvalds
15521da177e4SLinus Torvalds pci_set_drvdata(pci, card);
15531da177e4SLinus Torvalds dev++;
15541da177e4SLinus Torvalds return 0;
15551da177e4SLinus Torvalds }
15561da177e4SLinus Torvalds
snd_emu10k1x_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)1557f37019b6STakashi Iwai static int snd_emu10k1x_probe(struct pci_dev *pci,
1558f37019b6STakashi Iwai const struct pci_device_id *pci_id)
1559f37019b6STakashi Iwai {
1560f37019b6STakashi Iwai return snd_card_free_on_error(&pci->dev, __snd_emu10k1x_probe(pci, pci_id));
1561f37019b6STakashi Iwai }
1562f37019b6STakashi Iwai
15631da177e4SLinus Torvalds // PCI IDs
15649baa3c34SBenoit Taine static const struct pci_device_id snd_emu10k1x_ids[] = {
15650d7392e5SJoe Perches { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */
15661da177e4SLinus Torvalds { 0, }
15671da177e4SLinus Torvalds };
15681da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
15691da177e4SLinus Torvalds
15701da177e4SLinus Torvalds // pci_driver definition
1571e9f66d9bSTakashi Iwai static struct pci_driver emu10k1x_driver = {
15723733e424STakashi Iwai .name = KBUILD_MODNAME,
15731da177e4SLinus Torvalds .id_table = snd_emu10k1x_ids,
15741da177e4SLinus Torvalds .probe = snd_emu10k1x_probe,
15751da177e4SLinus Torvalds };
15761da177e4SLinus Torvalds
1577e9f66d9bSTakashi Iwai module_pci_driver(emu10k1x_driver);
1578