xref: /OK3568_Linux_fs/kernel/sound/pci/als300.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  als300.c - driver for Avance Logic ALS300/ALS300+ soundcards.
4*4882a593Smuzhiyun  *  Copyright (C) 2005 by Ash Willis <ashwillis@programmer.net>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  TODO
7*4882a593Smuzhiyun  *  4 channel playback for ALS300+
8*4882a593Smuzhiyun  *  gameport
9*4882a593Smuzhiyun  *  mpu401
10*4882a593Smuzhiyun  *  opl3
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *  NOTES
13*4882a593Smuzhiyun  *  The BLOCK_COUNTER registers for the ALS300(+) return a figure related to
14*4882a593Smuzhiyun  *  the position in the current period, NOT the whole buffer. It is important
15*4882a593Smuzhiyun  *  to know which period we are in so we can calculate the correct pointer.
16*4882a593Smuzhiyun  *  This is why we always use 2 periods. We can then use a flip-flop variable
17*4882a593Smuzhiyun  *  to keep track of what period we are in.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/pci.h>
24*4882a593Smuzhiyun #include <linux/dma-mapping.h>
25*4882a593Smuzhiyun #include <linux/interrupt.h>
26*4882a593Smuzhiyun #include <linux/slab.h>
27*4882a593Smuzhiyun #include <linux/io.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <sound/core.h>
30*4882a593Smuzhiyun #include <sound/control.h>
31*4882a593Smuzhiyun #include <sound/initval.h>
32*4882a593Smuzhiyun #include <sound/pcm.h>
33*4882a593Smuzhiyun #include <sound/pcm_params.h>
34*4882a593Smuzhiyun #include <sound/ac97_codec.h>
35*4882a593Smuzhiyun #include <sound/opl3.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* snd_als300_set_irq_flag */
38*4882a593Smuzhiyun #define IRQ_DISABLE		0
39*4882a593Smuzhiyun #define IRQ_ENABLE		1
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /* I/O port layout */
42*4882a593Smuzhiyun #define AC97_ACCESS		0x00
43*4882a593Smuzhiyun #define AC97_READ		0x04
44*4882a593Smuzhiyun #define AC97_STATUS		0x06
45*4882a593Smuzhiyun #define   AC97_DATA_AVAIL		(1<<6)
46*4882a593Smuzhiyun #define   AC97_BUSY			(1<<7)
47*4882a593Smuzhiyun #define ALS300_IRQ_STATUS	0x07		/* ALS300 Only */
48*4882a593Smuzhiyun #define   IRQ_PLAYBACK			(1<<3)
49*4882a593Smuzhiyun #define   IRQ_CAPTURE			(1<<2)
50*4882a593Smuzhiyun #define GCR_DATA		0x08
51*4882a593Smuzhiyun #define GCR_INDEX		0x0C
52*4882a593Smuzhiyun #define ALS300P_DRAM_IRQ_STATUS	0x0D		/* ALS300+ Only */
53*4882a593Smuzhiyun #define MPU_IRQ_STATUS		0x0E		/* ALS300 Rev. E+, ALS300+ */
54*4882a593Smuzhiyun #define ALS300P_IRQ_STATUS	0x0F		/* ALS300+ Only */
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /* General Control Registers */
57*4882a593Smuzhiyun #define PLAYBACK_START		0x80
58*4882a593Smuzhiyun #define PLAYBACK_END		0x81
59*4882a593Smuzhiyun #define PLAYBACK_CONTROL	0x82
60*4882a593Smuzhiyun #define   TRANSFER_START		(1<<16)
61*4882a593Smuzhiyun #define   FIFO_PAUSE			(1<<17)
62*4882a593Smuzhiyun #define RECORD_START		0x83
63*4882a593Smuzhiyun #define RECORD_END		0x84
64*4882a593Smuzhiyun #define RECORD_CONTROL		0x85
65*4882a593Smuzhiyun #define DRAM_WRITE_CONTROL	0x8B
66*4882a593Smuzhiyun #define   WRITE_TRANS_START		(1<<16)
67*4882a593Smuzhiyun #define   DRAM_MODE_2			(1<<17)
68*4882a593Smuzhiyun #define MISC_CONTROL		0x8C
69*4882a593Smuzhiyun #define   IRQ_SET_BIT			(1<<15)
70*4882a593Smuzhiyun #define   VMUTE_NORMAL			(1<<20)
71*4882a593Smuzhiyun #define   MMUTE_NORMAL			(1<<21)
72*4882a593Smuzhiyun #define MUS_VOC_VOL		0x8E
73*4882a593Smuzhiyun #define PLAYBACK_BLOCK_COUNTER	0x9A
74*4882a593Smuzhiyun #define RECORD_BLOCK_COUNTER	0x9B
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define DEBUG_PLAY_REC	0
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #if DEBUG_PLAY_REC
79*4882a593Smuzhiyun #define snd_als300_dbgplay(format, args...) printk(KERN_ERR format, ##args)
80*4882a593Smuzhiyun #else
81*4882a593Smuzhiyun #define snd_als300_dbgplay(format, args...)
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun enum {DEVICE_ALS300, DEVICE_ALS300_PLUS};
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun MODULE_AUTHOR("Ash Willis <ashwillis@programmer.net>");
87*4882a593Smuzhiyun MODULE_DESCRIPTION("Avance Logic ALS300");
88*4882a593Smuzhiyun MODULE_LICENSE("GPL");
89*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS300},{Avance Logic,ALS300+}}");
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
92*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
93*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
96*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for ALS300 sound card.");
97*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
98*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for ALS300 sound card.");
99*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
100*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "Enable ALS300 sound card.");
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun struct snd_als300 {
103*4882a593Smuzhiyun 	unsigned long port;
104*4882a593Smuzhiyun 	spinlock_t reg_lock;
105*4882a593Smuzhiyun 	struct snd_card *card;
106*4882a593Smuzhiyun 	struct pci_dev *pci;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	struct snd_pcm *pcm;
109*4882a593Smuzhiyun 	struct snd_pcm_substream *playback_substream;
110*4882a593Smuzhiyun 	struct snd_pcm_substream *capture_substream;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	struct snd_ac97 *ac97;
113*4882a593Smuzhiyun 	struct snd_opl3 *opl3;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	struct resource *res_port;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	int irq;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	int chip_type; /* ALS300 or ALS300+ */
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	char revision;
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun struct snd_als300_substream_data {
125*4882a593Smuzhiyun 	int period_flipflop;
126*4882a593Smuzhiyun 	int control_register;
127*4882a593Smuzhiyun 	int block_counter_register;
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static const struct pci_device_id snd_als300_ids[] = {
131*4882a593Smuzhiyun 	{ 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 },
132*4882a593Smuzhiyun 	{ 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS },
133*4882a593Smuzhiyun 	{ 0, }
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, snd_als300_ids);
137*4882a593Smuzhiyun 
snd_als300_gcr_read(unsigned long port,unsigned short reg)138*4882a593Smuzhiyun static inline u32 snd_als300_gcr_read(unsigned long port, unsigned short reg)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	outb(reg, port+GCR_INDEX);
141*4882a593Smuzhiyun 	return inl(port+GCR_DATA);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
snd_als300_gcr_write(unsigned long port,unsigned short reg,u32 val)144*4882a593Smuzhiyun static inline void snd_als300_gcr_write(unsigned long port,
145*4882a593Smuzhiyun 						unsigned short reg, u32 val)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	outb(reg, port+GCR_INDEX);
148*4882a593Smuzhiyun 	outl(val, port+GCR_DATA);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /* Enable/Disable Interrupts */
snd_als300_set_irq_flag(struct snd_als300 * chip,int cmd)152*4882a593Smuzhiyun static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* boolean XOR check, since old vs. new hardware have
157*4882a593Smuzhiyun 	   directly reversed bit setting for ENABLE and DISABLE.
158*4882a593Smuzhiyun 	   ALS300+ acts like newer versions of ALS300 */
159*4882a593Smuzhiyun 	if (((chip->revision > 5 || chip->chip_type == DEVICE_ALS300_PLUS) ^
160*4882a593Smuzhiyun 						(cmd == IRQ_ENABLE)) == 0)
161*4882a593Smuzhiyun 		tmp |= IRQ_SET_BIT;
162*4882a593Smuzhiyun 	else
163*4882a593Smuzhiyun 		tmp &= ~IRQ_SET_BIT;
164*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
snd_als300_free(struct snd_als300 * chip)167*4882a593Smuzhiyun static int snd_als300_free(struct snd_als300 *chip)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	snd_als300_set_irq_flag(chip, IRQ_DISABLE);
170*4882a593Smuzhiyun 	if (chip->irq >= 0)
171*4882a593Smuzhiyun 		free_irq(chip->irq, chip);
172*4882a593Smuzhiyun 	pci_release_regions(chip->pci);
173*4882a593Smuzhiyun 	pci_disable_device(chip->pci);
174*4882a593Smuzhiyun 	kfree(chip);
175*4882a593Smuzhiyun 	return 0;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
snd_als300_dev_free(struct snd_device * device)178*4882a593Smuzhiyun static int snd_als300_dev_free(struct snd_device *device)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct snd_als300 *chip = device->device_data;
181*4882a593Smuzhiyun 	return snd_als300_free(chip);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
snd_als300_interrupt(int irq,void * dev_id)184*4882a593Smuzhiyun static irqreturn_t snd_als300_interrupt(int irq, void *dev_id)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	u8 status;
187*4882a593Smuzhiyun 	struct snd_als300 *chip = dev_id;
188*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	status = inb(chip->port+ALS300_IRQ_STATUS);
191*4882a593Smuzhiyun 	if (!status) /* shared IRQ, for different device?? Exit ASAP! */
192*4882a593Smuzhiyun 		return IRQ_NONE;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* ACK everything ASAP */
195*4882a593Smuzhiyun 	outb(status, chip->port+ALS300_IRQ_STATUS);
196*4882a593Smuzhiyun 	if (status & IRQ_PLAYBACK) {
197*4882a593Smuzhiyun 		if (chip->pcm && chip->playback_substream) {
198*4882a593Smuzhiyun 			data = chip->playback_substream->runtime->private_data;
199*4882a593Smuzhiyun 			data->period_flipflop ^= 1;
200*4882a593Smuzhiyun 			snd_pcm_period_elapsed(chip->playback_substream);
201*4882a593Smuzhiyun 			snd_als300_dbgplay("IRQ_PLAYBACK\n");
202*4882a593Smuzhiyun 		}
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 	if (status & IRQ_CAPTURE) {
205*4882a593Smuzhiyun 		if (chip->pcm && chip->capture_substream) {
206*4882a593Smuzhiyun 			data = chip->capture_substream->runtime->private_data;
207*4882a593Smuzhiyun 			data->period_flipflop ^= 1;
208*4882a593Smuzhiyun 			snd_pcm_period_elapsed(chip->capture_substream);
209*4882a593Smuzhiyun 			snd_als300_dbgplay("IRQ_CAPTURE\n");
210*4882a593Smuzhiyun 		}
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 	return IRQ_HANDLED;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
snd_als300plus_interrupt(int irq,void * dev_id)215*4882a593Smuzhiyun static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	u8 general, mpu, dram;
218*4882a593Smuzhiyun 	struct snd_als300 *chip = dev_id;
219*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	general = inb(chip->port+ALS300P_IRQ_STATUS);
222*4882a593Smuzhiyun 	mpu = inb(chip->port+MPU_IRQ_STATUS);
223*4882a593Smuzhiyun 	dram = inb(chip->port+ALS300P_DRAM_IRQ_STATUS);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* shared IRQ, for different device?? Exit ASAP! */
226*4882a593Smuzhiyun 	if ((general == 0) && ((mpu & 0x80) == 0) && ((dram & 0x01) == 0))
227*4882a593Smuzhiyun 		return IRQ_NONE;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	if (general & IRQ_PLAYBACK) {
230*4882a593Smuzhiyun 		if (chip->pcm && chip->playback_substream) {
231*4882a593Smuzhiyun 			outb(IRQ_PLAYBACK, chip->port+ALS300P_IRQ_STATUS);
232*4882a593Smuzhiyun 			data = chip->playback_substream->runtime->private_data;
233*4882a593Smuzhiyun 			data->period_flipflop ^= 1;
234*4882a593Smuzhiyun 			snd_pcm_period_elapsed(chip->playback_substream);
235*4882a593Smuzhiyun 			snd_als300_dbgplay("IRQ_PLAYBACK\n");
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 	if (general & IRQ_CAPTURE) {
239*4882a593Smuzhiyun 		if (chip->pcm && chip->capture_substream) {
240*4882a593Smuzhiyun 			outb(IRQ_CAPTURE, chip->port+ALS300P_IRQ_STATUS);
241*4882a593Smuzhiyun 			data = chip->capture_substream->runtime->private_data;
242*4882a593Smuzhiyun 			data->period_flipflop ^= 1;
243*4882a593Smuzhiyun 			snd_pcm_period_elapsed(chip->capture_substream);
244*4882a593Smuzhiyun 			snd_als300_dbgplay("IRQ_CAPTURE\n");
245*4882a593Smuzhiyun 		}
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	/* FIXME: Ack other interrupt types. Not important right now as
248*4882a593Smuzhiyun 	 * those other devices aren't enabled. */
249*4882a593Smuzhiyun 	return IRQ_HANDLED;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
snd_als300_remove(struct pci_dev * pci)252*4882a593Smuzhiyun static void snd_als300_remove(struct pci_dev *pci)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	snd_card_free(pci_get_drvdata(pci));
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
snd_als300_ac97_read(struct snd_ac97 * ac97,unsigned short reg)257*4882a593Smuzhiyun static unsigned short snd_als300_ac97_read(struct snd_ac97 *ac97,
258*4882a593Smuzhiyun 							unsigned short reg)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	int i;
261*4882a593Smuzhiyun 	struct snd_als300 *chip = ac97->private_data;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	for (i = 0; i < 1000; i++) {
264*4882a593Smuzhiyun 		if ((inb(chip->port+AC97_STATUS) & (AC97_BUSY)) == 0)
265*4882a593Smuzhiyun 			break;
266*4882a593Smuzhiyun 		udelay(10);
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 	outl((reg << 24) | (1 << 31), chip->port+AC97_ACCESS);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	for (i = 0; i < 1000; i++) {
271*4882a593Smuzhiyun 		if ((inb(chip->port+AC97_STATUS) & (AC97_DATA_AVAIL)) != 0)
272*4882a593Smuzhiyun 			break;
273*4882a593Smuzhiyun 		udelay(10);
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 	return inw(chip->port+AC97_READ);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
snd_als300_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)278*4882a593Smuzhiyun static void snd_als300_ac97_write(struct snd_ac97 *ac97,
279*4882a593Smuzhiyun 				unsigned short reg, unsigned short val)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	int i;
282*4882a593Smuzhiyun 	struct snd_als300 *chip = ac97->private_data;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	for (i = 0; i < 1000; i++) {
285*4882a593Smuzhiyun 		if ((inb(chip->port+AC97_STATUS) & (AC97_BUSY)) == 0)
286*4882a593Smuzhiyun 			break;
287*4882a593Smuzhiyun 		udelay(10);
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	outl((reg << 24) | val, chip->port+AC97_ACCESS);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
snd_als300_ac97(struct snd_als300 * chip)292*4882a593Smuzhiyun static int snd_als300_ac97(struct snd_als300 *chip)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct snd_ac97_bus *bus;
295*4882a593Smuzhiyun 	struct snd_ac97_template ac97;
296*4882a593Smuzhiyun 	int err;
297*4882a593Smuzhiyun 	static const struct snd_ac97_bus_ops ops = {
298*4882a593Smuzhiyun 		.write = snd_als300_ac97_write,
299*4882a593Smuzhiyun 		.read = snd_als300_ac97_read,
300*4882a593Smuzhiyun 	};
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0)
303*4882a593Smuzhiyun 		return err;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	memset(&ac97, 0, sizeof(ac97));
306*4882a593Smuzhiyun 	ac97.private_data = chip;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return snd_ac97_mixer(bus, &ac97, &chip->ac97);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun /* hardware definition
312*4882a593Smuzhiyun  *
313*4882a593Smuzhiyun  * In AC97 mode, we always use 48k/16bit/stereo.
314*4882a593Smuzhiyun  * Any request to change data type is ignored by
315*4882a593Smuzhiyun  * the card when it is running outside of legacy
316*4882a593Smuzhiyun  * mode.
317*4882a593Smuzhiyun  */
318*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_als300_playback_hw =
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	.info =			(SNDRV_PCM_INFO_MMAP |
321*4882a593Smuzhiyun 				SNDRV_PCM_INFO_INTERLEAVED |
322*4882a593Smuzhiyun 				SNDRV_PCM_INFO_PAUSE |
323*4882a593Smuzhiyun 				SNDRV_PCM_INFO_MMAP_VALID),
324*4882a593Smuzhiyun 	.formats =		SNDRV_PCM_FMTBIT_S16,
325*4882a593Smuzhiyun 	.rates =		SNDRV_PCM_RATE_48000,
326*4882a593Smuzhiyun 	.rate_min =		48000,
327*4882a593Smuzhiyun 	.rate_max =		48000,
328*4882a593Smuzhiyun 	.channels_min =		2,
329*4882a593Smuzhiyun 	.channels_max =		2,
330*4882a593Smuzhiyun 	.buffer_bytes_max =	64 * 1024,
331*4882a593Smuzhiyun 	.period_bytes_min =	64,
332*4882a593Smuzhiyun 	.period_bytes_max =	32 * 1024,
333*4882a593Smuzhiyun 	.periods_min =		2,
334*4882a593Smuzhiyun 	.periods_max =		2,
335*4882a593Smuzhiyun };
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_als300_capture_hw =
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	.info =			(SNDRV_PCM_INFO_MMAP |
340*4882a593Smuzhiyun 				SNDRV_PCM_INFO_INTERLEAVED |
341*4882a593Smuzhiyun 				SNDRV_PCM_INFO_PAUSE |
342*4882a593Smuzhiyun 				SNDRV_PCM_INFO_MMAP_VALID),
343*4882a593Smuzhiyun 	.formats =		SNDRV_PCM_FMTBIT_S16,
344*4882a593Smuzhiyun 	.rates =		SNDRV_PCM_RATE_48000,
345*4882a593Smuzhiyun 	.rate_min =		48000,
346*4882a593Smuzhiyun 	.rate_max =		48000,
347*4882a593Smuzhiyun 	.channels_min =		2,
348*4882a593Smuzhiyun 	.channels_max =		2,
349*4882a593Smuzhiyun 	.buffer_bytes_max =	64 * 1024,
350*4882a593Smuzhiyun 	.period_bytes_min =	64,
351*4882a593Smuzhiyun 	.period_bytes_max =	32 * 1024,
352*4882a593Smuzhiyun 	.periods_min =		2,
353*4882a593Smuzhiyun 	.periods_max =		2,
354*4882a593Smuzhiyun };
355*4882a593Smuzhiyun 
snd_als300_playback_open(struct snd_pcm_substream * substream)356*4882a593Smuzhiyun static int snd_als300_playback_open(struct snd_pcm_substream *substream)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
359*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
360*4882a593Smuzhiyun 	struct snd_als300_substream_data *data = kzalloc(sizeof(*data),
361*4882a593Smuzhiyun 								GFP_KERNEL);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (!data)
364*4882a593Smuzhiyun 		return -ENOMEM;
365*4882a593Smuzhiyun 	chip->playback_substream = substream;
366*4882a593Smuzhiyun 	runtime->hw = snd_als300_playback_hw;
367*4882a593Smuzhiyun 	runtime->private_data = data;
368*4882a593Smuzhiyun 	data->control_register = PLAYBACK_CONTROL;
369*4882a593Smuzhiyun 	data->block_counter_register = PLAYBACK_BLOCK_COUNTER;
370*4882a593Smuzhiyun 	return 0;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
snd_als300_playback_close(struct snd_pcm_substream * substream)373*4882a593Smuzhiyun static int snd_als300_playback_close(struct snd_pcm_substream *substream)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
376*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	data = substream->runtime->private_data;
379*4882a593Smuzhiyun 	kfree(data);
380*4882a593Smuzhiyun 	chip->playback_substream = NULL;
381*4882a593Smuzhiyun 	return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
snd_als300_capture_open(struct snd_pcm_substream * substream)384*4882a593Smuzhiyun static int snd_als300_capture_open(struct snd_pcm_substream *substream)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
387*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
388*4882a593Smuzhiyun 	struct snd_als300_substream_data *data = kzalloc(sizeof(*data),
389*4882a593Smuzhiyun 								GFP_KERNEL);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	if (!data)
392*4882a593Smuzhiyun 		return -ENOMEM;
393*4882a593Smuzhiyun 	chip->capture_substream = substream;
394*4882a593Smuzhiyun 	runtime->hw = snd_als300_capture_hw;
395*4882a593Smuzhiyun 	runtime->private_data = data;
396*4882a593Smuzhiyun 	data->control_register = RECORD_CONTROL;
397*4882a593Smuzhiyun 	data->block_counter_register = RECORD_BLOCK_COUNTER;
398*4882a593Smuzhiyun 	return 0;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
snd_als300_capture_close(struct snd_pcm_substream * substream)401*4882a593Smuzhiyun static int snd_als300_capture_close(struct snd_pcm_substream *substream)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
404*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	data = substream->runtime->private_data;
407*4882a593Smuzhiyun 	kfree(data);
408*4882a593Smuzhiyun 	chip->capture_substream = NULL;
409*4882a593Smuzhiyun 	return 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
snd_als300_playback_prepare(struct snd_pcm_substream * substream)412*4882a593Smuzhiyun static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	u32 tmp;
415*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
416*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
417*4882a593Smuzhiyun 	unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
418*4882a593Smuzhiyun 	unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	spin_lock_irq(&chip->reg_lock);
421*4882a593Smuzhiyun 	tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
422*4882a593Smuzhiyun 	tmp &= ~TRANSFER_START;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	snd_als300_dbgplay("Period bytes: %d Buffer bytes %d\n",
425*4882a593Smuzhiyun 						period_bytes, buffer_bytes);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* set block size */
428*4882a593Smuzhiyun 	tmp &= 0xffff0000;
429*4882a593Smuzhiyun 	tmp |= period_bytes - 1;
430*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	/* set dma area */
433*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, PLAYBACK_START,
434*4882a593Smuzhiyun 					runtime->dma_addr);
435*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, PLAYBACK_END,
436*4882a593Smuzhiyun 					runtime->dma_addr + buffer_bytes - 1);
437*4882a593Smuzhiyun 	spin_unlock_irq(&chip->reg_lock);
438*4882a593Smuzhiyun 	return 0;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun 
snd_als300_capture_prepare(struct snd_pcm_substream * substream)441*4882a593Smuzhiyun static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	u32 tmp;
444*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
445*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
446*4882a593Smuzhiyun 	unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
447*4882a593Smuzhiyun 	unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	spin_lock_irq(&chip->reg_lock);
450*4882a593Smuzhiyun 	tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL);
451*4882a593Smuzhiyun 	tmp &= ~TRANSFER_START;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	snd_als300_dbgplay("Period bytes: %d Buffer bytes %d\n", period_bytes,
454*4882a593Smuzhiyun 							buffer_bytes);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/* set block size */
457*4882a593Smuzhiyun 	tmp &= 0xffff0000;
458*4882a593Smuzhiyun 	tmp |= period_bytes - 1;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	/* set dma area */
461*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, RECORD_CONTROL, tmp);
462*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, RECORD_START,
463*4882a593Smuzhiyun 					runtime->dma_addr);
464*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, RECORD_END,
465*4882a593Smuzhiyun 					runtime->dma_addr + buffer_bytes - 1);
466*4882a593Smuzhiyun 	spin_unlock_irq(&chip->reg_lock);
467*4882a593Smuzhiyun 	return 0;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
snd_als300_trigger(struct snd_pcm_substream * substream,int cmd)470*4882a593Smuzhiyun static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
473*4882a593Smuzhiyun 	u32 tmp;
474*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
475*4882a593Smuzhiyun 	unsigned short reg;
476*4882a593Smuzhiyun 	int ret = 0;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	data = substream->runtime->private_data;
479*4882a593Smuzhiyun 	reg = data->control_register;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	spin_lock(&chip->reg_lock);
482*4882a593Smuzhiyun 	switch (cmd) {
483*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
484*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_RESUME:
485*4882a593Smuzhiyun 		tmp = snd_als300_gcr_read(chip->port, reg);
486*4882a593Smuzhiyun 		data->period_flipflop = 1;
487*4882a593Smuzhiyun 		snd_als300_gcr_write(chip->port, reg, tmp | TRANSFER_START);
488*4882a593Smuzhiyun 		snd_als300_dbgplay("TRIGGER START\n");
489*4882a593Smuzhiyun 		break;
490*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
491*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_SUSPEND:
492*4882a593Smuzhiyun 		tmp = snd_als300_gcr_read(chip->port, reg);
493*4882a593Smuzhiyun 		snd_als300_gcr_write(chip->port, reg, tmp & ~TRANSFER_START);
494*4882a593Smuzhiyun 		snd_als300_dbgplay("TRIGGER STOP\n");
495*4882a593Smuzhiyun 		break;
496*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
497*4882a593Smuzhiyun 		tmp = snd_als300_gcr_read(chip->port, reg);
498*4882a593Smuzhiyun 		snd_als300_gcr_write(chip->port, reg, tmp | FIFO_PAUSE);
499*4882a593Smuzhiyun 		snd_als300_dbgplay("TRIGGER PAUSE\n");
500*4882a593Smuzhiyun 		break;
501*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
502*4882a593Smuzhiyun 		tmp = snd_als300_gcr_read(chip->port, reg);
503*4882a593Smuzhiyun 		snd_als300_gcr_write(chip->port, reg, tmp & ~FIFO_PAUSE);
504*4882a593Smuzhiyun 		snd_als300_dbgplay("TRIGGER RELEASE\n");
505*4882a593Smuzhiyun 		break;
506*4882a593Smuzhiyun 	default:
507*4882a593Smuzhiyun 		snd_als300_dbgplay("TRIGGER INVALID\n");
508*4882a593Smuzhiyun 		ret = -EINVAL;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 	spin_unlock(&chip->reg_lock);
511*4882a593Smuzhiyun 	return ret;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun 
snd_als300_pointer(struct snd_pcm_substream * substream)514*4882a593Smuzhiyun static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	u16 current_ptr;
517*4882a593Smuzhiyun 	struct snd_als300 *chip = snd_pcm_substream_chip(substream);
518*4882a593Smuzhiyun 	struct snd_als300_substream_data *data;
519*4882a593Smuzhiyun 	unsigned short period_bytes;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	data = substream->runtime->private_data;
522*4882a593Smuzhiyun 	period_bytes = snd_pcm_lib_period_bytes(substream);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	spin_lock(&chip->reg_lock);
525*4882a593Smuzhiyun 	current_ptr = (u16) snd_als300_gcr_read(chip->port,
526*4882a593Smuzhiyun 					data->block_counter_register) + 4;
527*4882a593Smuzhiyun 	spin_unlock(&chip->reg_lock);
528*4882a593Smuzhiyun 	if (current_ptr > period_bytes)
529*4882a593Smuzhiyun 		current_ptr = 0;
530*4882a593Smuzhiyun 	else
531*4882a593Smuzhiyun 		current_ptr = period_bytes - current_ptr;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (data->period_flipflop == 0)
534*4882a593Smuzhiyun 		current_ptr += period_bytes;
535*4882a593Smuzhiyun 	snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr);
536*4882a593Smuzhiyun 	return bytes_to_frames(substream->runtime, current_ptr);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun static const struct snd_pcm_ops snd_als300_playback_ops = {
540*4882a593Smuzhiyun 	.open =		snd_als300_playback_open,
541*4882a593Smuzhiyun 	.close =	snd_als300_playback_close,
542*4882a593Smuzhiyun 	.prepare =	snd_als300_playback_prepare,
543*4882a593Smuzhiyun 	.trigger =	snd_als300_trigger,
544*4882a593Smuzhiyun 	.pointer =	snd_als300_pointer,
545*4882a593Smuzhiyun };
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun static const struct snd_pcm_ops snd_als300_capture_ops = {
548*4882a593Smuzhiyun 	.open =		snd_als300_capture_open,
549*4882a593Smuzhiyun 	.close =	snd_als300_capture_close,
550*4882a593Smuzhiyun 	.prepare =	snd_als300_capture_prepare,
551*4882a593Smuzhiyun 	.trigger =	snd_als300_trigger,
552*4882a593Smuzhiyun 	.pointer =	snd_als300_pointer,
553*4882a593Smuzhiyun };
554*4882a593Smuzhiyun 
snd_als300_new_pcm(struct snd_als300 * chip)555*4882a593Smuzhiyun static int snd_als300_new_pcm(struct snd_als300 *chip)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	struct snd_pcm *pcm;
558*4882a593Smuzhiyun 	int err;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	err = snd_pcm_new(chip->card, "ALS300", 0, 1, 1, &pcm);
561*4882a593Smuzhiyun 	if (err < 0)
562*4882a593Smuzhiyun 		return err;
563*4882a593Smuzhiyun 	pcm->private_data = chip;
564*4882a593Smuzhiyun 	strcpy(pcm->name, "ALS300");
565*4882a593Smuzhiyun 	chip->pcm = pcm;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* set operators */
568*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
569*4882a593Smuzhiyun 				&snd_als300_playback_ops);
570*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
571*4882a593Smuzhiyun 				&snd_als300_capture_ops);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/* pre-allocation of buffers */
574*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
575*4882a593Smuzhiyun 				       64*1024, 64*1024);
576*4882a593Smuzhiyun 	return 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
snd_als300_init(struct snd_als300 * chip)579*4882a593Smuzhiyun static void snd_als300_init(struct snd_als300 *chip)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	unsigned long flags;
582*4882a593Smuzhiyun 	u32 tmp;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->reg_lock, flags);
585*4882a593Smuzhiyun 	chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16)
586*4882a593Smuzhiyun 								& 0x0000000F;
587*4882a593Smuzhiyun 	/* Setup DRAM */
588*4882a593Smuzhiyun 	tmp = snd_als300_gcr_read(chip->port, DRAM_WRITE_CONTROL);
589*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, DRAM_WRITE_CONTROL,
590*4882a593Smuzhiyun 						(tmp | DRAM_MODE_2)
591*4882a593Smuzhiyun 						& ~WRITE_TRANS_START);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	/* Enable IRQ output */
594*4882a593Smuzhiyun 	snd_als300_set_irq_flag(chip, IRQ_ENABLE);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/* Unmute hardware devices so their outputs get routed to
597*4882a593Smuzhiyun 	 * the onboard mixer */
598*4882a593Smuzhiyun 	tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
599*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, MISC_CONTROL,
600*4882a593Smuzhiyun 			tmp | VMUTE_NORMAL | MMUTE_NORMAL);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/* Reset volumes */
603*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, MUS_VOC_VOL, 0);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	/* Make sure playback transfer is stopped */
606*4882a593Smuzhiyun 	tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
607*4882a593Smuzhiyun 	snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL,
608*4882a593Smuzhiyun 			tmp & ~TRANSFER_START);
609*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->reg_lock, flags);
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
snd_als300_create(struct snd_card * card,struct pci_dev * pci,int chip_type,struct snd_als300 ** rchip)612*4882a593Smuzhiyun static int snd_als300_create(struct snd_card *card,
613*4882a593Smuzhiyun 			     struct pci_dev *pci, int chip_type,
614*4882a593Smuzhiyun 			     struct snd_als300 **rchip)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun 	struct snd_als300 *chip;
617*4882a593Smuzhiyun 	void *irq_handler;
618*4882a593Smuzhiyun 	int err;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	static const struct snd_device_ops ops = {
621*4882a593Smuzhiyun 		.dev_free = snd_als300_dev_free,
622*4882a593Smuzhiyun 	};
623*4882a593Smuzhiyun 	*rchip = NULL;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if ((err = pci_enable_device(pci)) < 0)
626*4882a593Smuzhiyun 		return err;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 ||
629*4882a593Smuzhiyun 		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) {
630*4882a593Smuzhiyun 		dev_err(card->dev, "error setting 28bit DMA mask\n");
631*4882a593Smuzhiyun 		pci_disable_device(pci);
632*4882a593Smuzhiyun 		return -ENXIO;
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 	pci_set_master(pci);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
637*4882a593Smuzhiyun 	if (chip == NULL) {
638*4882a593Smuzhiyun 		pci_disable_device(pci);
639*4882a593Smuzhiyun 		return -ENOMEM;
640*4882a593Smuzhiyun 	}
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	chip->card = card;
643*4882a593Smuzhiyun 	chip->pci = pci;
644*4882a593Smuzhiyun 	chip->irq = -1;
645*4882a593Smuzhiyun 	chip->chip_type = chip_type;
646*4882a593Smuzhiyun 	spin_lock_init(&chip->reg_lock);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	if ((err = pci_request_regions(pci, "ALS300")) < 0) {
649*4882a593Smuzhiyun 		kfree(chip);
650*4882a593Smuzhiyun 		pci_disable_device(pci);
651*4882a593Smuzhiyun 		return err;
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 	chip->port = pci_resource_start(pci, 0);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	if (chip->chip_type == DEVICE_ALS300_PLUS)
656*4882a593Smuzhiyun 		irq_handler = snd_als300plus_interrupt;
657*4882a593Smuzhiyun 	else
658*4882a593Smuzhiyun 		irq_handler = snd_als300_interrupt;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
661*4882a593Smuzhiyun 			KBUILD_MODNAME, chip)) {
662*4882a593Smuzhiyun 		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
663*4882a593Smuzhiyun 		snd_als300_free(chip);
664*4882a593Smuzhiyun 		return -EBUSY;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 	chip->irq = pci->irq;
667*4882a593Smuzhiyun 	card->sync_irq = chip->irq;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	snd_als300_init(chip);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	err = snd_als300_ac97(chip);
672*4882a593Smuzhiyun 	if (err < 0) {
673*4882a593Smuzhiyun 		dev_err(card->dev, "Could not create ac97\n");
674*4882a593Smuzhiyun 		snd_als300_free(chip);
675*4882a593Smuzhiyun 		return err;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if ((err = snd_als300_new_pcm(chip)) < 0) {
679*4882a593Smuzhiyun 		dev_err(card->dev, "Could not create PCM\n");
680*4882a593Smuzhiyun 		snd_als300_free(chip);
681*4882a593Smuzhiyun 		return err;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
685*4882a593Smuzhiyun 						chip, &ops)) < 0) {
686*4882a593Smuzhiyun 		snd_als300_free(chip);
687*4882a593Smuzhiyun 		return err;
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	*rchip = chip;
691*4882a593Smuzhiyun 	return 0;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
snd_als300_suspend(struct device * dev)695*4882a593Smuzhiyun static int snd_als300_suspend(struct device *dev)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	struct snd_card *card = dev_get_drvdata(dev);
698*4882a593Smuzhiyun 	struct snd_als300 *chip = card->private_data;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
701*4882a593Smuzhiyun 	snd_ac97_suspend(chip->ac97);
702*4882a593Smuzhiyun 	return 0;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
snd_als300_resume(struct device * dev)705*4882a593Smuzhiyun static int snd_als300_resume(struct device *dev)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun 	struct snd_card *card = dev_get_drvdata(dev);
708*4882a593Smuzhiyun 	struct snd_als300 *chip = card->private_data;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	snd_als300_init(chip);
711*4882a593Smuzhiyun 	snd_ac97_resume(chip->ac97);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
714*4882a593Smuzhiyun 	return 0;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume);
718*4882a593Smuzhiyun #define SND_ALS300_PM_OPS	&snd_als300_pm
719*4882a593Smuzhiyun #else
720*4882a593Smuzhiyun #define SND_ALS300_PM_OPS	NULL
721*4882a593Smuzhiyun #endif
722*4882a593Smuzhiyun 
snd_als300_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)723*4882a593Smuzhiyun static int snd_als300_probe(struct pci_dev *pci,
724*4882a593Smuzhiyun                              const struct pci_device_id *pci_id)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun 	static int dev;
727*4882a593Smuzhiyun 	struct snd_card *card;
728*4882a593Smuzhiyun 	struct snd_als300 *chip;
729*4882a593Smuzhiyun 	int err, chip_type;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (dev >= SNDRV_CARDS)
732*4882a593Smuzhiyun 		return -ENODEV;
733*4882a593Smuzhiyun 	if (!enable[dev]) {
734*4882a593Smuzhiyun 		dev++;
735*4882a593Smuzhiyun 		return -ENOENT;
736*4882a593Smuzhiyun 	}
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
739*4882a593Smuzhiyun 			   0, &card);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (err < 0)
742*4882a593Smuzhiyun 		return err;
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	chip_type = pci_id->driver_data;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if ((err = snd_als300_create(card, pci, chip_type, &chip)) < 0) {
747*4882a593Smuzhiyun 		snd_card_free(card);
748*4882a593Smuzhiyun 		return err;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 	card->private_data = chip;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	strcpy(card->driver, "ALS300");
753*4882a593Smuzhiyun 	if (chip->chip_type == DEVICE_ALS300_PLUS)
754*4882a593Smuzhiyun 		/* don't know much about ALS300+ yet
755*4882a593Smuzhiyun 		 * print revision number for now */
756*4882a593Smuzhiyun 		sprintf(card->shortname, "ALS300+ (Rev. %d)", chip->revision);
757*4882a593Smuzhiyun 	else
758*4882a593Smuzhiyun 		sprintf(card->shortname, "ALS300 (Rev. %c)", 'A' +
759*4882a593Smuzhiyun 							chip->revision - 1);
760*4882a593Smuzhiyun 	sprintf(card->longname, "%s at 0x%lx irq %i",
761*4882a593Smuzhiyun 				card->shortname, chip->port, chip->irq);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	if ((err = snd_card_register(card)) < 0) {
764*4882a593Smuzhiyun 		snd_card_free(card);
765*4882a593Smuzhiyun 		return err;
766*4882a593Smuzhiyun 	}
767*4882a593Smuzhiyun 	pci_set_drvdata(pci, card);
768*4882a593Smuzhiyun 	dev++;
769*4882a593Smuzhiyun 	return 0;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun static struct pci_driver als300_driver = {
773*4882a593Smuzhiyun 	.name = KBUILD_MODNAME,
774*4882a593Smuzhiyun 	.id_table = snd_als300_ids,
775*4882a593Smuzhiyun 	.probe = snd_als300_probe,
776*4882a593Smuzhiyun 	.remove = snd_als300_remove,
777*4882a593Smuzhiyun 	.driver = {
778*4882a593Smuzhiyun 		.pm = SND_ALS300_PM_OPS,
779*4882a593Smuzhiyun 	},
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun module_pci_driver(als300_driver);
783