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