Commit 7628700e08403618b0b07bd25b6456d8b2d074ef
Committed by
Takashi Iwai
1 parent
9d948d2700
ALSA: pcxhr - add support for pcxhr stereo sound cards (firmware support)
- Add support for pcxhr stereo cards and their firmware - autorize sound cards without analog IO - do some cleanup Signed-off-by: Markus Bollinger <bollinger@digigram.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 1 changed file with 108 additions and 40 deletions Side-by-side Diff
sound/pci/pcxhr/pcxhr_hwdep.c
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | #include "pcxhr_mixer.h" |
32 | 32 | #include "pcxhr_hwdep.h" |
33 | 33 | #include "pcxhr_core.h" |
34 | +#include "pcxhr_mix22.h" | |
34 | 35 | |
35 | 36 | |
36 | 37 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) |
37 | 38 | |
... | ... | @@ -40,10 +41,10 @@ |
40 | 41 | #endif |
41 | 42 | |
42 | 43 | |
44 | +static int pcxhr_sub_init(struct pcxhr_mgr *mgr); | |
43 | 45 | /* |
44 | 46 | * get basic information and init pcxhr card |
45 | 47 | */ |
46 | - | |
47 | 48 | static int pcxhr_init_board(struct pcxhr_mgr *mgr) |
48 | 49 | { |
49 | 50 | int err; |
... | ... | @@ -68,7 +69,7 @@ |
68 | 69 | if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2) |
69 | 70 | return -EINVAL; |
70 | 71 | /* test 8 or 2 phys in */ |
71 | - if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) != | |
72 | + if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) < | |
72 | 73 | mgr->capture_chips * 2) |
73 | 74 | return -EINVAL; |
74 | 75 | /* test max nb substream per board */ |
75 | 76 | |
76 | 77 | |
77 | 78 | |
... | ... | @@ -77,20 +78,34 @@ |
77 | 78 | /* test max nb substream per pipe */ |
78 | 79 | if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS) |
79 | 80 | return -EINVAL; |
81 | + snd_printdd("supported formats : playback=%x capture=%x\n", | |
82 | + rmh.stat[2], rmh.stat[3]); | |
80 | 83 | |
81 | 84 | pcxhr_init_rmh(&rmh, CMD_VERSION); |
82 | 85 | /* firmware num for DSP */ |
83 | 86 | rmh.cmd[0] |= mgr->firmware_num; |
84 | 87 | /* transfer granularity in samples (should be multiple of 48) */ |
85 | - rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY; | |
88 | + rmh.cmd[1] = (1<<23) + mgr->granularity; | |
86 | 89 | rmh.cmd_len = 2; |
87 | 90 | err = pcxhr_send_msg(mgr, &rmh); |
88 | 91 | if (err) |
89 | 92 | return err; |
90 | - snd_printdd("PCXHR DSP version is %d.%d.%d\n", | |
91 | - (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); | |
93 | + snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, | |
94 | + (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); | |
92 | 95 | mgr->dsp_version = rmh.stat[0]; |
93 | 96 | |
97 | + if (mgr->is_hr_stereo) | |
98 | + err = hr222_sub_init(mgr); | |
99 | + else | |
100 | + err = pcxhr_sub_init(mgr); | |
101 | + return err; | |
102 | +} | |
103 | + | |
104 | +static int pcxhr_sub_init(struct pcxhr_mgr *mgr) | |
105 | +{ | |
106 | + int err; | |
107 | + struct pcxhr_rmh rmh; | |
108 | + | |
94 | 109 | /* get options */ |
95 | 110 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); |
96 | 111 | rmh.cmd[0] |= IO_NUM_REG_STATUS; |
97 | 112 | |
98 | 113 | |
... | ... | @@ -100,20 +115,22 @@ |
100 | 115 | if (err) |
101 | 116 | return err; |
102 | 117 | |
103 | - if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD) | |
104 | - mgr->board_has_analog = 1; /* analog addon board available */ | |
105 | - else | |
106 | - /* analog addon board not available -> no support for instance */ | |
107 | - return -EINVAL; | |
118 | + if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == | |
119 | + REG_STATUS_OPT_ANALOG_BOARD) | |
120 | + mgr->board_has_analog = 1; /* analog addon board found */ | |
108 | 121 | |
109 | 122 | /* unmute inputs */ |
110 | 123 | err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, |
111 | 124 | REG_CONT_UNMUTE_INPUTS, NULL); |
112 | 125 | if (err) |
113 | 126 | return err; |
114 | - /* unmute outputs */ | |
115 | - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */ | |
127 | + /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */ | |
128 | + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); | |
116 | 129 | rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; |
130 | + if (DSP_EXT_CMD_SET(mgr)) { | |
131 | + rmh.cmd[1] = 1; /* unmute digital plugs */ | |
132 | + rmh.cmd_len = 2; | |
133 | + } | |
117 | 134 | err = pcxhr_send_msg(mgr, &rmh); |
118 | 135 | return err; |
119 | 136 | } |
120 | 137 | |
121 | 138 | |
122 | 139 | |
123 | 140 | |
... | ... | @@ -124,19 +141,25 @@ |
124 | 141 | |
125 | 142 | if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { |
126 | 143 | /* mute outputs */ |
144 | + if (!mgr->is_hr_stereo) { | |
127 | 145 | /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */ |
128 | 146 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); |
129 | 147 | rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; |
130 | 148 | pcxhr_send_msg(mgr, &rmh); |
131 | 149 | /* mute inputs */ |
132 | - pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL); | |
150 | + pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, | |
151 | + 0, NULL); | |
152 | + } | |
153 | + /* stereo cards mute with reset of dsp */ | |
133 | 154 | } |
134 | 155 | /* reset pcxhr dsp */ |
135 | - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) | |
156 | + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) | |
136 | 157 | pcxhr_reset_dsp(mgr); |
137 | 158 | /* reset second xilinx */ |
138 | - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) | |
159 | + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) { | |
139 | 160 | pcxhr_reset_xilinx_com(mgr); |
161 | + mgr->dsp_loaded = 1; | |
162 | + } | |
140 | 163 | return; |
141 | 164 | } |
142 | 165 | |
... | ... | @@ -144,8 +167,9 @@ |
144 | 167 | /* |
145 | 168 | * allocate a playback/capture pipe (pcmp0/pcmc0) |
146 | 169 | */ |
147 | -static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe, | |
148 | - int is_capture, int pin) | |
170 | +static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, | |
171 | + struct pcxhr_pipe *pipe, | |
172 | + int is_capture, int pin) | |
149 | 173 | { |
150 | 174 | int stream_count, audio_count; |
151 | 175 | int err; |
152 | 176 | |
153 | 177 | |
... | ... | @@ -161,15 +185,23 @@ |
161 | 185 | stream_count = PCXHR_PLAYBACK_STREAMS; |
162 | 186 | audio_count = 2; /* always stereo */ |
163 | 187 | } |
164 | - snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); | |
188 | + snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", | |
189 | + pin, is_capture ? 'c' : 'p'); | |
165 | 190 | pipe->is_capture = is_capture; |
166 | 191 | pipe->first_audio = pin; |
167 | 192 | /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */ |
168 | 193 | pcxhr_init_rmh(&rmh, CMD_RES_PIPE); |
169 | - pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); | |
194 | + pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, | |
195 | + audio_count, stream_count); | |
196 | + rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */ | |
197 | + if (DSP_EXT_CMD_SET(mgr)) { | |
198 | + /* add channel mask to command */ | |
199 | + rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03; | |
200 | + } | |
170 | 201 | err = pcxhr_send_msg(mgr, &rmh); |
171 | 202 | if (err < 0) { |
172 | - snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err ); | |
203 | + snd_printk(KERN_ERR "error pipe allocation " | |
204 | + "(CMD_RES_PIPE) err=%x!\n", err); | |
173 | 205 | return err; |
174 | 206 | } |
175 | 207 | pipe->status = PCXHR_PIPE_DEFINED; |
176 | 208 | |
... | ... | @@ -199,10 +231,12 @@ |
199 | 231 | snd_printk(KERN_ERR "error stopping pipe!\n"); |
200 | 232 | /* release the pipe */ |
201 | 233 | pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); |
202 | - pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); | |
234 | + pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, | |
235 | + 0, 0); | |
203 | 236 | err = pcxhr_send_msg(mgr, &rmh); |
204 | 237 | if (err < 0) |
205 | - snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err); | |
238 | + snd_printk(KERN_ERR "error pipe release " | |
239 | + "(CMD_FREE_PIPE) err(%x)\n", err); | |
206 | 240 | pipe->status = PCXHR_PIPE_UNDEFINED; |
207 | 241 | return err; |
208 | 242 | } |
209 | 243 | |
210 | 244 | |
... | ... | @@ -248,15 +282,16 @@ |
248 | 282 | for (i = 0; i < mgr->num_cards; i++) { |
249 | 283 | chip = mgr->chip[i]; |
250 | 284 | if (chip->nb_streams_play) |
251 | - playback_mask |= (1 << chip->playback_pipe.first_audio); | |
285 | + playback_mask |= 1 << chip->playback_pipe.first_audio; | |
252 | 286 | for (j = 0; j < chip->nb_streams_capt; j++) |
253 | - capture_mask |= (1 << chip->capture_pipe[j].first_audio); | |
287 | + capture_mask |= 1 << chip->capture_pipe[j].first_audio; | |
254 | 288 | } |
255 | 289 | return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); |
256 | 290 | } |
257 | 291 | |
258 | 292 | |
259 | -static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp) | |
293 | +static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, | |
294 | + const struct firmware *dsp) | |
260 | 295 | { |
261 | 296 | int err, card_index; |
262 | 297 | |
263 | 298 | |
264 | 299 | |
265 | 300 | |
... | ... | @@ -330,22 +365,33 @@ |
330 | 365 | |
331 | 366 | int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) |
332 | 367 | { |
333 | - static char *fw_files[5] = { | |
334 | - "xi_1_882.dat", | |
335 | - "xc_1_882.dat", | |
336 | - "e321_512.e56", | |
337 | - "b321_512.b56", | |
338 | - "d321_512.d56" | |
368 | + static char *fw_files[][5] = { | |
369 | + [0] = { "xi_1_882.dat", "xc_1_882.dat", | |
370 | + "e321_512.e56", "b321_512.b56", "d321_512.d56" }, | |
371 | + [1] = { "xi_1_882.dat", "xc_882e.dat", | |
372 | + "e321_512.e56", "b882e.b56", "d321_512.d56" }, | |
373 | + [2] = { "xi_1_882.dat", "xc_1222.dat", | |
374 | + "e321_512.e56", "b1222.b56", "d1222.d56" }, | |
375 | + [3] = { "xi_1_882.dat", "xc_1222e.dat", | |
376 | + "e321_512.e56", "b1222e.b56", "d1222.d56" }, | |
377 | + [4] = { NULL, "x1_222hr.dat", | |
378 | + "e924.e56", "b924.b56", "l_1_222.d56" }, | |
379 | + [5] = { NULL, "x1_924hr.dat", | |
380 | + "e924.e56", "b924.b56", "l_1_222.d56" }, | |
339 | 381 | }; |
340 | 382 | char path[32]; |
341 | 383 | |
342 | 384 | const struct firmware *fw_entry; |
343 | 385 | int i, err; |
386 | + int fw_set = mgr->fw_file_set; | |
344 | 387 | |
345 | - for (i = 0; i < ARRAY_SIZE(fw_files); i++) { | |
346 | - sprintf(path, "pcxhr/%s", fw_files[i]); | |
388 | + for (i = 0; i < 5; i++) { | |
389 | + if (!fw_files[fw_set][i]) | |
390 | + continue; | |
391 | + sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); | |
347 | 392 | if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { |
348 | - snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path); | |
393 | + snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", | |
394 | + path); | |
349 | 395 | return -ENOENT; |
350 | 396 | } |
351 | 397 | /* fake hwdep dsp record */ |
352 | 398 | |
353 | 399 | |
... | ... | @@ -360,10 +406,25 @@ |
360 | 406 | |
361 | 407 | MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); |
362 | 408 | MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); |
409 | +MODULE_FIRMWARE("pcxhr/xc_882e.dat"); | |
363 | 410 | MODULE_FIRMWARE("pcxhr/e321_512.e56"); |
364 | 411 | MODULE_FIRMWARE("pcxhr/b321_512.b56"); |
412 | +MODULE_FIRMWARE("pcxhr/b882e.b56"); | |
365 | 413 | MODULE_FIRMWARE("pcxhr/d321_512.d56"); |
366 | 414 | |
415 | +MODULE_FIRMWARE("pcxhr/xc_1222.dat"); | |
416 | +MODULE_FIRMWARE("pcxhr/xc_1222e.dat"); | |
417 | +MODULE_FIRMWARE("pcxhr/b1222.b56"); | |
418 | +MODULE_FIRMWARE("pcxhr/b1222e.b56"); | |
419 | +MODULE_FIRMWARE("pcxhr/d1222.d56"); | |
420 | + | |
421 | +MODULE_FIRMWARE("pcxhr/x1_222hr.dat"); | |
422 | +MODULE_FIRMWARE("pcxhr/x1_924hr.dat"); | |
423 | +MODULE_FIRMWARE("pcxhr/e924.e56"); | |
424 | +MODULE_FIRMWARE("pcxhr/b924.b56"); | |
425 | +MODULE_FIRMWARE("pcxhr/l_1_222.d56"); | |
426 | + | |
427 | + | |
367 | 428 | #else /* old style firmware loading */ |
368 | 429 | |
369 | 430 | /* pcxhr hwdep interface id string */ |
... | ... | @@ -373,7 +434,8 @@ |
373 | 434 | static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, |
374 | 435 | struct snd_hwdep_dsp_status *info) |
375 | 436 | { |
376 | - strcpy(info->id, "pcxhr"); | |
437 | + struct pcxhr_mgr *mgr = hw->private_data; | |
438 | + sprintf(info->id, "pcxhr%d", mgr->fw_file_set); | |
377 | 439 | info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; |
378 | 440 | |
379 | 441 | if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) |
... | ... | @@ -393,8 +455,8 @@ |
393 | 455 | fw.size = dsp->length; |
394 | 456 | fw.data = vmalloc(fw.size); |
395 | 457 | if (! fw.data) { |
396 | - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%lu bytes)\n", | |
397 | - (unsigned long)fw.size); | |
458 | + snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " | |
459 | + "(%lu bytes)\n", (unsigned long)fw.size); | |
398 | 460 | return -ENOMEM; |
399 | 461 | } |
400 | 462 | if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { |
... | ... | @@ -424,8 +486,11 @@ |
424 | 486 | int err; |
425 | 487 | struct snd_hwdep *hw; |
426 | 488 | |
427 | - /* only create hwdep interface for first cardX (see "index" module parameter)*/ | |
428 | - if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0) | |
489 | + /* only create hwdep interface for first cardX | |
490 | + * (see "index" module parameter) | |
491 | + */ | |
492 | + err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); | |
493 | + if (err < 0) | |
429 | 494 | return err; |
430 | 495 | |
431 | 496 | hw->iface = SNDRV_HWDEP_IFACE_PCXHR; |
432 | 497 | |
... | ... | @@ -435,10 +500,13 @@ |
435 | 500 | hw->ops.dsp_status = pcxhr_hwdep_dsp_status; |
436 | 501 | hw->ops.dsp_load = pcxhr_hwdep_dsp_load; |
437 | 502 | hw->exclusive = 1; |
503 | + /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ | |
504 | + hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; | |
438 | 505 | mgr->dsp_loaded = 0; |
439 | 506 | sprintf(hw->name, PCXHR_HWDEP_ID); |
440 | 507 | |
441 | - if ((err = snd_card_register(mgr->chip[0]->card)) < 0) | |
508 | + err = snd_card_register(mgr->chip[0]->card); | |
509 | + if (err < 0) | |
442 | 510 | return err; |
443 | 511 | return 0; |
444 | 512 | } |