Blame view

sound/pci/via82xx_modem.c 32.9 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *   ALSA modem driver for VIA VT82xx (South Bridge)
   *
   *   VT82C686A/B/C, VT8233A/C, VT8235
   *
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
7
   *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
   *	                   Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com>
   *                    2002 Takashi Iwai <tiwai@suse.de>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
   */
  
  /*
   * Changes:
   *
f01cc521a   Sasha Khapyorsky   [ALSA] Sasha Khap...
15
   * Sep. 2,  2004  Sasha Khapyorsky <sashak@alsa-project.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
   *      Modified from original audio driver 'via82xx.c' to support AC97
   *      modems.
   */
6cbbfe1c8   Takashi Iwai   ALSA: Include lin...
19
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
65a772172   Paul Gortmaker   sound: fix driver...
25
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
35
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/info.h>
  #include <sound/ac97_codec.h>
  #include <sound/initval.h>
  
  #if 0
  #define POINTER_DEBUG
  #endif
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
36
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  MODULE_DESCRIPTION("VIA VT82xx modem");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C modem,pci}}");
b7fe46220   Clemens Ladisch   [ALSA] highlander...
40
41
42
  static int index = -2; /* Exclude the first card */
  static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */
  static int ac97_clock = 48000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

b7fe46220   Clemens Ladisch   [ALSA] highlander...
44
  module_param(index, int, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge.");
b7fe46220   Clemens Ladisch   [ALSA] highlander...
46
  module_param(id, charp, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge.");
b7fe46220   Clemens Ladisch   [ALSA] highlander...
48
  module_param(ac97_clock, int, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
2b3e584b9   Takashi Iwai   [ALSA] Add dummy ...
50
  /* just for backward compatibility */
a67ff6a54   Rusty Russell   ALSA: module_para...
51
  static bool enable;
698444f31   Takashi Iwai   [ALSA] Fix the ty...
52
  module_param(enable, bool, 0444);
2b3e584b9   Takashi Iwai   [ALSA] Add dummy ...
53

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
80
81
82
83
84
85
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  
  /*
   *  Direct registers
   */
  
  #define VIAREG(via, x) ((via)->port + VIA_REG_##x)
  #define VIADEV_REG(viadev, x) ((viadev)->port + VIA_REG_##x)
  
  /* common offsets */
  #define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */
  #define   VIA_REG_STAT_ACTIVE		0x80	/* RO */
  #define   VIA_REG_STAT_PAUSED		0x40	/* RO */
  #define   VIA_REG_STAT_TRIGGER_QUEUED	0x08	/* RO */
  #define   VIA_REG_STAT_STOPPED		0x04	/* RWC */
  #define   VIA_REG_STAT_EOL		0x02	/* RWC */
  #define   VIA_REG_STAT_FLAG		0x01	/* RWC */
  #define VIA_REG_OFFSET_CONTROL		0x01	/* byte - channel control */
  #define   VIA_REG_CTRL_START		0x80	/* WO */
  #define   VIA_REG_CTRL_TERMINATE	0x40	/* WO */
  #define   VIA_REG_CTRL_AUTOSTART	0x20
  #define   VIA_REG_CTRL_PAUSE		0x08	/* RW */
  #define   VIA_REG_CTRL_INT_STOP		0x04		
  #define   VIA_REG_CTRL_INT_EOL		0x02
  #define   VIA_REG_CTRL_INT_FLAG		0x01
  #define   VIA_REG_CTRL_RESET		0x01	/* RW - probably reset? undocumented */
  #define   VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)
  #define VIA_REG_OFFSET_TYPE		0x02	/* byte - channel type (686 only) */
  #define   VIA_REG_TYPE_AUTOSTART	0x80	/* RW - autostart at EOL */
  #define   VIA_REG_TYPE_16BIT		0x20	/* RW */
  #define   VIA_REG_TYPE_STEREO		0x10	/* RW */
  #define   VIA_REG_TYPE_INT_LLINE	0x00
  #define   VIA_REG_TYPE_INT_LSAMPLE	0x04
  #define   VIA_REG_TYPE_INT_LESSONE	0x08
  #define   VIA_REG_TYPE_INT_MASK		0x0c
  #define   VIA_REG_TYPE_INT_EOL		0x02
  #define   VIA_REG_TYPE_INT_FLAG		0x01
  #define VIA_REG_OFFSET_TABLE_PTR	0x04	/* dword - channel table pointer */
  #define VIA_REG_OFFSET_CURR_PTR		0x04	/* dword - channel current pointer */
  #define VIA_REG_OFFSET_STOP_IDX		0x08	/* dword - stop index, channel type, sample rate */
  #define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count (24 bit) */
  #define VIA_REG_OFFSET_CURR_INDEX	0x0f	/* byte - channel current index (for via8233 only) */
  
  #define DEFINE_VIA_REGSET(name,val) \
  enum {\
  	VIA_REG_##name##_STATUS		= (val),\
  	VIA_REG_##name##_CONTROL	= (val) + 0x01,\
  	VIA_REG_##name##_TYPE		= (val) + 0x02,\
  	VIA_REG_##name##_TABLE_PTR	= (val) + 0x04,\
  	VIA_REG_##name##_CURR_PTR	= (val) + 0x04,\
  	VIA_REG_##name##_STOP_IDX	= (val) + 0x08,\
  	VIA_REG_##name##_CURR_COUNT	= (val) + 0x0c,\
  }
  
  /* modem block */
  DEFINE_VIA_REGSET(MO, 0x40);
  DEFINE_VIA_REGSET(MI, 0x50);
  
  /* AC'97 */
  #define VIA_REG_AC97			0x80	/* dword */
  #define   VIA_REG_AC97_CODEC_ID_MASK	(3<<30)
  #define   VIA_REG_AC97_CODEC_ID_SHIFT	30
  #define   VIA_REG_AC97_CODEC_ID_PRIMARY	0x00
  #define   VIA_REG_AC97_CODEC_ID_SECONDARY 0x01
  #define   VIA_REG_AC97_SECONDARY_VALID	(1<<27)
  #define   VIA_REG_AC97_PRIMARY_VALID	(1<<25)
  #define   VIA_REG_AC97_BUSY		(1<<24)
  #define   VIA_REG_AC97_READ		(1<<23)
  #define   VIA_REG_AC97_CMD_SHIFT	16
  #define   VIA_REG_AC97_CMD_MASK		0x7e
  #define   VIA_REG_AC97_DATA_SHIFT	0
  #define   VIA_REG_AC97_DATA_MASK	0xffff
  
  #define VIA_REG_SGD_SHADOW		0x84	/* dword */
  #define   VIA_REG_SGD_STAT_PB_FLAG	(1<<0)
  #define   VIA_REG_SGD_STAT_CP_FLAG	(1<<1)
  #define   VIA_REG_SGD_STAT_FM_FLAG	(1<<2)
  #define   VIA_REG_SGD_STAT_PB_EOL	(1<<4)
  #define   VIA_REG_SGD_STAT_CP_EOL	(1<<5)
  #define   VIA_REG_SGD_STAT_FM_EOL	(1<<6)
  #define   VIA_REG_SGD_STAT_PB_STOP	(1<<8)
  #define   VIA_REG_SGD_STAT_CP_STOP	(1<<9)
  #define   VIA_REG_SGD_STAT_FM_STOP	(1<<10)
  #define   VIA_REG_SGD_STAT_PB_ACTIVE	(1<<12)
  #define   VIA_REG_SGD_STAT_CP_ACTIVE	(1<<13)
  #define   VIA_REG_SGD_STAT_FM_ACTIVE	(1<<14)
  #define   VIA_REG_SGD_STAT_MR_FLAG      (1<<16)
  #define   VIA_REG_SGD_STAT_MW_FLAG      (1<<17)
  #define   VIA_REG_SGD_STAT_MR_EOL       (1<<20)
  #define   VIA_REG_SGD_STAT_MW_EOL       (1<<21)
  #define   VIA_REG_SGD_STAT_MR_STOP      (1<<24)
  #define   VIA_REG_SGD_STAT_MW_STOP      (1<<25)
  #define   VIA_REG_SGD_STAT_MR_ACTIVE    (1<<28)
  #define   VIA_REG_SGD_STAT_MW_ACTIVE    (1<<29)
  
  #define VIA_REG_GPI_STATUS		0x88
  #define VIA_REG_GPI_INTR		0x8c
  
  #define VIA_TBL_BIT_FLAG	0x40000000
  #define VIA_TBL_BIT_EOL		0x80000000
  
  /* pci space */
  #define VIA_ACLINK_STAT		0x40
  #define  VIA_ACLINK_C11_READY	0x20
  #define  VIA_ACLINK_C10_READY	0x10
  #define  VIA_ACLINK_C01_READY	0x04 /* secondary codec ready */
  #define  VIA_ACLINK_LOWPOWER	0x02 /* low-power state */
  #define  VIA_ACLINK_C00_READY	0x01 /* primary codec ready */
  #define VIA_ACLINK_CTRL		0x41
  #define  VIA_ACLINK_CTRL_ENABLE	0x80 /* 0: disable, 1: enable */
  #define  VIA_ACLINK_CTRL_RESET	0x40 /* 0: assert, 1: de-assert */
  #define  VIA_ACLINK_CTRL_SYNC	0x20 /* 0: release SYNC, 1: force SYNC hi */
  #define  VIA_ACLINK_CTRL_SDO	0x10 /* 0: release SDO, 1: force SDO hi */
  #define  VIA_ACLINK_CTRL_VRA	0x08 /* 0: disable VRA, 1: enable VRA */
  #define  VIA_ACLINK_CTRL_PCM	0x04 /* 0: disable PCM, 1: enable PCM */
  #define  VIA_ACLINK_CTRL_FM	0x02 /* via686 only */
  #define  VIA_ACLINK_CTRL_SB	0x01 /* via686 only */
  #define  VIA_ACLINK_CTRL_INIT	(VIA_ACLINK_CTRL_ENABLE|\
  				 VIA_ACLINK_CTRL_RESET|\
  				 VIA_ACLINK_CTRL_PCM)
  #define VIA_FUNC_ENABLE		0x42
  #define  VIA_FUNC_MIDI_PNP	0x80 /* FIXME: it's 0x40 in the datasheet! */
  #define  VIA_FUNC_MIDI_IRQMASK	0x40 /* FIXME: not documented! */
  #define  VIA_FUNC_RX2C_WRITE	0x20
  #define  VIA_FUNC_SB_FIFO_EMPTY	0x10
  #define  VIA_FUNC_ENABLE_GAME	0x08
  #define  VIA_FUNC_ENABLE_FM	0x04
  #define  VIA_FUNC_ENABLE_MIDI	0x02
  #define  VIA_FUNC_ENABLE_SB	0x01
  #define VIA_PNP_CONTROL		0x43
  #define VIA_MC97_CTRL		0x44
  #define  VIA_MC97_CTRL_ENABLE   0x80
  #define  VIA_MC97_CTRL_SECONDARY 0x40
  #define  VIA_MC97_CTRL_INIT     (VIA_MC97_CTRL_ENABLE|\
                                   VIA_MC97_CTRL_SECONDARY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
196
197
  /*
   * pcm stream
   */
  
  struct snd_via_sg_table {
  	unsigned int offset;
  	unsigned int size;
  } ;
  
  #define VIA_TABLE_SIZE	255
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
198
  struct viadev {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
  	unsigned int reg_offset;
  	unsigned long port;
  	int direction;	/* playback = 0, capture = 1 */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
202
          struct snd_pcm_substream *substream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
210
211
212
213
214
215
  	int running;
  	unsigned int tbl_entries; /* # descriptors */
  	struct snd_dma_buffer table;
  	struct snd_via_sg_table *idx_table;
  	/* for recovery from the unexpected pointer */
  	unsigned int lastpos;
  	unsigned int bufsize;
  	unsigned int bufsize2;
  };
  
  enum { TYPE_CARD_VIA82XX_MODEM = 1 };
  
  #define VIA_MAX_MODEM_DEVS	2
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
216
  struct via82xx_modem {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
223
  	int irq;
  
  	unsigned long port;
  
  	unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */
  
  	struct pci_dev *pci;
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
224
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
  
  	unsigned int num_devs;
  	unsigned int playback_devno, capture_devno;
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
228
  	struct viadev devs[VIA_MAX_MODEM_DEVS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229

e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
230
  	struct snd_pcm *pcms[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
232
233
  	struct snd_ac97_bus *ac97_bus;
  	struct snd_ac97 *ac97;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
  	unsigned int ac97_clock;
  	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */
  
  	spinlock_t reg_lock;
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
238
  	struct snd_info_entry *proc_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  };
9baa3c34a   Benoit Taine   PCI: Remove DEFIN...
240
  static const struct pci_device_id snd_via82xx_modem_ids[] = {
28d27aae9   Joe Perches   sound: Use PCI_VD...
241
  	{ PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
248
249
250
251
252
253
254
  	{ 0, }
  };
  
  MODULE_DEVICE_TABLE(pci, snd_via82xx_modem_ids);
  
  /*
   */
  
  /*
   * allocate and initialize the descriptor buffers
   * periods = number of periods
   * fragsize = period size in bytes
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
255
  static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  			   struct pci_dev *pci,
  			   unsigned int periods, unsigned int fragsize)
  {
  	unsigned int i, idx, ofs, rest;
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
260
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
c5bb08674   Takashi Iwai   ALSA: via82xx: Fi...
261
  	__le32 *pgtbl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  
  	if (dev->table.area == NULL) {
  		/* the start of each lists must be aligned to 8 bytes,
  		 * but the kernel pages are much bigger, so we don't care
  		 */
6974f8ad4   Takashi Iwai   ALSA: pci: Avoid ...
267
  		if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
  					PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8),
  					&dev->table) < 0)
  			return -ENOMEM;
  	}
  	if (! dev->idx_table) {
6da2ec560   Kees Cook   treewide: kmalloc...
273
274
275
  		dev->idx_table = kmalloc_array(VIA_TABLE_SIZE,
  					       sizeof(*dev->idx_table),
  					       GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
  		if (! dev->idx_table)
  			return -ENOMEM;
  	}
  
  	/* fill the entries */
  	idx = 0;
  	ofs = 0;
c5bb08674   Takashi Iwai   ALSA: via82xx: Fi...
283
  	pgtbl = (__le32 *)dev->table.area;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
289
290
291
292
  	for (i = 0; i < periods; i++) {
  		rest = fragsize;
  		/* fill descriptors for a period.
  		 * a period can be split to several descriptors if it's
  		 * over page boundary.
  		 */
  		do {
  			unsigned int r;
  			unsigned int flag;
77a23f269   Takashi Iwai   ALSA: Clean up SG...
293
  			unsigned int addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  
  			if (idx >= VIA_TABLE_SIZE) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
296
297
  				dev_err(&pci->dev, "too much table size!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  				return -EINVAL;
  			}
77a23f269   Takashi Iwai   ALSA: Clean up SG...
300
  			addr = snd_pcm_sgbuf_get_addr(substream, ofs);
c5bb08674   Takashi Iwai   ALSA: via82xx: Fi...
301
  			pgtbl[idx << 1] = cpu_to_le32(addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
310
311
312
  			r = PAGE_SIZE - (ofs % PAGE_SIZE);
  			if (rest < r)
  				r = rest;
  			rest -= r;
  			if (! rest) {
  				if (i == periods - 1)
  					flag = VIA_TBL_BIT_EOL; /* buffer boundary */
  				else
  					flag = VIA_TBL_BIT_FLAG; /* period boundary */
  			} else
  				flag = 0; /* period continues to the next */
ee419653a   Takashi Iwai   ALSA: Fix missing...
313
  			/*
473439e06   Takashi Iwai   ALSA: via82xx_mod...
314
315
316
317
  			dev_dbg(&pci->dev,
  				"tbl %d: at %d  size %d (rest %d)
  ",
  				idx, ofs, r, rest);
ee419653a   Takashi Iwai   ALSA: Fix missing...
318
  			*/
c5bb08674   Takashi Iwai   ALSA: via82xx: Fi...
319
  			pgtbl[(idx<<1) + 1] = cpu_to_le32(r | flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
325
326
327
328
329
330
  			dev->idx_table[idx].offset = ofs;
  			dev->idx_table[idx].size = r;
  			ofs += r;
  			idx++;
  		} while (rest > 0);
  	}
  	dev->tbl_entries = idx;
  	dev->bufsize = periods * fragsize;
  	dev->bufsize2 = dev->bufsize / 2;
  	return 0;
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
331
  static int clean_via_table(struct viadev *dev, struct snd_pcm_substream *substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
  			   struct pci_dev *pci)
  {
  	if (dev->table.area) {
  		snd_dma_free_pages(&dev->table);
  		dev->table.area = NULL;
  	}
4d572776d   Jesper Juhl   [ALSA] Remove red...
338
339
  	kfree(dev->idx_table);
  	dev->idx_table = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
  	return 0;
  }
  
  /*
   *  Basic I/O
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
346
  static inline unsigned int snd_via82xx_codec_xread(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
  {
  	return inl(VIAREG(chip, AC97));
  }
   
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
351
  static inline void snd_via82xx_codec_xwrite(struct via82xx_modem *chip, unsigned int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
  {
  	outl(val, VIAREG(chip, AC97));
  }
   
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
356
  static int snd_via82xx_codec_ready(struct via82xx_modem *chip, int secondary)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
362
363
364
365
  {
  	unsigned int timeout = 1000;	/* 1ms */
  	unsigned int val;
  	
  	while (timeout-- > 0) {
  		udelay(1);
  		if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
  			return val & 0xffff;
  	}
473439e06   Takashi Iwai   ALSA: via82xx_mod...
366
367
  	dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]
  ",
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
368
  		   secondary, snd_via82xx_codec_xread(chip));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
  	return -EIO;
  }
   
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
372
  static int snd_via82xx_codec_valid(struct via82xx_modem *chip, int secondary)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  {
  	unsigned int timeout = 1000;	/* 1ms */
  	unsigned int val, val1;
  	unsigned int stat = !secondary ? VIA_REG_AC97_PRIMARY_VALID :
  					 VIA_REG_AC97_SECONDARY_VALID;
  	
  	while (timeout-- > 0) {
  		val = snd_via82xx_codec_xread(chip);
  		val1 = val & (VIA_REG_AC97_BUSY | stat);
  		if (val1 == stat)
  			return val & 0xffff;
  		udelay(1);
  	}
  	return -EIO;
  }
   
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
389
  static void snd_via82xx_codec_wait(struct snd_ac97 *ac97)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
391
  	struct via82xx_modem *chip = ac97->private_data;
86a5d9cfb   Pierre-Louis Bossart   ALSA: pci/via82xx...
392
  	__always_unused int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
  	err = snd_via82xx_codec_ready(chip, ac97->num);
  	/* here we need to wait fairly for long time.. */
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
395
  	msleep(500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
397
  static void snd_via82xx_codec_write(struct snd_ac97 *ac97,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
  				    unsigned short reg,
  				    unsigned short val)
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
401
  	struct via82xx_modem *chip = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	unsigned int xval;
83a5b72ad   Sasha Khapyorsky   [ALSA] PCI modem ...
403
404
405
406
  	if(reg == AC97_GPIO_STATUS) {
  		outl(val, VIAREG(chip, GPI_STATUS));
  		return;
  	}	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
412
413
  	xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
  	xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
  	xval |= reg << VIA_REG_AC97_CMD_SHIFT;
  	xval |= val << VIA_REG_AC97_DATA_SHIFT;
  	snd_via82xx_codec_xwrite(chip, xval);
  	snd_via82xx_codec_ready(chip, ac97->num);
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
414
  static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned short reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
416
  	struct via82xx_modem *chip = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
421
422
423
424
425
  	unsigned int xval, val = 0xffff;
  	int again = 0;
  
  	xval = ac97->num << VIA_REG_AC97_CODEC_ID_SHIFT;
  	xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
  	xval |= VIA_REG_AC97_READ;
  	xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
        	while (1) {
        		if (again++ > 3) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
426
427
428
  			dev_err(chip->card->dev,
  				"codec_read: codec %i is not valid [0x%x]
  ",
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
429
  				   ac97->num, snd_via82xx_codec_xread(chip));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
440
441
  		      	return 0xffff;
  		}
  		snd_via82xx_codec_xwrite(chip, xval);
  		udelay (20);
  		if (snd_via82xx_codec_valid(chip, ac97->num) >= 0) {
  			udelay(25);
  			val = snd_via82xx_codec_xread(chip);
  			break;
  		}
  	}
  	return val & 0xffff;
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
442
  static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev *viadev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  {
  	outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET,
  	     VIADEV_REG(viadev, OFFSET_CONTROL));
  	inb(VIADEV_REG(viadev, OFFSET_CONTROL));
  	udelay(50);
  	/* disable interrupts */
  	outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL));
  	/* clear interrupts */
  	outb(0x03, VIADEV_REG(viadev, OFFSET_STATUS));
  	outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* for via686 */
  	// outl(0, VIADEV_REG(viadev, OFFSET_CURR_PTR));
  	viadev->lastpos = 0;
  }
  
  
  /*
   *  Interrupt handler
   */
7d12e780e   David Howells   IRQ: Maintain reg...
461
  static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
463
  	struct via82xx_modem *chip = dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
468
469
470
471
472
473
474
475
  	unsigned int status;
  	unsigned int i;
  
  	status = inl(VIAREG(chip, SGD_SHADOW));
  	if (! (status & chip->intr_mask)) {
  		return IRQ_NONE;
  	}
  // _skip_sgd:
  
  	/* check status for each stream */
  	spin_lock(&chip->reg_lock);
  	for (i = 0; i < chip->num_devs; i++) {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
476
  		struct viadev *viadev = &chip->devs[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  		unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS));
  		c_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED);
  		if (! c_status)
  			continue;
  		if (viadev->substream && viadev->running) {
  			spin_unlock(&chip->reg_lock);
  			snd_pcm_period_elapsed(viadev->substream);
  			spin_lock(&chip->reg_lock);
  		}
  		outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
  	}
  	spin_unlock(&chip->reg_lock);
  	return IRQ_HANDLED;
  }
  
  /*
   *  PCM callbacks
   */
  
  /*
   * trigger callback
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
499
  static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
501
502
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
  	unsigned char val = 0;
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
41e4845c4   Jaroslav Kysela   [ALSA] PCM resume...
507
  	case SNDRV_PCM_TRIGGER_SUSPEND:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  		val |= VIA_REG_CTRL_START;
  		viadev->running = 1;
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  		val = VIA_REG_CTRL_TERMINATE;
  		viadev->running = 0;
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  		val |= VIA_REG_CTRL_PAUSE;
  		viadev->running = 0;
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  		viadev->running = 1;
  		break;
  	default:
  		return -EINVAL;
  	}
  	outb(val, VIADEV_REG(viadev, OFFSET_CONTROL));
  	if (cmd == SNDRV_PCM_TRIGGER_STOP)
  		snd_via82xx_channel_reset(chip, viadev);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
534
535
536
537
538
  /*
   * pointer callbacks
   */
  
  /*
   * calculate the linear position at the given sg-buffer index and the rest count
   */
  
  #define check_invalid_pos(viadev,pos) \
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
539
540
  	((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\
  				     viadev->lastpos < viadev->bufsize2))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

473439e06   Takashi Iwai   ALSA: via82xx_mod...
542
543
544
  static inline unsigned int calc_linear_pos(struct via82xx_modem *chip,
  					   struct viadev *viadev,
  					   unsigned int idx,
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
545
  					   unsigned int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
551
552
553
  {
  	unsigned int size, res;
  
  	size = viadev->idx_table[idx].size;
  	res = viadev->idx_table[idx].offset + size - count;
  
  	/* check the validity of the calculated position */
  	if (size < count) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
554
555
556
  		dev_err(chip->card->dev,
  			"invalid via82xx_cur_ptr (size = %d, count = %d)
  ",
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
557
  			   (int)size, (int)count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
  		res = viadev->lastpos;
  	} else if (check_invalid_pos(viadev, res)) {
  #ifdef POINTER_DEBUG
473439e06   Takashi Iwai   ALSA: via82xx_mod...
561
562
563
564
  		dev_dbg(chip->card->dev,
  			"fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x
  ",
  			idx, viadev->tbl_entries, viadev->lastpos,
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
565
566
  		       viadev->bufsize2, viadev->idx_table[idx].offset,
  		       viadev->idx_table[idx].size, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
  #endif
  		if (count && size < count) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
569
570
571
  			dev_dbg(chip->card->dev,
  				"invalid via82xx_cur_ptr, using last valid pointer
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
574
575
576
577
  			res = viadev->lastpos;
  		} else {
  			if (! count)
  				/* bogus count 0 on the DMA boundary? */
  				res = viadev->idx_table[idx].offset;
  			else
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
578
579
580
  				/* count register returns full size
  				 * when end of buffer is reached
  				 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
  				res = viadev->idx_table[idx].offset + size;
  			if (check_invalid_pos(viadev, res)) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
583
584
585
  				dev_dbg(chip->card->dev,
  					"invalid via82xx_cur_ptr (2), using last valid pointer
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
591
592
593
594
595
596
597
598
  				res = viadev->lastpos;
  			}
  		}
  	}
  	viadev->lastpos = res; /* remember the last position */
  	if (res >= viadev->bufsize)
  		res -= viadev->bufsize;
  	return res;
  }
  
  /*
   * get the current pointer on via686
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
599
  static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
601
602
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  	unsigned int idx, ptr, count, res;
da3cec35d   Takashi Iwai   ALSA: Kill snd_as...
604
605
  	if (snd_BUG_ON(!viadev->tbl_entries))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
  	if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
  		return 0;
  
  	spin_lock(&chip->reg_lock);
  	count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff;
  	/* The via686a does not have the current index register,
  	 * so we need to calculate the index from CURR_PTR.
  	 */
  	ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR));
  	if (ptr <= (unsigned int)viadev->table.addr)
  		idx = 0;
  	else /* CURR_PTR holds the address + 8 */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
618
619
  		idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) %
  			viadev->tbl_entries;
473439e06   Takashi Iwai   ALSA: via82xx_mod...
620
  	res = calc_linear_pos(chip, viadev, idx, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
  	spin_unlock(&chip->reg_lock);
  
  	return bytes_to_frames(substream->runtime, res);
  }
  
  /*
   * hw_params callback:
   * allocate the buffer and build up the buffer description table
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
630
631
  static int snd_via82xx_hw_params(struct snd_pcm_substream *substream,
  				 struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
633
634
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  	err = build_via_table(viadev, substream, chip->pci,
  			      params_periods(hw_params),
  			      params_period_bytes(hw_params));
  	if (err < 0)
  		return err;
  
  	snd_ac97_write(chip->ac97, AC97_LINE1_RATE, params_rate(hw_params));
  	snd_ac97_write(chip->ac97, AC97_LINE1_LEVEL, 0);
  
  	return 0;
  }
  
  /*
   * hw_free callback:
   * clean up the buffer description table and release the buffer
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
652
  static int snd_via82xx_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
654
655
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  
  	clean_via_table(viadev, substream, chip->pci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
661
662
663
664
  	return 0;
  }
  
  
  /*
   * set up the table pointer
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
665
  static void snd_via82xx_set_table_ptr(struct via82xx_modem *chip, struct viadev *viadev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
668
669
670
671
672
673
674
675
  {
  	snd_via82xx_codec_ready(chip, chip->ac97_secondary);
  	outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR));
  	udelay(20);
  	snd_via82xx_codec_ready(chip, chip->ac97_secondary);
  }
  
  /*
   * prepare callback for playback and capture
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
676
  static int snd_via82xx_pcm_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
678
679
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
684
685
686
687
688
689
690
691
  
  	snd_via82xx_channel_reset(chip, viadev);
  	/* this must be set after channel_reset */
  	snd_via82xx_set_table_ptr(chip, viadev);
  	outb(VIA_REG_TYPE_AUTOSTART|VIA_REG_TYPE_INT_EOL|VIA_REG_TYPE_INT_FLAG,
  	     VIADEV_REG(viadev, OFFSET_TYPE));
  	return 0;
  }
  
  /*
   * pcm hardware definition, identical for both playback and capture
   */
dee49895b   Bhumika Goyal   ALSA: pci: make s...
692
  static const struct snd_pcm_hardware snd_via82xx_hw =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
  {
  	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
  				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
  				 SNDRV_PCM_INFO_MMAP_VALID |
41e4845c4   Jaroslav Kysela   [ALSA] PCM resume...
697
  				 /* SNDRV_PCM_INFO_RESUME | */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  				 SNDRV_PCM_INFO_PAUSE),
  	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
  	.rates =		SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
  	.rate_min =		8000,
  	.rate_max =		16000,
  	.channels_min =		1,
  	.channels_max =		1,
  	.buffer_bytes_max =	128 * 1024,
  	.period_bytes_min =	32,
  	.period_bytes_max =	128 * 1024,
  	.periods_min =		2,
  	.periods_max =		VIA_TABLE_SIZE / 2,
  	.fifo_size =		0,
  };
  
  
  /*
   * open callback skeleton
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
717
718
  static int snd_via82xx_modem_pcm_open(struct via82xx_modem *chip, struct viadev *viadev,
  				      struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
720
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  	int err;
fbc57b2a3   Takashi Iwai   ALSA: via82xx: Co...
722
723
  	static const unsigned int rates[] = { 8000,  9600, 12000, 16000 };
  	static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
727
728
729
730
                  .count = ARRAY_SIZE(rates),
                  .list = rates,
                  .mask = 0,
          };
  
  	runtime->hw = snd_via82xx_hw;
  	
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
731
732
          if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
  					      &hw_constraints_rates)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
                  return err;
  
  	/* we may remove following constaint when we modify table entries
  	   in interrupt */
  	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
  		return err;
  
  	runtime->private_data = viadev;
  	viadev->substream = substream;
  
  	return 0;
  }
  
  
  /*
   * open callback for playback
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
750
  static int snd_via82xx_playback_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
752
753
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = &chip->devs[chip->playback_devno + substream->number];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
758
759
760
  
  	return snd_via82xx_modem_pcm_open(chip, viadev, substream);
  }
  
  /*
   * open callback for capture
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
761
  static int snd_via82xx_capture_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
763
764
  	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
  	struct viadev *viadev = &chip->devs[chip->capture_devno + substream->pcm->device];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
771
  
  	return snd_via82xx_modem_pcm_open(chip, viadev, substream);
  }
  
  /*
   * close callback
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
772
  static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
774
  	struct viadev *viadev = substream->runtime->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
781
  
  	viadev->substream = NULL;
  	return 0;
  }
  
  
  /* via686 playback callbacks */
6769e988b   Julia Lawall   ALSA: constify sn...
782
  static const struct snd_pcm_ops snd_via686_playback_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  	.open =		snd_via82xx_playback_open,
  	.close =	snd_via82xx_pcm_close,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
  	.hw_params =	snd_via82xx_hw_params,
  	.hw_free =	snd_via82xx_hw_free,
  	.prepare =	snd_via82xx_pcm_prepare,
83a5b72ad   Sasha Khapyorsky   [ALSA] PCI modem ...
788
  	.trigger =	snd_via82xx_pcm_trigger,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  	.pointer =	snd_via686_pcm_pointer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
  };
  
  /* via686 capture callbacks */
6769e988b   Julia Lawall   ALSA: constify sn...
793
  static const struct snd_pcm_ops snd_via686_capture_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
  	.open =		snd_via82xx_capture_open,
  	.close =	snd_via82xx_pcm_close,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
  	.hw_params =	snd_via82xx_hw_params,
  	.hw_free =	snd_via82xx_hw_free,
  	.prepare =	snd_via82xx_pcm_prepare,
83a5b72ad   Sasha Khapyorsky   [ALSA] PCI modem ...
799
  	.trigger =	snd_via82xx_pcm_trigger,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  	.pointer =	snd_via686_pcm_pointer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  };
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
802
803
  static void init_viadev(struct via82xx_modem *chip, int idx, unsigned int reg_offset,
  			int direction)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
810
811
812
  {
  	chip->devs[idx].reg_offset = reg_offset;
  	chip->devs[idx].direction = direction;
  	chip->devs[idx].port = chip->port + reg_offset;
  }
  
  /*
   * create a pcm instance for via686a/b
   */
e23e7a143   Bill Pemberton   ALSA: pci: remove...
813
  static int snd_via686_pcm_new(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
815
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
823
824
825
826
827
  	int err;
  
  	chip->playback_devno = 0;
  	chip->capture_devno = 1;
  	chip->num_devs = 2;
  	chip->intr_mask = 0x330000; /* FLAGS | EOL for MR, MW */
  
  	err = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
  	if (err < 0)
  		return err;
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops);
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);
6632d198c   Sasha Khapyorsky   [ALSA] dev_class=...
828
  	pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
  	pcm->private_data = chip;
  	strcpy(pcm->name, chip->card->shortname);
  	chip->pcms[0] = pcm;
  	init_viadev(chip, 0, VIA_REG_MO_STATUS, 0);
  	init_viadev(chip, 1, VIA_REG_MI_STATUS, 1);
8e2c75249   Takashi Iwai   ALSA: via82xx: Us...
834
835
  	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
  				       &chip->pci->dev, 64*1024, 128*1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
  	return 0;
  }
  
  
  /*
   *  Mixer part
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
843
  static void snd_via82xx_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
845
  	struct via82xx_modem *chip = bus->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
  	chip->ac97_bus = NULL;
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
848
  static void snd_via82xx_mixer_free_ac97(struct snd_ac97 *ac97)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
850
  	struct via82xx_modem *chip = ac97->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
  	chip->ac97 = NULL;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
853
  static int snd_via82xx_mixer_new(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
855
  	struct snd_ac97_template ac97;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  	int err;
51055da51   Takashi Iwai   ALSA: pci: Consti...
857
  	static const struct snd_ac97_bus_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
862
863
864
865
866
  		.write = snd_via82xx_codec_write,
  		.read = snd_via82xx_codec_read,
  		.wait = snd_via82xx_codec_wait,
  	};
  
  	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)
  		return err;
  	chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus;
  	chip->ac97_bus->clock = chip->ac97_clock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
  
  	memset(&ac97, 0, sizeof(ac97));
  	ac97.private_data = chip;
  	ac97.private_free = snd_via82xx_mixer_free_ac97;
  	ac97.pci = chip->pci;
f1a63a38d   Takashi Iwai   [ALSA] ac97 - Sup...
872
  	ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
878
879
880
881
882
883
884
  	ac97.num = chip->ac97_secondary;
  
  	if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
  		return err;
  
  	return 0;
  }
  
  
  /*
   * proc interface
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
885
  static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
887
  	struct via82xx_modem *chip = entry->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
892
893
894
895
896
897
  	int i;
  	
  	snd_iprintf(buffer, "%s
  
  ", chip->card->longname);
  	for (i = 0; i < 0xa0; i += 4) {
  		snd_iprintf(buffer, "%02x: %08x
  ", i, inl(chip->port + i));
  	}
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
898
  static void snd_via82xx_proc_init(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  {
47f2769b4   Takashi Iwai   ALSA: pci: Clean ...
900
901
  	snd_card_ro_proc_new(chip->card, "via82xx", chip,
  			     snd_via82xx_proc_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
905
906
  }
  
  /*
   *
   */
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
907
  static int snd_via82xx_chip_init(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
  {
  	unsigned int val;
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
910
  	unsigned long end_time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  	unsigned char pval;
  
  	pci_read_config_byte(chip->pci, VIA_MC97_CTRL, &pval);
  	if((pval & VIA_MC97_CTRL_INIT) != VIA_MC97_CTRL_INIT) {
  		pci_write_config_byte(chip->pci, 0x44, pval|VIA_MC97_CTRL_INIT);
  		udelay(100);
  	}
  
  	pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
  	if (! (pval & VIA_ACLINK_C00_READY)) { /* codec not ready? */
  		/* deassert ACLink reset, force SYNC */
  		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,
  				      VIA_ACLINK_CTRL_ENABLE |
  				      VIA_ACLINK_CTRL_RESET |
  				      VIA_ACLINK_CTRL_SYNC);
  		udelay(100);
  #if 1 /* FIXME: should we do full reset here for all chip models? */
  		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00);
  		udelay(100);
  #else
  		/* deassert ACLink reset, force SYNC (warm AC'97 reset) */
  		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,
  				      VIA_ACLINK_CTRL_RESET|VIA_ACLINK_CTRL_SYNC);
  		udelay(2);
  #endif
  		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
  		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);
  		udelay(100);
  	}
  	
  	pci_read_config_byte(chip->pci, VIA_ACLINK_CTRL, &pval);
  	if ((pval & VIA_ACLINK_CTRL_INIT) != VIA_ACLINK_CTRL_INIT) {
  		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
  		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);
  		udelay(100);
  	}
  
  	/* wait until codec ready */
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
949
  	end_time = jiffies + msecs_to_jiffies(750);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
  	do {
  		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
  		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
  			break;
d86d01935   Rene Herman   [ALSA] alsa-kerne...
954
  		schedule_timeout_uninterruptible(1);
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
955
  	} while (time_before(jiffies, end_time));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
  
  	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
473439e06   Takashi Iwai   ALSA: via82xx_mod...
958
959
960
  		dev_err(chip->card->dev,
  			"AC'97 codec is not ready [0x%x]
  ", val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
  
  	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
  				 VIA_REG_AC97_SECONDARY_VALID |
  				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
965
  	end_time = jiffies + msecs_to_jiffies(750);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
969
970
971
972
973
  	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
  				 VIA_REG_AC97_SECONDARY_VALID |
  				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
  	do {
  		if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {
  			chip->ac97_secondary = 1;
  			goto __ac97_ok2;
  		}
d86d01935   Rene Herman   [ALSA] alsa-kerne...
974
  		schedule_timeout_uninterruptible(1);
ef21ca24f   Nishanth Aravamudan   [ALSA] sound/pci:...
975
  	} while (time_before(jiffies, end_time));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
982
983
984
985
986
  	/* This is ok, the most of motherboards have only one codec */
  
        __ac97_ok2:
  
  	/* route FM trap to IRQ, disable FM trap */
  	// pci_write_config_byte(chip->pci, VIA_FM_NMI_CTRL, 0);
  	/* disable all GPI interrupts */
  	outl(0, VIAREG(chip, GPI_INTR));
  
  	return 0;
  }
c7561cd80   Takashi Iwai   ALSA: PCI: Replac...
987
  #ifdef CONFIG_PM_SLEEP
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
  /*
   * power management
   */
68cb2b559   Takashi Iwai   ALSA: Convert to ...
991
  static int snd_via82xx_suspend(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  {
68cb2b559   Takashi Iwai   ALSA: Convert to ...
993
  	struct snd_card *card = dev_get_drvdata(dev);
57feb8350   Takashi Iwai   [ALSA] via82xx - ...
994
  	struct via82xx_modem *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  	int i;
57feb8350   Takashi Iwai   [ALSA] via82xx - ...
996
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
  	for (i = 0; i < chip->num_devs; i++)
  		snd_via82xx_channel_reset(chip, &chip->devs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
  	snd_ac97_suspend(chip->ac97);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
  	return 0;
  }
68cb2b559   Takashi Iwai   ALSA: Convert to ...
1002
  static int snd_via82xx_resume(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
  {
68cb2b559   Takashi Iwai   ALSA: Convert to ...
1004
  	struct snd_card *card = dev_get_drvdata(dev);
57feb8350   Takashi Iwai   [ALSA] via82xx - ...
1005
  	struct via82xx_modem *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
1012
  	snd_via82xx_chip_init(chip);
  
  	snd_ac97_resume(chip->ac97);
  
  	for (i = 0; i < chip->num_devs; i++)
  		snd_via82xx_channel_reset(chip, &chip->devs[i]);
57feb8350   Takashi Iwai   [ALSA] via82xx - ...
1013
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
  	return 0;
  }
68cb2b559   Takashi Iwai   ALSA: Convert to ...
1016
1017
1018
1019
1020
  
  static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
  #define SND_VIA82XX_PM_OPS	&snd_via82xx_pm
  #else
  #define SND_VIA82XX_PM_OPS	NULL
c7561cd80   Takashi Iwai   ALSA: PCI: Replac...
1021
  #endif /* CONFIG_PM_SLEEP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022

e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1023
  static int snd_via82xx_free(struct via82xx_modem *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
1028
1029
1030
1031
  {
  	unsigned int i;
  
  	if (chip->irq < 0)
  		goto __end_hw;
  	/* disable interrupts */
  	for (i = 0; i < chip->num_devs; i++)
  		snd_via82xx_channel_reset(chip, &chip->devs[i]);
f000fd809   Jeff Garzik   [ALSA] Fix synchr...
1032

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
        __end_hw:
  	if (chip->irq >= 0)
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1035
  		free_irq(chip->irq, chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
1038
1039
1040
  	pci_release_regions(chip->pci);
  	pci_disable_device(chip->pci);
  	kfree(chip);
  	return 0;
  }
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1041
  static int snd_via82xx_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1043
  	struct via82xx_modem *chip = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
  	return snd_via82xx_free(chip);
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1046
1047
1048
1049
1050
1051
  static int snd_via82xx_create(struct snd_card *card,
  			      struct pci_dev *pci,
  			      int chip_type,
  			      int revision,
  			      unsigned int ac97_clock,
  			      struct via82xx_modem **r_via)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1053
  	struct via82xx_modem *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
  	int err;
efb0ad25d   Takashi Iwai   ALSA: pci: Consti...
1055
  	static const struct snd_device_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
1059
1060
  		.dev_free =	snd_via82xx_dev_free,
          };
  
  	if ((err = pci_enable_device(pci)) < 0)
  		return err;
e560d8d83   Takashi Iwai   [ALSA] Replace wi...
1061
  	if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  		pci_disable_device(pci);
  		return -ENOMEM;
  	}
  
  	spin_lock_init(&chip->reg_lock);
  	chip->card = card;
  	chip->pci = pci;
  	chip->irq = -1;
  
  	if ((err = pci_request_regions(pci, card->driver)) < 0) {
  		kfree(chip);
  		pci_disable_device(pci);
  		return err;
  	}
  	chip->port = pci_resource_start(pci, 0);
437a5a460   Takashi Iwai   [ALSA] Remove IRQ...
1077
  	if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
934c2b6d0   Takashi Iwai   ALSA: use KBUILD_...
1078
  			KBUILD_MODNAME, chip)) {
473439e06   Takashi Iwai   ALSA: via82xx_mod...
1079
1080
  		dev_err(card->dev, "unable to grab IRQ %d
  ", pci->irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
  		snd_via82xx_free(chip);
  		return -EBUSY;
  	}
  	chip->irq = pci->irq;
c47583b0e   Takashi Iwai   ALSA: via82xx: Su...
1085
  	card->sync_irq = chip->irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
  	if (ac97_clock >= 8000 && ac97_clock <= 48000)
  		chip->ac97_clock = ac97_clock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  
  	if ((err = snd_via82xx_chip_init(chip)) < 0) {
  		snd_via82xx_free(chip);
  		return err;
  	}
  
  	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
  		snd_via82xx_free(chip);
  		return err;
  	}
  
  	/* The 8233 ac97 controller does not implement the master bit
  	 * in the pci command register. IMHO this is a violation of the PCI spec.
  	 * We call pci_set_master here because it does not hurt. */
  	pci_set_master(pci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
1105
  	*r_via = chip;
  	return 0;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1106
1107
  static int snd_via82xx_probe(struct pci_dev *pci,
  			     const struct pci_device_id *pci_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
  {
e437e3d7c   Takashi Iwai   [ALSA] Remove xxx...
1109
1110
  	struct snd_card *card;
  	struct via82xx_modem *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
1112
1113
  	int chip_type = 0, card_type;
  	unsigned int i;
  	int err;
60c5772b5   Takashi Iwai   ALSA: pci: Conver...
1114
  	err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
e58de7baf   Takashi Iwai   ALSA: Convert to ...
1115
1116
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
  
  	card_type = pci_id->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
1123
1124
  	switch (card_type) {
  	case TYPE_CARD_VIA82XX_MODEM:
  		strcpy(card->driver, "VIA82XX-MODEM");
  		sprintf(card->shortname, "VIA 82XX modem");
  		break;
  	default:
473439e06   Takashi Iwai   ALSA: via82xx_mod...
1125
1126
  		dev_err(card->dev, "invalid card type %d
  ", card_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
  		err = -EINVAL;
  		goto __error;
  	}
  		
44c10138f   Auke Kok   PCI: Change all d...
1131
  	if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision,
b7fe46220   Clemens Ladisch   [ALSA] highlander...
1132
  				      ac97_clock, &chip)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  		goto __error;
57feb8350   Takashi Iwai   [ALSA] via82xx - ...
1134
  	card->private_data = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
1138
1139
  	if ((err = snd_via82xx_mixer_new(chip)) < 0)
  		goto __error;
  
  	if ((err = snd_via686_pcm_new(chip)) < 0 )
  		goto __error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
  	/* disable interrupts */
  	for (i = 0; i < chip->num_devs; i++)
  		snd_via82xx_channel_reset(chip, &chip->devs[i]);
  
  	sprintf(card->longname, "%s at 0x%lx, irq %d",
  		card->shortname, chip->port, chip->irq);
  
  	snd_via82xx_proc_init(chip);
  
  	if ((err = snd_card_register(card)) < 0) {
  		snd_card_free(card);
  		return err;
  	}
  	pci_set_drvdata(pci, card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
1157
1158
1159
  	return 0;
  
   __error:
  	snd_card_free(card);
  	return err;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1160
  static void snd_via82xx_remove(struct pci_dev *pci)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
  {
  	snd_card_free(pci_get_drvdata(pci));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  }
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
1164
  static struct pci_driver via82xx_modem_driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
1165
  	.name = KBUILD_MODNAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
  	.id_table = snd_via82xx_modem_ids,
  	.probe = snd_via82xx_probe,
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1168
  	.remove = snd_via82xx_remove,
68cb2b559   Takashi Iwai   ALSA: Convert to ...
1169
1170
1171
  	.driver = {
  		.pm = SND_VIA82XX_PM_OPS,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
  };
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
1173
  module_pci_driver(via82xx_modem_driver);