1 |
/* |
/* |
2 |
* Vortex PCM ALSA driver. |
* Vortex PCM ALSA driver. |
3 |
* |
* |
4 |
* Supports ADB and WT DMA. Unfortunately, WT routing is still a |
* Supports ADB and WT DMA. Unfortunately, WT routing is still a |
5 |
* mistery. To discover that, we need to disassemble the windoze |
* mistery. To discover that, we need to disassemble the windoze |
6 |
* driver too. |
* driver too. |
7 |
* |
* |
8 |
* |
* |
9 |
*/ |
*/ |
10 |
|
|
11 |
#include <sound/driver.h> |
#include <sound/driver.h> |
12 |
#include <linux/time.h> |
#include <linux/time.h> |
13 |
#include <sound/core.h> |
#include <sound/core.h> |
14 |
#include <sound/pcm.h> |
#include <sound/pcm.h> |
15 |
#include <sound/pcm_params.h> |
#include <sound/pcm_params.h> |
|
|
|
16 |
#include "au88x0.h" |
#include "au88x0.h" |
17 |
|
|
|
|
|
18 |
#define chip_t vortex_t |
#define chip_t vortex_t |
19 |
|
|
|
|
|
20 |
/* hardware definition */ |
/* hardware definition */ |
21 |
static snd_pcm_hardware_t snd_vortex_playback_hw_adb = { |
static snd_pcm_hardware_t snd_vortex_playback_hw_adb = { |
22 |
.info = (SNDRV_PCM_INFO_MMAP | |
.info = (SNDRV_PCM_INFO_MMAP | |
58 |
chip_t *chip = snd_pcm_substream_chip(substream); |
chip_t *chip = snd_pcm_substream_chip(substream); |
59 |
snd_pcm_runtime_t *runtime = substream->runtime; |
snd_pcm_runtime_t *runtime = substream->runtime; |
60 |
int dma; |
int dma; |
61 |
|
|
62 |
if (substream->pcm == chip->pcm_adb) { |
if (substream->pcm == chip->pcm_adb) { |
63 |
runtime->hw = snd_vortex_playback_hw_adb; |
runtime->hw = snd_vortex_playback_hw_adb; |
64 |
dma = vortex_getadb(chip); |
dma = vortex_getadb(chip); |
66 |
return -EBUSY; |
return -EBUSY; |
67 |
substream->runtime->private_data = &chip->dma_adb[dma]; |
substream->runtime->private_data = &chip->dma_adb[dma]; |
68 |
chip->dma_adb[dma].substream = substream; |
chip->dma_adb[dma].substream = substream; |
69 |
} else { |
} else { |
70 |
runtime->hw = snd_vortex_playback_hw_wt; |
runtime->hw = snd_vortex_playback_hw_wt; |
71 |
dma = vortex_getwt(chip); |
dma = vortex_getwt(chip); |
72 |
if (dma < 0) |
if (dma < 0) |
81 |
static int snd_vortex_pcm_close(snd_pcm_substream_t * substream) { |
static int snd_vortex_pcm_close(snd_pcm_substream_t * substream) { |
82 |
//vortex_t *chip = snd_pcm_substream_chip(substream); |
//vortex_t *chip = snd_pcm_substream_chip(substream); |
83 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
84 |
|
|
85 |
// the hardware-specific codes will be here |
// the hardware-specific codes will be here |
86 |
// Dealloc DMA and remove audio route. |
// Dealloc DMA and remove audio route. |
87 |
dma->substream = NULL; |
dma->substream = NULL; |
91 |
} |
} |
92 |
|
|
93 |
/* hw_params callback */ |
/* hw_params callback */ |
94 |
static int snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { |
static int snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { |
95 |
chip_t *chip = snd_pcm_substream_chip(substream); |
chip_t *chip = snd_pcm_substream_chip(substream); |
96 |
snd_pcm_runtime_t *runtime = substream->runtime; |
snd_pcm_runtime_t *runtime = substream->runtime; |
97 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
98 |
|
|
99 |
int err; |
int err; |
100 |
|
|
101 |
// Alloc buffer memory. |
// Alloc buffer memory. |
102 |
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); |
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); |
103 |
if (err < 0) { |
if (err < 0) { |
104 |
printk("Vortex: pcm page alloc failed!\n"); |
printk("Vortex: pcm page alloc failed!\n"); |
105 |
return err; |
return err; |
106 |
} |
} |
107 |
|
|
108 |
printk("Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), |
printk("Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), |
109 |
params_period_bytes(hw_params), params_channels(hw_params)); |
params_period_bytes(hw_params), params_channels(hw_params)); |
110 |
|
|
111 |
// Make audio routes and config buffer DMA. |
// Make audio routes and config buffer DMA. |
112 |
if (substream->pcm == chip->pcm_adb) { |
if (substream->pcm == chip->pcm_adb) { |
113 |
vortex_adbdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params)); |
vortex_adbdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params)); |
120 |
if (dma->nr_ch) |
if (dma->nr_ch) |
121 |
vortex_wt_waveroute(chip, dma->dma, 0); |
vortex_wt_waveroute(chip, dma->dma, 0); |
122 |
if (params_channels(hw_params)) |
if (params_channels(hw_params)) |
123 |
vortex_wt_waveroute(chip, dma->dma, params_channels(hw_params)); |
vortex_wt_waveroute(chip, dma->dma, params_channels(hw_params)); |
124 |
} |
} |
125 |
return 0; |
return 0; |
126 |
} |
} |
129 |
static int snd_vortex_pcm_hw_free(snd_pcm_substream_t *substream) { |
static int snd_vortex_pcm_hw_free(snd_pcm_substream_t *substream) { |
130 |
chip_t *chip = snd_pcm_substream_chip(substream); |
chip_t *chip = snd_pcm_substream_chip(substream); |
131 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
132 |
|
|
133 |
// Delete audio routes. |
// Delete audio routes. |
134 |
if (substream->pcm == chip->pcm_adb) |
if (substream->pcm == chip->pcm_adb) |
135 |
vortex_adb_waveroute(chip, dma->dma, 0); |
vortex_adb_waveroute(chip, dma->dma, 0); |
136 |
else |
else |
137 |
vortex_wt_waveroute(chip, dma->dma, 0); |
vortex_wt_waveroute(chip, dma->dma, 0); |
138 |
|
|
139 |
return snd_pcm_lib_free_pages(substream); |
return snd_pcm_lib_free_pages(substream); |
140 |
} |
} |
141 |
|
|
145 |
snd_pcm_runtime_t *runtime = substream->runtime; |
snd_pcm_runtime_t *runtime = substream->runtime; |
146 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
147 |
int fmt, i, cvrt; |
int fmt, i, cvrt; |
148 |
|
|
149 |
// set up the hardware with the current configuration. |
// set up the hardware with the current configuration. |
150 |
fmt = vortex_alsafmt_aspfmt(runtime->format); |
fmt = vortex_alsafmt_aspfmt(runtime->format); |
151 |
if (substream->pcm == chip->pcm_adb) { |
if (substream->pcm == chip->pcm_adb) { |
159 |
vortex_adbdma_setmode(chip, dma->dma, 1, i/*direction*/, fmt, 1/*?*/, 0); |
vortex_adbdma_setmode(chip, dma->dma, 1, i/*direction*/, fmt, 1/*?*/, 0); |
160 |
for (i=0; i<(chip->dma_adb[dma->dma].nr_ch); i++) |
for (i=0; i<(chip->dma_adb[dma->dma].nr_ch); i++) |
161 |
vortex_src_change_convratio(chip, i+(dma->dma*2), cvrt); |
vortex_src_change_convratio(chip, i+(dma->dma*2), cvrt); |
162 |
|
|
163 |
vortex_adbdma_setstartbuffer(chip, dma->dma, 0); |
vortex_adbdma_setstartbuffer(chip, dma->dma, 0); |
164 |
} else { |
} else { |
165 |
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
166 |
i = 1; |
i = 1; |
167 |
else |
else |
168 |
i = 0; |
i = 0; |
169 |
vortex_wtdma_setmode(chip, dma->dma, 1, i, fmt, 1, 0); |
vortex_wtdma_setmode(chip, dma->dma, 1, i, fmt, 1, 0); |
170 |
// FIXME: Set rate (if possible). |
// FIXME: Set rate (if possible). |
177 |
static int snd_vortex_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { |
static int snd_vortex_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { |
178 |
chip_t *chip = snd_pcm_substream_chip(substream); |
chip_t *chip = snd_pcm_substream_chip(substream); |
179 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
180 |
|
|
181 |
switch (cmd) { |
switch (cmd) { |
182 |
case SNDRV_PCM_TRIGGER_START: |
case SNDRV_PCM_TRIGGER_START: |
183 |
// do something to start the PCM engine |
// do something to start the PCM engine |
225 |
vortex_t *chip = snd_pcm_substream_chip(substream); |
vortex_t *chip = snd_pcm_substream_chip(substream); |
226 |
snd_pcm_uframes_t current_ptr = 0; |
snd_pcm_uframes_t current_ptr = 0; |
227 |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
dma_t *dma = (dma_t*)substream->runtime->private_data; |
228 |
|
|
229 |
spin_lock(chip->lock); |
spin_lock(chip->lock); |
230 |
if (substream->pcm == chip->pcm_adb) |
if (substream->pcm == chip->pcm_adb) |
231 |
current_ptr = vortex_adbdma_getlinearpos(chip, dma->dma); |
current_ptr = vortex_adbdma_getlinearpos(chip, dma->dma); |
257 |
int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr) { |
int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr) { |
258 |
snd_pcm_t *pcm; |
snd_pcm_t *pcm; |
259 |
int err; |
int err; |
260 |
|
|
261 |
if ((chip == 0)||(idx < 0)||(idx>1)) |
if ((chip == 0)||(idx < 0)||(idx>1)) |
262 |
return -ENODEV; |
return -ENODEV; |
263 |
|
|
264 |
if (idx == 0) { |
if (idx == 0) { |
265 |
if ((err = snd_pcm_new(chip->card, "Aureal Vortex ADB", idx, nr, nr, &pcm)) < 0) |
if ((err = snd_pcm_new(chip->card, "Aureal Vortex ADB", idx, nr, nr, &pcm)) < 0) |
266 |
return err; |
return err; |
279 |
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vortex_playback_ops); |
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vortex_playback_ops); |
280 |
/* pre-allocation of buffers */ |
/* pre-allocation of buffers */ |
281 |
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci_dev, pcm, 0x10000, 0x10000); |
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci_dev, pcm, 0x10000, 0x10000); |
282 |
|
|
283 |
return 0; |
return 0; |
284 |
} |
} |
|
|
|
|
/* end */ |
|