Blame view

sound/pci/ali5451/ali5451.c 56.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   *  Matt Wu <Matt_Wu@acersoftech.com.cn>
   *  Apr 26, 2001
   *  Routines for control of ALi pci audio M5451
   *
   *  BUGS:
   *    --
   *
   *  TODO:
   *    --
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public Lcodecnse as published by
   *   the Free Software Foundation; either version 2 of the Lcodecnse, 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 Lcodecnse for more details.
   *
   *   You should have received a copy of the GNU General Public Lcodecnse
   *   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
27
28
29
30
31
32
  #include <asm/io.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
65a772172   Paul Gortmaker   sound: fix driver...
33
  #include <linux/module.h>
910638ae7   Matthias Gehre   [PATCH] Replace 0...
34
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/info.h>
  #include <sound/ac97_codec.h>
  #include <sound/mpu401.h>
  #include <sound/initval.h>
  
  MODULE_AUTHOR("Matt Wu <Matt_Wu@acersoftech.com.cn>");
  MODULE_DESCRIPTION("ALI M5451");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
46
47
48
  static int index = SNDRV_DEFAULT_IDX1;	/* Index */
  static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */
  static int pcm_channels = 32;
a67ff6a54   Rusty Russell   ALSA: module_para...
49
  static bool spdif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
51
  module_param(index, int, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
53
  module_param(id, charp, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio.");
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
55
  module_param(pcm_channels, int, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  MODULE_PARM_DESC(pcm_channels, "PCM Channels");
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
57
  module_param(spdif, bool, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
59
  /* just for backward compatibility */
a67ff6a54   Rusty Russell   ALSA: module_para...
60
  static bool enable;
8a3fb4d0c   Takashi Iwai   [ALSA] Remove mul...
61
  module_param(enable, bool, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
  /*
   *  Debug part definitions
   */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
65
  /* #define ALI_DEBUG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  
  #ifdef ALI_DEBUG
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
68
  #define snd_ali_printk(format, args...) printk(KERN_DEBUG format, ##args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
  #else
  #define snd_ali_printk(format, args...)
  #endif
  
  /*
   *  Constants definition
   */
8cdfd2519   Takashi Iwai   [ALSA] Remove sup...
76
  #define DEVICE_ID_ALI5451	((PCI_VENDOR_ID_AL<<16)|PCI_DEVICE_ID_AL_M5451)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
  
  
  #define ALI_CHANNELS		32
  
  #define ALI_PCM_IN_CHANNEL	31
  #define ALI_SPDIF_IN_CHANNEL	19
  #define ALI_SPDIF_OUT_CHANNEL	15
  #define ALI_CENTER_CHANNEL	24
  #define ALI_LEF_CHANNEL		23
  #define ALI_SURR_LEFT_CHANNEL	26
  #define ALI_SURR_RIGHT_CHANNEL	25
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
88
89
  #define ALI_MODEM_IN_CHANNEL    21
  #define ALI_MODEM_OUT_CHANNEL   20
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
  
  #define	SNDRV_ALI_VOICE_TYPE_PCM	01
  #define SNDRV_ALI_VOICE_TYPE_OTH	02
  
  #define	ALI_5451_V02		0x02
  
  /*
   *  Direct Registers
   */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
99
100
101
102
  #define ALI_LEGACY_DMAR0        0x00  /* ADR0 */
  #define ALI_LEGACY_DMAR4        0x04  /* CNT0 */
  #define ALI_LEGACY_DMAR11       0x0b  /* MOD  */
  #define ALI_LEGACY_DMAR15       0x0f  /* MMR  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
111
112
  #define ALI_MPUR0		0x20
  #define ALI_MPUR1		0x21
  #define ALI_MPUR2		0x22
  #define ALI_MPUR3		0x23
  
  #define	ALI_AC97_WRITE		0x40
  #define ALI_AC97_READ		0x44
  
  #define ALI_SCTRL		0x48
  #define   ALI_SPDIF_OUT_ENABLE		0x20
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
113
114
115
116
117
118
  #define   ALI_SCTRL_LINE_IN2		(1 << 9)
  #define   ALI_SCTRL_GPIO_IN2		(1 << 13)
  #define   ALI_SCTRL_LINE_OUT_EN 	(1 << 20)
  #define   ALI_SCTRL_GPIO_OUT_EN 	(1 << 23)
  #define   ALI_SCTRL_CODEC1_READY	(1 << 24)
  #define   ALI_SCTRL_CODEC2_READY	(1 << 25)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  #define ALI_AC97_GPIO		0x4c
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
120
121
  #define   ALI_AC97_GPIO_ENABLE		0x8000
  #define   ALI_AC97_GPIO_DATA_SHIFT	16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  #define ALI_SPDIF_CS		0x70
  #define ALI_SPDIF_CTRL		0x74
  #define   ALI_SPDIF_IN_FUNC_ENABLE	0x02
  #define   ALI_SPDIF_IN_CH_STATUS	0x40
  #define   ALI_SPDIF_OUT_CH_STATUS	0xbf
  #define ALI_START		0x80
  #define ALI_STOP		0x84
  #define ALI_CSPF		0x90
  #define ALI_AINT		0x98
  #define ALI_GC_CIR		0xa0
  	#define ENDLP_IE		0x00001000
  	#define MIDLP_IE		0x00002000
  #define ALI_AINTEN		0xa4
  #define ALI_VOLUME		0xa8
  #define ALI_SBDELTA_DELTA_R     0xac
  #define ALI_MISCINT		0xb0
  	#define ADDRESS_IRQ		0x00000020
  	#define TARGET_REACHED		0x00008000
  	#define MIXER_OVERFLOW		0x00000800
  	#define MIXER_UNDERFLOW		0x00000400
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
142
  	#define GPIO_IRQ		0x01000000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  #define ALI_SBBL_SBCL           0xc0
  #define ALI_SBCTRL_SBE2R_SBDD   0xc4
  #define ALI_STIMER		0xc8
  #define ALI_GLOBAL_CONTROL	0xd4
  #define   ALI_SPDIF_OUT_SEL_PCM		0x00000400 /* bit 10 */
  #define   ALI_SPDIF_IN_SUPPORT		0x00000800 /* bit 11 */
  #define   ALI_SPDIF_OUT_CH_ENABLE	0x00008000 /* bit 15 */
  #define   ALI_SPDIF_IN_CH_ENABLE	0x00080000 /* bit 19 */
  #define   ALI_PCM_IN_ENABLE		0x80000000 /* bit 31 */
  
  #define ALI_CSO_ALPHA_FMS	0xe0
  #define ALI_LBA			0xe4
  #define ALI_ESO_DELTA		0xe8
  #define ALI_GVSEL_PAN_VOC_CTRL_EC	0xf0
  #define ALI_EBUF1		0xf4
  #define ALI_EBUF2		0xf8
  
  #define ALI_REG(codec, x) ((codec)->port + x)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
161
  #define MAX_CODECS 2
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
162
163
  struct snd_ali;
  struct snd_ali_voice;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
165
  struct snd_ali_channel_control {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
166
  	/* register data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
  	struct REGDATA {
  		unsigned int start;
  		unsigned int stop;
  		unsigned int aint;
  		unsigned int ainten;
  	} data;
  		
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
174
  	/* register addresses */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
  	struct REGS {
  		unsigned int start;
  		unsigned int stop;
  		unsigned int aint;
  		unsigned int ainten;
  		unsigned int ac97read;
  		unsigned int ac97write;
  	} regs;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
183
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
185
  struct snd_ali_voice {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  	unsigned int number;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
187
188
189
190
191
192
  	unsigned int use :1,
  		pcm :1,
  		midi :1,
  		mode :1,
  		synth :1,
  		running :1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  
  	/* PCM data */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
195
196
197
  	struct snd_ali *codec;
  	struct snd_pcm_substream *substream;
  	struct snd_ali_voice *extra;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
205
206
  	int eso;                /* final ESO value for channel */
  	int count;              /* runtime->period_size */
  
  	/* --- */
  
  	void *private_data;
  	void (*private_free)(void *private_data);
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
207
  struct snd_alidev {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
209
  	struct snd_ali_voice voices[ALI_CHANNELS];	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  
  	unsigned int	chcnt;			/* num of opened channels */
  	unsigned int	chmap;			/* bitmap for opened channels */
  	unsigned int synthcount;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
214
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  #define ALI_GLOBAL_REGS		56
  #define ALI_CHANNEL_REGS	8
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
218
  struct snd_ali_image {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
219
220
  	u32 regs[ALI_GLOBAL_REGS];
  	u32 channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
221
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222

d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
223
  struct snd_ali {
ba8c3c37d   Takashi Iwai   [ALSA] ali5451 - ...
224
  	int		irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  	unsigned long	port;
  	unsigned char	revision;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
227
228
  	unsigned int hw_initialized :1;
  	unsigned int spdif_support :1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  
  	struct pci_dev	*pci;
  	struct pci_dev	*pci_m1533;
  	struct pci_dev	*pci_m7101;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
233
234
235
236
  	struct snd_card	*card;
  	struct snd_pcm	*pcm[MAX_CODECS];
  	struct snd_alidev	synth;
  	struct snd_ali_channel_control chregs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
  
  	/* S/PDIF Mask */
  	unsigned int	spdif_mask;
  
  	unsigned int spurious_irq_count;
  	unsigned int spurious_irq_max_delta;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
243
  	unsigned int num_of_codecs;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
244
245
  	struct snd_ac97_bus *ac97_bus;
  	struct snd_ac97 *ac97[MAX_CODECS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
251
252
  	unsigned short	ac97_ext_id;
  	unsigned short	ac97_ext_status;
  
  	spinlock_t	reg_lock;
  	spinlock_t	voice_alloc;
  
  #ifdef CONFIG_PM
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
253
  	struct snd_ali_image *image;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  #endif
  };
cebe41d4b   Alexey Dobriyan   sound: use DEFINE...
256
  static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = {
ec6c8c3b2   Jon Mason   [ALSA] ali5451: A...
257
  	{PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
  	{0, }
  };
  MODULE_DEVICE_TABLE(pci, snd_ali_ids);
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
261
262
  static void snd_ali_clear_voices(struct snd_ali *, unsigned int, unsigned int);
  static unsigned short snd_ali_codec_peek(struct snd_ali *, int, unsigned short);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
263
264
  static void snd_ali_codec_poke(struct snd_ali *, int, unsigned short,
  			       unsigned short);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
  
  /*
   *  AC97 ACCESS
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
269
  static inline unsigned int snd_ali_5451_peek(struct snd_ali *codec,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
270
  					     unsigned int port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
  {
  	return (unsigned int)inl(ALI_REG(codec, port)); 
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
274
275
276
  static inline void snd_ali_5451_poke(struct snd_ali *codec,
  				     unsigned int port,
  				     unsigned int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
  {
  	outl((unsigned int)val, ALI_REG(codec, port));
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
280
281
  static int snd_ali_codec_ready(struct snd_ali *codec,
  			       unsigned int port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
  {
  	unsigned long end_time;
  	unsigned int res;
  	
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
286
  	end_time = jiffies + msecs_to_jiffies(250);
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
287
288
  
  	for (;;) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  		res = snd_ali_5451_peek(codec,port);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
290
  		if (!(res & 0x8000))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  			return 0;
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
292
293
  		if (!time_after_eq(end_time, jiffies))
  			break;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
294
  		schedule_timeout_uninterruptible(1);
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
295
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
  	snd_ali_5451_poke(codec, port, res & ~0x8000);
  	snd_printdd("ali_codec_ready: codec is not ready.
   ");
  	return -EIO;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
301
  static int snd_ali_stimer_ready(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
  {
  	unsigned long end_time;
  	unsigned long dwChk1,dwChk2;
  	
  	dwChk1 = snd_ali_5451_peek(codec, ALI_STIMER);
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
307
  	end_time = jiffies + msecs_to_jiffies(250);
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
308
309
  
  	for (;;) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
  		dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);
  		if (dwChk2 != dwChk1)
  			return 0;
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
313
314
  		if (!time_after_eq(end_time, jiffies))
  			break;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
315
  		schedule_timeout_uninterruptible(1);
70bdbd3d1   Bartlomiej Zolnierkiewicz   ALSA: ali5451: fi...
316
  	}
99b359ba1   Takashi Iwai   [ALSA] Add missin...
317
318
  	snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	return -EIO;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
321
  static void snd_ali_codec_poke(struct snd_ali *codec,int secondary,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
322
323
  			       unsigned short reg,
  			       unsigned short val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
325
326
  	unsigned int dwVal;
  	unsigned int port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  
  	if (reg >= 0x80) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
329
330
  		snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.
  ", reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
  		return;
  	}
  
  	port = codec->chregs.regs.ac97write;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
335
  	if (snd_ali_codec_ready(codec, port) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  		return;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
337
  	if (snd_ali_stimer_ready(codec) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
  		return;
  
  	dwVal  = (unsigned int) (reg & 0xff);
  	dwVal |= 0x8000 | (val << 16);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
342
343
344
345
  	if (secondary)
  		dwVal |= 0x0080;
  	if (codec->revision == ALI_5451_V02)
  		dwVal |= 0x0100;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
347
  	snd_ali_5451_poke(codec, port, dwVal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
  
  	return ;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
351
352
353
  static unsigned short snd_ali_codec_peek(struct snd_ali *codec,
  					 int secondary,
  					 unsigned short reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
355
356
  	unsigned int dwVal;
  	unsigned int port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  
  	if (reg >= 0x80) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
359
360
  		snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.
  ", reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
  		return ~0;
  	}
  
  	port = codec->chregs.regs.ac97read;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
365
  	if (snd_ali_codec_ready(codec, port) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  		return ~0;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
367
  	if (snd_ali_stimer_ready(codec) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
  		return ~0;
  
  	dwVal  = (unsigned int) (reg & 0xff);
  	dwVal |= 0x8000;				/* bit 15*/
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
372
373
  	if (secondary)
  		dwVal |= 0x0080;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  
  	snd_ali_5451_poke(codec, port, dwVal);
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
376
  	if (snd_ali_stimer_ready(codec) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  		return ~0;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
378
  	if (snd_ali_codec_ready(codec, port) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
  		return ~0;
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
381
  	return (snd_ali_5451_peek(codec, port) & 0xffff0000) >> 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
383
  static void snd_ali_codec_write(struct snd_ac97 *ac97,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
  				unsigned short reg,
  				unsigned short val )
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
387
  	struct snd_ali *codec = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
  
  	snd_ali_printk("codec_write: reg=%xh data=%xh.
  ", reg, val);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
391
392
393
  	if (reg == AC97_GPIO_STATUS) {
  		outl((val << ALI_AC97_GPIO_DATA_SHIFT) | ALI_AC97_GPIO_ENABLE,
  		     ALI_REG(codec, ALI_AC97_GPIO));
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
394
395
396
  		return;
  	}
  	snd_ali_codec_poke(codec, ac97->num, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  	return ;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
399
400
  static unsigned short snd_ali_codec_read(struct snd_ac97 *ac97,
  					 unsigned short reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
402
  	struct snd_ali *codec = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
  
  	snd_ali_printk("codec_read reg=%xh.
  ", reg);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
406
  	return snd_ali_codec_peek(codec, ac97->num, reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
  }
  
  /*
   *	AC97 Reset
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
412
  static int snd_ali_reset_5451(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
414
  	struct pci_dev *pci_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
  	unsigned short wCount, wReg;
  	unsigned int   dwVal;
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
418
419
  	pci_dev = codec->pci_m1533;
  	if (pci_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  		pci_read_config_dword(pci_dev, 0x7c, &dwVal);
  		pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000);
  		udelay(5000);
  		pci_read_config_dword(pci_dev, 0x7c, &dwVal);
  		pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);
  		udelay(5000);
  	}
  	
  	pci_dev = codec->pci;
  	pci_read_config_dword(pci_dev, 0x44, &dwVal);
  	pci_write_config_dword(pci_dev, 0x44, dwVal | 0x000c0000);
  	udelay(500);
  	pci_read_config_dword(pci_dev, 0x44, &dwVal);
  	pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);
  	udelay(5000);
  	
  	wCount = 200;
  	while(wCount--) {
  		wReg = snd_ali_codec_peek(codec, 0, AC97_POWERDOWN);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
439
  		if ((wReg & 0x000f) == 0x000f)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
443
444
445
446
447
448
  			return 0;
  		udelay(5000);
  	}
  
  	/* non-fatal if you have a non PM capable codec */
  	/* snd_printk(KERN_WARNING "ali5451: reset time out
  "); */
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
  /*
   *  ALI 5451 Controller
   */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
452
453
  static void snd_ali_enable_special_channel(struct snd_ali *codec,
  					   unsigned int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
455
  	unsigned long dwVal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
457
  	dwVal  = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  	dwVal |= 1 << (channel & 0x0000001f);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
459
  	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
461
462
  static void snd_ali_disable_special_channel(struct snd_ali *codec,
  					    unsigned int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
464
  	unsigned long dwVal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
466
  	dwVal  = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  	dwVal &= ~(1 << (channel & 0x0000001f));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
468
  	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
470
  static void snd_ali_enable_address_interrupt(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
  {
  	unsigned int gc;
  
  	gc  = inl(ALI_REG(codec, ALI_GC_CIR));
  	gc |= ENDLP_IE;
  	gc |= MIDLP_IE;
  	outl( gc, ALI_REG(codec, ALI_GC_CIR));
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
479
  static void snd_ali_disable_address_interrupt(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
485
486
487
  {
  	unsigned int gc;
  
  	gc  = inl(ALI_REG(codec, ALI_GC_CIR));
  	gc &= ~ENDLP_IE;
  	gc &= ~MIDLP_IE;
  	outl(gc, ALI_REG(codec, ALI_GC_CIR));
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
488
489
  static void snd_ali_disable_voice_irq(struct snd_ali *codec,
  				      unsigned int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  {
  	unsigned int mask;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
492
  	struct snd_ali_channel_control *pchregs = &(codec->chregs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
  
  	snd_ali_printk("disable_voice_irq channel=%d
  ",channel);
  
  	mask = 1 << (channel & 0x1f);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
498
  	pchregs->data.ainten  = inl(ALI_REG(codec, pchregs->regs.ainten));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  	pchregs->data.ainten &= ~mask;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
500
  	outl(pchregs->data.ainten, ALI_REG(codec, pchregs->regs.ainten));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
502
  static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
  {
  	unsigned int idx =  channel & 0x1f;
  
  	if (codec->synth.chcnt >= ALI_CHANNELS){
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
507
508
509
  		snd_printk(KERN_ERR
  			   "ali_alloc_pcm_channel: no free channels.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
515
516
517
518
519
520
521
  		return -1;
  	}
  
  	if (!(codec->synth.chmap & (1 << idx))) {
  		codec->synth.chmap |= 1 << idx;
  		codec->synth.chcnt++;
  		snd_ali_printk("alloc_pcm_channel no. %d.
  ",idx);
  		return idx;
  	}
  	return -1;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
522
  static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
  {
  	int idx;
  	int result = -1;
  
  	snd_ali_printk("find_free_channel: for %s
  ",rec ? "rec" : "pcm");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
529
  	/* recording */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  	if (rec) {
  		if (codec->spdif_support &&
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
532
533
  		    (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) &
  		     ALI_SPDIF_IN_SUPPORT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
  			idx = ALI_SPDIF_IN_CHANNEL;
  		else
  			idx = ALI_PCM_IN_CHANNEL;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
537
538
  		result = snd_ali_alloc_pcm_channel(codec, idx);
  		if (result >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  			return result;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
540
541
542
543
  		else {
  			snd_printk(KERN_ERR "ali_find_free_channel: "
  				   "record channel is busy now.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
  			return -1;
  		}
  	}
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
547
  	/* playback... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	if (codec->spdif_support &&
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
549
550
  	    (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) &
  	     ALI_SPDIF_OUT_CH_ENABLE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  		idx = ALI_SPDIF_OUT_CHANNEL;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
552
553
  		result = snd_ali_alloc_pcm_channel(codec, idx);
  		if (result >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  			return result;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
555
556
557
558
  		else
  			snd_printk(KERN_ERR "ali_find_free_channel: "
  				   "S/PDIF out channel is in busy now.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
  	}
  
  	for (idx = 0; idx < ALI_CHANNELS; idx++) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
562
563
  		result = snd_ali_alloc_pcm_channel(codec, idx);
  		if (result >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
  			return result;
  	}
99b359ba1   Takashi Iwai   [ALSA] Add missin...
566
567
  	snd_printk(KERN_ERR "ali_find_free_channel: no free channels.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	return -1;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
570
  static void snd_ali_free_channel_pcm(struct snd_ali *codec, int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
578
579
580
  {
  	unsigned int idx = channel & 0x0000001f;
  
  	snd_ali_printk("free_channel_pcm channel=%d
  ",channel);
  
  	if (channel < 0 || channel >= ALI_CHANNELS)
  		return;
  
  	if (!(codec->synth.chmap & (1 << idx))) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
581
582
583
  		snd_printk(KERN_ERR "ali_free_channel_pcm: "
  			   "channel %d is not in use.
  ", channel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
589
  		return;
  	} else {
  		codec->synth.chmap &= ~(1 << idx);
  		codec->synth.chcnt--;
  	}
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
590
  static void snd_ali_stop_voice(struct snd_ali *codec, unsigned int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
599
600
601
  {
  	unsigned int mask = 1 << (channel & 0x1f);
  
  	snd_ali_printk("stop_voice: channel=%d
  ",channel);
  	outl(mask, ALI_REG(codec, codec->chregs.regs.stop));
  }
  
  /*
   *    S/PDIF Part
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
602
  static void snd_ali_delay(struct snd_ali *codec,int interval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
  {
  	unsigned long  begintimer,currenttimer;
  
  	begintimer   = inl(ALI_REG(codec, ALI_STIMER));
  	currenttimer = inl(ALI_REG(codec, ALI_STIMER));
  
  	while (currenttimer < begintimer + interval) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
610
  		if (snd_ali_stimer_ready(codec) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
  			break;
  		currenttimer = inl(ALI_REG(codec,  ALI_STIMER));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
613
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  	}
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
616
  static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
618
  	u16 wval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  	u16 count = 0;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
620
  	u8  bval, R1 = 0, R2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
622
  	bval  = inb(ALI_REG(codec, ALI_SPDIF_CTRL + 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  	bval |= 0x1F;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
624
  	outb(bval, ALI_REG(codec, ALI_SPDIF_CTRL + 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
626
  	while ((R1 < 0x0b || R1 > 0x0e) && R1 != 0x12 && count <= 50000) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
  		count ++;
  		snd_ali_delay(codec, 6);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
629
  		bval = inb(ALI_REG(codec, ALI_SPDIF_CTRL + 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
  		R1 = bval & 0x1F;
  	}
  
  	if (count > 50000) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
634
635
  		snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  		return;
  	}
1c3973240   Andrew Morton   [ALSA] ali5451 wa...
638
  	for (count = 0; count <= 50000; count++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
641
  		snd_ali_delay(codec, 6);
  		bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));
  		R2 = bval & 0x1F;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
642
643
644
645
  		if (R2 != R1)
  			R1 = R2;
  		else
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  	}
  
  	if (count > 50000) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
649
650
  		snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
  		return;
  	}
  
  	if (R2 >= 0x0b && R2 <= 0x0e) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
655
656
657
658
  		wval  = inw(ALI_REG(codec, ALI_SPDIF_CTRL + 2));
  		wval &= 0xe0f0;
  		wval |= (0x09 << 8) | 0x05;
  		outw(wval, ALI_REG(codec, ALI_SPDIF_CTRL + 2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
660
661
  		bval  = inb(ALI_REG(codec, ALI_SPDIF_CS + 3)) & 0xf0;
  		outb(bval | 0x02, ALI_REG(codec, ALI_SPDIF_CS + 3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	} else if (R2 == 0x12) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
663
664
665
666
  		wval  = inw(ALI_REG(codec, ALI_SPDIF_CTRL + 2));
  		wval &= 0xe0f0;
  		wval |= (0x0e << 8) | 0x08;
  		outw(wval, ALI_REG(codec, ALI_SPDIF_CTRL + 2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
668
669
  		bval  = inb(ALI_REG(codec,ALI_SPDIF_CS + 3)) & 0xf0;
  		outb(bval | 0x03, ALI_REG(codec, ALI_SPDIF_CS + 3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
  	}
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
672
  static unsigned int snd_ali_get_spdif_in_rate(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
674
675
  	u32	dwRate;
  	u8	bval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
677
678
  	bval  = inb(ALI_REG(codec, ALI_SPDIF_CTRL));
  	bval &= 0x7f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  	bval |= 0x40;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
680
  	outb(bval, ALI_REG(codec, ALI_SPDIF_CTRL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
  
  	snd_ali_detect_spdif_rate(codec);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
683
684
  	bval  = inb(ALI_REG(codec, ALI_SPDIF_CS + 3));
  	bval &= 0x0f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
686
687
688
689
690
691
  	switch (bval) {
  	case 0: dwRate = 44100; break;
  	case 1: dwRate = 48000; break;
  	case 2: dwRate = 32000; break;
  	default: dwRate = 0; break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
  
  	return dwRate;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
695
  static void snd_ali_enable_spdif_in(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
707
708
  {	
  	unsigned int dwVal;
  
  	dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	dwVal |= ALI_SPDIF_IN_SUPPORT;
  	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  
  	dwVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL));
  	dwVal |= 0x02;
  	outb(dwVal, ALI_REG(codec, ALI_SPDIF_CTRL));
  
  	snd_ali_enable_special_channel(codec, ALI_SPDIF_IN_CHANNEL);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
709
  static void snd_ali_disable_spdif_in(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
715
716
717
718
  {
  	unsigned int dwVal;
  	
  	dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	dwVal &= ~ALI_SPDIF_IN_SUPPORT;
  	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	
  	snd_ali_disable_special_channel(codec, ALI_SPDIF_IN_CHANNEL);	
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
719
  static void snd_ali_set_spdif_out_rate(struct snd_ali *codec, unsigned int rate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
  {
  	unsigned char  bVal;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
722
  	unsigned int  dwRate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
724
725
726
727
728
  	switch (rate) {
  	case 32000: dwRate = 0x300; break;
  	case 48000: dwRate = 0x200; break;
  	default: dwRate = 0; break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
731
732
  	
  	bVal  = inb(ALI_REG(codec, ALI_SPDIF_CTRL));
  	bVal &= (unsigned char)(~(1<<6));
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
733
  	bVal |= 0x80;		/* select right */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
  	outb(bVal, ALI_REG(codec, ALI_SPDIF_CTRL));
  	outb(dwRate | 0x20, ALI_REG(codec, ALI_SPDIF_CS + 2));
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
737
  	bVal &= ~0x80;	/* select left */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
  	outb(bVal, ALI_REG(codec, ALI_SPDIF_CTRL));
  	outw(rate | 0x10, ALI_REG(codec, ALI_SPDIF_CS + 2));
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
741
  static void snd_ali_enable_spdif_out(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
  {
  	unsigned short wVal;
  	unsigned char bVal;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
745
          struct pci_dev *pci_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  
          pci_dev = codec->pci_m1533;
          if (pci_dev == NULL)
                  return;
          pci_read_config_byte(pci_dev, 0x61, &bVal);
          bVal |= 0x40;
          pci_write_config_byte(pci_dev, 0x61, bVal);
          pci_read_config_byte(pci_dev, 0x7d, &bVal);
          bVal |= 0x01;
          pci_write_config_byte(pci_dev, 0x7d, bVal);
  
          pci_read_config_byte(pci_dev, 0x7e, &bVal);
          bVal &= (~0x20);
          bVal |= 0x10;
          pci_write_config_byte(pci_dev, 0x7e, bVal);
  
  	bVal = inb(ALI_REG(codec, ALI_SCTRL));
  	outb(bVal | ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL));
  
  	bVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL));
  	outb(bVal & ALI_SPDIF_OUT_CH_STATUS, ALI_REG(codec, ALI_SPDIF_CTRL));
     
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
768
769
770
771
  	wVal = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	wVal |= ALI_SPDIF_OUT_SEL_PCM;
  	outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	snd_ali_disable_special_channel(codec, ALI_SPDIF_OUT_CHANNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
773
  static void snd_ali_enable_spdif_chnout(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
775
  	unsigned short wVal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
780
781
782
783
784
785
786
787
  
  	wVal  = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));
     	wVal &= ~ALI_SPDIF_OUT_SEL_PCM;
     	outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  /*
  	wVal = inw(ALI_REG(codec, ALI_SPDIF_CS));
  	if (flag & ALI_SPDIF_OUT_NON_PCM)
     		wVal |= 0x0002;
  	else	
  		wVal &= (~0x0002);
     	outw(wVal, ALI_REG(codec, ALI_SPDIF_CS));
  */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
788
  	snd_ali_enable_special_channel(codec, ALI_SPDIF_OUT_CHANNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
790
  static void snd_ali_disable_spdif_chnout(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
792
  	unsigned short wVal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
794
795
796
797
798
    	wVal  = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));
     	wVal |= ALI_SPDIF_OUT_SEL_PCM;
     	outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  
  	snd_ali_enable_special_channel(codec, ALI_SPDIF_OUT_CHANNEL);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
799
  static void snd_ali_disable_spdif_out(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
804
805
806
807
  {
  	unsigned char  bVal;
  
  	bVal = inb(ALI_REG(codec, ALI_SCTRL));
  	outb(bVal & ~ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL));
  
  	snd_ali_disable_spdif_chnout(codec);
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
808
  static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
810
  	struct snd_ali_voice *pvoice;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
811
  	struct snd_pcm_runtime *runtime;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
812
  	struct snd_ali_channel_control *pchregs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
818
  	unsigned int old, mask;
  #ifdef ALI_DEBUG
  	unsigned int temp, cspf;
  #endif
  
  	pchregs = &(codec->chregs);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
819
  	/* check if interrupt occurred for channel */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
  	old  = pchregs->data.aint;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
821
  	mask = 1U << (channel & 0x1f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  
  	if (!(old & mask))
  		return;
  
  	pvoice = &codec->synth.voices[channel];
  	runtime = pvoice->substream->runtime;
  
  	udelay(100);
  	spin_lock(&codec->reg_lock);
  
  	if (pvoice->pcm && pvoice->substream) {
  		/* pcm interrupt */
  #ifdef ALI_DEBUG
  		outb((u8)(pvoice->number), ALI_REG(codec, ALI_GC_CIR));
  		temp = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
  		cspf = (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask;
  #endif
  		if (pvoice->running) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
840
841
842
  			snd_ali_printk("update_ptr: cso=%4.4x cspf=%d.
  ",
  				       (u16)temp, cspf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
  			spin_unlock(&codec->reg_lock);
  			snd_pcm_period_elapsed(pvoice->substream);
  			spin_lock(&codec->reg_lock);
  		} else {
  			snd_ali_stop_voice(codec, channel);
  			snd_ali_disable_voice_irq(codec, channel);
  		}	
  	} else if (codec->synth.voices[channel].synth) {
  		/* synth interrupt */
  	} else if (codec->synth.voices[channel].midi) {
  		/* midi interrupt */
  	} else {
  		/* unknown interrupt */
  		snd_ali_stop_voice(codec, channel);
  		snd_ali_disable_voice_irq(codec, channel);
  	}
  	spin_unlock(&codec->reg_lock);
  	outl(mask,ALI_REG(codec,pchregs->regs.aint));
  	pchregs->data.aint = old & (~mask);
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
863
  static irqreturn_t snd_ali_card_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
865
  	struct snd_ali 	*codec = dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
  	int channel;
  	unsigned int audio_int;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
868
869
870
871
  	struct snd_ali_channel_control *pchregs;
  
  	if (codec == NULL || !codec->hw_initialized)
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
  
  	audio_int = inl(ALI_REG(codec, ALI_MISCINT));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
874
875
876
877
  	if (!audio_int)
  		return IRQ_NONE;
  
  	pchregs = &(codec->chregs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	if (audio_int & ADDRESS_IRQ) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
879
880
881
  		/* get interrupt status for all channels */
  		pchregs->data.aint = inl(ALI_REG(codec, pchregs->regs.aint));
  		for (channel = 0; channel < ALI_CHANNELS; channel++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  			snd_ali_update_ptr(codec, channel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  	}
  	outl((TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
885
  		ALI_REG(codec, ALI_MISCINT));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
  	return IRQ_HANDLED;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
889
890
  static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec,
  						 int type, int rec, int channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
892
  	struct snd_ali_voice *pvoice;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  	int idx;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
894
895
  	snd_ali_printk("alloc_voice: type=%d rec=%d
  ", type, rec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896

755e13713   Takashi Iwai   [ALSA] ali5451 - ...
897
  	spin_lock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  	if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
899
900
  		idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
  			snd_ali_find_free_channel(codec,rec);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
901
  		if (idx < 0) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
902
903
  			snd_printk(KERN_ERR "ali_alloc_voice: err.
  ");
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
904
  			spin_unlock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
  			return NULL;
  		}
  		pvoice = &(codec->synth.voices[idx]);
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
908
  		pvoice->codec = codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
  		pvoice->use = 1;
  		pvoice->pcm = 1;
  		pvoice->mode = rec;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
912
  		spin_unlock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
  		return pvoice;
  	}
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
915
  	spin_unlock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
  	return NULL;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
918
919
  static void snd_ali_free_voice(struct snd_ali * codec,
  			       struct snd_ali_voice *pvoice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
  	void (*private_free)(void *);
  	void *private_data;
  
  	snd_ali_printk("free_voice: channel=%d
  ",pvoice->number);
4b3be6afa   Julia Lawall   ALSA: sound: Move...
926
  	if (!pvoice->use)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
  		return;
  	snd_ali_clear_voices(codec, pvoice->number, pvoice->number);
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
929
  	spin_lock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
933
  	private_free = pvoice->private_free;
  	private_data = pvoice->private_data;
  	pvoice->private_free = NULL;
  	pvoice->private_data = NULL;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
934
  	if (pvoice->pcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  		snd_ali_free_channel_pcm(codec, pvoice->number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  	pvoice->use = pvoice->pcm = pvoice->synth = 0;
  	pvoice->substream = NULL;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
938
  	spin_unlock_irq(&codec->voice_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
  	if (private_free)
  		private_free(private_data);
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
942
943
944
  static void snd_ali_clear_voices(struct snd_ali *codec,
  				 unsigned int v_min,
  				 unsigned int v_max)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
950
951
952
  {
  	unsigned int i;
  
  	for (i = v_min; i <= v_max; i++) {
  		snd_ali_stop_voice(codec, i);
  		snd_ali_disable_voice_irq(codec, i);
  	}
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
953
  static void snd_ali_write_voice_regs(struct snd_ali *codec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  			 unsigned int Channel,
  			 unsigned int LBA,
  			 unsigned int CSO,
  			 unsigned int ESO,
  			 unsigned int DELTA,
  			 unsigned int ALPHA_FMS,
  			 unsigned int GVSEL,
  			 unsigned int PAN,
  			 unsigned int VOL,
  			 unsigned int CTRL,
  			 unsigned int EC)
  {
  	unsigned int ctlcmds[4];
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
968
  	outb((unsigned char)(Channel & 0x001f), ALI_REG(codec, ALI_GC_CIR));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
  
  	ctlcmds[0] =  (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
  	ctlcmds[1] =  LBA;
  	ctlcmds[2] =  (ESO << 16) | (DELTA & 0x0ffff);
  	ctlcmds[3] =  (GVSEL << 31) |
  		      ((PAN & 0x0000007f) << 24) |
  		      ((VOL & 0x000000ff) << 16) |
  		      ((CTRL & 0x0000000f) << 12) |
  		      (EC & 0x00000fff);
  
  	outb(Channel, ALI_REG(codec, ALI_GC_CIR));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
980
981
982
983
  	outl(ctlcmds[0], ALI_REG(codec, ALI_CSO_ALPHA_FMS));
  	outl(ctlcmds[1], ALI_REG(codec, ALI_LBA));
  	outl(ctlcmds[2], ALI_REG(codec, ALI_ESO_DELTA));
  	outl(ctlcmds[3], ALI_REG(codec, ALI_GVSEL_PAN_VOC_CTRL_EC));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
987
988
989
990
991
  
  	outl(0x30000000, ALI_REG(codec, ALI_EBUF1));	/* Still Mode */
  	outl(0x30000000, ALI_REG(codec, ALI_EBUF2));	/* Still Mode */
  }
  
  static unsigned int snd_ali_convert_rate(unsigned int rate, int rec)
  {
  	unsigned int delta;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
992
993
994
995
  	if (rate < 4000)
  		rate = 4000;
  	if (rate > 48000)
  		rate = 48000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  
  	if (rec) {
  		if (rate == 44100)
  			delta = 0x116a;
  		else if (rate == 8000)
  			delta = 0x6000;
  		else if (rate == 48000)
  			delta = 0x1000;
  		else
  			delta = ((48000 << 12) / rate) & 0x0000ffff;
  	} else {
  		if (rate == 44100)
  			delta = 0xeb3;
  		else if (rate == 8000)
  			delta = 0x2ab;
  		else if (rate == 48000)
  			delta = 0x1000;
  		else 
  			delta = (((rate << 12) + rate) / 48000) & 0x0000ffff;
  	}
  
  	return delta;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1019
  static unsigned int snd_ali_control_mode(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  {
  	unsigned int CTRL;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1022
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
1027
1028
  
  	/* set ctrl mode
  	   CTRL default: 8-bit (unsigned) mono, loop mode enabled
  	 */
  	CTRL = 0x00000001;
  	if (snd_pcm_format_width(runtime->format) == 16)
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1029
  		CTRL |= 0x00000008;	/* 16-bit data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  	if (!snd_pcm_format_unsigned(runtime->format))
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1031
  		CTRL |= 0x00000002;	/* signed data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
  	if (runtime->channels > 1)
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1033
  		CTRL |= 0x00000004;	/* stereo data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
  	return CTRL;
  }
  
  /*
   *  PCM part
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1040
  static int snd_ali_trigger(struct snd_pcm_substream *substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
  			       int cmd)
  				    
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1044
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1045
  	struct snd_pcm_substream *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
  	unsigned int what, whati, capture_flag;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1047
  	struct snd_ali_voice *pvoice, *evoice;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
1052
1053
  	unsigned int val;
  	int do_start;
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1054
1055
  		do_start = 1;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1058
1059
  		do_start = 0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
  	default:
  		return -EINVAL;
  	}
  
  	what = whati = capture_flag = 0;
ef991b95a   Takashi Iwai   [ALSA] Add snd_pc...
1065
  	snd_pcm_group_for_each_entry(s, substream) {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1066
1067
  		if ((struct snd_ali *) snd_pcm_substream_chip(s) == codec) {
  			pvoice = s->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
1069
  			evoice = pvoice->extra;
  			what |= 1 << (pvoice->number & 0x1f);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1070
  			if (evoice == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  				whati |= 1 << (pvoice->number & 0x1f);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1072
  			else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  				whati |= 1 << (evoice->number & 0x1f);
  				what |= 1 << (evoice->number & 0x1f);
  			}
  			if (do_start) {
  				pvoice->running = 1;
  				if (evoice != NULL)
  					evoice->running = 1;
  			} else {
  				pvoice->running = 0;
  				if (evoice != NULL)
  					evoice->running = 0;
  			}
  			snd_pcm_trigger_done(s, substream);
  			if (pvoice->mode)
  				capture_flag = 1;
  		}
  	}
  	spin_lock(&codec->reg_lock);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1091
  	if (!do_start)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  		outl(what, ALI_REG(codec, ALI_STOP));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  	val = inl(ALI_REG(codec, ALI_AINTEN));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1094
  	if (do_start)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  		val |= whati;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1096
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  		val &= ~whati;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
  	outl(val, ALI_REG(codec, ALI_AINTEN));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1099
  	if (do_start)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  		outl(what, ALI_REG(codec, ALI_START));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1101
1102
  	snd_ali_printk("trigger: what=%xh whati=%xh
  ", what, whati);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
1105
1106
  	spin_unlock(&codec->reg_lock);
  
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1107
  static int snd_ali_playback_hw_params(struct snd_pcm_substream *substream,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1108
  				      struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1110
1111
1112
1113
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
  	struct snd_ali_voice *evoice = pvoice->extra;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  	int err;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1115
1116
1117
1118
1119
  
  	err = snd_pcm_lib_malloc_pages(substream,
  				       params_buffer_bytes(hw_params));
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
1121
  	
  	/* voice management */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1122
1123
1124
1125
1126
1127
1128
  	if (params_buffer_size(hw_params) / 2 !=
  	    params_period_size(hw_params)) {
  		if (!evoice) {
  			evoice = snd_ali_alloc_voice(codec,
  						     SNDRV_ALI_VOICE_TYPE_PCM,
  						     0, -1);
  			if (!evoice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
1133
  				return -ENOMEM;
  			pvoice->extra = evoice;
  			evoice->substream = substream;
  		}
  	} else {
270436424   Takashi Iwai   [ALSA] ali5451 - ...
1134
  		if (evoice) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
1138
1139
1140
1141
  			snd_ali_free_voice(codec, evoice);
  			pvoice->extra = evoice = NULL;
  		}
  	}
  
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1142
  static int snd_ali_playback_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1144
1145
1146
1147
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
  	struct snd_ali_voice *evoice = pvoice ? pvoice->extra : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
  
  	snd_pcm_lib_free_pages(substream);
270436424   Takashi Iwai   [ALSA] ali5451 - ...
1150
  	if (evoice) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
1153
1154
1155
  		snd_ali_free_voice(codec, evoice);
  		pvoice->extra = NULL;
  	}
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1156
  static int snd_ali_hw_params(struct snd_pcm_substream *substream,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1157
  			     struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1159
1160
  	return snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1162
  static int snd_ali_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
1165
  {
  	return snd_pcm_lib_free_pages(substream);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1166
  static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1168
1169
1170
1171
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
  	struct snd_ali_voice *evoice = pvoice->extra;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  
  	unsigned int LBA;
  	unsigned int Delta;
  	unsigned int ESO;
  	unsigned int CTRL;
  	unsigned int GVSEL;
  	unsigned int PAN;
  	unsigned int VOL;
  	unsigned int EC;
  	
  	snd_ali_printk("playback_prepare ...
  ");
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1184
  	spin_lock_irq(&codec->reg_lock);	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
  	
  	/* set Delta (rate) value */
  	Delta = snd_ali_convert_rate(runtime->rate, 0);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1188
1189
  	if (pvoice->number == ALI_SPDIF_IN_CHANNEL || 
  	    pvoice->number == ALI_PCM_IN_CHANNEL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
  		snd_ali_disable_special_channel(codec, pvoice->number);
  	else if (codec->spdif_support &&
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1192
1193
1194
  		 (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) &
  		  ALI_SPDIF_OUT_CH_ENABLE)
  		 && pvoice->number == ALI_SPDIF_OUT_CHANNEL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  		snd_ali_set_spdif_out_rate(codec, runtime->rate);
  		Delta = 0x1000;
  	}
  	
  	/* set Loop Back Address */
  	LBA = runtime->dma_addr;
  
  	/* set interrupt count size */
  	pvoice->count = runtime->period_size;
  
  	/* set target ESO for channel */
  	pvoice->eso = runtime->buffer_size; 
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1207
1208
1209
  	snd_ali_printk("playback_prepare: eso=%xh count=%xh
  ",
  		       pvoice->eso, pvoice->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
  
  	/* set ESO to capture first MIDLP interrupt */
  	ESO = pvoice->eso -1;
  	/* set ctrl mode */
  	CTRL = snd_ali_control_mode(substream);
  
  	GVSEL = 1;
  	PAN = 0;
  	VOL = 0;
  	EC = 0;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  	snd_ali_printk("playback_prepare:
  ");
  	snd_ali_printk("ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh
  ",
  		       pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL);
  	snd_ali_write_voice_regs(codec,
  				 pvoice->number,
  				 LBA,
  				 0,	/* cso */
  				 ESO,
  				 Delta,
  				 0,	/* alpha */
  				 GVSEL,
  				 PAN,
  				 VOL,
  				 CTRL,
  				 EC);
270436424   Takashi Iwai   [ALSA] ali5451 - ...
1237
  	if (evoice) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
1240
1241
  		evoice->count = pvoice->count;
  		evoice->eso = pvoice->count << 1;
  		ESO = evoice->eso - 1;
  		snd_ali_write_voice_regs(codec,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
  					 evoice->number,
  					 LBA,
  					 0,	/* cso */
  					 ESO,
  					 Delta,
  					 0,	/* alpha */
  					 GVSEL,
  					 0x7f,
  					 0x3ff,
  					 CTRL,
  					 EC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  	}
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1254
  	spin_unlock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255
1256
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1257
  static int snd_ali_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1259
1260
1261
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
1266
1267
1268
1269
1270
  	unsigned int LBA;
  	unsigned int Delta;
  	unsigned int ESO;
  	unsigned int CTRL;
  	unsigned int GVSEL;
  	unsigned int PAN;
  	unsigned int VOL;
  	unsigned int EC;
  	u8	 bValue;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1271
  	spin_lock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272

5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1273
1274
  	snd_ali_printk("ali_prepare...
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
  
  	snd_ali_enable_special_channel(codec,pvoice->number);
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1277
1278
1279
  	Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL ||
  		 pvoice->number == ALI_MODEM_OUT_CHANNEL) ? 
  		0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1281
  	/* Prepare capture intr channel */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
1284
1285
  	if (pvoice->number == ALI_SPDIF_IN_CHANNEL) {
  
  		unsigned int rate;
  		
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1286
1287
  		spin_unlock_irq(&codec->reg_lock);
  		if (codec->revision != ALI_5451_V02)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
  			return -1;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1289

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
1291
  		rate = snd_ali_get_spdif_in_rate(codec);
  		if (rate == 0) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1292
1293
1294
  			snd_printk(KERN_WARNING "ali_capture_preapre: "
  				   "spdif rate detect err!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
1296
  			rate = 48000;
  		}
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1297
  		spin_lock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
1300
  		bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL));
  		if (bValue & 0x10) {
  			outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL));
99b359ba1   Takashi Iwai   [ALSA] Add missin...
1301
1302
  			printk(KERN_WARNING "clear SPDIF parity error flag.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
  		}
  
  		if (rate != 48000)
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1306
  			Delta = ((rate << 12) / runtime->rate) & 0x00ffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  	}
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1308
  	/* set target ESO for channel  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
  	pvoice->eso = runtime->buffer_size; 
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1310
  	/* set interrupt count size  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
  	pvoice->count = runtime->period_size;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1312
  	/* set Loop Back Address  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
  	LBA = runtime->dma_addr;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1314
  	/* set ESO to capture first MIDLP interrupt  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
  	ESO = pvoice->eso - 1;
  	CTRL = snd_ali_control_mode(substream);
  	GVSEL = 0;
  	PAN = 0x00;
  	VOL = 0x00;
  	EC = 0;
  
  	snd_ali_write_voice_regs(    codec,
  				     pvoice->number,
  				     LBA,
  				     0,	/* cso */
  				     ESO,
  				     Delta,
  				     0,	/* alpha */
  				     GVSEL,
  				     PAN,
  				     VOL,
  				     CTRL,
  				     EC);
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1334
  	spin_unlock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
  
  	return 0;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1338
1339
  static snd_pcm_uframes_t
  snd_ali_playback_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1341
1342
1343
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  	unsigned int cso;
  
  	spin_lock(&codec->reg_lock);
  	if (!pvoice->running) {
  		spin_unlock(&codec->reg_lock);
  		return 0;
  	}
  	outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
  	cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
  	spin_unlock(&codec->reg_lock);
  	snd_ali_printk("playback pointer returned cso=%xh.
  ", cso);
  
  	return cso;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1359
  static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1361
1362
1363
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
  	unsigned int cso;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365

755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1366
  	spin_lock(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
  	if (!pvoice->running) {
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1368
  		spin_unlock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
1371
1372
  		return 0;
  	}
  	outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
  	cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1373
  	spin_unlock(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
  
  	return cso;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1377
  static struct snd_pcm_hardware snd_ali_playback =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1379
1380
1381
1382
1383
1384
1385
1386
  	.info =		(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  			 SNDRV_PCM_INFO_BLOCK_TRANSFER |
  			 SNDRV_PCM_INFO_MMAP_VALID |
  			 SNDRV_PCM_INFO_RESUME |
  			 SNDRV_PCM_INFO_SYNC_START),
  	.formats =	(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
  			 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
  	.rates =	SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  	.rate_min =		4000,
  	.rate_max =		48000,
  	.channels_min =		1,
  	.channels_max =		2,
  	.buffer_bytes_max =	(256*1024),
  	.period_bytes_min =	64,
  	.period_bytes_max =	(256*1024),
  	.periods_min =		1,
  	.periods_max =		1024,
  	.fifo_size =		0,
  };
  
  /*
   *  Capture support device description
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1402
  static struct snd_pcm_hardware snd_ali_capture =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1404
1405
1406
1407
1408
1409
1410
1411
  	.info =		(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  			 SNDRV_PCM_INFO_BLOCK_TRANSFER |
  			 SNDRV_PCM_INFO_MMAP_VALID |
  			 SNDRV_PCM_INFO_RESUME |
  			 SNDRV_PCM_INFO_SYNC_START),
  	.formats =	(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
  			 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
  	.rates =	SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  	.rate_min =		4000,
  	.rate_max =		48000,
  	.channels_min =		1,
  	.channels_max =		2,
  	.buffer_bytes_max =	(128*1024),
  	.period_bytes_min =	64,
  	.period_bytes_max =	(128*1024),
  	.periods_min =		1,
  	.periods_max =		1024,
  	.fifo_size =		0,
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1423
  static void snd_ali_pcm_free_substream(struct snd_pcm_runtime *runtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1425
1426
  	struct snd_ali_voice *pvoice = runtime->private_data;
  	struct snd_ali *codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
1429
  
  	if (pvoice) {
  		codec = pvoice->codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
  		snd_ali_free_voice(pvoice->codec, pvoice);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
  	}
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1433
1434
  static int snd_ali_open(struct snd_pcm_substream *substream, int rec,
  			int channel, struct snd_pcm_hardware *phw)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1436
1437
1438
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ali_voice *pvoice;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1440
1441
1442
  	pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec,
  				     channel);
  	if (!pvoice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
1447
  
  	pvoice->substream = substream;
  	runtime->private_data = pvoice;
  	runtime->private_free = snd_ali_pcm_free_substream;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1448
  	runtime->hw = *phw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1449
  	snd_pcm_set_sync(substream);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1450
1451
  	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
  				     0, 64*1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1454
  static int snd_ali_playback_open(struct snd_pcm_substream *substream)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1455
1456
1457
  {
  	return snd_ali_open(substream, 0, -1, &snd_ali_playback);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458

d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1459
  static int snd_ali_capture_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460
  {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1461
  	return snd_ali_open(substream, 1, -1, &snd_ali_capture);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1463
  static int snd_ali_playback_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
1465
1466
  {
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1467
  static int snd_ali_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1469
1470
  	struct snd_ali *codec = snd_pcm_substream_chip(substream);
  	struct snd_ali_voice *pvoice = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
1474
1475
  
  	snd_ali_disable_special_channel(codec,pvoice->number);
  
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1476
  static struct snd_pcm_ops snd_ali_playback_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477
1478
  	.open =		snd_ali_playback_open,
  	.close =	snd_ali_playback_close,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1479
  	.ioctl =	snd_pcm_lib_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
1481
1482
1483
1484
1485
  	.hw_params =	snd_ali_playback_hw_params,
  	.hw_free =	snd_ali_playback_hw_free,
  	.prepare =	snd_ali_playback_prepare,
  	.trigger =	snd_ali_trigger,
  	.pointer =	snd_ali_playback_pointer,
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1486
  static struct snd_pcm_ops snd_ali_capture_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
  	.open =		snd_ali_capture_open,
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1488
  	.close =	snd_ali_close,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1489
  	.ioctl =	snd_pcm_lib_ioctl,
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  	.hw_params =	snd_ali_hw_params,
  	.hw_free =	snd_ali_hw_free,
  	.prepare =	snd_ali_prepare,
  	.trigger =	snd_ali_trigger,
  	.pointer =	snd_ali_pointer,
  };
  
  /*
   * Modem PCM
   */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1500
1501
  static int snd_ali_modem_hw_params(struct snd_pcm_substream *substream,
  				 struct snd_pcm_hw_params *hw_params)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1502
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1503
  	struct snd_ali *chip = snd_pcm_substream_chip(substream);
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1504
  	unsigned int modem_num = chip->num_of_codecs - 1;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1505
1506
  	snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE,
  		       params_rate(hw_params));
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1507
1508
1509
  	snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0);
  	return snd_ali_hw_params(substream, hw_params);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1510
  static struct snd_pcm_hardware snd_ali_modem =
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1511
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1512
1513
1514
1515
1516
1517
1518
1519
  	.info =		(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  			 SNDRV_PCM_INFO_BLOCK_TRANSFER |
  			 SNDRV_PCM_INFO_MMAP_VALID |
  			 SNDRV_PCM_INFO_RESUME |
  			 SNDRV_PCM_INFO_SYNC_START),
  	.formats =	SNDRV_PCM_FMTBIT_S16_LE,
  	.rates =	(SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000 |
  			 SNDRV_PCM_RATE_16000),
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
  	.rate_min =		8000,
  	.rate_max =		16000,
  	.channels_min =		1,
  	.channels_max =		1,
  	.buffer_bytes_max =	(256*1024),
  	.period_bytes_min =	64,
  	.period_bytes_max =	(256*1024),
  	.periods_min =		1,
  	.periods_max =		1024,
  	.fifo_size =		0,
  };
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1531
1532
  static int snd_ali_modem_open(struct snd_pcm_substream *substream, int rec,
  			      int channel)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1533
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1534
  	static unsigned int rates[] = {8000, 9600, 12000, 16000};
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1535
  	static struct snd_pcm_hw_constraint_list hw_constraint_rates = {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1536
1537
1538
1539
1540
  		.count = ARRAY_SIZE(rates),
  		.list = rates,
  		.mask = 0,
  	};
  	int err = snd_ali_open(substream, rec, channel, &snd_ali_modem);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1541

5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1542
1543
1544
1545
1546
  	if (err)
  		return err;
  	return snd_pcm_hw_constraint_list(substream->runtime, 0,
  			SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1547
  static int snd_ali_modem_playback_open(struct snd_pcm_substream *substream)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1548
1549
1550
  {
  	return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1551
  static int snd_ali_modem_capture_open(struct snd_pcm_substream *substream)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1552
1553
1554
  {
  	return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL);
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1555
  static struct snd_pcm_ops snd_ali_modem_playback_ops = {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1556
1557
1558
1559
1560
1561
1562
1563
1564
  	.open =		snd_ali_modem_playback_open,
  	.close =	snd_ali_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_ali_modem_hw_params,
  	.hw_free =	snd_ali_hw_free,
  	.prepare =	snd_ali_prepare,
  	.trigger =	snd_ali_trigger,
  	.pointer =	snd_ali_pointer,
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1565
  static struct snd_pcm_ops snd_ali_modem_capture_ops = {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1566
1567
1568
1569
1570
1571
  	.open =		snd_ali_modem_capture_open,
  	.close =	snd_ali_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_ali_modem_hw_params,
  	.hw_free =	snd_ali_hw_free,
  	.prepare =	snd_ali_prepare,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
  	.trigger =	snd_ali_trigger,
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1573
1574
1575
1576
1577
1578
1579
1580
  	.pointer =	snd_ali_pointer,
  };
  
  
  struct ali_pcm_description {
  	char *name;
  	unsigned int playback_num;
  	unsigned int capture_num;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1581
1582
  	struct snd_pcm_ops *playback_ops;
  	struct snd_pcm_ops *capture_ops;
6632d198c   Sasha Khapyorsky   [ALSA] dev_class=...
1583
  	unsigned short class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1585
  static void snd_ali_pcm_free(struct snd_pcm *pcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1587
  	struct snd_ali *codec = pcm->private_data;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1588
  	codec->pcm[pcm->device] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  }
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1590

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1591
1592
  static int __devinit snd_ali_pcm(struct snd_ali * codec, int device,
  				 struct ali_pcm_description *desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1594
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
  	int err;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1596
1597
  	err = snd_pcm_new(codec->card, desc->name, device,
  			  desc->playback_num, desc->capture_num, &pcm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
  	if (err < 0) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
1599
1600
  		snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
1604
  		return err;
  	}
  	pcm->private_data = codec;
  	pcm->private_free = snd_ali_pcm_free;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1605
  	if (desc->playback_ops)
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1606
1607
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  				desc->playback_ops);
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1608
  	if (desc->capture_ops)
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1609
1610
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
  				desc->capture_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
  
  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1613
1614
  					      snd_dma_pci_data(codec->pci),
  					      64*1024, 128*1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
  
  	pcm->info_flags = 0;
6632d198c   Sasha Khapyorsky   [ALSA] dev_class=...
1617
  	pcm->dev_class = desc->class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
  	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1619
1620
  	strcpy(pcm->name, desc->name);
  	codec->pcm[0] = pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
1622
  	return 0;
  }
a53fc188e   Clemens Ladisch   [ALSA] make local...
1623
  static struct ali_pcm_description ali_pcms[] = {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
  	{ .name = "ALI 5451",
  	  .playback_num = ALI_CHANNELS,
  	  .capture_num = 1,
  	  .playback_ops = &snd_ali_playback_ops,
  	  .capture_ops = &snd_ali_capture_ops
  	},
  	{ .name = "ALI 5451 modem",
  	  .playback_num = 1,
  	  .capture_num = 1,
  	  .playback_ops = &snd_ali_modem_playback_ops,
  	  .capture_ops = &snd_ali_modem_capture_ops,
  	  .class = SNDRV_PCM_CLASS_MODEM
  	}
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1637
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1638
  static int __devinit snd_ali_build_pcms(struct snd_ali *codec)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1639
1640
  {
  	int i, err;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1641
1642
1643
  	for (i = 0; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms); i++) {
  		err = snd_ali_pcm(codec, i, &ali_pcms[i]);
  		if (err < 0)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1644
  			return err;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1645
  	}
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1646
1647
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
1649
1650
1651
  #define ALI5451_SPDIF(xname, xindex, value) \
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \
  .put = snd_ali5451_spdif_put, .private_value = value}
a5ce88909   Takashi Iwai   [ALSA] Clean up w...
1652
  #define snd_ali5451_spdif_info		snd_ctl_boolean_mono_info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1654
1655
  static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1657
  	struct snd_ali *codec = kcontrol->private_data;
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1658
  	unsigned int spdif_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659

c74056d43   Harvey Harrison   [ALSA] sound: ali...
1660
  	spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1661

755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1662
  	spin_lock_irq(&codec->reg_lock);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1663
  	switch (kcontrol->private_value) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
  	case 0:
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1665
  		spdif_enable = (codec->spdif_mask & 0x02) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
1667
  		break;
  	case 1:
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1668
  		spdif_enable = ((codec->spdif_mask & 0x02) &&
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1669
  			  (codec->spdif_mask & 0x04)) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
  		break;
  	case 2:
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1672
  		spdif_enable = (codec->spdif_mask & 0x01) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
1674
1675
1676
  		break;
  	default:
  		break;
  	}
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1677
  	ucontrol->value.integer.value[0] = spdif_enable;
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1678
  	spin_unlock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
  	return 0;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1681
1682
  static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1684
  	struct snd_ali *codec = kcontrol->private_data;
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1685
  	unsigned int change = 0, spdif_enable = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686

c74056d43   Harvey Harrison   [ALSA] sound: ali...
1687
  	spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688

755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1689
  	spin_lock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
1691
1692
  	switch (kcontrol->private_value) {
  	case 0:
  		change = (codec->spdif_mask & 0x02) ? 1 : 0;
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1693
  		change = change ^ spdif_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694
  		if (change) {
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1695
  			if (spdif_enable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
  				codec->spdif_mask |= 0x02;
  				snd_ali_enable_spdif_out(codec);
  			} else {
  				codec->spdif_mask &= ~(0x02);
  				codec->spdif_mask &= ~(0x04);
  				snd_ali_disable_spdif_out(codec);
  			}
  		}
  		break;
  	case 1: 
  		change = (codec->spdif_mask & 0x04) ? 1 : 0;
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1707
  		change = change ^ spdif_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
  		if (change && (codec->spdif_mask & 0x02)) {
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1709
  			if (spdif_enable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
  				codec->spdif_mask |= 0x04;
  				snd_ali_enable_spdif_chnout(codec);
  			} else {
  				codec->spdif_mask &= ~(0x04);
  				snd_ali_disable_spdif_chnout(codec);
  			}
  		}
  		break;
  	case 2:
  		change = (codec->spdif_mask & 0x01) ? 1 : 0;
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1720
  		change = change ^ spdif_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
  		if (change) {
c74056d43   Harvey Harrison   [ALSA] sound: ali...
1722
  			if (spdif_enable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
  				codec->spdif_mask |= 0x01;
  				snd_ali_enable_spdif_in(codec);
  			} else {
  				codec->spdif_mask &= ~(0x01);
  				snd_ali_disable_spdif_in(codec);
  			}
  		}
  		break;
  	default:
  		break;
  	}
755e13713   Takashi Iwai   [ALSA] ali5451 - ...
1734
  	spin_unlock_irq(&codec->reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735
1736
1737
  	
  	return change;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1738
  static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739
1740
  	/* spdif aplayback switch */
  	/* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */
10e8d78a9   Clemens Ladisch   [ALSA] use SNDRV_...
1741
  	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1742
  	/* spdif out to spdif channel */
10e8d78a9   Clemens Ladisch   [ALSA] use SNDRV_...
1743
  	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
1745
1746
  	/* spdif in from spdif channel */
  	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)
  };
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1747
  static int __devinit snd_ali_mixer(struct snd_ali * codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1748
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1749
  	struct snd_ac97_template ac97;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
  	unsigned int idx;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1751
  	int i, err;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1752
  	static struct snd_ac97_bus_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
  		.write = snd_ali_codec_write,
  		.read = snd_ali_codec_read,
  	};
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1756
1757
  	err = snd_ac97_bus(codec->card, 0, &ops, codec, &codec->ac97_bus);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1758
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
1760
1761
  
  	memset(&ac97, 0, sizeof(ac97));
  	ac97.private_data = codec;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1762

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1763
  	for (i = 0; i < codec->num_of_codecs; i++) {
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1764
  		ac97.num = i;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1765
1766
1767
1768
1769
1770
  		err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]);
  		if (err < 0) {
  			snd_printk(KERN_ERR
  				   "ali mixer %d creating error.
  ", i);
  			if (i == 0)
4d060fd16   Takashi Iwai   [ALSA] ali5451 - ...
1771
1772
1773
1774
  				return err;
  			codec->num_of_codecs = 1;
  			break;
  		}
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1775
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
  	if (codec->spdif_support) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1777
1778
1779
1780
1781
  		for (idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) {
  			err = snd_ctl_add(codec->card,
  					  snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec));
  			if (err < 0)
  				return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
1783
1784
1785
1786
1787
  		}
  	}
  	return 0;
  }
  
  #ifdef CONFIG_PM
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1788
  static int ali_suspend(struct pci_dev *pci, pm_message_t state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
  {
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1790
1791
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_ali *chip = card->private_data;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1792
  	struct snd_ali_image *im;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
1794
1795
  	int i, j;
  
  	im = chip->image;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1796
  	if (!im)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
  		return 0;
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1798
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1799
  	for (i = 0; i < chip->num_of_codecs; i++) {
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1800
1801
  		snd_pcm_suspend_all(chip->pcm[i]);
  		snd_ac97_suspend(chip->ac97[i]);
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1802
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
1806
  
  	spin_lock_irq(&chip->reg_lock);
  	
  	im->regs[ALI_MISCINT >> 2] = inl(ALI_REG(chip, ALI_MISCINT));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1807
  	/* im->regs[ALI_START >> 2] = inl(ALI_REG(chip, ALI_START)); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
1809
  	im->regs[ALI_STOP >> 2] = inl(ALI_REG(chip, ALI_STOP));
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1810
  	/* disable all IRQ bits */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
  	outl(0, ALI_REG(chip, ALI_MISCINT));
  	
  	for (i = 0; i < ALI_GLOBAL_REGS; i++) {	
  		if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP))
  			continue;
  		im->regs[i] = inl(ALI_REG(chip, i*4));
  	}
  	
  	for (i = 0; i < ALI_CHANNELS; i++) {
  		outb(i, ALI_REG(chip, ALI_GC_CIR));
  		for (j = 0; j < ALI_CHANNEL_REGS; j++) 
  			im->channel_regs[i][j] = inl(ALI_REG(chip, j*4 + 0xe0));
  	}
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1824
  	/* stop all HW channel */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1825
1826
1827
  	outl(0xffffffff, ALI_REG(chip, ALI_STOP));
  
  	spin_unlock_irq(&chip->reg_lock);
30b35399c   Takashi Iwai   [ALSA] Various fi...
1828

bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1829
1830
  	pci_disable_device(pci);
  	pci_save_state(pci);
30b35399c   Takashi Iwai   [ALSA] Various fi...
1831
  	pci_set_power_state(pci, pci_choose_state(pci, state));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
  	return 0;
  }
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1834
  static int ali_resume(struct pci_dev *pci)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
  {
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1836
1837
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_ali *chip = card->private_data;
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1838
  	struct snd_ali_image *im;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1839
1840
1841
  	int i, j;
  
  	im = chip->image;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1842
  	if (!im)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
  		return 0;
30b35399c   Takashi Iwai   [ALSA] Various fi...
1844
  	pci_set_power_state(pci, PCI_D0);
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1845
  	pci_restore_state(pci);
30b35399c   Takashi Iwai   [ALSA] Various fi...
1846
1847
1848
1849
1850
1851
1852
1853
  	if (pci_enable_device(pci) < 0) {
  		printk(KERN_ERR "ali5451: pci_enable_device failed, "
  		       "disabling device
  ");
  		snd_card_disconnect(card);
  		return -EIO;
  	}
  	pci_set_master(pci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
  
  	spin_lock_irq(&chip->reg_lock);
  	
  	for (i = 0; i < ALI_CHANNELS; i++) {
  		outb(i, ALI_REG(chip, ALI_GC_CIR));
  		for (j = 0; j < ALI_CHANNEL_REGS; j++) 
  			outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0));
  	}
  	
  	for (i = 0; i < ALI_GLOBAL_REGS; i++) {	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1864
1865
  		if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) ||
  		    (i*4 == ALI_START))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
1867
1868
1869
  			continue;
  		outl(im->regs[i], ALI_REG(chip, i*4));
  	}
  	
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1870
  	/* start HW channel */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1871
  	outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START));
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1872
  	/* restore IRQ enable bits */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1873
1874
1875
  	outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));
  	
  	spin_unlock_irq(&chip->reg_lock);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1876
  	for (i = 0 ; i < chip->num_of_codecs; i++)
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1877
  		snd_ac97_resume(chip->ac97[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
  	
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
1879
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
  	return 0;
  }
  #endif /* CONFIG_PM */
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1883
  static int snd_ali_free(struct snd_ali * codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
1885
1886
  {
  	if (codec->hw_initialized)
  		snd_ali_disable_address_interrupt(codec);
f000fd809   Jeff Garzik   [ALSA] Fix synchr...
1887
  	if (codec->irq >= 0)
437a5a460   Takashi Iwai   [ALSA] Remove IRQ...
1888
  		free_irq(codec->irq, codec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1889
1890
1891
1892
1893
1894
  	if (codec->port)
  		pci_release_regions(codec->pci);
  	pci_disable_device(codec->pci);
  #ifdef CONFIG_PM
  	kfree(codec->image);
  #endif
0dd119f70   Jiri Slaby   [ALSA] pci_find_d...
1895
1896
  	pci_dev_put(codec->pci_m1533);
  	pci_dev_put(codec->pci_m7101);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1897
1898
1899
  	kfree(codec);
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1900
  static int snd_ali_chip_init(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
  {
  	unsigned int legacy;
  	unsigned char temp;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1904
  	struct pci_dev *pci_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1905
1906
1907
1908
1909
  
  	snd_ali_printk("chip initializing ... 
  ");
  
  	if (snd_ali_reset_5451(codec)) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
1910
1911
  		snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
  		return -1;
  	}
  
  	if (codec->revision == ALI_5451_V02) {
          	pci_dev = codec->pci_m1533;
  		pci_read_config_byte(pci_dev, 0x59, &temp);
  		temp |= 0x80;
  		pci_write_config_byte(pci_dev, 0x59, temp);
  	
  		pci_dev = codec->pci_m7101;
  		pci_read_config_byte(pci_dev, 0xb8, &temp);
  		temp |= 0x20;
  		pci_write_config_byte(pci_dev, 0xB8, temp);
  	}
  
  	pci_read_config_dword(codec->pci, 0x44, &legacy);
  	legacy &= 0xff00ff00;
  	legacy |= 0x000800aa;
  	pci_write_config_dword(codec->pci, 0x44, legacy);
  
  	outl(0x80000001, ALI_REG(codec, ALI_GLOBAL_CONTROL));
  	outl(0x00000000, ALI_REG(codec, ALI_AINTEN));
  	outl(0xffffffff, ALI_REG(codec, ALI_AINT));
  	outl(0x00000000, ALI_REG(codec, ALI_VOLUME));
  	outb(0x10, 	 ALI_REG(codec, ALI_MPUR2));
  
  	codec->ac97_ext_id = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_ID);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1939
1940
  	codec->ac97_ext_status = snd_ali_codec_peek(codec, 0,
  						    AC97_EXTENDED_STATUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
1942
1943
1944
  	if (codec->spdif_support) {
  		snd_ali_enable_spdif_out(codec);
  		codec->spdif_mask = 0x00000002;
  	}
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1945
1946
1947
1948
1949
1950
  	codec->num_of_codecs = 1;
  
  	/* secondary codec - modem */
  	if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) {
  		codec->num_of_codecs++;
  		outl(inl(ALI_REG(codec, ALI_SCTRL)) |
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1951
1952
1953
  		     (ALI_SCTRL_LINE_IN2 | ALI_SCTRL_GPIO_IN2 |
  		      ALI_SCTRL_LINE_OUT_EN),
  		     ALI_REG(codec, ALI_SCTRL));
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1954
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
1956
1957
1958
1959
  	snd_ali_printk("chip initialize succeed.
  ");
  	return 0;
  
  }
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1960
  /* proc for register dump */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1961
1962
  static void snd_ali_proc_read(struct snd_info_entry *entry,
  			      struct snd_info_buffer *buf)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1963
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1964
  	struct snd_ali *codec = entry->private_data;
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1965
  	int i;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1966
  	for (i = 0; i < 256 ; i+= 4)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1967
1968
1969
  		snd_iprintf(buf, "%02x: %08x
  ", i, inl(ALI_REG(codec, i)));
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1970
  static void __devinit snd_ali_proc_init(struct snd_ali *codec)
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1971
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1972
  	struct snd_info_entry *entry;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1973
  	if (!snd_card_proc_new(codec->card, "ali5451", &entry))
bf850204a   Takashi Iwai   [ALSA] Remove unn...
1974
  		snd_info_set_text_ops(entry, codec, snd_ali_proc_read);
5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
1975
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
1976
  static int __devinit snd_ali_resources(struct snd_ali *codec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977
1978
  {
  	int err;
c468ac29e   Wolfram Sang   ALSA: sound/ali54...
1979
1980
  	snd_ali_printk("resources allocation ...
  ");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1981
1982
  	err = pci_request_regions(codec->pci, "ALI 5451");
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1983
1984
  		return err;
  	codec->port = pci_resource_start(codec->pci, 0);
437a5a460   Takashi Iwai   [ALSA] Remove IRQ...
1985
  	if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
934c2b6d0   Takashi Iwai   ALSA: use KBUILD_...
1986
  			IRQF_SHARED, KBUILD_MODNAME, codec)) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
1987
1988
  		snd_printk(KERN_ERR "Unable to request irq.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1989
1990
1991
  		return -EBUSY;
  	}
  	codec->irq = codec->pci->irq;
c468ac29e   Wolfram Sang   ALSA: sound/ali54...
1992
1993
  	snd_ali_printk("resources allocated.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994
1995
  	return 0;
  }
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1996
  static int snd_ali_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1997
  {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
1998
  	struct snd_ali *codec = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999
2000
2001
  	snd_ali_free(codec);
  	return 0;
  }
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
2002
  static int __devinit snd_ali_create(struct snd_card *card,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2003
2004
2005
  				    struct pci_dev *pci,
  				    int pcm_streams,
  				    int spdif_support,
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
2006
  				    struct snd_ali ** r_ali)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
2008
  	struct snd_ali *codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
  	int i, err;
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
2010
2011
  	unsigned short cmdw;
  	static struct snd_device_ops ops = {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
2012
  		.dev_free = snd_ali_dev_free,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2013
2014
2015
2016
2017
2018
2019
2020
          };
  
  	*r_ali = NULL;
  
  	snd_ali_printk("creating ...
  ");
  
  	/* enable PCI device */
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2021
2022
  	err = pci_enable_device(pci);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2023
2024
  		return err;
  	/* check, if we can restrict PCI DMA transfers to 31 bits */
929a22a55   Yang Hongyang   dma-mapping: repl...
2025
2026
  	if (pci_set_dma_mask(pci, DMA_BIT_MASK(31)) < 0 ||
  	    pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(31)) < 0) {
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2027
2028
2029
  		snd_printk(KERN_ERR "architecture does not support "
  			   "31bit PCI busmaster DMA
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
2032
  		pci_disable_device(pci);
  		return -ENXIO;
  	}
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2033
2034
  	codec = kzalloc(sizeof(*codec), GFP_KERNEL);
  	if (!codec) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
  		pci_disable_device(pci);
  		return -ENOMEM;
  	}
  
  	spin_lock_init(&codec->reg_lock);
  	spin_lock_init(&codec->voice_alloc);
  
  	codec->card = card;
  	codec->pci = pci;
  	codec->irq = -1;
44c10138f   Auke Kok   PCI: Change all d...
2045
  	codec->revision = pci->revision;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
  	codec->spdif_support = spdif_support;
  
  	if (pcm_streams < 1)
  		pcm_streams = 1;
  	if (pcm_streams > 32)
  		pcm_streams = 32;
  	
  	pci_set_master(pci);
  	pci_read_config_word(pci, PCI_COMMAND, &cmdw);
  	if ((cmdw & PCI_COMMAND_IO) != PCI_COMMAND_IO) {
  		cmdw |= PCI_COMMAND_IO;
  		pci_write_config_word(pci, PCI_COMMAND, cmdw);
  	}
  	pci_set_master(pci);
  	
  	if (snd_ali_resources(codec)) {
  		snd_ali_free(codec);
  		return -EBUSY;
  	}
  
  	synchronize_irq(pci->irq);
  
  	codec->synth.chmap = 0;
  	codec->synth.chcnt = 0;
  	codec->spdif_mask = 0;
  	codec->synth.synthcount = 0;
  
  	if (codec->revision == ALI_5451_V02)
  		codec->chregs.regs.ac97read = ALI_AC97_WRITE;
  	else
  		codec->chregs.regs.ac97read = ALI_AC97_READ;
  	codec->chregs.regs.ac97write = ALI_AC97_WRITE;
  
  	codec->chregs.regs.start  = ALI_START;
  	codec->chregs.regs.stop   = ALI_STOP;
  	codec->chregs.regs.aint   = ALI_AINT;
  	codec->chregs.regs.ainten = ALI_AINTEN;
  
  	codec->chregs.data.start  = 0x00;
  	codec->chregs.data.stop   = 0x00;
  	codec->chregs.data.aint   = 0x00;
  	codec->chregs.data.ainten = 0x00;
  
  	/* M1533: southbridge */
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
2090
  	codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2091
  	if (!codec->pci_m1533) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
2093
2094
2095
2096
2097
  		snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.
  ");
  		snd_ali_free(codec);
  		return -ENODEV;
  	}
  	/* M7101: power management */
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
2098
  	codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2099
  	if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
2101
2102
2103
2104
2105
2106
2107
  		snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.
  ");
  		snd_ali_free(codec);
  		return -ENODEV;
  	}
  
  	snd_ali_printk("snd_device_new is called.
  ");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2108
2109
  	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
2111
2112
  		snd_ali_free(codec);
  		return err;
  	}
c187c041c   Takashi Iwai   [ALSA] Add missin...
2113
  	snd_card_set_dev(card, &pci->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114
  	/* initialise synth voices*/
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2115
  	for (i = 0; i < ALI_CHANNELS; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
  		codec->synth.voices[i].number = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2118
2119
  	err = snd_ali_chip_init(codec);
  	if (err < 0) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
2120
2121
  		snd_printk(KERN_ERR "ali create: chip init error.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2122
2123
2124
2125
2126
  		return err;
  	}
  
  #ifdef CONFIG_PM
  	codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2127
  	if (!codec->image)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
2129
  		snd_printk(KERN_WARNING "can't allocate apm buffer
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
  #endif
  
  	snd_ali_enable_address_interrupt(codec);
  	codec->hw_initialized = 1;
  
  	*r_ali = codec;
  	snd_ali_printk("created.
  ");
  	return 0;
  }
  
  static int __devinit snd_ali_probe(struct pci_dev *pci,
  				   const struct pci_device_id *pci_id)
  {
d1fabd9cb   Takashi Iwai   [ALSA] Remove xxx...
2144
2145
  	struct snd_card *card;
  	struct snd_ali *codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146
2147
2148
2149
  	int err;
  
  	snd_ali_printk("probe ...
  ");
e58de7baf   Takashi Iwai   ALSA: Convert to ...
2150
2151
2152
  	err = snd_card_create(index, id, THIS_MODULE, 0, &card);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153

f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2154
2155
2156
  	err = snd_ali_create(card, pci, pcm_channels, spdif, &codec);
  	if (err < 0)
  		goto error;
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
2157
  	card->private_data = codec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
2159
2160
  
  	snd_ali_printk("mixer building ...
  ");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2161
2162
2163
  	err = snd_ali_mixer(codec);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
2165
2166
  	
  	snd_ali_printk("pcm building ...
  ");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2167
2168
2169
  	err = snd_ali_build_pcms(codec);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170

5cbff89cb   Sasha Khapyorsky   [ALSA] Modem supp...
2171
  	snd_ali_proc_init(codec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2172
2173
2174
  	strcpy(card->driver, "ALI5451");
  	strcpy(card->shortname, "ALI 5451");
  	
ba8c3c37d   Takashi Iwai   [ALSA] ali5451 - ...
2175
  	sprintf(card->longname, "%s at 0x%lx, irq %i",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
2179
  		card->shortname, codec->port, codec->irq);
  
  	snd_ali_printk("register card.
  ");
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2180
2181
2182
  	err = snd_card_register(card);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2183
  	pci_set_drvdata(pci, card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
  	return 0;
f9ab2b1c3   Takashi Iwai   [ALSA] ali5451 - ...
2185
2186
2187
2188
  
   error:
  	snd_card_free(card);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
2191
2192
2193
2194
2195
2196
2197
  }
  
  static void __devexit snd_ali_remove(struct pci_dev *pci)
  {
  	snd_card_free(pci_get_drvdata(pci));
  	pci_set_drvdata(pci, NULL);
  }
  
  static struct pci_driver driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
2198
  	.name = KBUILD_MODNAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
2201
  	.id_table = snd_ali_ids,
  	.probe = snd_ali_probe,
  	.remove = __devexit_p(snd_ali_remove),
bf53c3b3f   Takashi Iwai   [ALSA] ali5451 - ...
2202
2203
2204
2205
  #ifdef CONFIG_PM
  	.suspend = ali_suspend,
  	.resume = ali_resume,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2206
2207
2208
2209
  };                                
  
  static int __init alsa_card_ali_init(void)
  {
01d25d460   Takashi Iwai   [ALSA] Replace pc...
2210
  	return pci_register_driver(&driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2211
2212
2213
2214
2215
2216
2217
2218
2219
  }
  
  static void __exit alsa_card_ali_exit(void)
  {
  	pci_unregister_driver(&driver);
  }
  
  module_init(alsa_card_ali_init)
  module_exit(alsa_card_ali_exit)