xref: /linux/sound/pci/emu10k1/emu10k1x.c (revision f37019b6)
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", &reg, &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