aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/pcxhr/pcxhr_hwdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/pcxhr/pcxhr_hwdep.c')
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c438
1 files changed, 438 insertions, 0 deletions
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
new file mode 100644
index 000000000000..03517c10e99c
--- /dev/null
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -0,0 +1,438 @@
1/*
2 * Driver for Digigram pcxhr compatible soundcards
3 *
4 * hwdep device manager
5 *
6 * Copyright (c) 2004 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/interrupt.h>
25#include <linux/vmalloc.h>
26#include <linux/firmware.h>
27#include <linux/pci.h>
28#include <asm/io.h>
29#include <sound/core.h>
30#include <sound/hwdep.h>
31#include "pcxhr.h"
32#include "pcxhr_mixer.h"
33#include "pcxhr_hwdep.h"
34#include "pcxhr_core.h"
35
36
37#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
38#if !defined(CONFIG_USE_PCXHRLOADER) && !defined(CONFIG_SND_PCXHR) /* built-in kernel */
39#define SND_PCXHR_FW_LOADER /* use the standard firmware loader */
40#endif
41#endif
42
43
44/*
45 * get basic information and init pcxhr card
46 */
47
48static int pcxhr_init_board(struct pcxhr_mgr *mgr)
49{
50 int err;
51 struct pcxhr_rmh rmh;
52 int card_streams;
53
54 /* calc the number of all streams used */
55 if (mgr->mono_capture)
56 card_streams = mgr->capture_chips * 2;
57 else
58 card_streams = mgr->capture_chips;
59 card_streams += mgr->playback_chips * PCXHR_PLAYBACK_STREAMS;
60
61 /* enable interrupts */
62 pcxhr_enable_dsp(mgr);
63
64 pcxhr_init_rmh(&rmh, CMD_SUPPORTED);
65 err = pcxhr_send_msg(mgr, &rmh);
66 if (err)
67 return err;
68 /* test 8 or 12 phys out */
69 snd_assert((rmh.stat[0] & MASK_FIRST_FIELD) == mgr->playback_chips*2,
70 return -EINVAL);
71 /* test 8 or 2 phys in */
72 snd_assert(((rmh.stat[0] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD) ==
73 mgr->capture_chips * 2, return -EINVAL);
74 /* test max nb substream per board */
75 snd_assert((rmh.stat[1] & 0x5F) >= card_streams, return -EINVAL);
76 /* test max nb substream per pipe */
77 snd_assert(((rmh.stat[1]>>7)&0x5F) >= PCXHR_PLAYBACK_STREAMS, return -EINVAL);
78
79 pcxhr_init_rmh(&rmh, CMD_VERSION);
80 /* firmware num for DSP */
81 rmh.cmd[0] |= mgr->firmware_num;
82 /* transfer granularity in samples (should be multiple of 48) */
83 rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY;
84 rmh.cmd_len = 2;
85 err = pcxhr_send_msg(mgr, &rmh);
86 if (err)
87 return err;
88 snd_printdd("PCXHR DSP version is %d.%d.%d\n",
89 (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
90 mgr->dsp_version = rmh.stat[0];
91
92 /* get options */
93 pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
94 rmh.cmd[0] |= IO_NUM_REG_STATUS;
95 rmh.cmd[1] = REG_STATUS_OPTIONS;
96 rmh.cmd_len = 2;
97 err = pcxhr_send_msg(mgr, &rmh);
98 if (err)
99 return err;
100
101 if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD)
102 mgr->board_has_analog = 1; /* analog addon board available */
103 else
104 /* analog addon board not available -> no support for instance */
105 return -EINVAL;
106
107 /* unmute inputs */
108 err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
109 REG_CONT_UNMUTE_INPUTS, NULL);
110 if (err)
111 return err;
112 /* unmute outputs */
113 pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */
114 rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
115 err = pcxhr_send_msg(mgr, &rmh);
116 return err;
117}
118
119void pcxhr_reset_board(struct pcxhr_mgr *mgr)
120{
121 struct pcxhr_rmh rmh;
122
123 if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
124 /* mute outputs */
125 /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
126 pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
127 rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
128 pcxhr_send_msg(mgr, &rmh);
129 /* mute inputs */
130 pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL);
131 }
132 /* reset pcxhr dsp */
133 if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
134 pcxhr_reset_dsp(mgr);
135 /* reset second xilinx */
136 if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX))
137 pcxhr_reset_xilinx_com(mgr);
138 return;
139}
140
141
142/*
143 * allocate a playback/capture pipe (pcmp0/pcmc0)
144 */
145static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe,
146 int is_capture, int pin)
147{
148 int stream_count, audio_count;
149 int err;
150 struct pcxhr_rmh rmh;
151
152 if (is_capture) {
153 stream_count = 1;
154 if (mgr->mono_capture)
155 audio_count = 1;
156 else
157 audio_count = 2;
158 } else {
159 stream_count = PCXHR_PLAYBACK_STREAMS;
160 audio_count = 2; /* always stereo */
161 }
162 snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p');
163 pipe->is_capture = is_capture;
164 pipe->first_audio = pin;
165 /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
166 pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
167 pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count);
168 err = pcxhr_send_msg(mgr, &rmh);
169 if (err < 0) {
170 snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err );
171 return err;
172 }
173 pipe->status = PCXHR_PIPE_DEFINED;
174
175 return 0;
176}
177
178/*
179 * free playback/capture pipe (pcmp0/pcmc0)
180 */
181#if 0
182static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
183{
184 struct pcxhr_rmh rmh;
185 int capture_mask = 0;
186 int playback_mask = 0;
187 int err = 0;
188
189 if (pipe->is_capture)
190 capture_mask = (1 << pipe->first_audio);
191 else
192 playback_mask = (1 << pipe->first_audio);
193
194 /* stop one pipe */
195 err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
196 if (err < 0)
197 snd_printk(KERN_ERR "error stopping pipe!\n");
198 /* release the pipe */
199 pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
200 pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0);
201 err = pcxhr_send_msg(mgr, &rmh);
202 if (err < 0)
203 snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err);
204 pipe->status = PCXHR_PIPE_UNDEFINED;
205 return err;
206}
207#endif
208
209
210static int pcxhr_config_pipes(struct pcxhr_mgr *mgr)
211{
212 int err, i, j;
213 struct snd_pcxhr *chip;
214 struct pcxhr_pipe *pipe;
215
216 /* allocate the pipes on the dsp */
217 for (i = 0; i < mgr->num_cards; i++) {
218 chip = mgr->chip[i];
219 if (chip->nb_streams_play) {
220 pipe = &chip->playback_pipe;
221 err = pcxhr_dsp_allocate_pipe( mgr, pipe, 0, i*2);
222 if (err)
223 return err;
224 for(j = 0; j < chip->nb_streams_play; j++)
225 chip->playback_stream[j].pipe = pipe;
226 }
227 for (j = 0; j < chip->nb_streams_capt; j++) {
228 pipe = &chip->capture_pipe[j];
229 err = pcxhr_dsp_allocate_pipe(mgr, pipe, 1, i*2 + j);
230 if (err)
231 return err;
232 chip->capture_stream[j].pipe = pipe;
233 }
234 }
235 return 0;
236}
237
238static int pcxhr_start_pipes(struct pcxhr_mgr *mgr)
239{
240 int i, j;
241 struct snd_pcxhr *chip;
242 int playback_mask = 0;
243 int capture_mask = 0;
244
245 /* start all the pipes on the dsp */
246 for (i = 0; i < mgr->num_cards; i++) {
247 chip = mgr->chip[i];
248 if (chip->nb_streams_play)
249 playback_mask |= (1 << chip->playback_pipe.first_audio);
250 for (j = 0; j < chip->nb_streams_capt; j++)
251 capture_mask |= (1 << chip->capture_pipe[j].first_audio);
252 }
253 return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
254}
255
256
257static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp)
258{
259 int err, card_index;
260
261 snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size);
262
263 switch (index) {
264 case PCXHR_FIRMWARE_XLX_INT_INDEX:
265 pcxhr_reset_xilinx_com(mgr);
266 return pcxhr_load_xilinx_binary(mgr, dsp, 0);
267
268 case PCXHR_FIRMWARE_XLX_COM_INDEX:
269 pcxhr_reset_xilinx_com(mgr);
270 return pcxhr_load_xilinx_binary(mgr, dsp, 1);
271
272 case PCXHR_FIRMWARE_DSP_EPRM_INDEX:
273 pcxhr_reset_dsp(mgr);
274 return pcxhr_load_eeprom_binary(mgr, dsp);
275
276 case PCXHR_FIRMWARE_DSP_BOOT_INDEX:
277 return pcxhr_load_boot_binary(mgr, dsp);
278
279 case PCXHR_FIRMWARE_DSP_MAIN_INDEX:
280 err = pcxhr_load_dsp_binary(mgr, dsp);
281 if (err)
282 return err;
283 break; /* continue with first init */
284 default:
285 snd_printk(KERN_ERR "wrong file index\n");
286 return -EFAULT;
287 } /* end of switch file index*/
288
289 /* first communication with embedded */
290 err = pcxhr_init_board(mgr);
291 if (err < 0) {
292 snd_printk(KERN_ERR "pcxhr could not be set up\n");
293 return err;
294 }
295 err = pcxhr_config_pipes(mgr);
296 if (err < 0) {
297 snd_printk(KERN_ERR "pcxhr pipes could not be set up\n");
298 return err;
299 }
300 /* create devices and mixer in accordance with HW options*/
301 for (card_index = 0; card_index < mgr->num_cards; card_index++) {
302 struct snd_pcxhr *chip = mgr->chip[card_index];
303
304 if ((err = pcxhr_create_pcm(chip)) < 0)
305 return err;
306
307 if (card_index == 0) {
308 if ((err = pcxhr_create_mixer(chip->mgr)) < 0)
309 return err;
310 }
311 if ((err = snd_card_register(chip->card)) < 0)
312 return err;
313 }
314 err = pcxhr_start_pipes(mgr);
315 if (err < 0) {
316 snd_printk(KERN_ERR "pcxhr pipes could not be started\n");
317 return err;
318 }
319 snd_printdd("pcxhr firmware downloaded and successfully set up\n");
320
321 return 0;
322}
323
324/*
325 * fw loader entry
326 */
327#ifdef SND_PCXHR_FW_LOADER
328
329int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
330{
331 static char *fw_files[5] = {
332 "xi_1_882.dat",
333 "xc_1_882.dat",
334 "e321_512.e56",
335 "b321_512.b56",
336 "d321_512.d56"
337 };
338 char path[32];
339
340 const struct firmware *fw_entry;
341 int i, err;
342
343 for (i = 0; i < ARRAY_SIZE(fw_files); i++) {
344 sprintf(path, "pcxhr/%s", fw_files[i]);
345 if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
346 snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path);
347 return -ENOENT;
348 }
349 /* fake hwdep dsp record */
350 err = pcxhr_dsp_load(mgr, i, fw_entry);
351 release_firmware(fw_entry);
352 if (err < 0)
353 return err;
354 mgr->dsp_loaded |= 1 << i;
355 }
356 return 0;
357}
358
359#else /* old style firmware loading */
360
361/* pcxhr hwdep interface id string */
362#define PCXHR_HWDEP_ID "pcxhr loader"
363
364
365static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw,
366 struct snd_hwdep_dsp_status *info)
367{
368 strcpy(info->id, "pcxhr");
369 info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX;
370
371 if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))
372 info->chip_ready = 1;
373
374 info->version = PCXHR_DRIVER_VERSION;
375 return 0;
376}
377
378static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
379 struct snd_hwdep_dsp_image *dsp)
380{
381 struct pcxhr_mgr *mgr = hw->private_data;
382 int err;
383 struct firmware fw;
384
385 fw.size = dsp->length;
386 fw.data = vmalloc(fw.size);
387 if (! fw.data) {
388 snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%d bytes)\n",
389 fw.size);
390 return -ENOMEM;
391 }
392 if (copy_from_user(fw.data, dsp->image, dsp->length)) {
393 vfree(fw.data);
394 return -EFAULT;
395 }
396 err = pcxhr_dsp_load(mgr, dsp->index, &fw);
397 vfree(fw.data);
398 if (err < 0)
399 return err;
400 mgr->dsp_loaded |= 1 << dsp->index;
401 return 0;
402}
403
404static int pcxhr_hwdep_open(struct snd_hwdep *hw, struct file *file)
405{
406 return 0;
407}
408
409static int pcxhr_hwdep_release(struct snd_hwdep *hw, struct file *file)
410{
411 return 0;
412}
413
414int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
415{
416 int err;
417 struct snd_hwdep *hw;
418
419 /* only create hwdep interface for first cardX (see "index" module parameter)*/
420 if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0)
421 return err;
422
423 hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
424 hw->private_data = mgr;
425 hw->ops.open = pcxhr_hwdep_open;
426 hw->ops.release = pcxhr_hwdep_release;
427 hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
428 hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
429 hw->exclusive = 1;
430 mgr->dsp_loaded = 0;
431 sprintf(hw->name, PCXHR_HWDEP_ID);
432
433 if ((err = snd_card_register(mgr->chip[0]->card)) < 0)
434 return err;
435 return 0;
436}
437
438#endif /* SND_PCXHR_FW_LOADER */