Blame view

sound/pci/als4000.c 31.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *  card-als4000.c - driver for Avance Logic ALS4000 based soundcards.
   *  Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>,
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
4
   *			  Jaroslav Kysela <perex@perex.cz>
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
5
   *  Copyright (C) 2002, 2008 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
   *
   *  Framework borrowed from Massimo Piccioni's card-als100.c.
   *
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
  
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
   * NOTES
   *
   *  Since Avance does not provide any meaningful documentation, and I
   *  bought an ALS4000 based soundcard, I was forced to base this driver
   *  on reverse engineering.
   *
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
30
31
32
33
   *  Note: this is no longer true (thank you!):
   *  pretty verbose chip docu (ALS4000a.PDF) can be found on the ALSA web site.
   *  Page numbers stated anywhere below with the "SPECS_PAGE:" tag
   *  refer to: ALS4000a.PDF specs Ver 1.0, May 28th, 1998.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
   *
   *  The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an
   *  ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport 
   *  interface. These subsystems can be mapped into ISA io-port space, 
   *  using the PCI-interface. In addition, the PCI-bit provides DMA and IRQ 
   *  services to the subsystems.
   * 
   * While ALS4000 is very similar to a SoundBlaster, the differences in
   * DMA and capturing require more changes to the SoundBlaster than
   * desirable, so I made this separate driver.
   * 
   * The ALS4000 can do real full duplex playback/capture.
   *
   * FMDAC:
   * - 0x4f -> port 0x14
   * - port 0x15 |= 1
   *
   * Enable/disable 3D sound:
   * - 0x50 -> port 0x14
   * - change bit 6 (0x40) of port 0x15
   *
   * Set QSound:
   * - 0xdb -> port 0x14
   * - set port 0x15:
   *   0x3e (mode 3), 0x3c (mode 2), 0x3a (mode 1), 0x38 (mode 0)
   *
   * Set KSound:
   * - value -> some port 0x0c0d
   *
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
63
   * ToDo:
c08744498   Andreas Mohr   ALSA: als4000 - C...
64
   * - by default, don't enable legacy game and use PCI game I/O
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
65
   * - power management? (card can do voice wakeup according to datasheet!!)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
  #include <asm/io.h>
  #include <linux/init.h>
  #include <linux/pci.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #include <linux/gameport.h>
65a772172   Paul Gortmaker   sound: fix driver...
71
  #include <linux/module.h>
910638ae7   Matthias Gehre   [PATCH] Replace 0...
72
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/rawmidi.h>
  #include <sound/mpu401.h>
  #include <sound/opl3.h>
  #include <sound/sb.h>
  #include <sound/initval.h>
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
80
  MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>, Andreas Mohr");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
87
88
89
90
  MODULE_DESCRIPTION("Avance Logic ALS4000");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
  
  #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
  #define SUPPORT_JOYSTICK 1
  #endif
  
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
91
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  #ifdef SUPPORT_JOYSTICK
  static int joystick_port[SNDRV_CARDS];
  #endif
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for ALS4000 soundcard.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for ALS4000 soundcard.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard.");
  #ifdef SUPPORT_JOYSTICK
  module_param_array(joystick_port, int, NULL, 0444);
  MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)");
  #endif
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
106
  struct snd_card_als4000 {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
107
  	/* most frequent access first */
c08744498   Andreas Mohr   ALSA: als4000 - C...
108
  	unsigned long iobase;
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
109
  	struct pci_dev *pci;
703529140   Takashi Iwai   [ALSA] als4000 - ...
110
  	struct snd_sb *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
  #ifdef SUPPORT_JOYSTICK
  	struct gameport *gameport;
  #endif
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
114
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

cebe41d4b   Alexey Dobriyan   sound: use DEFINE...
116
  static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
  	{ 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ALS4000 */
  	{ 0, }
  };
  
  MODULE_DEVICE_TABLE(pci, snd_als4000_ids);
c08744498   Andreas Mohr   ALSA: als4000 - C...
122
  enum als4k_iobase_t {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
123
  	/* IOx: B == Byte, W = Word, D = DWord; SPECS_PAGE: 37 */
c08744498   Andreas Mohr   ALSA: als4000 - C...
124
125
126
127
128
129
  	ALS4K_IOD_00_AC97_ACCESS = 0x00,
  	ALS4K_IOW_04_AC97_READ = 0x04,
  	ALS4K_IOB_06_AC97_STATUS = 0x06,
  	ALS4K_IOB_07_IRQSTATUS = 0x07,
  	ALS4K_IOD_08_GCR_DATA = 0x08,
  	ALS4K_IOB_0C_GCR_INDEX = 0x0c,
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
130
  	ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU = 0x0e,
c08744498   Andreas Mohr   ALSA: als4000 - C...
131
132
133
134
135
136
  	ALS4K_IOB_10_ADLIB_ADDR0 = 0x10,
  	ALS4K_IOB_11_ADLIB_ADDR1 = 0x11,
  	ALS4K_IOB_12_ADLIB_ADDR2 = 0x12,
  	ALS4K_IOB_13_ADLIB_ADDR3 = 0x13,
  	ALS4K_IOB_14_MIXER_INDEX = 0x14,
  	ALS4K_IOB_15_MIXER_DATA = 0x15,
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
137
138
  	ALS4K_IOB_16_ESP_RESET = 0x16,
  	ALS4K_IOB_16_ACK_FOR_CR1E = 0x16, /* 2nd function */
c08744498   Andreas Mohr   ALSA: als4000 - C...
139
140
141
142
143
144
145
146
147
148
149
150
151
  	ALS4K_IOB_18_OPL_ADDR0 = 0x18,
  	ALS4K_IOB_19_OPL_ADDR1 = 0x19,
  	ALS4K_IOB_1A_ESP_RD_DATA = 0x1a,
  	ALS4K_IOB_1C_ESP_CMD_DATA = 0x1c,
  	ALS4K_IOB_1C_ESP_WR_STATUS = 0x1c, /* 2nd function */
  	ALS4K_IOB_1E_ESP_RD_STATUS8 = 0x1e,
  	ALS4K_IOB_1F_ESP_RD_STATUS16 = 0x1f,
  	ALS4K_IOB_20_ESP_GAMEPORT_200 = 0x20,
  	ALS4K_IOB_21_ESP_GAMEPORT_201 = 0x21,
  	ALS4K_IOB_30_MIDI_DATA = 0x30,
  	ALS4K_IOB_31_MIDI_STATUS = 0x31,
  	ALS4K_IOB_31_MIDI_COMMAND = 0x31, /* 2nd function */
  };
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
152
153
154
155
  enum als4k_iobase_0e_t {
  	ALS4K_IOB_0E_MPU_IRQ = 0x10,
  	ALS4K_IOB_0E_CR1E_IRQ = 0x40,
  	ALS4K_IOB_0E_SB_DMA_IRQ = 0x80,
c08744498   Andreas Mohr   ALSA: als4000 - C...
156
  };
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  enum als4k_gcr_t { /* all registers 32bit wide; SPECS_PAGE: 38 to 42 */
  	ALS4K_GCR8C_MISC_CTRL = 0x8c,
  	ALS4K_GCR90_TEST_MODE_REG = 0x90,
  	ALS4K_GCR91_DMA0_ADDR = 0x91,
  	ALS4K_GCR92_DMA0_MODE_COUNT = 0x92,
  	ALS4K_GCR93_DMA1_ADDR = 0x93,
  	ALS4K_GCR94_DMA1_MODE_COUNT = 0x94,
  	ALS4K_GCR95_DMA3_ADDR = 0x95,
  	ALS4K_GCR96_DMA3_MODE_COUNT = 0x96,
  	ALS4K_GCR99_DMA_EMULATION_CTRL = 0x99,
  	ALS4K_GCRA0_FIFO1_CURRENT_ADDR = 0xa0,
  	ALS4K_GCRA1_FIFO1_STATUS_BYTECOUNT = 0xa1,
  	ALS4K_GCRA2_FIFO2_PCIADDR = 0xa2,
  	ALS4K_GCRA3_FIFO2_COUNT = 0xa3,
  	ALS4K_GCRA4_FIFO2_CURRENT_ADDR = 0xa4,
  	ALS4K_GCRA5_FIFO1_STATUS_BYTECOUNT = 0xa5,
  	ALS4K_GCRA6_PM_CTRL = 0xa6,
  	ALS4K_GCRA7_PCI_ACCESS_STORAGE = 0xa7,
  	ALS4K_GCRA8_LEGACY_CFG1 = 0xa8,
  	ALS4K_GCRA9_LEGACY_CFG2 = 0xa9,
  	ALS4K_GCRFF_DUMMY_SCRATCH = 0xff,
c08744498   Andreas Mohr   ALSA: als4000 - C...
178
  };
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
179
180
181
182
183
184
185
186
  enum als4k_gcr8c_t {
  	ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE = 0x8000,
  	ALS4K_GCR8C_CHIP_REV_MASK = 0xf0000
  };
  
  static inline void snd_als4k_iobase_writeb(unsigned long iobase,
  						enum als4k_iobase_t reg,
  						u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
188
  	outb(val, iobase + reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  }
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  static inline void snd_als4k_iobase_writel(unsigned long iobase,
  						enum als4k_iobase_t reg,
  						u32 val)
  {
  	outl(val, iobase + reg);
  }
  
  static inline u8 snd_als4k_iobase_readb(unsigned long iobase,
  						enum als4k_iobase_t reg)
  {
  	return inb(iobase + reg);
  }
  
  static inline u32 snd_als4k_iobase_readl(unsigned long iobase,
  						enum als4k_iobase_t reg)
  {
  	return inl(iobase + reg);
  }
  
  static inline void snd_als4k_gcr_write_addr(unsigned long iobase,
c08744498   Andreas Mohr   ALSA: als4000 - C...
210
211
  						 enum als4k_gcr_t reg,
  						 u32 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
213
214
215
216
217
218
219
220
221
  	snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
  	snd_als4k_iobase_writel(iobase, ALS4K_IOD_08_GCR_DATA, val);
  }
  
  static inline void snd_als4k_gcr_write(struct snd_sb *sb,
  					 enum als4k_gcr_t reg,
  					 u32 val)
  {
  	snd_als4k_gcr_write_addr(sb->alt_port, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  }	
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
223
  static inline u32 snd_als4k_gcr_read_addr(unsigned long iobase,
c08744498   Andreas Mohr   ALSA: als4000 - C...
224
  						 enum als4k_gcr_t reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	/* SPECS_PAGE: 37/38 */
  	snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
  	return snd_als4k_iobase_readl(iobase, ALS4K_IOD_08_GCR_DATA);
  }
  
  static inline u32 snd_als4k_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg)
  {
  	return snd_als4k_gcr_read_addr(sb->alt_port, reg);
  }
  
  enum als4k_cr_t { /* all registers 8bit wide; SPECS_PAGE: 20 to 23 */
  	ALS4K_CR0_SB_CONFIG = 0x00,
  	ALS4K_CR2_MISC_CONTROL = 0x02,
  	ALS4K_CR3_CONFIGURATION = 0x03,
  	ALS4K_CR17_FIFO_STATUS = 0x17,
  	ALS4K_CR18_ESP_MAJOR_VERSION = 0x18,
  	ALS4K_CR19_ESP_MINOR_VERSION = 0x19,
  	ALS4K_CR1A_MPU401_UART_MODE_CONTROL = 0x1a,
  	ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO = 0x1c,
  	ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI = 0x1d,
  	ALS4K_CR1E_FIFO2_CONTROL = 0x1e, /* secondary PCM FIFO (recording) */
  	ALS4K_CR3A_MISC_CONTROL = 0x3a,
  	ALS4K_CR3B_CRC32_BYTE0 = 0x3b, /* for testing, activate via CR3A */
  	ALS4K_CR3C_CRC32_BYTE1 = 0x3c,
  	ALS4K_CR3D_CRC32_BYTE2 = 0x3d,
  	ALS4K_CR3E_CRC32_BYTE3 = 0x3e,
  };
  
  enum als4k_cr0_t {
  	ALS4K_CR0_DMA_CONTIN_MODE_CTRL = 0x02, /* IRQ/FIFO controlled for 0/1 */
  	ALS4K_CR0_DMA_90H_MODE_CTRL = 0x04, /* IRQ/FIFO controlled for 0/1 */
  	ALS4K_CR0_MX80_81_REG_WRITE_ENABLE = 0x80,
  };
  
  static inline void snd_als4_cr_write(struct snd_sb *chip,
  					enum als4k_cr_t reg,
  					u8 data)
  {
  	/* Control Register is reg | 0xc0 (bit 7, 6 set) on sbmixer_index
  	 * NOTE: assumes chip->mixer_lock to be locked externally already!
  	 * SPECS_PAGE: 6 */
  	snd_sbmixer_write(chip, reg | 0xc0, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
269
270
  static inline u8 snd_als4_cr_read(struct snd_sb *chip,
  					enum als4k_cr_t reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
272
273
  	/* NOTE: assumes chip->mixer_lock to be locked externally already! */
  	return snd_sbmixer_read(chip, reg | 0xc0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  }
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
275

17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
276
  static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
  {
  	if (!(chip->mode & SB_RATE_LOCK)) {
  		snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT);
  		snd_sbdsp_command(chip, rate>>8);
  		snd_sbdsp_command(chip, rate);
  	}
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
284
285
  static inline void snd_als4000_set_capture_dma(struct snd_sb *chip,
  					       dma_addr_t addr, unsigned size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
287
288
289
  	/* SPECS_PAGE: 40 */
  	snd_als4k_gcr_write(chip, ALS4K_GCRA2_FIFO2_PCIADDR, addr);
  	snd_als4k_gcr_write(chip, ALS4K_GCRA3_FIFO2_COUNT, (size-1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
291
  static inline void snd_als4000_set_playback_dma(struct snd_sb *chip,
c08744498   Andreas Mohr   ALSA: als4000 - C...
292
293
  						dma_addr_t addr,
  						unsigned size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
295
296
297
  	/* SPECS_PAGE: 38 */
  	snd_als4k_gcr_write(chip, ALS4K_GCR91_DMA0_ADDR, addr);
  	snd_als4k_gcr_write(chip, ALS4K_GCR92_DMA0_MODE_COUNT,
c08744498   Andreas Mohr   ALSA: als4000 - C...
298
  							(size-1)|0x180000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
  }
  
  #define ALS4000_FORMAT_SIGNED	(1<<0)
  #define ALS4000_FORMAT_16BIT	(1<<1)
  #define ALS4000_FORMAT_STEREO	(1<<2)
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
304
  static int snd_als4000_get_format(struct snd_pcm_runtime *runtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  {
  	int result;
  
  	result = 0;
  	if (snd_pcm_format_signed(runtime->format))
  		result |= ALS4000_FORMAT_SIGNED;
  	if (snd_pcm_format_physical_width(runtime->format) == 16)
  		result |= ALS4000_FORMAT_16BIT;
  	if (runtime->channels > 1)
  		result |= ALS4000_FORMAT_STEREO;
  	return result;
  }
  
  /* structure for setting up playback */
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
319
  static const struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  	unsigned char dsp_cmd, dma_on, dma_off, format;
  } playback_cmd_vals[]={
  /* ALS4000_FORMAT_U8_MONO */
  { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_UNS_MONO },
  /* ALS4000_FORMAT_S8_MONO */	
  { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_SIGN_MONO },
  /* ALS4000_FORMAT_U16L_MONO */
  { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_UNS_MONO },
  /* ALS4000_FORMAT_S16L_MONO */
  { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_SIGN_MONO },
  /* ALS4000_FORMAT_U8_STEREO */
  { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_UNS_STEREO },
  /* ALS4000_FORMAT_S8_STEREO */	
  { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_SIGN_STEREO },
  /* ALS4000_FORMAT_U16L_STEREO */
  { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_UNS_STEREO },
  /* ALS4000_FORMAT_S16L_STEREO */
  { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_SIGN_STEREO },
  };
  #define playback_cmd(chip) (playback_cmd_vals[(chip)->playback_format])
  
  /* structure for setting up capture */
  enum { CMD_WIDTH8=0x04, CMD_SIGNED=0x10, CMD_MONO=0x80, CMD_STEREO=0xA0 };
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
343
  static const unsigned char capture_cmd_vals[]=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
  {
  CMD_WIDTH8|CMD_MONO,			/* ALS4000_FORMAT_U8_MONO */
  CMD_WIDTH8|CMD_SIGNED|CMD_MONO,		/* ALS4000_FORMAT_S8_MONO */	
  CMD_MONO,				/* ALS4000_FORMAT_U16L_MONO */
  CMD_SIGNED|CMD_MONO,			/* ALS4000_FORMAT_S16L_MONO */
  CMD_WIDTH8|CMD_STEREO,			/* ALS4000_FORMAT_U8_STEREO */
  CMD_WIDTH8|CMD_SIGNED|CMD_STEREO,	/* ALS4000_FORMAT_S8_STEREO */	
  CMD_STEREO,				/* ALS4000_FORMAT_U16L_STEREO */
  CMD_SIGNED|CMD_STEREO,			/* ALS4000_FORMAT_S16L_STEREO */
  };	
  #define capture_cmd(chip) (capture_cmd_vals[(chip)->capture_format])
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
355
356
  static int snd_als4000_hw_params(struct snd_pcm_substream *substream,
  				 struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
  {
  	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
360
  static int snd_als4000_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
  {
  	snd_pcm_lib_free_pages(substream);
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
365
  static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
367
368
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
374
375
376
377
  	unsigned long size;
  	unsigned count;
  
  	chip->capture_format = snd_als4000_get_format(runtime);
  		
  	size = snd_pcm_lib_buffer_bytes(substream);
  	count = snd_pcm_lib_period_bytes(substream);
  	
  	if (chip->capture_format & ALS4000_FORMAT_16BIT)
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
378
  		count >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  	count--;
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
380
  	spin_lock_irq(&chip->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
  	snd_als4000_set_rate(chip, runtime->rate);
  	snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
383
384
  	spin_unlock_irq(&chip->reg_lock);
  	spin_lock_irq(&chip->mixer_lock);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
385
386
  	snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff);
  	snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8);
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
387
  	spin_unlock_irq(&chip->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
390
  static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
392
393
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
400
401
402
  	unsigned long size;
  	unsigned count;
  
  	chip->playback_format = snd_als4000_get_format(runtime);
  	
  	size = snd_pcm_lib_buffer_bytes(substream);
  	count = snd_pcm_lib_period_bytes(substream);
  	
  	if (chip->playback_format & ALS4000_FORMAT_16BIT)
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
403
  		count >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
408
409
410
411
  	count--;
  	
  	/* FIXME: from second playback on, there's a lot more clicks and pops
  	 * involved here than on first playback. Fiddling with
  	 * tons of different settings didn't help (DMA, speaker on/off,
  	 * reordering, ...). Something seems to get enabled on playback
  	 * that I haven't found out how to disable again, which then causes
  	 * the switching pops to reach the speakers the next time here. */
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
412
  	spin_lock_irq(&chip->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
  	snd_als4000_set_rate(chip, runtime->rate);
  	snd_als4000_set_playback_dma(chip, runtime->dma_addr, size);
  	
  	/* SPEAKER_ON not needed, since dma_on seems to also enable speaker */
  	/* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */
  	snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd);
  	snd_sbdsp_command(chip, playback_cmd(chip).format);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
420
421
  	snd_sbdsp_command(chip, count & 0xff);
  	snd_sbdsp_command(chip, count >> 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  	snd_sbdsp_command(chip, playback_cmd(chip).dma_off);	
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
423
  	spin_unlock_irq(&chip->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
  	
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
427
  static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
429
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  	int result = 0;
  	
c08744498   Andreas Mohr   ALSA: als4000 - C...
432
433
434
435
436
437
  	/* FIXME race condition in here!!!
  	   chip->mode non-atomic update gets consistently protected
  	   by reg_lock always, _except_ for this place!!
  	   Probably need to take reg_lock as outer (or inner??) lock, too.
  	   (or serialize both lock operations? probably not, though... - racy?)
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  	spin_lock(&chip->mixer_lock);
703529140   Takashi Iwai   [ALSA] als4000 - ...
439
440
441
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  		chip->mode |= SB_RATE_LOCK_CAPTURE;
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
443
444
  		snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
  							 capture_cmd(chip));
703529140   Takashi Iwai   [ALSA] als4000 - ...
445
446
447
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  		chip->mode &= ~SB_RATE_LOCK_CAPTURE;
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
449
450
  		snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
  							 capture_cmd(chip));
703529140   Takashi Iwai   [ALSA] als4000 - ...
451
452
  		break;
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  		result = -EINVAL;
703529140   Takashi Iwai   [ALSA] als4000 - ...
454
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
  	}
  	spin_unlock(&chip->mixer_lock);
  	return result;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
459
  static int snd_als4000_playback_trigger(struct snd_pcm_substream *substream, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
461
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
  	int result = 0;
  
  	spin_lock(&chip->reg_lock);
703529140   Takashi Iwai   [ALSA] als4000 - ...
465
466
467
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  		chip->mode |= SB_RATE_LOCK_PLAYBACK;
  		snd_sbdsp_command(chip, playback_cmd(chip).dma_on);
703529140   Takashi Iwai   [ALSA] als4000 - ...
470
471
472
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  		snd_sbdsp_command(chip, playback_cmd(chip).dma_off);
  		chip->mode &= ~SB_RATE_LOCK_PLAYBACK;
703529140   Takashi Iwai   [ALSA] als4000 - ...
475
476
  		break;
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  		result = -EINVAL;
703529140   Takashi Iwai   [ALSA] als4000 - ...
478
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
  	}
  	spin_unlock(&chip->reg_lock);
  	return result;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
483
  static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
485
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
  	unsigned int result;
  
  	spin_lock(&chip->reg_lock);	
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
489
  	result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  	spin_unlock(&chip->reg_lock);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
491
  	result &= 0xffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
  	return bytes_to_frames( substream->runtime, result );
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
494
  static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
496
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
  	unsigned result;
  
  	spin_lock(&chip->reg_lock);	
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
500
  	result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  	spin_unlock(&chip->reg_lock);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
502
  	result &= 0xffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  	return bytes_to_frames( substream->runtime, result );
  }
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
505
506
507
508
  /* FIXME: this IRQ routine doesn't really support IRQ sharing (we always
   * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not).
   * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK
   * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
509
   * register (alt_port + ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU). Probably something
c08744498   Andreas Mohr   ALSA: als4000 - C...
510
   * could be optimized here to query/write one register only...
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
511
512
513
514
   * And even if both registers need to be queried, then there's still the
   * question of whether it's actually correct to ACK PCI IRQ before reading
   * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear*
   * SB IRQ status.
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
515
   * (hmm, SPECS_PAGE: 38 mentions it the other way around!)
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
516
517
   * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
   * */
7d12e780e   David Howells   IRQ: Maintain reg...
518
  static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
520
  	struct snd_sb *chip = dev_id;
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
521
522
523
524
525
526
527
528
529
  	unsigned pci_irqstatus;
  	unsigned sb_irqstatus;
  
  	/* find out which bit of the ALS4000 PCI block produced the interrupt,
  	   SPECS_PAGE: 38, 5 */
  	pci_irqstatus = snd_als4k_iobase_readb(chip->alt_port,
  				 ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU);
  	if ((pci_irqstatus & ALS4K_IOB_0E_SB_DMA_IRQ)
  	 && (chip->playback_substream)) /* playback */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  		snd_pcm_period_elapsed(chip->playback_substream);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
531
532
  	if ((pci_irqstatus & ALS4K_IOB_0E_CR1E_IRQ)
  	 && (chip->capture_substream)) /* capturing */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  		snd_pcm_period_elapsed(chip->capture_substream);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
534
535
  	if ((pci_irqstatus & ALS4K_IOB_0E_MPU_IRQ)
  	 && (chip->rmidi)) /* MPU401 interrupt */
7d12e780e   David Howells   IRQ: Maintain reg...
536
  		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
537
538
539
  	/* ACK the PCI block IRQ */
  	snd_als4k_iobase_writeb(chip->alt_port,
  			 ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  	
  	spin_lock(&chip->mixer_lock);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
542
543
  	/* SPECS_PAGE: 20 */
  	sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  	spin_unlock(&chip->mixer_lock);
  	
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
546
  	if (sb_irqstatus & SB_IRQTYPE_8BIT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  		snd_sb_ack_8bit(chip);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
548
  	if (sb_irqstatus & SB_IRQTYPE_16BIT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  		snd_sb_ack_16bit(chip);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
550
  	if (sb_irqstatus & SB_IRQTYPE_MPUIN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  		inb(chip->mpu_port);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  	if (sb_irqstatus & ALS4K_IRQTYPE_CR1E_DMA)
  		snd_als4k_iobase_readb(chip->alt_port,
  					ALS4K_IOB_16_ACK_FOR_CR1E);
  
  	/* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x
  ",
  					 pci_irqstatus, sb_irqstatus); */
  
  	/* only ack the things we actually handled above */
  	return IRQ_RETVAL(
  	     (pci_irqstatus & (ALS4K_IOB_0E_SB_DMA_IRQ|ALS4K_IOB_0E_CR1E_IRQ|
  				ALS4K_IOB_0E_MPU_IRQ))
  	  || (sb_irqstatus & (SB_IRQTYPE_8BIT|SB_IRQTYPE_16BIT|
  				SB_IRQTYPE_MPUIN|ALS4K_IRQTYPE_CR1E_DMA))
  	);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
  }
  
  /*****************************************************************/
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
570
  static struct snd_pcm_hardware snd_als4000_playback =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  {
  	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  				 SNDRV_PCM_INFO_MMAP_VALID),
  	.formats =		SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
  				SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE,	/* formats */
  	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
  	.rate_min =		4000,
  	.rate_max =		48000,
  	.channels_min =		1,
  	.channels_max =		2,
  	.buffer_bytes_max =	65536,
  	.period_bytes_min =	64,
  	.period_bytes_max =	65536,
  	.periods_min =		1,
  	.periods_max =		1024,
  	.fifo_size =		0
  };
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
588
  static struct snd_pcm_hardware snd_als4000_capture =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
  {
  	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  				 SNDRV_PCM_INFO_MMAP_VALID),
  	.formats =		SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
  				SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE,	/* formats */
  	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
  	.rate_min =		4000,
  	.rate_max =		48000,
  	.channels_min =		1,
  	.channels_max =		2,
  	.buffer_bytes_max =	65536,
  	.period_bytes_min =	64,
  	.period_bytes_max =	65536,
  	.periods_min =		1,
  	.periods_max =		1024,
  	.fifo_size =		0
  };
  
  /*****************************************************************/
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
608
  static int snd_als4000_playback_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
610
611
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
  
  	chip->playback_substream = substream;
  	runtime->hw = snd_als4000_playback;
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
617
  static int snd_als4000_playback_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
619
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
  
  	chip->playback_substream = NULL;
  	snd_pcm_lib_free_pages(substream);
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
625
  static int snd_als4000_capture_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
627
628
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
632
633
  
  	chip->capture_substream = substream;
  	runtime->hw = snd_als4000_capture;
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
634
  static int snd_als4000_capture_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
636
  	struct snd_sb *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
640
641
642
643
  
  	chip->capture_substream = NULL;
  	snd_pcm_lib_free_pages(substream);
  	return 0;
  }
  
  /******************************************************************/
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
644
  static struct snd_pcm_ops snd_als4000_playback_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
652
653
  	.open =		snd_als4000_playback_open,
  	.close =	snd_als4000_playback_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_als4000_hw_params,
  	.hw_free =	snd_als4000_hw_free,
  	.prepare =	snd_als4000_playback_prepare,
  	.trigger =	snd_als4000_playback_trigger,
  	.pointer =	snd_als4000_playback_pointer
  };
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
654
  static struct snd_pcm_ops snd_als4000_capture_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
658
659
660
661
662
663
  	.open =		snd_als4000_capture_open,
  	.close =	snd_als4000_capture_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_als4000_hw_params,
  	.hw_free =	snd_als4000_hw_free,
  	.prepare =	snd_als4000_capture_prepare,
  	.trigger =	snd_als4000_capture_trigger,
  	.pointer =	snd_als4000_capture_pointer
  };
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
664
  static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  {
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
666
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	int err;
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
668
669
  	err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  	pcm->private_data = chip;
  	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops);
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops);
  
  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
  					      64*1024, 64*1024);
  
  	chip->pcm = pcm;
  
  	return 0;
  }
  
  /******************************************************************/
c08744498   Andreas Mohr   ALSA: als4000 - C...
685
686
687
688
689
  static void snd_als4000_set_addr(unsigned long iobase,
  					unsigned int sb_io,
  					unsigned int mpu_io,
  					unsigned int opl_io,
  					unsigned int game_io)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  {
c08744498   Andreas Mohr   ALSA: als4000 - C...
691
692
  	u32 cfg1 = 0;
  	u32 cfg2 = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

c08744498   Andreas Mohr   ALSA: als4000 - C...
694
695
696
697
698
699
700
701
  	if (mpu_io > 0)
  		cfg2 |= (mpu_io | 1) << 16;
  	if (sb_io > 0)
  		cfg2 |= (sb_io | 1);
  	if (game_io > 0)
  		cfg1 |= (game_io | 1) << 16;
  	if (opl_io > 0)
  		cfg1 |= (opl_io | 1);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
702
703
  	snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA8_LEGACY_CFG1, cfg1);
  	snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA9_LEGACY_CFG2, cfg2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  }
703529140   Takashi Iwai   [ALSA] als4000 - ...
705
  static void snd_als4000_configure(struct snd_sb *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  {
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
707
  	u8 tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
  	int i;
  
  	/* do some more configuration */
  	spin_lock_irq(&chip->mixer_lock);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
712
713
714
715
716
  	tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG);
  	snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
  				tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
  	/* always select DMA channel 0, since we do not actually use DMA
  	 * SPECS_PAGE: 19/20 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  	snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
718
719
  	snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
  				 tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
  	spin_unlock_irq(&chip->mixer_lock);
  	
  	spin_lock_irq(&chip->reg_lock);
c08744498   Andreas Mohr   ALSA: als4000 - C...
723
  	/* enable interrupts */
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
724
725
  	snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL,
  					ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE);
c08744498   Andreas Mohr   ALSA: als4000 - C...
726

cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
727
728
729
  	/* SPECS_PAGE: 39 */
  	for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
  		snd_als4k_gcr_write(chip, i, 0);
b9619230e   Ondrej Zary   ALSA: als4000: en...
730
  	/* enable burst mode to prevent dropouts during high PCI bus usage */
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
731
  	snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
c4685849b   Ondrej Zary   ALSA: als4000: Fi...
732
  		(snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
  	spin_unlock_irq(&chip->reg_lock);
  }
  
  #ifdef SUPPORT_JOYSTICK
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
737
  static int __devinit snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
  {
  	struct gameport *gp;
  	struct resource *r;
  	int io_port;
  
  	if (joystick_port[dev] == 0)
  		return -ENODEV;
  
  	if (joystick_port[dev] == 1) { /* auto-detect */
  		for (io_port = 0x200; io_port <= 0x218; io_port += 8) {
  			r = request_region(io_port, 8, "ALS4000 gameport");
  			if (r)
  				break;
  		}
  	} else {
  		io_port = joystick_port[dev];
  		r = request_region(io_port, 8, "ALS4000 gameport");
  	}
  
  	if (!r) {
  		printk(KERN_WARNING "als4000: cannot reserve joystick ports
  ");
  		return -EBUSY;
  	}
  
  	acard->gameport = gp = gameport_allocate_port();
  	if (!gp) {
  		printk(KERN_ERR "als4000: cannot allocate memory for gameport
  ");
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
767
  		release_and_free_resource(r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
773
774
775
776
777
  		return -ENOMEM;
  	}
  
  	gameport_set_name(gp, "ALS4000 Gameport");
  	gameport_set_phys(gp, "pci%s/gameport0", pci_name(acard->pci));
  	gameport_set_dev_parent(gp, &acard->pci->dev);
  	gp->io = io_port;
  	gameport_set_port_data(gp, r);
  
  	/* Enable legacy joystick port */
c08744498   Andreas Mohr   ALSA: als4000 - C...
778
  	snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
  
  	gameport_register_port(acard->gameport);
  
  	return 0;
  }
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
784
  static void snd_als4000_free_gameport(struct snd_card_als4000 *acard)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
  {
  	if (acard->gameport) {
  		struct resource *r = gameport_get_port_data(acard->gameport);
  
  		gameport_unregister_port(acard->gameport);
  		acard->gameport = NULL;
c08744498   Andreas Mohr   ALSA: als4000 - C...
791
792
  		/* disable joystick */
  		snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
793
  		release_and_free_resource(r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
  	}
  }
  #else
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
797
798
  static inline int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) { return -ENOSYS; }
  static inline void snd_als4000_free_gameport(struct snd_card_als4000 *acard) { }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  #endif
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
800
  static void snd_card_als4000_free( struct snd_card *card )
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  {
c08744498   Andreas Mohr   ALSA: als4000 - C...
802
  	struct snd_card_als4000 *acard = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
  
  	/* make sure that interrupts are disabled */
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
805
  	snd_als4k_gcr_write_addr(acard->iobase, ALS4K_GCR8C_MISC_CTRL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
810
811
812
813
814
815
  	/* free resources */
  	snd_als4000_free_gameport(acard);
  	pci_release_regions(acard->pci);
  	pci_disable_device(acard->pci);
  }
  
  static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
  					  const struct pci_device_id *pci_id)
  {
  	static int dev;
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
816
817
  	struct snd_card *card;
  	struct snd_card_als4000 *acard;
c08744498   Andreas Mohr   ALSA: als4000 - C...
818
  	unsigned long iobase;
17c39d9a5   Takashi Iwai   [ALSA] Remove xxx...
819
820
  	struct snd_sb *chip;
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  	unsigned short word;
  	int err;
  
  	if (dev >= SNDRV_CARDS)
  		return -ENODEV;
  	if (!enable[dev]) {
  		dev++;
  		return -ENOENT;
  	}
  
  	/* enable PCI device */
  	if ((err = pci_enable_device(pci)) < 0) {
  		return err;
  	}
  	/* check, if we can restrict PCI DMA transfers to 24 bits */
2f4f27d42   Yang Hongyang   dma-mapping: repl...
836
837
  	if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
  	    pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
838
839
  		snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
844
845
846
847
  		pci_disable_device(pci);
  		return -ENXIO;
  	}
  
  	if ((err = pci_request_regions(pci, "ALS4000")) < 0) {
  		pci_disable_device(pci);
  		return err;
  	}
c08744498   Andreas Mohr   ALSA: als4000 - C...
848
  	iobase = pci_resource_start(pci, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
851
852
853
  
  	pci_read_config_word(pci, PCI_COMMAND, &word);
  	pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
  	pci_set_master(pci);
  	
e58de7baf   Takashi Iwai   ALSA: Convert to ...
854
855
856
857
  	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 
  			      sizeof(*acard) /* private_data: acard */,
  			      &card);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
  		pci_release_regions(pci);
  		pci_disable_device(pci);
e58de7baf   Takashi Iwai   ALSA: Convert to ...
860
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  	}
c08744498   Andreas Mohr   ALSA: als4000 - C...
862
  	acard = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	acard->pci = pci;
c08744498   Andreas Mohr   ALSA: als4000 - C...
864
  	acard->iobase = iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
  	card->private_free = snd_card_als4000_free;
  
  	/* disable all legacy ISA stuff */
c08744498   Andreas Mohr   ALSA: als4000 - C...
868
  	snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
  
  	if ((err = snd_sbdsp_create(card,
c08744498   Andreas Mohr   ALSA: als4000 - C...
871
  				    iobase + ALS4K_IOB_10_ADLIB_ADDR0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  				    pci->irq,
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
873
  		/* internally registered as IRQF_SHARED in case of ALS4000 SB */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
  				    snd_als4000_interrupt,
  				    -1,
  				    -1,
  				    SB_HW_ALS4000,
  				    &chip)) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
879
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
  	}
703529140   Takashi Iwai   [ALSA] als4000 - ...
881
  	acard->chip = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  
  	chip->pci = pci;
c08744498   Andreas Mohr   ALSA: als4000 - C...
884
  	chip->alt_port = iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
892
893
894
  	snd_card_set_dev(card, &pci->dev);
  
  	snd_als4000_configure(chip);
  
  	strcpy(card->driver, "ALS4000");
  	strcpy(card->shortname, "Avance Logic ALS4000");
  	sprintf(card->longname, "%s at 0x%lx, irq %i",
  		card->shortname, chip->alt_port, chip->irq);
  
  	if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
c08744498   Andreas Mohr   ALSA: als4000 - C...
895
  					iobase + ALS4K_IOB_30_MIDI_DATA,
dba8b4699   Clemens Ladisch   ALSA: mpu401: cle...
896
897
898
  					MPU401_INFO_INTEGRATED |
  					MPU401_INFO_IRQ_HOOK,
  					-1, &chip->rmidi)) < 0) {
c08744498   Andreas Mohr   ALSA: als4000 - C...
899
900
901
  		printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?
  ",
  				iobase + ALS4K_IOB_30_MIDI_DATA);
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
902
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  	}
c08744498   Andreas Mohr   ALSA: als4000 - C...
904
  	/* FIXME: ALS4000 has interesting MPU401 configuration features
cb780cdd8   Andreas Mohr   ALSA: ALS4000 dri...
905
906
907
908
  	 * at ALS4K_CR1A_MPU401_UART_MODE_CONTROL
  	 * (pass-thru / UART switching, fast MIDI clock, etc.),
  	 * however there doesn't seem to be an ALSA API for this...
  	 * SPECS_PAGE: 21 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
  
  	if ((err = snd_als4000_pcm(chip, 0)) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
911
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
  	}
  	if ((err = snd_sbmixer_new(chip)) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
914
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  	}	    
c08744498   Andreas Mohr   ALSA: als4000 - C...
916
917
918
  	if (snd_opl3_create(card,
  				iobase + ALS4K_IOB_10_ADLIB_ADDR0,
  				iobase + ALS4K_IOB_12_ADLIB_ADDR2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  			    OPL3_HW_AUTO, 1, &opl3) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
920
921
  		printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?
  ",
c08744498   Andreas Mohr   ALSA: als4000 - C...
922
923
  			   iobase + ALS4K_IOB_10_ADLIB_ADDR0,
  			   iobase + ALS4K_IOB_12_ADLIB_ADDR2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
  	} else {
  		if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
926
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
  		}
  	}
  
  	snd_als4000_create_gameport(acard, dev);
  
  	if ((err = snd_card_register(card)) < 0) {
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
933
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
  	}
  	pci_set_drvdata(pci, card);
  	dev++;
ba7301c7d   Andreas Mohr   [ALSA] ALS4000 up...
937
938
939
940
941
942
943
944
  	err = 0;
  	goto out;
  
  out_err:
  	snd_card_free(card);
  	
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
950
951
  }
  
  static void __devexit snd_card_als4000_remove(struct pci_dev *pci)
  {
  	snd_card_free(pci_get_drvdata(pci));
  	pci_set_drvdata(pci, NULL);
  }
703529140   Takashi Iwai   [ALSA] als4000 - ...
952
953
954
955
956
957
958
959
960
961
962
  #ifdef CONFIG_PM
  static int snd_als4000_suspend(struct pci_dev *pci, pm_message_t state)
  {
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_card_als4000 *acard = card->private_data;
  	struct snd_sb *chip = acard->chip;
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
  	
  	snd_pcm_suspend_all(chip->pcm);
  	snd_sbmixer_suspend(chip);
703529140   Takashi Iwai   [ALSA] als4000 - ...
963
964
  	pci_disable_device(pci);
  	pci_save_state(pci);
30b35399c   Takashi Iwai   [ALSA] Various fi...
965
  	pci_set_power_state(pci, pci_choose_state(pci, state));
703529140   Takashi Iwai   [ALSA] als4000 - ...
966
967
968
969
970
971
972
973
  	return 0;
  }
  
  static int snd_als4000_resume(struct pci_dev *pci)
  {
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_card_als4000 *acard = card->private_data;
  	struct snd_sb *chip = acard->chip;
703529140   Takashi Iwai   [ALSA] als4000 - ...
974
  	pci_set_power_state(pci, PCI_D0);
30b35399c   Takashi Iwai   [ALSA] Various fi...
975
976
977
978
979
980
981
982
  	pci_restore_state(pci);
  	if (pci_enable_device(pci) < 0) {
  		printk(KERN_ERR "als4000: pci_enable_device failed, "
  		       "disabling device
  ");
  		snd_card_disconnect(card);
  		return -EIO;
  	}
703529140   Takashi Iwai   [ALSA] als4000 - ...
983
984
985
986
987
988
989
990
  	pci_set_master(pci);
  
  	snd_als4000_configure(chip);
  	snd_sbdsp_reset(chip);
  	snd_sbmixer_resume(chip);
  
  #ifdef SUPPORT_JOYSTICK
  	if (acard->gameport)
c08744498   Andreas Mohr   ALSA: als4000 - C...
991
  		snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
703529140   Takashi Iwai   [ALSA] als4000 - ...
992
993
994
995
996
  #endif
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return 0;
  }
c08744498   Andreas Mohr   ALSA: als4000 - C...
997
  #endif /* CONFIG_PM */
703529140   Takashi Iwai   [ALSA] als4000 - ...
998

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
  static struct pci_driver driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
1000
  	.name = KBUILD_MODNAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
  	.id_table = snd_als4000_ids,
  	.probe = snd_card_als4000_probe,
  	.remove = __devexit_p(snd_card_als4000_remove),
703529140   Takashi Iwai   [ALSA] als4000 - ...
1004
1005
1006
1007
  #ifdef CONFIG_PM
  	.suspend = snd_als4000_suspend,
  	.resume = snd_als4000_resume,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
  };
  
  static int __init alsa_card_als4000_init(void)
  {
01d25d460   Takashi Iwai   [ALSA] Replace pc...
1012
  	return pci_register_driver(&driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
1021
  }
  
  static void __exit alsa_card_als4000_exit(void)
  {
  	pci_unregister_driver(&driver);
  }
  
  module_init(alsa_card_als4000_init)
  module_exit(alsa_card_als4000_exit)