xref: /openbmc/linux/sound/pci/pcxhr/pcxhr_hwdep.c (revision df2634f43f5106947f3735a0b61a6527a4b278cd)
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 <linux/interrupt.h>
24 #include <linux/vmalloc.h>
25 #include <linux/firmware.h>
26 #include <linux/pci.h>
27 #include <asm/io.h>
28 #include <sound/core.h>
29 #include <sound/hwdep.h>
30 #include "pcxhr.h"
31 #include "pcxhr_mixer.h"
32 #include "pcxhr_hwdep.h"
33 #include "pcxhr_core.h"
34 #include "pcxhr_mix22.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 static int pcxhr_sub_init(struct pcxhr_mgr *mgr);
45 /*
46  * get basic information and init pcxhr card
47  */
48 static 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 	if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
70 		return -EINVAL;
71 	/* test 8 or 2 phys in */
72 	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
73 	    mgr->capture_chips * 2)
74 		return -EINVAL;
75 	/* test max nb substream per board */
76 	if ((rmh.stat[1] & 0x5F) < card_streams)
77 		return -EINVAL;
78 	/* test max nb substream per pipe */
79 	if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
80 		return -EINVAL;
81 	snd_printdd("supported formats : playback=%x capture=%x\n",
82 		    rmh.stat[2], rmh.stat[3]);
83 
84 	pcxhr_init_rmh(&rmh, CMD_VERSION);
85 	/* firmware num for DSP */
86 	rmh.cmd[0] |= mgr->firmware_num;
87 	/* transfer granularity in samples (should be multiple of 48) */
88 	rmh.cmd[1] = (1<<23) + mgr->granularity;
89 	rmh.cmd_len = 2;
90 	err = pcxhr_send_msg(mgr, &rmh);
91 	if (err)
92 		return err;
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);
95 	mgr->dsp_version = rmh.stat[0];
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 
109 	/* get options */
110 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
111 	rmh.cmd[0] |= IO_NUM_REG_STATUS;
112 	rmh.cmd[1]  = REG_STATUS_OPTIONS;
113 	rmh.cmd_len = 2;
114 	err = pcxhr_send_msg(mgr, &rmh);
115 	if (err)
116 		return err;
117 
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 */
121 
122 	/* unmute inputs */
123 	err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
124 					  REG_CONT_UNMUTE_INPUTS, NULL);
125 	if (err)
126 		return err;
127 	/* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */
128 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
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 	}
134 	err = pcxhr_send_msg(mgr, &rmh);
135 	return err;
136 }
137 
138 void pcxhr_reset_board(struct pcxhr_mgr *mgr)
139 {
140 	struct pcxhr_rmh rmh;
141 
142 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
143 		/* mute outputs */
144 	    if (!mgr->is_hr_stereo) {
145 		/* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
146 		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
147 		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
148 		pcxhr_send_msg(mgr, &rmh);
149 		/* mute inputs */
150 		pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
151 					    0, NULL);
152 	    }
153 		/* stereo cards mute with reset of dsp */
154 	}
155 	/* reset pcxhr dsp */
156 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
157 		pcxhr_reset_dsp(mgr);
158 	/* reset second xilinx */
159 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) {
160 		pcxhr_reset_xilinx_com(mgr);
161 		mgr->dsp_loaded = 1;
162 	}
163 	return;
164 }
165 
166 
167 /*
168  *  allocate a playback/capture pipe (pcmp0/pcmc0)
169  */
170 static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
171 				   struct pcxhr_pipe *pipe,
172 				   int is_capture, int pin)
173 {
174 	int stream_count, audio_count;
175 	int err;
176 	struct pcxhr_rmh rmh;
177 
178 	if (is_capture) {
179 		stream_count = 1;
180 		if (mgr->mono_capture)
181 			audio_count = 1;
182 		else
183 			audio_count = 2;
184 	} else {
185 		stream_count = PCXHR_PLAYBACK_STREAMS;
186 		audio_count = 2;	/* always stereo */
187 	}
188 	snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
189 		    pin, is_capture ? 'c' : 'p');
190 	pipe->is_capture = is_capture;
191 	pipe->first_audio = pin;
192 	/* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
193 	pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
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 	}
201 	err = pcxhr_send_msg(mgr, &rmh);
202 	if (err < 0) {
203 		snd_printk(KERN_ERR "error pipe allocation "
204 			   "(CMD_RES_PIPE) err=%x!\n", err);
205 		return err;
206 	}
207 	pipe->status = PCXHR_PIPE_DEFINED;
208 
209 	return 0;
210 }
211 
212 /*
213  *  free playback/capture pipe (pcmp0/pcmc0)
214  */
215 #if 0
216 static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
217 {
218 	struct pcxhr_rmh rmh;
219 	int capture_mask = 0;
220 	int playback_mask = 0;
221 	int err = 0;
222 
223 	if (pipe->is_capture)
224 		capture_mask  = (1 << pipe->first_audio);
225 	else
226 		playback_mask = (1 << pipe->first_audio);
227 
228 	/* stop one pipe */
229 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
230 	if (err < 0)
231 		snd_printk(KERN_ERR "error stopping pipe!\n");
232 	/* release the pipe */
233 	pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
234 	pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
235 				  0, 0);
236 	err = pcxhr_send_msg(mgr, &rmh);
237 	if (err < 0)
238 		snd_printk(KERN_ERR "error pipe release "
239 			   "(CMD_FREE_PIPE) err(%x)\n", err);
240 	pipe->status = PCXHR_PIPE_UNDEFINED;
241 	return err;
242 }
243 #endif
244 
245 
246 static int pcxhr_config_pipes(struct pcxhr_mgr *mgr)
247 {
248 	int err, i, j;
249 	struct snd_pcxhr *chip;
250 	struct pcxhr_pipe *pipe;
251 
252 	/* allocate the pipes on the dsp */
253 	for (i = 0; i < mgr->num_cards; i++) {
254 		chip = mgr->chip[i];
255 		if (chip->nb_streams_play) {
256 			pipe = &chip->playback_pipe;
257 			err = pcxhr_dsp_allocate_pipe( mgr, pipe, 0, i*2);
258 			if (err)
259 				return err;
260 			for(j = 0; j < chip->nb_streams_play; j++)
261 				chip->playback_stream[j].pipe = pipe;
262 		}
263 		for (j = 0; j < chip->nb_streams_capt; j++) {
264 			pipe = &chip->capture_pipe[j];
265 			err = pcxhr_dsp_allocate_pipe(mgr, pipe, 1, i*2 + j);
266 			if (err)
267 				return err;
268 			chip->capture_stream[j].pipe = pipe;
269 		}
270 	}
271 	return 0;
272 }
273 
274 static int pcxhr_start_pipes(struct pcxhr_mgr *mgr)
275 {
276 	int i, j;
277 	struct snd_pcxhr *chip;
278 	int playback_mask = 0;
279 	int capture_mask = 0;
280 
281 	/* start all the pipes on the dsp */
282 	for (i = 0; i < mgr->num_cards; i++) {
283 		chip = mgr->chip[i];
284 		if (chip->nb_streams_play)
285 			playback_mask |= 1 << chip->playback_pipe.first_audio;
286 		for (j = 0; j < chip->nb_streams_capt; j++)
287 			capture_mask |= 1 << chip->capture_pipe[j].first_audio;
288 	}
289 	return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
290 }
291 
292 
293 static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
294 			  const struct firmware *dsp)
295 {
296 	int err, card_index;
297 
298 	snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size);
299 
300 	switch (index) {
301 	case PCXHR_FIRMWARE_XLX_INT_INDEX:
302 		pcxhr_reset_xilinx_com(mgr);
303 		return pcxhr_load_xilinx_binary(mgr, dsp, 0);
304 
305 	case PCXHR_FIRMWARE_XLX_COM_INDEX:
306 		pcxhr_reset_xilinx_com(mgr);
307 		return pcxhr_load_xilinx_binary(mgr, dsp, 1);
308 
309 	case PCXHR_FIRMWARE_DSP_EPRM_INDEX:
310 		pcxhr_reset_dsp(mgr);
311 		return pcxhr_load_eeprom_binary(mgr, dsp);
312 
313 	case PCXHR_FIRMWARE_DSP_BOOT_INDEX:
314 		return pcxhr_load_boot_binary(mgr, dsp);
315 
316 	case PCXHR_FIRMWARE_DSP_MAIN_INDEX:
317 		err = pcxhr_load_dsp_binary(mgr, dsp);
318 		if (err)
319 			return err;
320 		break;	/* continue with first init */
321 	default:
322 		snd_printk(KERN_ERR "wrong file index\n");
323 		return -EFAULT;
324 	} /* end of switch file index*/
325 
326 	/* first communication with embedded */
327 	err = pcxhr_init_board(mgr);
328         if (err < 0) {
329 		snd_printk(KERN_ERR "pcxhr could not be set up\n");
330 		return err;
331 	}
332 	err = pcxhr_config_pipes(mgr);
333         if (err < 0) {
334 		snd_printk(KERN_ERR "pcxhr pipes could not be set up\n");
335 		return err;
336 	}
337        	/* create devices and mixer in accordance with HW options*/
338         for (card_index = 0; card_index < mgr->num_cards; card_index++) {
339 		struct snd_pcxhr *chip = mgr->chip[card_index];
340 
341 		if ((err = pcxhr_create_pcm(chip)) < 0)
342 			return err;
343 
344 		if (card_index == 0) {
345 			if ((err = pcxhr_create_mixer(chip->mgr)) < 0)
346 				return err;
347 		}
348 		if ((err = snd_card_register(chip->card)) < 0)
349 			return err;
350 	}
351 	err = pcxhr_start_pipes(mgr);
352         if (err < 0) {
353 		snd_printk(KERN_ERR "pcxhr pipes could not be started\n");
354 		return err;
355 	}
356 	snd_printdd("pcxhr firmware downloaded and successfully set up\n");
357 
358 	return 0;
359 }
360 
361 /*
362  * fw loader entry
363  */
364 #ifdef SND_PCXHR_FW_LOADER
365 
366 int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
367 {
368 	static char *fw_files[][5] = {
369 	[0] = { "xlxint.dat", "xlxc882hr.dat",
370 		"dspe882.e56", "dspb882hr.b56", "dspd882.d56" },
371 	[1] = { "xlxint.dat", "xlxc882e.dat",
372 		"dspe882.e56", "dspb882e.b56", "dspd882.d56" },
373 	[2] = { "xlxint.dat", "xlxc1222hr.dat",
374 		"dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" },
375 	[3] = { "xlxint.dat", "xlxc1222e.dat",
376 		"dspe882.e56", "dspb1222e.b56", "dspd1222.d56" },
377 	[4] = { NULL, "xlxc222.dat",
378 		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
379 	[5] = { NULL, "xlxc924.dat",
380 		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
381 	};
382 	char path[32];
383 
384 	const struct firmware *fw_entry;
385 	int i, err;
386 	int fw_set = mgr->fw_file_set;
387 
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]);
392 		if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
393 			snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
394 				   path);
395 			return -ENOENT;
396 		}
397 		/* fake hwdep dsp record */
398 		err = pcxhr_dsp_load(mgr, i, fw_entry);
399 		release_firmware(fw_entry);
400 		if (err < 0)
401 			return err;
402 		mgr->dsp_loaded |= 1 << i;
403 	}
404 	return 0;
405 }
406 
407 MODULE_FIRMWARE("pcxhr/xlxint.dat");
408 MODULE_FIRMWARE("pcxhr/xlxc882hr.dat");
409 MODULE_FIRMWARE("pcxhr/xlxc882e.dat");
410 MODULE_FIRMWARE("pcxhr/dspe882.e56");
411 MODULE_FIRMWARE("pcxhr/dspb882hr.b56");
412 MODULE_FIRMWARE("pcxhr/dspb882e.b56");
413 MODULE_FIRMWARE("pcxhr/dspd882.d56");
414 
415 MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat");
416 MODULE_FIRMWARE("pcxhr/xlxc1222e.dat");
417 MODULE_FIRMWARE("pcxhr/dspb1222hr.b56");
418 MODULE_FIRMWARE("pcxhr/dspb1222e.b56");
419 MODULE_FIRMWARE("pcxhr/dspd1222.d56");
420 
421 MODULE_FIRMWARE("pcxhr/xlxc222.dat");
422 MODULE_FIRMWARE("pcxhr/xlxc924.dat");
423 MODULE_FIRMWARE("pcxhr/dspe924.e56");
424 MODULE_FIRMWARE("pcxhr/dspb924.b56");
425 MODULE_FIRMWARE("pcxhr/dspd222.d56");
426 
427 
428 #else /* old style firmware loading */
429 
430 /* pcxhr hwdep interface id string */
431 #define PCXHR_HWDEP_ID       "pcxhr loader"
432 
433 
434 static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw,
435 				  struct snd_hwdep_dsp_status *info)
436 {
437 	struct pcxhr_mgr *mgr = hw->private_data;
438 	sprintf(info->id, "pcxhr%d", mgr->fw_file_set);
439         info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX;
440 
441 	if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))
442 		info->chip_ready = 1;
443 
444 	info->version = PCXHR_DRIVER_VERSION;
445 	return 0;
446 }
447 
448 static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
449 				struct snd_hwdep_dsp_image *dsp)
450 {
451 	struct pcxhr_mgr *mgr = hw->private_data;
452 	int err;
453 	struct firmware fw;
454 
455 	fw.size = dsp->length;
456 	fw.data = vmalloc(fw.size);
457 	if (! fw.data) {
458 		snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image "
459 			   "(%lu bytes)\n", (unsigned long)fw.size);
460 		return -ENOMEM;
461 	}
462 	if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) {
463 		vfree(fw.data);
464 		return -EFAULT;
465 	}
466 	err = pcxhr_dsp_load(mgr, dsp->index, &fw);
467 	vfree(fw.data);
468 	if (err < 0)
469 		return err;
470 	mgr->dsp_loaded |= 1 << dsp->index;
471 	return 0;
472 }
473 
474 int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
475 {
476 	int err;
477 	struct snd_hwdep *hw;
478 
479 	/* only create hwdep interface for first cardX
480 	 * (see "index" module parameter)
481 	 */
482 	err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw);
483 	if (err < 0)
484 		return err;
485 
486 	hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
487 	hw->private_data = mgr;
488 	hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
489 	hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
490 	hw->exclusive = 1;
491 	/* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */
492 	hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0;
493 	mgr->dsp_loaded = 0;
494 	sprintf(hw->name, PCXHR_HWDEP_ID);
495 
496 	err = snd_card_register(mgr->chip[0]->card);
497 	if (err < 0)
498 		return err;
499 	return 0;
500 }
501 
502 #endif /* SND_PCXHR_FW_LOADER */
503