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