Blame view

sound/pci/ca0106/ca0106_main.c 58.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
   *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
485100706   Trent Piepho   [ALSA] ca0106: po...
4
   *  Version: 0.0.25
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
   *
   *  FEATURES currently supported:
   *    Front, Rear and Center/LFE.
   *    Surround40 and Surround51.
   *    Capture from MIC an LINE IN input.
   *    SPDIF digital playback of PCM stereo and AC3/DTS works.
   *    (One can use a standard mono mini-jack to one RCA plugs cable.
   *     or one can use a standard stereo mini-jack to two RCA plugs cable.
   *     Plug one of the RCA plugs into the Coax input of the external decoder/receiver.)
   *    ( In theory one could output 3 different AC3 streams at once, to 3 different SPDIF outputs. )
   *    Notes on how to capture sound:
   *      The AC97 is used in the PLAYBACK direction.
   *      The output from the AC97 chip, instead of reaching the speakers, is fed into the Philips 1361T ADC.
   *      So, to record from the MIC, set the MIC Playback volume to max,
   *      unmute the MIC and turn up the MASTER Playback volume.
   *      So, to prevent feedback when capturing, minimise the "Capture feedback into Playback" volume.
   *   
   *    The only playback controls that currently do anything are: -
   *    Analog Front
   *    Analog Rear
   *    Analog Center/LFE
   *    SPDIF Front
   *    SPDIF Rear
   *    SPDIF Center/LFE
   *   
   *    For capture from Mic in or Line in.
   *    Digital/Analog ( switch must be in Analog mode for CAPTURE. )
   * 
   *    CAPTURE feedback into PLAYBACK
   * 
   *  Changelog:
   *    Support interrupts per period.
   *    Removed noise from Center/LFE channel when in Analog mode.
   *    Rename and remove mixer controls.
   *  0.0.6
   *    Use separate card based DMA buffer for periods table list.
   *  0.0.7
   *    Change remove and rename ctrls into lists.
   *  0.0.8
   *    Try to fix capture sources.
   *  0.0.9
   *    Fix AC3 output.
   *    Enable S32_LE format support.
   *  0.0.10
   *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
   *  0.0.11
   *    Add Model name recognition.
   *  0.0.12
   *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
   *    Remove redundent "voice" handling.
   *  0.0.13
   *    Single trigger call for multi channels.
   *  0.0.14
   *    Set limits based on what the sound card hardware can do.
   *    playback periods_min=2, periods_max=8
   *    capture hw constraints require period_size = n * 64 bytes.
   *    playback hw constraints require period_size = n * 64 bytes.
   *  0.0.15
   *    Minor updates.
   *  0.0.16
   *    Implement 192000 sample rate.
   *  0.0.17
   *    Add support for SB0410 and SB0413.
   *  0.0.18
   *    Modified Copyright message.
   *  0.0.19
   *    Finally fix support for SB Live 24 bit. SB0410 and SB0413.
   *    The output codec needs resetting, otherwise all output is muted.
   *  0.0.20
   *    Merge "pci_disable_device(pci);" fixes.
   *  0.0.21
   *    Add 4 capture channels. (SPDIF only comes in on channel 0. )
   *    Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.)
   *  0.0.22
   *    Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
80
81
   *  0.0.23
   *    Implement support for Line-in capture on SB Live 24bit.
b18cd538a   Trent Piepho   [ALSA] ca0106: Ad...
82
83
   *  0.0.24
   *    Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
485100706   Trent Piepho   [ALSA] ca0106: po...
84
85
   *  0.0.25
   *    Powerdown SPI DAC channels when not in use
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
   *
   *  BUGS:
   *    Some stability problems when unloading the snd-ca0106 kernel module.
   *    --
   *
   *  TODO:
   *    4 Capture channels, only one implemented so far.
   *    Other capture rates apart from 48khz not implemented.
   *    MIDI
   *    --
   *  GENERAL INFO:
   *    Model: SB0310
   *    P17 Chip: CA0106-DAT
   *    AC97 Codec: STAC 9721
   *    ADC: Philips 1361T (Stereo 24bit)
   *    DAC: WM8746EDS (6-channel, 24bit, 192Khz)
   *
   *  GENERAL INFO:
   *    Model: SB0410
   *    P17 Chip: CA0106-DAT
   *    AC97 Codec: None
   *    ADC: WM8775EDS (4 Channel)
   *    DAC: CS4382 (114 dB, 24-Bit, 192 kHz, 8-Channel D/A Converter with DSD Support)
   *    SPDIF Out control switches between Mic in and SPDIF out.
   *    No sound out or mic input working yet.
   * 
   *  GENERAL INFO:
   *    Model: SB0413
   *    P17 Chip: CA0106-DAT
   *    AC97 Codec: None.
   *    ADC: Unknown
   *    DAC: Unknown
   *    Trying to handle it like the SB0410.
   *
25985edce   Lucas De Marchi   Fix common misspe...
120
   *  This code was initially based on code from ALSA's emu10k1x.c which is:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
   *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
65a772172   Paul Gortmaker   sound: fix driver...
143
  #include <linux/module.h>
299676b1d   Tobias Klauser   [ALSA] sound/pci/...
144
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  #include <sound/core.h>
  #include <sound/initval.h>
  #include <sound/pcm.h>
  #include <sound/ac97_codec.h>
  #include <sound/info.h>
  
  MODULE_AUTHOR("James Courtier-Dutton <James@superbug.demon.co.uk>");
  MODULE_DESCRIPTION("CA0106");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}");
  
  // module parameters (see "Module Parameters")
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
a67ff6a54   Rusty Russell   ALSA: module_para...
159
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
e4f55d801   James Courtier-Dutton   [ALSA] snd-ca0106...
160
  static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for the CA0106 soundcard.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for the CA0106 soundcard.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard.");
e4f55d801   James Courtier-Dutton   [ALSA] snd-ca0106...
168
169
  module_param_array(subsystem, uint, NULL, 0444);
  MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  
  #include "ca0106.h"
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
172
  static struct snd_ca0106_details ca0106_chip_details[] = {
8632649b1   James Courtier-Dutton   [ALSA] snd-ca0106...
173
174
  	 /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
  	 /* It is really just a normal SB Live 24bit. */
aaccf54f6   James Courtier-Dutton   [ALSA] snd-ca0106...
175
176
177
178
179
180
181
182
183
  	 /* Tested:
  	  * See ALSA bug#3251
  	  */
  	 { .serial = 0x10131102,
  	   .name   = "X-Fi Extreme Audio [SBxxxx]",
  	   .gpio_type = 1,
  	   .i2c_adc = 1 } ,
  	 /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
  	 /* It is really just a normal SB Live 24bit. */
8632649b1   James Courtier-Dutton   [ALSA] snd-ca0106...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	 /*
   	  * CTRL:CA0111-WTLF
  	  * ADC: WM8775SEDS
  	  * DAC: CS4382-KQZ
  	  */
  	 /* Tested:
  	  * Playback on front, rear, center/lfe speakers
  	  * Capture from Mic in.
  	  * Not-Tested:
  	  * Capture from Line in.
  	  * Playback to digital out.
  	  */
  	 { .serial = 0x10121102,
  	   .name   = "X-Fi Extreme Audio [SB0790]",
  	   .gpio_type = 1,
  	   .i2c_adc = 1 } ,
  	 /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
1baa705b7   James Courtier-Dutton   [ALSA] Tidy up ca...
201
202
203
204
205
206
207
208
209
210
211
  	 /* AudigyLS[SB0310] */
  	 { .serial = 0x10021102,
  	   .name   = "AudigyLS [SB0310]",
  	   .ac97   = 1 } , 
  	 /* Unknown AudigyLS that also says SB0310 on it */
  	 { .serial = 0x10051102,
  	   .name   = "AudigyLS [SB0310b]",
  	   .ac97   = 1 } ,
  	 /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */
  	 { .serial = 0x10061102,
  	   .name   = "Live! 7.1 24bit [SB0410]",
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
212
213
  	   .gpio_type = 1,
  	   .i2c_adc = 1 } ,
1baa705b7   James Courtier-Dutton   [ALSA] Tidy up ca...
214
215
216
  	 /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
  	 { .serial = 0x10071102,
  	   .name   = "Live! 7.1 24bit [SB0413]",
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
217
218
  	   .gpio_type = 1,
  	   .i2c_adc = 1 } ,
a5875159d   James Courtier-Dutton   [ALSA] snd-ca0106...
219
220
221
  	 /* New Audigy SE. Has a different DAC. */
  	 /* SB0570:
  	  * CTRL:CA0106-DAT
583988956   James Courtier-Dutton   [ALSA] snd-ca0106...
222
223
  	  * ADC: WM8775EDS
  	  * DAC: WM8768GEDS
a5875159d   James Courtier-Dutton   [ALSA] snd-ca0106...
224
225
226
227
228
  	  */
  	 { .serial = 0x100a1102,
  	   .name   = "Audigy SE [SB0570]",
  	   .gpio_type = 1,
  	   .i2c_adc = 1,
6fef153af   Andy Owen   ALSA: ca0106: All...
229
  	   .spi_dac = 0x4021 } ,
e4f55d801   James Courtier-Dutton   [ALSA] snd-ca0106...
230
231
232
233
234
235
236
  	 /* New Audigy LS. Has a different DAC. */
  	 /* SB0570:
  	  * CTRL:CA0106-DAT
  	  * ADC: WM8775EDS
  	  * DAC: WM8768GEDS
  	  */
  	 { .serial = 0x10111102,
d5f6a38d9   James Courtier-Dutton   [ALSA] snd-ca0106...
237
  	   .name   = "Audigy SE OEM [SB0570a]",
e4f55d801   James Courtier-Dutton   [ALSA] snd-ca0106...
238
239
  	   .gpio_type = 1,
  	   .i2c_adc = 1,
6fef153af   Andy Owen   ALSA: ca0106: All...
240
  	   .spi_dac = 0x4021 } ,
23156e8fa   Andy Owen   ALSA: ca0106 - ad...
241
242
243
244
245
246
247
248
  	/* Sound Blaster 5.1vx
  	 * Tested: Playback on front, rear, center/lfe speakers
  	 * Not-Tested: Capture
  	 */
  	{ .serial = 0x10041102,
  	  .name   = "Sound Blaster 5.1vx [SB1070]",
  	  .gpio_type = 1,
  	  .i2c_adc = 0,
6fef153af   Andy Owen   ALSA: ca0106: All...
249
  	  .spi_dac = 0x0124
23156e8fa   Andy Owen   ALSA: ca0106 - ad...
250
  	 } ,
1baa705b7   James Courtier-Dutton   [ALSA] Tidy up ca...
251
  	 /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
be0b7b011   James Courtier-Dutton   [ALSA] ca0106: Fi...
252
253
254
255
256
  	 /* SB0438
  	  * CTRL:CA0106-DAT
  	  * ADC: WM8775SEDS
  	  * DAC: CS4382-KQZ
  	  */
1baa705b7   James Courtier-Dutton   [ALSA] Tidy up ca...
257
258
  	 { .serial = 0x10091462,
  	   .name   = "MSI K8N Diamond MB [SB0438]",
be0b7b011   James Courtier-Dutton   [ALSA] ca0106: Fi...
259
  	   .gpio_type = 2,
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
260
  	   .i2c_adc = 1 } ,
c5d44423d   Travis Place   ALSA: CA0106 on M...
261
  	 /* MSI K8N Diamond PLUS MB */
f52845ad7   Takashi Iwai   ALSA: ca0106 - Ad...
262
263
264
  	 { .serial = 0x10091102,
  	   .name   = "MSI K8N Diamond MB",
  	   .gpio_type = 2,
c5d44423d   Travis Place   ALSA: CA0106 on M...
265
  	   .i2c_adc = 1,
6fef153af   Andy Owen   ALSA: ca0106: All...
266
  	   .spi_dac = 0x4021 } ,
f3a374e55   Takashi Iwai   ALSA: ca0106 - Ad...
267
268
269
270
271
272
273
274
  	/* Giga-byte GA-G1975X mobo
  	 * Novell bnc#395807
  	 */
  	/* FIXME: the GPIO and I2C setting aren't tested well */
  	{ .serial = 0x1458a006,
  	  .name = "Giga-byte GA-G1975X",
  	  .gpio_type = 1,
  	  .i2c_adc = 1 },
be3cd57aa   James Courtier-Dutton   [ALSA] snd-ca0106...
275
276
  	 /* Shuttle XPC SD31P which has an onboard Creative Labs
  	  * Sound Blaster Live! 24-bit EAX
1b05962e8   James Courtier-Dutton   [ALSA] Add new ID...
277
278
279
280
281
282
283
  	  * high-definition 7.1 audio processor".
  	  * Added using info from andrewvegan in alsa bug #1298
  	  */
  	 { .serial = 0x30381297,
  	   .name   = "Shuttle XPC SD31P [SD31P]",
  	   .gpio_type = 1,
  	   .i2c_adc = 1 } ,
be3cd57aa   James Courtier-Dutton   [ALSA] snd-ca0106...
284
285
286
287
288
289
290
291
292
  	/* Shuttle XPC SD11G5 which has an onboard Creative Labs
  	 * Sound Blaster Live! 24-bit EAX
  	 * high-definition 7.1 audio processor".
  	 * Fixes ALSA bug#1600
           */
  	{ .serial = 0x30411297,
  	  .name = "Shuttle XPC SD11G5 [SD11G5]",
  	  .gpio_type = 1,
  	  .i2c_adc = 1 } ,
1baa705b7   James Courtier-Dutton   [ALSA] Tidy up ca...
293
294
  	 { .serial = 0,
  	   .name   = "AudigyLS [Unknown]" }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
  };
  
  /* hardware definition */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
298
  static struct snd_pcm_hardware snd_ca0106_playback_hw = {
b83f346bc   Clemens Ladisch   [ALSA] remove inc...
299
300
301
302
303
  	.info =			SNDRV_PCM_INFO_MMAP | 
  				SNDRV_PCM_INFO_INTERLEAVED |
  				SNDRV_PCM_INFO_BLOCK_TRANSFER |
  				SNDRV_PCM_INFO_MMAP_VALID |
  				SNDRV_PCM_INFO_SYNC_START,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
305
306
  	.rates =		(SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
  				 SNDRV_PCM_RATE_192000),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
317
  	.rate_min =		48000,
  	.rate_max =		192000,
  	.channels_min =		2,  //1,
  	.channels_max =		2,  //6,
  	.buffer_bytes_max =	((65536 - 64) * 8),
  	.period_bytes_min =	64,
  	.period_bytes_max =	(65536 - 64),
  	.periods_min =		2,
  	.periods_max =		8,
  	.fifo_size =		0,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
318
  static struct snd_pcm_hardware snd_ca0106_capture_hw = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
  	.info =			(SNDRV_PCM_INFO_MMAP | 
  				 SNDRV_PCM_INFO_INTERLEAVED |
  				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
  				 SNDRV_PCM_INFO_MMAP_VALID),
883130b47   James Courtier-Dutton   [ALSA] Implement ...
323
  	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
ff75427a7   Takashi Iwai   ALSA: ca0106 - di...
324
  #if 0 /* FIXME: looks like 44.1kHz capture causes noisy output on 48kHz */
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
325
326
  	.rates =		(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
  				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
883130b47   James Courtier-Dutton   [ALSA] Implement ...
327
  	.rate_min =		44100,
ff75427a7   Takashi Iwai   ALSA: ca0106 - di...
328
329
330
331
332
  #else
  	.rates =		(SNDRV_PCM_RATE_48000 |
  				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
  	.rate_min =		48000,
  #endif /* FIXME */
883130b47   James Courtier-Dutton   [ALSA] Implement ...
333
  	.rate_max =		192000,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  	.channels_min =		2,
  	.channels_max =		2,
34fdeb2d0   Takashi Iwai   ALSA: ca0106 - Fi...
336
  	.buffer_bytes_max =	65536 - 128,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	.period_bytes_min =	64,
34fdeb2d0   Takashi Iwai   ALSA: ca0106 - Fi...
338
  	.period_bytes_max =	32768 - 64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
  	.periods_min =		2,
  	.periods_max =		2,
  	.fifo_size =		0,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
343
  unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  					  unsigned int reg, 
  					  unsigned int chn)
  {
  	unsigned long flags;
  	unsigned int regptr, val;
    
  	regptr = (reg << 16) | chn;
  
  	spin_lock_irqsave(&emu->emu_lock, flags);
  	outl(regptr, emu->port + PTR);
  	val = inl(emu->port + DATA);
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  	return val;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
358
  void snd_ca0106_ptr_write(struct snd_ca0106 *emu, 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  				   unsigned int reg, 
  				   unsigned int chn, 
  				   unsigned int data)
  {
  	unsigned int regptr;
  	unsigned long flags;
  
  	regptr = (reg << 16) | chn;
  
  	spin_lock_irqsave(&emu->emu_lock, flags);
  	outl(regptr, emu->port + PTR);
  	outl(data, emu->port + DATA);
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  }
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
373
374
  int snd_ca0106_spi_write(struct snd_ca0106 * emu,
  				   unsigned int data)
a5875159d   James Courtier-Dutton   [ALSA] snd-ca0106...
375
  {
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  	unsigned int reset, set;
  	unsigned int reg, tmp;
  	int n, result;
  	reg = SPI;
  	if (data > 0xffff) /* Only 16bit values allowed */
  		return 1;
  	tmp = snd_ca0106_ptr_read(emu, reg, 0);
  	reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
  	set = reset | 0x10000; /* Set xxx1xxxx */
  	snd_ca0106_ptr_write(emu, reg, 0, reset | data);
  	tmp = snd_ca0106_ptr_read(emu, reg, 0); /* write post */
  	snd_ca0106_ptr_write(emu, reg, 0, set | data);
  	result = 1;
  	/* Wait for status bit to return to 0 */
  	for (n = 0; n < 100; n++) {
  		udelay(10);
  		tmp = snd_ca0106_ptr_read(emu, reg, 0);
  		if (!(tmp & 0x10000)) {
  			result = 0;
  			break;
  		}
  	}
  	if (result) /* Timed out */
  		return 1;
  	snd_ca0106_ptr_write(emu, reg, 0, reset | data);
  	tmp = snd_ca0106_ptr_read(emu, reg, 0); /* Write post */
a5875159d   James Courtier-Dutton   [ALSA] snd-ca0106...
402
403
  	return 0;
  }
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
404
  /* The ADC does not support i2c read, so only write is implemented */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
405
  int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
406
407
408
409
  				u32 reg,
  				u32 value)
  {
  	u32 tmp;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
410
  	int timeout = 0;
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
411
412
  	int status;
  	int retry;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
413
  	if ((reg > 0x7f) || (value > 0x1ff)) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
414
415
  		snd_printk(KERN_ERR "i2c_write: invalid values.
  ");
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
416
417
418
419
  		return -EINVAL;
  	}
  
  	tmp = reg << 25 | value << 16;
ee419653a   Takashi Iwai   ALSA: Fix missing...
420
421
422
423
  	/*
  	snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x
  ", reg, value);
  	*/
8fabab15d   James Courtier-Dutton   [ALSA] Be more sp...
424
425
426
427
  	/* Not sure what this I2C channel controls. */
  	/* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
  
  	/* This controls the I2C connected to the WM8775 ADC Codec */
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
428
  	snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp);
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
429
  	for (retry = 0; retry < 10; retry++) {
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
430
  		/* Send the data to i2c */
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
431
432
433
  		//tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
  		//tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
  		tmp = 0;
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
434
435
436
437
  		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
  		snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
  
  		/* Wait till the transaction ends */
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
438
  		while (1) {
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
439
  			status = snd_ca0106_ptr_read(emu, I2C_A, 0);
ee419653a   Takashi Iwai   ALSA: Fix missing...
440
441
  			/*snd_printk(KERN_DEBUG "I2C:status=0x%x
  ", status);*/
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
442
  			timeout++;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
443
  			if ((status & I2C_A_ADC_START) == 0)
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
444
  				break;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
445
  			if (timeout > 1000)
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
446
447
448
  				break;
  		}
  		//Read back and see if the transaction is successful
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
449
  		if ((status & I2C_A_ADC_ABORT) == 0)
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
450
451
  			break;
  	}
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
452
  	if (retry == 10) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
453
454
  		snd_printk(KERN_ERR "Writing to ADC failed!
  ");
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
455
456
457
458
459
  		return -EINVAL;
  	}
      
      	return 0;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
460
  static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
  {
  	unsigned long flags;
d967a0271   Harvey Harrison   [ALSA] sound: ca0...
463
  	unsigned int intr_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	spin_lock_irqsave(&emu->emu_lock, flags);
d967a0271   Harvey Harrison   [ALSA] sound: ca0...
465
466
  	intr_enable = inl(emu->port + INTE) | intrenb;
  	outl(intr_enable, emu->port + INTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
469
  static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb)
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
470
471
  {
  	unsigned long flags;
d967a0271   Harvey Harrison   [ALSA] sound: ca0...
472
  	unsigned int intr_enable;
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
473
  	spin_lock_irqsave(&emu->emu_lock, flags);
d967a0271   Harvey Harrison   [ALSA] sound: ca0...
474
475
  	intr_enable = inl(emu->port + INTE) & ~intrenb;
  	outl(intr_enable, emu->port + INTE);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
476
477
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
478
  static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  {
4d572776d   Jesper Juhl   [ALSA] Remove red...
480
  	kfree(runtime->private_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  }
485100706   Trent Piepho   [ALSA] ca0106: po...
482
  static const int spi_dacd_reg[] = {
861391d3a   Andy Owen   ALSA: ca0106: Cre...
483
484
485
486
487
  	SPI_DACD0_REG,
  	SPI_DACD1_REG,
  	SPI_DACD2_REG,
  	0,
  	SPI_DACD4_REG,
485100706   Trent Piepho   [ALSA] ca0106: po...
488
489
  };
  static const int spi_dacd_bit[] = {
861391d3a   Andy Owen   ALSA: ca0106: Cre...
490
491
492
493
494
  	SPI_DACD0_BIT,
  	SPI_DACD1_BIT,
  	SPI_DACD2_BIT,
  	0,
  	SPI_DACD4_BIT,
485100706   Trent Piepho   [ALSA] ca0106: po...
495
  };
3d4758299   Takashi Iwai   ALSA: ca0106 - Ad...
496
497
498
499
500
501
502
503
  static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
  {
  	if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) {
  		chip->spdif_str_bits[idx] = chip->spdif_bits[idx];
  		snd_ca0106_ptr_write(chip, SPCS0 + idx, 0,
  				     chip->spdif_str_bits[idx]);
  	}
  }
861391d3a   Andy Owen   ALSA: ca0106: Cre...
504
505
506
507
  static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
  				  int channel_id)
  {
  	switch (channel_id) {
6fef153af   Andy Owen   ALSA: ca0106: All...
508
509
510
511
512
513
514
515
516
517
518
519
  	case PCM_FRONT_CHANNEL:
  		return (details->spi_dac & 0xf000) >> (4 * 3);
  	case PCM_REAR_CHANNEL:
  		return (details->spi_dac & 0x0f00) >> (4 * 2);
  	case PCM_CENTER_LFE_CHANNEL:
  		return (details->spi_dac & 0x00f0) >> (4 * 1);
  	case PCM_UNKNOWN_CHANNEL:
  		return (details->spi_dac & 0x000f) >> (4 * 0);
  	default:
  		snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d
  ",
  			   channel_id);
861391d3a   Andy Owen   ALSA: ca0106: Cre...
520
  	}
861391d3a   Andy Owen   ALSA: ca0106: Cre...
521
522
  	return 0;
  }
51630142e   Andy Owen   ALSA: ca0106: Pul...
523
524
525
526
  static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
  				    int power)
  {
  	if (chip->details->spi_dac) {
861391d3a   Andy Owen   ALSA: ca0106: Cre...
527
528
529
530
  		const int dac = snd_ca0106_channel_dac(chip->details,
  						       channel_id);
  		const int reg = spi_dacd_reg[dac];
  		const int bit = spi_dacd_bit[dac];
51630142e   Andy Owen   ALSA: ca0106: Pul...
531
532
533
  
  		if (power)
  			/* Power up */
861391d3a   Andy Owen   ALSA: ca0106: Cre...
534
  			chip->spi_dac_reg[reg] &= ~bit;
51630142e   Andy Owen   ALSA: ca0106: Pul...
535
536
  		else
  			/* Power down */
861391d3a   Andy Owen   ALSA: ca0106: Cre...
537
  			chip->spi_dac_reg[reg] |= bit;
51630142e   Andy Owen   ALSA: ca0106: Pul...
538
539
540
541
  		return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  /* open_playback callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
543
544
  static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
  						int channel_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
546
547
548
549
  	struct snd_ca0106 *chip = snd_pcm_substream_chip(substream);
          struct snd_ca0106_channel *channel = &(chip->playback_channels[channel_id]);
  	struct snd_ca0106_pcm *epcm;
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	int err;
e560d8d83   Takashi Iwai   [ALSA] Replace wi...
551
  	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  
  	if (epcm == NULL)
  		return -ENOMEM;
  	epcm->emu = chip;
  	epcm->substream = substream;
          epcm->channel_id=channel_id;
    
  	runtime->private_data = epcm;
  	runtime->private_free = snd_ca0106_pcm_free_substream;
    
  	runtime->hw = snd_ca0106_playback_hw;
  
          channel->emu = chip;
          channel->number = channel_id;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
566
  	channel->use = 1;
ee419653a   Takashi Iwai   ALSA: Fix missing...
567
568
569
570
571
  	/*
  	printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p
  ",
  	       channel_id, chip, channel);
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
          //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
573
  	channel->epcm = epcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
  	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                  return err;
  	if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0)
                  return err;
b83f346bc   Clemens Ladisch   [ALSA] remove inc...
578
  	snd_pcm_set_sync(substream);
485100706   Trent Piepho   [ALSA] ca0106: po...
579

51630142e   Andy Owen   ALSA: ca0106: Pul...
580
581
582
  	/* Front channel dac should already be on */
  	if (channel_id != PCM_FRONT_CHANNEL) {
  		err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
485100706   Trent Piepho   [ALSA] ca0106: po...
583
584
585
  		if (err < 0)
  			return err;
  	}
3d4758299   Takashi Iwai   ALSA: ca0106 - Ad...
586
587
  
  	restore_spdif_bits(chip, channel_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
  	return 0;
  }
  
  /* close callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
592
  static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
594
595
596
597
  	struct snd_ca0106 *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
          struct snd_ca0106_pcm *epcm = runtime->private_data;
  	chip->playback_channels[epcm->channel_id].use = 0;
485100706   Trent Piepho   [ALSA] ca0106: po...
598

3d4758299   Takashi Iwai   ALSA: ca0106 - Ad...
599
  	restore_spdif_bits(chip, epcm->channel_id);
51630142e   Andy Owen   ALSA: ca0106: Pul...
600
601
602
603
604
605
  	/* Front channel dac should stay on */
  	if (epcm->channel_id != PCM_FRONT_CHANNEL) {
  		int err;
  		err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
  		if (err < 0)
  			return err;
485100706   Trent Piepho   [ALSA] ca0106: po...
606
  	}
51630142e   Andy Owen   ALSA: ca0106: Pul...
607

e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
608
  	/* FIXME: maybe zero others */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  	return 0;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
611
  static int snd_ca0106_pcm_open_playback_front(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
  {
  	return snd_ca0106_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
615
  static int snd_ca0106_pcm_open_playback_center_lfe(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
  {
  	return snd_ca0106_pcm_open_playback_channel(substream, PCM_CENTER_LFE_CHANNEL);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
619
  static int snd_ca0106_pcm_open_playback_unknown(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
  {
  	return snd_ca0106_pcm_open_playback_channel(substream, PCM_UNKNOWN_CHANNEL);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
623
  static int snd_ca0106_pcm_open_playback_rear(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
  {
  	return snd_ca0106_pcm_open_playback_channel(substream, PCM_REAR_CHANNEL);
  }
  
  /* open_capture callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
629
630
  static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substream,
  					       int channel_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
632
633
634
635
  	struct snd_ca0106 *chip = snd_pcm_substream_chip(substream);
          struct snd_ca0106_channel *channel = &(chip->capture_channels[channel_id]);
  	struct snd_ca0106_pcm *epcm;
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	int err;
e560d8d83   Takashi Iwai   [ALSA] Replace wi...
637
  	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  	if (epcm == NULL) {
99b359ba1   Takashi Iwai   [ALSA] Add missin...
639
640
  		snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
649
650
651
652
653
  		return -ENOMEM;
          }
  	epcm->emu = chip;
  	epcm->substream = substream;
          epcm->channel_id=channel_id;
    
  	runtime->private_data = epcm;
  	runtime->private_free = snd_ca0106_pcm_free_substream;
    
  	runtime->hw = snd_ca0106_capture_hw;
  
          channel->emu = chip;
          channel->number = channel_id;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
654
  	channel->use = 1;
ee419653a   Takashi Iwai   ALSA: Fix missing...
655
656
657
658
659
  	/*
          printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p
  ",
  	       channel_id, chip, channel);
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
          //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
661
          channel->epcm = epcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
668
669
670
  	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                  return err;
  	//snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_capture_period_sizes);
  	if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0)
                  return err;
  	return 0;
  }
  
  /* close callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
671
  static int snd_ca0106_pcm_close_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
673
674
675
676
677
  	struct snd_ca0106 *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
          struct snd_ca0106_pcm *epcm = runtime->private_data;
  	chip->capture_channels[epcm->channel_id].use = 0;
  	/* FIXME: maybe zero others */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
  	return 0;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
680
  static int snd_ca0106_pcm_open_0_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
  {
  	return snd_ca0106_pcm_open_capture_channel(substream, 0);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
684
  static int snd_ca0106_pcm_open_1_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
  {
  	return snd_ca0106_pcm_open_capture_channel(substream, 1);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
688
  static int snd_ca0106_pcm_open_2_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
  {
  	return snd_ca0106_pcm_open_capture_channel(substream, 2);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
692
  static int snd_ca0106_pcm_open_3_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
  {
  	return snd_ca0106_pcm_open_capture_channel(substream, 3);
  }
  
  /* hw_params callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
698
699
  static int snd_ca0106_pcm_hw_params_playback(struct snd_pcm_substream *substream,
  				      struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
  {
  	return snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  }
  
  /* hw_free callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
706
  static int snd_ca0106_pcm_hw_free_playback(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
  {
  	return snd_pcm_lib_free_pages(substream);
  }
  
  /* hw_params callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
712
713
  static int snd_ca0106_pcm_hw_params_capture(struct snd_pcm_substream *substream,
  				      struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
  {
  	return snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  }
  
  /* hw_free callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
720
  static int snd_ca0106_pcm_hw_free_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
  {
  	return snd_pcm_lib_free_pages(substream);
  }
  
  /* prepare playback callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
726
  static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
728
729
730
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ca0106_pcm *epcm = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  	int channel = epcm->channel_id;
  	u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel));
  	u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
  	u32 hcfg_mask = HCFG_PLAYBACK_S32_LE;
  	u32 hcfg_set = 0x00000000;
  	u32 hcfg;
  	u32 reg40_mask = 0x30000 << (channel<<1);
  	u32 reg40_set = 0;
  	u32 reg40;
  	/* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */
  	u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */
  	u32 reg71_set = 0;
  	u32 reg71;
  	int i;
  	
ee419653a   Takashi Iwai   ALSA: Fix missing...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
  #if 0 /* debug */
  	snd_printk(KERN_DEBUG
  		   "prepare:channel_number=%d, rate=%d, format=0x%x, "
  		   "channels=%d, buffer_size=%ld, period_size=%ld, "
  		   "periods=%u, frames_to_bytes=%d
  ",
  		   channel, runtime->rate, runtime->format,
  		   runtime->channels, runtime->buffer_size,
  		   runtime->period_size, runtime->periods,
  		   frames_to_bytes(runtime, 1));
  	snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p
  ",
  		   runtime->dma_addr, runtime->dma_area, table_base);
  	snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x
  ",
  		   emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
  #endif /* debug */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
  	/* Rate can be set per channel. */
  	/* reg40 control host to fifo */
  	/* reg71 controls DAC rate. */
  	switch (runtime->rate) {
  	case 44100:
  		reg40_set = 0x10000 << (channel<<1);
  		reg71_set = 0x01010000; 
  		break;
          case 48000:
  		reg40_set = 0;
  		reg71_set = 0; 
  		break;
  	case 96000:
  		reg40_set = 0x20000 << (channel<<1);
  		reg71_set = 0x02020000; 
  		break;
  	case 192000:
  		reg40_set = 0x30000 << (channel<<1);
  		reg71_set = 0x03030000; 
  		break;
  	default:
  		reg40_set = 0;
  		reg71_set = 0; 
  		break;
  	}
  	/* Format is a global setting */
  	/* FIXME: Only let the first channel accessed set this. */
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
  		hcfg_set = 0;
  		break;
  	case SNDRV_PCM_FORMAT_S32_LE:
  		hcfg_set = HCFG_PLAYBACK_S32_LE;
  		break;
  	default:
  		hcfg_set = 0;
  		break;
  	}
  	hcfg = inl(emu->port + HCFG) ;
  	hcfg = (hcfg & ~hcfg_mask) | hcfg_set;
  	outl(hcfg, emu->port + HCFG);
  	reg40 = snd_ca0106_ptr_read(emu, 0x40, 0);
  	reg40 = (reg40 & ~reg40_mask) | reg40_set;
  	snd_ca0106_ptr_write(emu, 0x40, 0, reg40);
  	reg71 = snd_ca0106_ptr_read(emu, 0x71, 0);
  	reg71 = (reg71 & ~reg71_mask) | reg71_set;
  	snd_ca0106_ptr_write(emu, 0x71, 0, reg71);
  
  	/* FIXME: Check emu->buffer.size before actually writing to it. */
          for(i=0; i < runtime->periods; i++) {
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
813
814
  		table_base[i*2] = runtime->dma_addr + (i * period_size_bytes);
  		table_base[i*2+1] = period_size_bytes << 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  	}
   
  	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_ADDR, channel, emu->buffer.addr+(8*16*channel));
  	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);
  	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0);
  	snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);
  	snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
  	/* FIXME  test what 0 bytes does. */
  	snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes
  	snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0);
  	snd_ca0106_ptr_write(emu, 0x07, channel, 0x0);
  	snd_ca0106_ptr_write(emu, 0x08, channel, 0);
          snd_ca0106_ptr_write(emu, PLAYBACK_MUTE, 0x0, 0x0); /* Unmute output */
  #if 0
  	snd_ca0106_ptr_write(emu, SPCS0, 0,
  			       SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
  			       SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
  			       SPCS_GENERATIONSTATUS | 0x00001200 |
  			       0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT );
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
836
837
838
839
  #endif
  
  	return 0;
  }
  
  /* prepare capture callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
840
  static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
842
843
844
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ca0106_pcm *epcm = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  	int channel = epcm->channel_id;
883130b47   James Courtier-Dutton   [ALSA] Implement ...
846
847
848
849
850
851
852
853
  	u32 hcfg_mask = HCFG_CAPTURE_S32_LE;
  	u32 hcfg_set = 0x00000000;
  	u32 hcfg;
  	u32 over_sampling=0x2;
  	u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */
  	u32 reg71_set = 0;
  	u32 reg71;
  	
ee419653a   Takashi Iwai   ALSA: Fix missing...
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  #if 0 /* debug */
  	snd_printk(KERN_DEBUG
  		   "prepare:channel_number=%d, rate=%d, format=0x%x, "
  		   "channels=%d, buffer_size=%ld, period_size=%ld, "
  		   "periods=%u, frames_to_bytes=%d
  ",
  		   channel, runtime->rate, runtime->format,
  		   runtime->channels, runtime->buffer_size,
  		   runtime->period_size, runtime->periods,
  		   frames_to_bytes(runtime, 1));
          snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p
  ",
  		   runtime->dma_addr, runtime->dma_area, table_base);
  	snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x
  ",
  		   emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
  #endif /* debug */
883130b47   James Courtier-Dutton   [ALSA] Implement ...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  	/* reg71 controls ADC rate. */
  	switch (runtime->rate) {
  	case 44100:
  		reg71_set = 0x00004000;
  		break;
          case 48000:
  		reg71_set = 0; 
  		break;
  	case 96000:
  		reg71_set = 0x00008000;
  		over_sampling=0xa;
  		break;
  	case 192000:
  		reg71_set = 0x0000c000; 
  		over_sampling=0xa;
  		break;
  	default:
  		reg71_set = 0; 
  		break;
  	}
  	/* Format is a global setting */
  	/* FIXME: Only let the first channel accessed set this. */
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
  		hcfg_set = 0;
  		break;
  	case SNDRV_PCM_FORMAT_S32_LE:
  		hcfg_set = HCFG_CAPTURE_S32_LE;
  		break;
  	default:
  		hcfg_set = 0;
  		break;
  	}
  	hcfg = inl(emu->port + HCFG) ;
  	hcfg = (hcfg & ~hcfg_mask) | hcfg_set;
  	outl(hcfg, emu->port + HCFG);
  	reg71 = snd_ca0106_ptr_read(emu, 0x71, 0);
  	reg71 = (reg71 & ~reg71_mask) | reg71_set;
  	snd_ca0106_ptr_write(emu, 0x71, 0, reg71);
          if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
  	        snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */
  	}
ee419653a   Takashi Iwai   ALSA: Fix missing...
913
914
915
916
917
918
919
920
921
  	/*
  	printk(KERN_DEBUG
  	       "prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, "
  	       "buffer_size=%ld, period_size=%ld, frames_to_bytes=%d
  ",
  	       channel, runtime->rate, runtime->format, runtime->channels,
  	       runtime->buffer_size, runtime->period_size,
  	       frames_to_bytes(runtime, 1));
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
925
926
927
928
929
930
  	snd_ca0106_ptr_write(emu, 0x13, channel, 0);
  	snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
  	snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
  	snd_ca0106_ptr_write(emu, CAPTURE_POINTER, channel, 0);
  
  	return 0;
  }
  
  /* trigger_playback callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
931
  static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
  				    int cmd)
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
934
935
936
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime;
  	struct snd_ca0106_pcm *epcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
  	int channel;
  	int result = 0;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
939
          struct snd_pcm_substream *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
  	u32 basic = 0;
  	u32 extended = 0;
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
942
943
  	u32 bits;
  	int running = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
947
948
  	case SNDRV_PCM_TRIGGER_RESUME:
  		running = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
951
  	case SNDRV_PCM_TRIGGER_SUSPEND:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  	default:
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
953
  		running = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
  		break;
  	}
ef991b95a   Takashi Iwai   [ALSA] Add snd_pc...
956
          snd_pcm_group_for_each_entry(s, substream) {
29998d24a   Clemens Ladisch   [ALSA] check for ...
957
958
959
  		if (snd_pcm_substream_chip(s) != emu ||
  		    s->stream != SNDRV_PCM_STREAM_PLAYBACK)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
  		runtime = s->runtime;
  		epcm = runtime->private_data;
  		channel = epcm->channel_id;
ee419653a   Takashi Iwai   ALSA: Fix missing...
963
964
  		/* snd_printk(KERN_DEBUG "channel=%d
  ", channel); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  		epcm->running = running;
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
966
967
  		basic |= (0x1 << channel);
  		extended |= (0x10 << channel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
                  snd_pcm_trigger_done(s, substream);
          }
ee419653a   Takashi Iwai   ALSA: Fix missing...
970
971
  	/* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x
  ",basic, extended); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
975
976
977
978
979
980
981
  	case SNDRV_PCM_TRIGGER_RESUME:
  		bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0);
  		bits |= extended;
  		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits);
  		bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0);
  		bits |= basic;
  		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
984
985
986
987
988
989
990
  	case SNDRV_PCM_TRIGGER_SUSPEND:
  		bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0);
  		bits &= ~basic;
  		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits);
  		bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0);
  		bits &= ~extended;
  		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
994
995
996
997
998
999
  		break;
  	default:
  		result = -EINVAL;
  		break;
  	}
  	return result;
  }
  
  /* trigger_capture callback */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1000
  static int snd_ca0106_pcm_trigger_capture(struct snd_pcm_substream *substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
  				    int cmd)
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1003
1004
1005
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ca0106_pcm *epcm = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  	int channel = epcm->channel_id;
  	int result = 0;
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
  		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel));
  		epcm->running = 1;
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel));
  		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel));
  		epcm->running = 0;
  		break;
  	default:
  		result = -EINVAL;
  		break;
  	}
  	return result;
  }
  
  /* pointer_playback callback */
  static snd_pcm_uframes_t
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1029
  snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1031
1032
1033
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ca0106_pcm *epcm = runtime->private_data;
add7c0a6a   Takashi Iwai   ALSA: ca0106 - cl...
1034
  	unsigned int ptr, prev_ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  	int channel = epcm->channel_id;
add7c0a6a   Takashi Iwai   ALSA: ca0106 - cl...
1036
  	int timeout = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
  
  	if (!epcm->running)
  		return 0;
add7c0a6a   Takashi Iwai   ALSA: ca0106 - cl...
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  	prev_ptr = -1;
  	do {
  		ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
  		ptr = (ptr >> 3) * runtime->period_size;
  		ptr += bytes_to_frames(runtime,
  			snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
  		if (ptr >= runtime->buffer_size)
  			ptr -= runtime->buffer_size;
  		if (prev_ptr == ptr)
  			return ptr;
  		prev_ptr = ptr;
  	} while (--timeout);
  	snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!
  ");
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
1057
1058
  }
  
  /* pointer_capture callback */
  static snd_pcm_uframes_t
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1059
  snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1061
1062
1063
  	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct snd_ca0106_pcm *epcm = runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
  	snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;
c521dde6a   Jesper Juhl   sound, ca0106: Fi...
1065
  	int channel = epcm->channel_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
1068
1069
1070
1071
1072
1073
1074
  
  	if (!epcm->running)
  		return 0;
  
  	ptr1 = snd_ca0106_ptr_read(emu, CAPTURE_POINTER, channel);
  	ptr2 = bytes_to_frames(runtime, ptr1);
  	ptr=ptr2;
          if (ptr >= runtime->buffer_size)
  		ptr -= runtime->buffer_size;
ee419653a   Takashi Iwai   ALSA: Fix missing...
1075
1076
1077
1078
1079
1080
1081
1082
  	/*
  	printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
  	       "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d
  ",
  	       ptr1, ptr2, ptr, (int)runtime->buffer_size,
  	       (int)runtime->period_size, (int)runtime->frame_bits,
  	       (int)runtime->rate);
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
1085
1086
  	return ptr;
  }
  
  /* operators */
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1087
  static struct snd_pcm_ops snd_ca0106_playback_front_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
1092
1093
1094
1095
1096
  	.open =        snd_ca0106_pcm_open_playback_front,
  	.close =       snd_ca0106_pcm_close_playback,
  	.ioctl =       snd_pcm_lib_ioctl,
  	.hw_params =   snd_ca0106_pcm_hw_params_playback,
  	.hw_free =     snd_ca0106_pcm_hw_free_playback,
  	.prepare =     snd_ca0106_pcm_prepare_playback,
  	.trigger =     snd_ca0106_pcm_trigger_playback,
  	.pointer =     snd_ca0106_pcm_pointer_playback,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1097
  static struct snd_pcm_ops snd_ca0106_capture_0_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	.open =        snd_ca0106_pcm_open_0_capture,
  	.close =       snd_ca0106_pcm_close_capture,
  	.ioctl =       snd_pcm_lib_ioctl,
  	.hw_params =   snd_ca0106_pcm_hw_params_capture,
  	.hw_free =     snd_ca0106_pcm_hw_free_capture,
  	.prepare =     snd_ca0106_pcm_prepare_capture,
  	.trigger =     snd_ca0106_pcm_trigger_capture,
  	.pointer =     snd_ca0106_pcm_pointer_capture,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1107
  static struct snd_pcm_ops snd_ca0106_capture_1_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
1110
1111
1112
1113
1114
1115
1116
  	.open =        snd_ca0106_pcm_open_1_capture,
  	.close =       snd_ca0106_pcm_close_capture,
  	.ioctl =       snd_pcm_lib_ioctl,
  	.hw_params =   snd_ca0106_pcm_hw_params_capture,
  	.hw_free =     snd_ca0106_pcm_hw_free_capture,
  	.prepare =     snd_ca0106_pcm_prepare_capture,
  	.trigger =     snd_ca0106_pcm_trigger_capture,
  	.pointer =     snd_ca0106_pcm_pointer_capture,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1117
  static struct snd_pcm_ops snd_ca0106_capture_2_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
1125
1126
  	.open =        snd_ca0106_pcm_open_2_capture,
  	.close =       snd_ca0106_pcm_close_capture,
  	.ioctl =       snd_pcm_lib_ioctl,
  	.hw_params =   snd_ca0106_pcm_hw_params_capture,
  	.hw_free =     snd_ca0106_pcm_hw_free_capture,
  	.prepare =     snd_ca0106_pcm_prepare_capture,
  	.trigger =     snd_ca0106_pcm_trigger_capture,
  	.pointer =     snd_ca0106_pcm_pointer_capture,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1127
  static struct snd_pcm_ops snd_ca0106_capture_3_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
1130
1131
1132
1133
1134
1135
1136
  	.open =        snd_ca0106_pcm_open_3_capture,
  	.close =       snd_ca0106_pcm_close_capture,
  	.ioctl =       snd_pcm_lib_ioctl,
  	.hw_params =   snd_ca0106_pcm_hw_params_capture,
  	.hw_free =     snd_ca0106_pcm_hw_free_capture,
  	.prepare =     snd_ca0106_pcm_prepare_capture,
  	.trigger =     snd_ca0106_pcm_trigger_capture,
  	.pointer =     snd_ca0106_pcm_pointer_capture,
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1137
  static struct snd_pcm_ops snd_ca0106_playback_center_lfe_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
1144
1145
1146
          .open =         snd_ca0106_pcm_open_playback_center_lfe,
          .close =        snd_ca0106_pcm_close_playback,
          .ioctl =        snd_pcm_lib_ioctl,
          .hw_params =    snd_ca0106_pcm_hw_params_playback,
          .hw_free =      snd_ca0106_pcm_hw_free_playback,
          .prepare =      snd_ca0106_pcm_prepare_playback,     
          .trigger =      snd_ca0106_pcm_trigger_playback,  
          .pointer =      snd_ca0106_pcm_pointer_playback, 
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1147
  static struct snd_pcm_ops snd_ca0106_playback_unknown_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
1152
1153
1154
1155
1156
          .open =         snd_ca0106_pcm_open_playback_unknown,
          .close =        snd_ca0106_pcm_close_playback,
          .ioctl =        snd_pcm_lib_ioctl,
          .hw_params =    snd_ca0106_pcm_hw_params_playback,
          .hw_free =      snd_ca0106_pcm_hw_free_playback,
          .prepare =      snd_ca0106_pcm_prepare_playback,     
          .trigger =      snd_ca0106_pcm_trigger_playback,  
          .pointer =      snd_ca0106_pcm_pointer_playback, 
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1157
  static struct snd_pcm_ops snd_ca0106_playback_rear_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
1164
1165
1166
          .open =         snd_ca0106_pcm_open_playback_rear,
          .close =        snd_ca0106_pcm_close_playback,
          .ioctl =        snd_pcm_lib_ioctl,
          .hw_params =    snd_ca0106_pcm_hw_params_playback,
  		.hw_free =      snd_ca0106_pcm_hw_free_playback,
          .prepare =      snd_ca0106_pcm_prepare_playback,     
          .trigger =      snd_ca0106_pcm_trigger_playback,  
          .pointer =      snd_ca0106_pcm_pointer_playback, 
  };
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1167
  static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
  					     unsigned short reg)
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1170
  	struct snd_ca0106 *emu = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
1174
1175
1176
1177
1178
1179
  	unsigned long flags;
  	unsigned short val;
  
  	spin_lock_irqsave(&emu->emu_lock, flags);
  	outb(reg, emu->port + AC97ADDRESS);
  	val = inw(emu->port + AC97DATA);
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  	return val;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1180
  static void snd_ca0106_ac97_write(struct snd_ac97 *ac97,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
  				    unsigned short reg, unsigned short val)
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1183
  	struct snd_ca0106 *emu = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
1185
1186
1187
1188
1189
1190
  	unsigned long flags;
    
  	spin_lock_irqsave(&emu->emu_lock, flags);
  	outb(reg, emu->port + AC97ADDRESS);
  	outw(val, emu->port + AC97DATA);
  	spin_unlock_irqrestore(&emu->emu_lock, flags);
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1191
  static int snd_ca0106_ac97(struct snd_ca0106 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1193
1194
  	struct snd_ac97_bus *pbus;
  	struct snd_ac97_template ac97;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
  	int err;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1196
  	static struct snd_ac97_bus_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  		.write = snd_ca0106_ac97_write,
  		.read = snd_ca0106_ac97_read,
  	};
    
  	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)
  		return err;
  	pbus->no_vra = 1; /* we don't need VRA */
  
  	memset(&ac97, 0, sizeof(ac97));
  	ac97.private_data = chip;
36c4dc422   Takashi Iwai   [ALSA] Skip ac97 ...
1207
  	ac97.scaps = AC97_SCAP_NO_SPDIF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
  	return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
  }
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1210
  static void ca0106_stop_chip(struct snd_ca0106 *chip);
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1211
  static int snd_ca0106_free(struct snd_ca0106 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
  {
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1213
1214
1215
  	if (chip->res_port != NULL) {
  		/* avoid access to already used hardware */
  		ca0106_stop_chip(chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  	}
ebf029da3   Takashi Iwai   [ALSA] Fix possib...
1217
1218
  	if (chip->irq >= 0)
  		free_irq(chip->irq, chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
1221
1222
1223
1224
1225
  	// release the data
  #if 1
  	if (chip->buffer.area)
  		snd_dma_free_pages(&chip->buffer);
  #endif
  
  	// release the i/o port
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
1226
  	release_and_free_resource(chip->res_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
1229
1230
  	pci_disable_device(chip->pci);
  	kfree(chip);
  	return 0;
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1231
  static int snd_ca0106_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1233
  	struct snd_ca0106 *chip = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
  	return snd_ca0106_free(chip);
  }
7d12e780e   David Howells   IRQ: Maintain reg...
1236
  static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
  {
  	unsigned int status;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1239
  	struct snd_ca0106 *chip = dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
1241
1242
  	int i;
  	int mask;
          unsigned int stat76;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1243
  	struct snd_ca0106_channel *pchannel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
  	status = inl(chip->port + IPR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
1247
1248
1249
  	if (! status)
  		return IRQ_NONE;
  
          stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);
ee419653a   Takashi Iwai   ALSA: Fix missing...
1250
1251
1252
1253
1254
1255
1256
1257
  	/*
  	snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x
  ",
  		   status, stat76);
  	snd_printk(KERN_DEBUG "ptr=0x%08x
  ",
  		   snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
1260
          mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */
  	for(i = 0; i < 4; i++) {
  		pchannel = &(chip->playback_channels[i]);
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1261
  		if (stat76 & mask) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
  /* FIXME: Select the correct substream for period elapsed */
  			if(pchannel->use) {
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1264
1265
1266
  				snd_pcm_period_elapsed(pchannel->epcm->substream);
  				//printk(KERN_INFO "interrupt [%d] used
  ", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
                          }
  		}
  	        //printk(KERN_INFO "channel=%p
  ",pchannel);
  	        //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d
  ", i, stat76, pchannel->use, pchannel->number);
  		mask <<= 1;
  	}
          mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */
  	for(i = 0; i < 4; i++) {
  		pchannel = &(chip->capture_channels[i]);
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1278
  		if (stat76 & mask) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
  /* FIXME: Select the correct substream for period elapsed */
  			if(pchannel->use) {
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1281
1282
1283
  				snd_pcm_period_elapsed(pchannel->epcm->substream);
  				//printk(KERN_INFO "interrupt [%d] used
  ", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
                          }
  		}
  	        //printk(KERN_INFO "channel=%p
  ",pchannel);
  	        //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d
  ", i, stat76, pchannel->use, pchannel->number);
  		mask <<= 1;
  	}
  
          snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1294
1295
  
  	if (chip->midi.dev_id &&
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1296
  	    (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) {
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1297
1298
1299
1300
1301
  		if (chip->midi.interrupt)
  			chip->midi.interrupt(&chip->midi, status);
  		else
  			chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
  	// acknowledge the interrupt if necessary
  	outl(status, chip->port+IPR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
  	return IRQ_HANDLED;
  }
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1306
  static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1308
1309
  	struct snd_pcm *pcm;
  	struct snd_pcm_substream *substream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
1311
  	int err;
    
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1312
1313
  	err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
1316
  		return err;
    
  	pcm->private_data = emu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
  
  	switch (device) {
  	case 0:
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops);
            break;
  	case 1:
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops);
            break;
  	case 2:
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops);
            break;
  	case 3:
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);
  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops);
            break;
          }
  
  	pcm->info_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
  	strcpy(pcm->name, "CA0106");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
  
  	for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 
  	    substream; 
  	    substream = substream->next) {
  		if ((err = snd_pcm_lib_preallocate_pages(substream, 
  							 SNDRV_DMA_TYPE_DEV, 
  							 snd_dma_pci_data(emu->pci), 
  							 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */
  			return err;
  	}
  
  	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 
  	      substream; 
  	      substream = substream->next) {
   		if ((err = snd_pcm_lib_preallocate_pages(substream, 
  	                                           SNDRV_DMA_TYPE_DEV, 
  	                                           snd_dma_pci_data(emu->pci), 
  	                                           64*1024, 64*1024)) < 0)
  			return err;
  	}
    
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1360
  	emu->pcm[device] = pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
    
  	return 0;
  }
18b5d32f2   Trent Piepho   [ALSA] ca0106: Ad...
1364
  #define SPI_REG(reg, value)	(((reg) << SPI_REG_SHIFT) | (value))
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
1365
  static unsigned int spi_dac_init[] = {
18b5d32f2   Trent Piepho   [ALSA] ca0106: Ad...
1366
1367
  	SPI_REG(SPI_LDA1_REG,	SPI_DA_BIT_0dB), /* 0dB dig. attenuation */
  	SPI_REG(SPI_RDA1_REG,	SPI_DA_BIT_0dB),
b87c464ea   Trent Piepho   [ALSA] ca0106: re...
1368
1369
  	SPI_REG(SPI_PL_REG,	SPI_PL_BIT_L_L | SPI_PL_BIT_R_R | SPI_IZD_BIT),
  	SPI_REG(SPI_FMT_REG,	SPI_FMT_BIT_I2S | SPI_IWL_BIT_24),
18b5d32f2   Trent Piepho   [ALSA] ca0106: Ad...
1370
1371
1372
1373
1374
1375
  	SPI_REG(SPI_LDA2_REG,	SPI_DA_BIT_0dB),
  	SPI_REG(SPI_RDA2_REG,	SPI_DA_BIT_0dB),
  	SPI_REG(SPI_LDA3_REG,	SPI_DA_BIT_0dB),
  	SPI_REG(SPI_RDA3_REG,	SPI_DA_BIT_0dB),
  	SPI_REG(SPI_MASTDA_REG,	SPI_DA_BIT_0dB),
  	SPI_REG(9,		0x00),
b87c464ea   Trent Piepho   [ALSA] ca0106: re...
1376
  	SPI_REG(SPI_MS_REG,	SPI_DACD0_BIT | SPI_DACD1_BIT | SPI_DACD2_BIT),
18b5d32f2   Trent Piepho   [ALSA] ca0106: Ad...
1377
1378
  	SPI_REG(12,		0x00),
  	SPI_REG(SPI_LDA4_REG,	SPI_DA_BIT_0dB),
b87c464ea   Trent Piepho   [ALSA] ca0106: re...
1379
  	SPI_REG(SPI_RDA4_REG,	SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
9bfd94132   Andy Owen   ALSA: ca0106: Mov...
1380
  	SPI_REG(SPI_DACD4_REG,	SPI_DACD4_BIT),
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
1381
  };
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
  static unsigned int i2c_adc_init[][2] = {
  	{ 0x17, 0x00 }, /* Reset */
  	{ 0x07, 0x00 }, /* Timeout */
  	{ 0x0b, 0x22 },  /* Interface control */
  	{ 0x0c, 0x22 },  /* Master mode control */
  	{ 0x0d, 0x08 },  /* Powerdown control */
  	{ 0x0e, 0xcf },  /* Attenuation Left  0x01 = -103dB, 0xff = 24dB */
  	{ 0x0f, 0xcf },  /* Attenuation Right 0.5dB steps */
  	{ 0x10, 0x7b },  /* ALC Control 1 */
  	{ 0x11, 0x00 },  /* ALC Control 2 */
  	{ 0x12, 0x32 },  /* ALC Control 3 */
  	{ 0x13, 0x00 },  /* Noise gate control */
  	{ 0x14, 0xa6 },  /* Limiter control */
  	{ 0x15, ADC_MUX_LINEIN },  /* ADC Mixer control */
  };
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1397
  static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
  	int ch;
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1400
  	unsigned int def_bits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
  
  	outl(0, chip->port + INTE);
  
  	/*
  	 *  Init to 0x02109204 :
  	 *  Clock accuracy    = 0     (1000ppm)
  	 *  Sample Rate       = 2     (48kHz)
  	 *  Audio Channel     = 1     (Left of 2)
  	 *  Source Number     = 0     (Unspecified)
  	 *  Generation Status = 1     (Original for Cat Code 12)
  	 *  Cat Code          = 12    (Digital Signal Mixer)
  	 *  Mode              = 0     (Mode 0)
  	 *  Emphasis          = 0     (None)
  	 *  CP                = 1     (Copyright unasserted)
  	 *  AN                = 0     (Audio data)
  	 *  P                 = 0     (Consumer)
  	 */
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1418
  	def_bits =
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1419
1420
1421
1422
  		SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
  		SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
  		SPCS_GENERATIONSTATUS | 0x00001200 |
  		0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1423
  	if (!resume) {
3d4758299   Takashi Iwai   ALSA: ca0106 - Ad...
1424
1425
1426
1427
  		chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits;
  		chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits;
  		chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits;
  		chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits;
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1428
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429
  	/* Only SPCS1 has been tested */
3d4758299   Takashi Iwai   ALSA: ca0106 - Ad...
1430
1431
1432
1433
  	snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]);
  	snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]);
  	snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]);
  	snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
1435
1436
1437
1438
1439
1440
  
          snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000);
          snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000);
  
          /* Write 0x8000 to AC97_REC_GAIN to mute it. */
          outb(AC97_REC_GAIN, chip->port + AC97ADDRESS);
          outw(0x8000, chip->port + AC97DATA);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1441
  #if 0 /* FIXME: what are these? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
1443
1444
1445
1446
  	snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006);
  	snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006);
  	snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006);
  	snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006);
  #endif
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1447
1448
  	/* OSS drivers set this. */
  	/* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1449
1450
  	/* Analog or Digital output */
  	snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1451
1452
1453
1454
  	/* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers.
  	 * Use 0x000f0000 for surround71
  	 */
  	snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  	chip->spdif_enable = 0; /* Set digital SPDIF output off */
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  	/*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */
  	/*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */
  
  	/* goes to 0x40c80000 when doing SPDIF IN/OUT */
  	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000);
  	/* (Mute) CAPTURE feedback into PLAYBACK volume.
  	 * Only lower 16 bits matter.
  	 */
  	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff);
  	/* SPDIF IN Volume */
  	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000);
  	/* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */
  	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
1473
  	snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410);
  	snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676);
  	snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410);
  	snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1474
1475
1476
1477
  
  	for (ch = 0; ch < 4; ch++) {
  		/* Only high 16 bits matter */
  		snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
  		snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1479
1480
1481
1482
1483
1484
  #if 0 /* Mute */
  		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040);
  		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040);
  		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff);
  		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485
  	}
7c157069b   James Courtier-Dutton   [ALSA] ca0106: Fi...
1486
1487
1488
1489
  	if (chip->details->i2c_adc == 1) {
  	        /* Select MIC, Line in, TAD in, AUX in */
  	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
  		/* Default to CAPTURE_SOURCE to i2s in */
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1490
1491
  		if (!resume)
  			chip->capture_source = 3;
7c157069b   James Courtier-Dutton   [ALSA] ca0106: Fi...
1492
1493
1494
1495
  	} else if (chip->details->ac97 == 1) {
  	        /* Default to AC97 in */
  	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
  		/* Default to CAPTURE_SOURCE to AC97 in */
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1496
1497
  		if (!resume)
  			chip->capture_source = 4;
7c157069b   James Courtier-Dutton   [ALSA] ca0106: Fi...
1498
1499
1500
1501
  	} else {
  	        /* Select MIC, Line in, TAD in, AUX in */
  	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
  		/* Default to Set CAPTURE_SOURCE to i2s in */
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1502
1503
  		if (!resume)
  			chip->capture_source = 3;
7c157069b   James Courtier-Dutton   [ALSA] ca0106: Fi...
1504
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1506
1507
1508
1509
1510
  	if (chip->details->gpio_type == 2) {
  		/* The SB0438 use GPIO differently. */
  		/* FIXME: Still need to find out what the other GPIO bits do.
  		 * E.g. For digital spdif out.
  		 */
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
1511
  		outl(0x0, chip->port+GPIO);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1512
  		/* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
1513
  		outl(0x005f5301, chip->port+GPIO); /* Analog */
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1514
1515
1516
1517
1518
  	} else if (chip->details->gpio_type == 1) {
  		/* The SB0410 and SB0413 use GPIO differently. */
  		/* FIXME: Still need to find out what the other GPIO bits do.
  		 * E.g. For digital spdif out.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
  		outl(0x0, chip->port+GPIO);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1520
  		/* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */
c82bf829c   James Courtier-Dutton   [ALSA] ca0106: Fi...
1521
  		outl(0x005f5301, chip->port+GPIO); /* Analog */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
1524
  	} else {
  		outl(0x0, chip->port+GPIO);
  		outl(0x005f03a3, chip->port+GPIO); /* Analog */
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1525
  		/* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526
1527
  	}
  	snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1528
1529
1530
1531
1532
1533
  	/* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */
  	/* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */
  	/* outl(0x00001409, chip->port+HCFG); */
  	/* outl(0x00000009, chip->port+HCFG); */
  	/* AC97 2.0, Enable outputs. */
  	outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1535
1536
  	if (chip->details->i2c_adc == 1) {
  		/* The SB0410 and SB0413 use I2C to control ADC. */
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
1537
1538
1539
  		int size, n;
  
  		size = ARRAY_SIZE(i2c_adc_init);
ee419653a   Takashi Iwai   ALSA: Fix missing...
1540
1541
  		/* snd_printk(KERN_DEBUG "I2C:array size=0x%x
  ", size); */
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1542
1543
1544
1545
1546
1547
  		for (n = 0; n < size; n++)
  			snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
  					     i2c_adc_init[n][1]);
  		for (n = 0; n < 4; n++) {
  			chip->i2c_capture_volume[n][0] = 0xcf;
  			chip->i2c_capture_volume[n][1] = 0xcf;
6129daaa0   James Courtier-Dutton   [ALSA] ca0106: Ad...
1548
  		}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1549
1550
1551
  		chip->i2c_capture_source = 2; /* Line in */
  		/* Enable Line-in capture. MIC in currently untested. */
  		/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
1552
  	}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1553

6fef153af   Andy Owen   ALSA: ca0106: All...
1554
  	if (chip->details->spi_dac) {
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1555
  		/* The SB0570 use SPI to control DAC. */
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
1556
1557
1558
  		int size, n;
  
  		size = ARRAY_SIZE(spi_dac_init);
b18cd538a   Trent Piepho   [ALSA] ca0106: Ad...
1559
1560
  		for (n = 0; n < size; n++) {
  			int reg = spi_dac_init[n] >> SPI_REG_SHIFT;
aad909532   James Courtier-Dutton   [ALSA] snd-ca0106...
1561
  			snd_ca0106_spi_write(chip, spi_dac_init[n]);
b18cd538a   Trent Piepho   [ALSA] ca0106: Ad...
1562
1563
1564
  			if (reg < ARRAY_SIZE(chip->spi_dac_reg))
  				chip->spi_dac_reg[reg] = spi_dac_init[n];
  		}
9bfd94132   Andy Owen   ALSA: ca0106: Mov...
1565
1566
1567
  
  		/* Enable front dac only */
  		snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
a5875159d   James Courtier-Dutton   [ALSA] snd-ca0106...
1568
  	}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
  }
  
  static void ca0106_stop_chip(struct snd_ca0106 *chip)
  {
  	/* disable interrupts */
  	snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0);
  	outl(0, chip->port + INTE);
  	snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0);
  	udelay(1000);
  	/* disable audio */
  	/* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */
  	outl(0, chip->port + HCFG);
  	/* FIXME: We need to stop and DMA transfers here.
  	 *        But as I am not sure how yet, we cannot from the dma pages.
  	 * So we can fix: snd-malloc: Memory leak?  pages not freed = 8
  	 */
  }
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
1586

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
  					 struct pci_dev *pci,
  					 struct snd_ca0106 **rchip)
  {
  	struct snd_ca0106 *chip;
  	struct snd_ca0106_details *c;
  	int err;
  	static struct snd_device_ops ops = {
  		.dev_free = snd_ca0106_dev_free,
  	};
  
  	*rchip = NULL;
7199acdc7   James Courtier-Dutton   [ALSA] Implement ...
1599

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1600
1601
1602
  	err = pci_enable_device(pci);
  	if (err < 0)
  		return err;
284901a90   Yang Hongyang   dma-mapping: repl...
1603
1604
  	if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
  	    pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
  		printk(KERN_ERR "error to set 32bit mask DMA
  ");
  		pci_disable_device(pci);
  		return -ENXIO;
  	}
  
  	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
  	if (chip == NULL) {
  		pci_disable_device(pci);
  		return -ENOMEM;
  	}
  
  	chip->card = card;
  	chip->pci = pci;
  	chip->irq = -1;
  
  	spin_lock_init(&chip->emu_lock);
  
  	chip->port = pci_resource_start(pci, 0);
  	chip->res_port = request_region(chip->port, 0x20, "snd_ca0106");
  	if (!chip->res_port) {
  		snd_ca0106_free(chip);
  		printk(KERN_ERR "cannot allocate the port
  ");
  		return -EBUSY;
  	}
  
  	if (request_irq(pci->irq, snd_ca0106_interrupt,
934c2b6d0   Takashi Iwai   ALSA: use KBUILD_...
1633
  			IRQF_SHARED, KBUILD_MODNAME, chip)) {
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  		snd_ca0106_free(chip);
  		printk(KERN_ERR "cannot grab irq
  ");
  		return -EBUSY;
  	}
  	chip->irq = pci->irq;
  
  	/* This stores the periods table. */
  	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
  				1024, &chip->buffer) < 0) {
  		snd_ca0106_free(chip);
  		return -ENOMEM;
  	}
  
  	pci_set_master(pci);
  	/* read serial */
  	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
  	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
  	printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x
  ",
  	       chip->model, pci->revision, chip->serial);
  	strcpy(card->driver, "CA0106");
  	strcpy(card->shortname, "CA0106");
  
  	for (c = ca0106_chip_details; c->serial; c++) {
  		if (subsystem[dev]) {
  			if (c->serial == subsystem[dev])
  				break;
  		} else if (c->serial == chip->serial)
  			break;
  	}
  	chip->details = c;
  	if (subsystem[dev]) {
  		printk(KERN_INFO "snd-ca0106: Sound card name=%s, "
  		       "subsystem=0x%x. Forced to subsystem=0x%x
  ",
  		       c->name, chip->serial, subsystem[dev]);
  	}
  
  	sprintf(card->longname, "%s at 0x%lx irq %i",
  		c->name, chip->port, chip->irq);
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1675
  	ca0106_init_chip(chip, 0);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1676
1677
1678
  
  	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
1681
1682
1683
1684
  		snd_ca0106_free(chip);
  		return err;
  	}
  	*rchip = chip;
  	return 0;
  }
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1685

e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1686
  static void ca0106_midi_interrupt_enable(struct snd_ca_midi *midi, int intr)
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1687
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1688
  	snd_ca0106_intr_enable((struct snd_ca0106 *)(midi->dev_id), intr);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1689
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1690
  static void ca0106_midi_interrupt_disable(struct snd_ca_midi *midi, int intr)
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1691
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1692
  	snd_ca0106_intr_disable((struct snd_ca0106 *)(midi->dev_id), intr);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1693
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1694
  static unsigned char ca0106_midi_read(struct snd_ca_midi *midi, int idx)
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1695
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1696
1697
  	return (unsigned char)snd_ca0106_ptr_read((struct snd_ca0106 *)(midi->dev_id),
  						  midi->port + idx, 0);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1698
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1699
  static void ca0106_midi_write(struct snd_ca_midi *midi, int data, int idx)
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1700
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1701
  	snd_ca0106_ptr_write((struct snd_ca0106 *)(midi->dev_id), midi->port + idx, 0, data);
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1702
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1703
  static struct snd_card *ca0106_dev_id_card(void *dev_id)
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1704
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1705
  	return ((struct snd_ca0106 *)dev_id)->card;
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1706
  }
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1707
1708
  static int ca0106_dev_id_port(void *dev_id)
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1709
  	return ((struct snd_ca0106 *)dev_id)->port;
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1710
  }
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1711
  static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel)
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1712
  {
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1713
  	struct snd_ca_midi *midi;
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1714
1715
  	char *name;
  	int err;
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1716
  	if (channel == CA0106_MIDI_CHAN_B) {
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
  		name = "CA0106 MPU-401 (UART) B";
  		midi =  &chip->midi2;
  		midi->tx_enable = INTE_MIDI_TX_B;
  		midi->rx_enable = INTE_MIDI_RX_B;
  		midi->ipr_tx = IPR_MIDI_TX_B;
  		midi->ipr_rx = IPR_MIDI_RX_B;
  		midi->port = MIDI_UART_B_DATA;
  	} else {
  		name = "CA0106 MPU-401 (UART)";
  		midi =  &chip->midi;
  		midi->tx_enable = INTE_MIDI_TX_A;
  		midi->rx_enable = INTE_MIDI_TX_B;
  		midi->ipr_tx = IPR_MIDI_TX_A;
  		midi->ipr_rx = IPR_MIDI_RX_A;
  		midi->port = MIDI_UART_A_DATA;
  	}
  
  	midi->reset = CA0106_MPU401_RESET;
  	midi->enter_uart = CA0106_MPU401_ENTER_UART;
  	midi->ack = CA0106_MPU401_ACK;
  
  	midi->input_avail = CA0106_MIDI_INPUT_AVAIL;
  	midi->output_ready = CA0106_MIDI_OUTPUT_READY;
  
  	midi->channel = channel;
  
  	midi->interrupt_enable = ca0106_midi_interrupt_enable;
  	midi->interrupt_disable = ca0106_midi_interrupt_disable;
  
  	midi->read = ca0106_midi_read;
  	midi->write = ca0106_midi_write;
  
  	midi->get_dev_id_card = ca0106_dev_id_card;
  	midi->get_dev_id_port = ca0106_dev_id_port;
  
  	midi->dev_id = chip;
  	
  	if ((err = ca_midi_init(chip, midi, 0, name)) < 0)
  		return err;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
1760
1761
1762
  static int __devinit snd_ca0106_probe(struct pci_dev *pci,
  					const struct pci_device_id *pci_id)
  {
  	static int dev;
e4a3d1454   Takashi Iwai   [ALSA] Remove xxx...
1763
1764
  	struct snd_card *card;
  	struct snd_ca0106 *chip;
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1765
  	int i, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
1768
1769
1770
1771
1772
  
  	if (dev >= SNDRV_CARDS)
  		return -ENODEV;
  	if (!enable[dev]) {
  		dev++;
  		return -ENOENT;
  	}
e58de7baf   Takashi Iwai   ALSA: Convert to ...
1773
1774
1775
  	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1777
1778
1779
  	err = snd_ca0106_create(dev, card, pci, &chip);
  	if (err < 0)
  		goto error;
72077aa33   Takashi Iwai   ALSA: ca0106 - Ad...
1780
  	card->private_data = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781

5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1782
1783
1784
1785
  	for (i = 0; i < 4; i++) {
  		err = snd_ca0106_pcm(chip, i);
  		if (err < 0)
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786
  	}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1787
1788
1789
1790
1791
1792
  
  	if (chip->details->ac97 == 1) {
  		/* The SB0410 and SB0413 do not have an AC97 chip. */
  		err = snd_ca0106_ac97(chip);
  		if (err < 0)
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
  	}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1794
1795
1796
  	err = snd_ca0106_mixer(chip);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797

7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1798
  	snd_printdd("ca0106: probe for MIDI channel A ...");
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1799
1800
1801
  	err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A);
  	if (err < 0)
  		goto error;
7cf4783b3   James Courtier-Dutton   [ALSA] ca0106: Co...
1802
1803
  	snd_printdd(" done.
  ");
8a5afd29d   James Courtier-Dutton   [ALSA] snd-ca0106...
1804

adf1b3d25   Takashi Iwai   [ALSA] Optimize f...
1805
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1806
  	snd_ca0106_proc_init(chip);
adf1b3d25   Takashi Iwai   [ALSA] Optimize f...
1807
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808

c6d6eeeac   Takashi Iwai   [ALSA] ca0106 - A...
1809
  	snd_card_set_dev(card, &pci->dev);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1810
1811
1812
  	err = snd_card_register(card);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
1815
1816
  
  	pci_set_drvdata(pci, card);
  	dev++;
  	return 0;
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1817
1818
1819
1820
  
   error:
  	snd_card_free(card);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
1823
1824
1825
1826
1827
  }
  
  static void __devexit snd_ca0106_remove(struct pci_dev *pci)
  {
  	snd_card_free(pci_get_drvdata(pci));
  	pci_set_drvdata(pci, NULL);
  }
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
  #ifdef CONFIG_PM
  static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state)
  {
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_ca0106 *chip = card->private_data;
  	int i;
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
  	for (i = 0; i < 4; i++)
  		snd_pcm_suspend_all(chip->pcm[i]);
50232d62c   Takashi Iwai   ALSA: ca0106 - Ch...
1838
1839
  	if (chip->details->ac97)
  		snd_ac97_suspend(chip->ac97);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
  	snd_ca0106_mixer_suspend(chip);
  
  	ca0106_stop_chip(chip);
  
  	pci_disable_device(pci);
  	pci_save_state(pci);
  	pci_set_power_state(pci, pci_choose_state(pci, state));
  	return 0;
  }
  
  static int snd_ca0106_resume(struct pci_dev *pci)
  {
  	struct snd_card *card = pci_get_drvdata(pci);
  	struct snd_ca0106 *chip = card->private_data;
  	int i;
  
  	pci_set_power_state(pci, PCI_D0);
  	pci_restore_state(pci);
44411e07c   Takashi Iwai   ALSA: ca0106 - Ch...
1858
1859
1860
1861
1862
  
  	if (pci_enable_device(pci) < 0) {
  		snd_card_disconnect(card);
  		return -EIO;
  	}
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1863
  	pci_set_master(pci);
86effd7e1   Takashi Iwai   ALSA: ca0106 - Do...
1864
  	ca0106_init_chip(chip, 1);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1865

50232d62c   Takashi Iwai   ALSA: ca0106 - Ch...
1866
1867
  	if (chip->details->ac97)
  		snd_ac97_resume(chip->ac97);
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
  	snd_ca0106_mixer_resume(chip);
  	if (chip->details->spi_dac) {
  		for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++)
  			snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]);
  	}
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
  // PCI IDs
cebe41d4b   Alexey Dobriyan   sound: use DEFINE...
1879
  static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = {
0d7392e54   Joe Perches   sound: Use PCI_VD...
1880
  	{ PCI_VDEVICE(CREATIVE, 0x0007), 0 },	/* Audigy LS or Live 24bit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
1882
1883
1884
1885
1886
  	{ 0, }
  };
  MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
  
  // pci_driver definition
  static struct pci_driver driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
1887
  	.name = KBUILD_MODNAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
1889
1890
  	.id_table = snd_ca0106_ids,
  	.probe = snd_ca0106_probe,
  	.remove = __devexit_p(snd_ca0106_remove),
5da95273c   Takashi Iwai   ALSA: ca0106 - Ad...
1891
1892
1893
1894
  #ifdef CONFIG_PM
  	.suspend = snd_ca0106_suspend,
  	.resume = snd_ca0106_resume,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
1896
1897
1898
1899
  };
  
  // initialization of the module
  static int __init alsa_card_ca0106_init(void)
  {
95a98265e   Takashi Iwai   [ALSA] ca0106 - C...
1900
  	return pci_register_driver(&driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
  }
  
  // clean up the module
  static void __exit alsa_card_ca0106_exit(void)
  {
  	pci_unregister_driver(&driver);
  }
  
  module_init(alsa_card_ca0106_init)
  module_exit(alsa_card_ca0106_exit)