xref: /openbmc/linux/sound/pci/pcxhr/pcxhr_hwdep.c (revision 8c3f1b1c)
1e12229b4SMarkus Bollinger /*
2e12229b4SMarkus Bollinger  * Driver for Digigram pcxhr compatible soundcards
3e12229b4SMarkus Bollinger  *
4e12229b4SMarkus Bollinger  * hwdep device manager
5e12229b4SMarkus Bollinger  *
6e12229b4SMarkus Bollinger  * Copyright (c) 2004 by Digigram <alsa@digigram.com>
7e12229b4SMarkus Bollinger  *
8e12229b4SMarkus Bollinger  *   This program is free software; you can redistribute it and/or modify
9e12229b4SMarkus Bollinger  *   it under the terms of the GNU General Public License as published by
10e12229b4SMarkus Bollinger  *   the Free Software Foundation; either version 2 of the License, or
11e12229b4SMarkus Bollinger  *   (at your option) any later version.
12e12229b4SMarkus Bollinger  *
13e12229b4SMarkus Bollinger  *   This program is distributed in the hope that it will be useful,
14e12229b4SMarkus Bollinger  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15e12229b4SMarkus Bollinger  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e12229b4SMarkus Bollinger  *   GNU General Public License for more details.
17e12229b4SMarkus Bollinger  *
18e12229b4SMarkus Bollinger  *   You should have received a copy of the GNU General Public License
19e12229b4SMarkus Bollinger  *   along with this program; if not, write to the Free Software
20e12229b4SMarkus Bollinger  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21e12229b4SMarkus Bollinger  */
22e12229b4SMarkus Bollinger 
23e12229b4SMarkus Bollinger #include <linux/interrupt.h>
24e12229b4SMarkus Bollinger #include <linux/vmalloc.h>
25e12229b4SMarkus Bollinger #include <linux/firmware.h>
26e12229b4SMarkus Bollinger #include <linux/pci.h>
27da155d5bSPaul Gortmaker #include <linux/module.h>
28e12229b4SMarkus Bollinger #include <asm/io.h>
29e12229b4SMarkus Bollinger #include <sound/core.h>
30e12229b4SMarkus Bollinger #include <sound/hwdep.h>
31e12229b4SMarkus Bollinger #include "pcxhr.h"
32e12229b4SMarkus Bollinger #include "pcxhr_mixer.h"
33e12229b4SMarkus Bollinger #include "pcxhr_hwdep.h"
34e12229b4SMarkus Bollinger #include "pcxhr_core.h"
357628700eSMarkus Bollinger #include "pcxhr_mix22.h"
36e12229b4SMarkus Bollinger 
37e12229b4SMarkus Bollinger 
38e12229b4SMarkus Bollinger #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
39e12229b4SMarkus Bollinger #if !defined(CONFIG_USE_PCXHRLOADER) && !defined(CONFIG_SND_PCXHR) /* built-in kernel */
40e12229b4SMarkus Bollinger #define SND_PCXHR_FW_LOADER	/* use the standard firmware loader */
41e12229b4SMarkus Bollinger #endif
42e12229b4SMarkus Bollinger #endif
43e12229b4SMarkus Bollinger 
44e12229b4SMarkus Bollinger 
457628700eSMarkus Bollinger static int pcxhr_sub_init(struct pcxhr_mgr *mgr);
46e12229b4SMarkus Bollinger /*
47e12229b4SMarkus Bollinger  * get basic information and init pcxhr card
48e12229b4SMarkus Bollinger  */
49e12229b4SMarkus Bollinger static int pcxhr_init_board(struct pcxhr_mgr *mgr)
50e12229b4SMarkus Bollinger {
51e12229b4SMarkus Bollinger 	int err;
52e12229b4SMarkus Bollinger 	struct pcxhr_rmh rmh;
53e12229b4SMarkus Bollinger 	int card_streams;
54e12229b4SMarkus Bollinger 
55e12229b4SMarkus Bollinger 	/* calc the number of all streams used */
56e12229b4SMarkus Bollinger 	if (mgr->mono_capture)
57e12229b4SMarkus Bollinger 		card_streams = mgr->capture_chips * 2;
58e12229b4SMarkus Bollinger 	else
59e12229b4SMarkus Bollinger 		card_streams = mgr->capture_chips;
60e12229b4SMarkus Bollinger 	card_streams += mgr->playback_chips * PCXHR_PLAYBACK_STREAMS;
61e12229b4SMarkus Bollinger 
62e12229b4SMarkus Bollinger 	/* enable interrupts */
63e12229b4SMarkus Bollinger 	pcxhr_enable_dsp(mgr);
64e12229b4SMarkus Bollinger 
65e12229b4SMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_SUPPORTED);
66e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
67e12229b4SMarkus Bollinger 	if (err)
68e12229b4SMarkus Bollinger 		return err;
698c3f1b1cSMarkus Bollinger 	/* test 4, 8 or 12 phys out */
708c3f1b1cSMarkus Bollinger 	if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)
71da3cec35STakashi Iwai 		return -EINVAL;
728c3f1b1cSMarkus Bollinger 	/* test 4, 8 or 2 phys in */
737628700eSMarkus Bollinger 	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
74da3cec35STakashi Iwai 	    mgr->capture_chips * 2)
75da3cec35STakashi Iwai 		return -EINVAL;
76e12229b4SMarkus Bollinger 	/* test max nb substream per board */
77da3cec35STakashi Iwai 	if ((rmh.stat[1] & 0x5F) < card_streams)
78da3cec35STakashi Iwai 		return -EINVAL;
79e12229b4SMarkus Bollinger 	/* test max nb substream per pipe */
80da3cec35STakashi Iwai 	if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
81da3cec35STakashi Iwai 		return -EINVAL;
827628700eSMarkus Bollinger 	snd_printdd("supported formats : playback=%x capture=%x\n",
837628700eSMarkus Bollinger 		    rmh.stat[2], rmh.stat[3]);
84e12229b4SMarkus Bollinger 
85e12229b4SMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_VERSION);
86e12229b4SMarkus Bollinger 	/* firmware num for DSP */
87e12229b4SMarkus Bollinger 	rmh.cmd[0] |= mgr->firmware_num;
88e12229b4SMarkus Bollinger 	/* transfer granularity in samples (should be multiple of 48) */
897628700eSMarkus Bollinger 	rmh.cmd[1] = (1<<23) + mgr->granularity;
90e12229b4SMarkus Bollinger 	rmh.cmd_len = 2;
91e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
92e12229b4SMarkus Bollinger 	if (err)
93e12229b4SMarkus Bollinger 		return err;
947628700eSMarkus Bollinger 	snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
957628700eSMarkus Bollinger 		    (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
96e12229b4SMarkus Bollinger 	mgr->dsp_version = rmh.stat[0];
97e12229b4SMarkus Bollinger 
987628700eSMarkus Bollinger 	if (mgr->is_hr_stereo)
997628700eSMarkus Bollinger 		err = hr222_sub_init(mgr);
1007628700eSMarkus Bollinger 	else
1017628700eSMarkus Bollinger 		err = pcxhr_sub_init(mgr);
1027628700eSMarkus Bollinger 	return err;
1037628700eSMarkus Bollinger }
1047628700eSMarkus Bollinger 
1057628700eSMarkus Bollinger static int pcxhr_sub_init(struct pcxhr_mgr *mgr)
1067628700eSMarkus Bollinger {
1077628700eSMarkus Bollinger 	int err;
1087628700eSMarkus Bollinger 	struct pcxhr_rmh rmh;
1097628700eSMarkus Bollinger 
110e12229b4SMarkus Bollinger 	/* get options */
111e12229b4SMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
112e12229b4SMarkus Bollinger 	rmh.cmd[0] |= IO_NUM_REG_STATUS;
113e12229b4SMarkus Bollinger 	rmh.cmd[1]  = REG_STATUS_OPTIONS;
114e12229b4SMarkus Bollinger 	rmh.cmd_len = 2;
115e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
116e12229b4SMarkus Bollinger 	if (err)
117e12229b4SMarkus Bollinger 		return err;
118e12229b4SMarkus Bollinger 
1197628700eSMarkus Bollinger 	if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) ==
1207628700eSMarkus Bollinger 	    REG_STATUS_OPT_ANALOG_BOARD)
1217628700eSMarkus Bollinger 		mgr->board_has_analog = 1;	/* analog addon board found */
122e12229b4SMarkus Bollinger 
123e12229b4SMarkus Bollinger 	/* unmute inputs */
124e12229b4SMarkus Bollinger 	err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
125e12229b4SMarkus Bollinger 					  REG_CONT_UNMUTE_INPUTS, NULL);
126e12229b4SMarkus Bollinger 	if (err)
127e12229b4SMarkus Bollinger 		return err;
1287628700eSMarkus Bollinger 	/* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */
1297628700eSMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
130e12229b4SMarkus Bollinger 	rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
1317628700eSMarkus Bollinger 	if (DSP_EXT_CMD_SET(mgr)) {
1327628700eSMarkus Bollinger 		rmh.cmd[1]  = 1;	/* unmute digital plugs */
1337628700eSMarkus Bollinger 		rmh.cmd_len = 2;
1347628700eSMarkus Bollinger 	}
135e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
136e12229b4SMarkus Bollinger 	return err;
137e12229b4SMarkus Bollinger }
138e12229b4SMarkus Bollinger 
139e12229b4SMarkus Bollinger void pcxhr_reset_board(struct pcxhr_mgr *mgr)
140e12229b4SMarkus Bollinger {
141e12229b4SMarkus Bollinger 	struct pcxhr_rmh rmh;
142e12229b4SMarkus Bollinger 
143e12229b4SMarkus Bollinger 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
144e12229b4SMarkus Bollinger 		/* mute outputs */
1457628700eSMarkus Bollinger 	    if (!mgr->is_hr_stereo) {
146e12229b4SMarkus Bollinger 		/* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
147e12229b4SMarkus Bollinger 		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
148e12229b4SMarkus Bollinger 		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
149e12229b4SMarkus Bollinger 		pcxhr_send_msg(mgr, &rmh);
150e12229b4SMarkus Bollinger 		/* mute inputs */
1517628700eSMarkus Bollinger 		pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
1527628700eSMarkus Bollinger 					    0, NULL);
1537628700eSMarkus Bollinger 	    }
1547628700eSMarkus Bollinger 		/* stereo cards mute with reset of dsp */
155e12229b4SMarkus Bollinger 	}
156e12229b4SMarkus Bollinger 	/* reset pcxhr dsp */
157e12229b4SMarkus Bollinger 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
158e12229b4SMarkus Bollinger 		pcxhr_reset_dsp(mgr);
159e12229b4SMarkus Bollinger 	/* reset second xilinx */
1607628700eSMarkus Bollinger 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) {
161e12229b4SMarkus Bollinger 		pcxhr_reset_xilinx_com(mgr);
1627628700eSMarkus Bollinger 		mgr->dsp_loaded = 1;
1637628700eSMarkus Bollinger 	}
164e12229b4SMarkus Bollinger 	return;
165e12229b4SMarkus Bollinger }
166e12229b4SMarkus Bollinger 
167e12229b4SMarkus Bollinger 
168e12229b4SMarkus Bollinger /*
169e12229b4SMarkus Bollinger  *  allocate a playback/capture pipe (pcmp0/pcmc0)
170e12229b4SMarkus Bollinger  */
1717628700eSMarkus Bollinger static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
1727628700eSMarkus Bollinger 				   struct pcxhr_pipe *pipe,
173e12229b4SMarkus Bollinger 				   int is_capture, int pin)
174e12229b4SMarkus Bollinger {
175e12229b4SMarkus Bollinger 	int stream_count, audio_count;
176e12229b4SMarkus Bollinger 	int err;
177e12229b4SMarkus Bollinger 	struct pcxhr_rmh rmh;
178e12229b4SMarkus Bollinger 
179e12229b4SMarkus Bollinger 	if (is_capture) {
180e12229b4SMarkus Bollinger 		stream_count = 1;
181e12229b4SMarkus Bollinger 		if (mgr->mono_capture)
182e12229b4SMarkus Bollinger 			audio_count = 1;
183e12229b4SMarkus Bollinger 		else
184e12229b4SMarkus Bollinger 			audio_count = 2;
185e12229b4SMarkus Bollinger 	} else {
186e12229b4SMarkus Bollinger 		stream_count = PCXHR_PLAYBACK_STREAMS;
187e12229b4SMarkus Bollinger 		audio_count = 2;	/* always stereo */
188e12229b4SMarkus Bollinger 	}
1897628700eSMarkus Bollinger 	snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
1907628700eSMarkus Bollinger 		    pin, is_capture ? 'c' : 'p');
191e12229b4SMarkus Bollinger 	pipe->is_capture = is_capture;
192e12229b4SMarkus Bollinger 	pipe->first_audio = pin;
193e12229b4SMarkus Bollinger 	/* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
194e12229b4SMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
1957628700eSMarkus Bollinger 	pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin,
1967628700eSMarkus Bollinger 				  audio_count, stream_count);
1977628700eSMarkus Bollinger 	rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */
1987628700eSMarkus Bollinger 	if (DSP_EXT_CMD_SET(mgr)) {
1997628700eSMarkus Bollinger 		/* add channel mask to command */
2007628700eSMarkus Bollinger 	  rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03;
2017628700eSMarkus Bollinger 	}
202e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
203e12229b4SMarkus Bollinger 	if (err < 0) {
2047628700eSMarkus Bollinger 		snd_printk(KERN_ERR "error pipe allocation "
2057628700eSMarkus Bollinger 			   "(CMD_RES_PIPE) err=%x!\n", err);
206e12229b4SMarkus Bollinger 		return err;
207e12229b4SMarkus Bollinger 	}
208e12229b4SMarkus Bollinger 	pipe->status = PCXHR_PIPE_DEFINED;
209e12229b4SMarkus Bollinger 
210e12229b4SMarkus Bollinger 	return 0;
211e12229b4SMarkus Bollinger }
212e12229b4SMarkus Bollinger 
213e12229b4SMarkus Bollinger /*
214e12229b4SMarkus Bollinger  *  free playback/capture pipe (pcmp0/pcmc0)
215e12229b4SMarkus Bollinger  */
216e12229b4SMarkus Bollinger #if 0
217e12229b4SMarkus Bollinger static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
218e12229b4SMarkus Bollinger {
219e12229b4SMarkus Bollinger 	struct pcxhr_rmh rmh;
220e12229b4SMarkus Bollinger 	int capture_mask = 0;
221e12229b4SMarkus Bollinger 	int playback_mask = 0;
222e12229b4SMarkus Bollinger 	int err = 0;
223e12229b4SMarkus Bollinger 
224e12229b4SMarkus Bollinger 	if (pipe->is_capture)
225e12229b4SMarkus Bollinger 		capture_mask  = (1 << pipe->first_audio);
226e12229b4SMarkus Bollinger 	else
227e12229b4SMarkus Bollinger 		playback_mask = (1 << pipe->first_audio);
228e12229b4SMarkus Bollinger 
229e12229b4SMarkus Bollinger 	/* stop one pipe */
230e12229b4SMarkus Bollinger 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
231e12229b4SMarkus Bollinger 	if (err < 0)
232e12229b4SMarkus Bollinger 		snd_printk(KERN_ERR "error stopping pipe!\n");
233e12229b4SMarkus Bollinger 	/* release the pipe */
234e12229b4SMarkus Bollinger 	pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
2357628700eSMarkus Bollinger 	pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
2367628700eSMarkus Bollinger 				  0, 0);
237e12229b4SMarkus Bollinger 	err = pcxhr_send_msg(mgr, &rmh);
238e12229b4SMarkus Bollinger 	if (err < 0)
2397628700eSMarkus Bollinger 		snd_printk(KERN_ERR "error pipe release "
2407628700eSMarkus Bollinger 			   "(CMD_FREE_PIPE) err(%x)\n", err);
241e12229b4SMarkus Bollinger 	pipe->status = PCXHR_PIPE_UNDEFINED;
242e12229b4SMarkus Bollinger 	return err;
243e12229b4SMarkus Bollinger }
244e12229b4SMarkus Bollinger #endif
245e12229b4SMarkus Bollinger 
246e12229b4SMarkus Bollinger 
247e12229b4SMarkus Bollinger static int pcxhr_config_pipes(struct pcxhr_mgr *mgr)
248e12229b4SMarkus Bollinger {
249e12229b4SMarkus Bollinger 	int err, i, j;
250e12229b4SMarkus Bollinger 	struct snd_pcxhr *chip;
251e12229b4SMarkus Bollinger 	struct pcxhr_pipe *pipe;
252e12229b4SMarkus Bollinger 
253e12229b4SMarkus Bollinger 	/* allocate the pipes on the dsp */
254e12229b4SMarkus Bollinger 	for (i = 0; i < mgr->num_cards; i++) {
255e12229b4SMarkus Bollinger 		chip = mgr->chip[i];
256e12229b4SMarkus Bollinger 		if (chip->nb_streams_play) {
257e12229b4SMarkus Bollinger 			pipe = &chip->playback_pipe;
258e12229b4SMarkus Bollinger 			err = pcxhr_dsp_allocate_pipe( mgr, pipe, 0, i*2);
259e12229b4SMarkus Bollinger 			if (err)
260e12229b4SMarkus Bollinger 				return err;
261e12229b4SMarkus Bollinger 			for(j = 0; j < chip->nb_streams_play; j++)
262e12229b4SMarkus Bollinger 				chip->playback_stream[j].pipe = pipe;
263e12229b4SMarkus Bollinger 		}
264e12229b4SMarkus Bollinger 		for (j = 0; j < chip->nb_streams_capt; j++) {
265e12229b4SMarkus Bollinger 			pipe = &chip->capture_pipe[j];
266e12229b4SMarkus Bollinger 			err = pcxhr_dsp_allocate_pipe(mgr, pipe, 1, i*2 + j);
267e12229b4SMarkus Bollinger 			if (err)
268e12229b4SMarkus Bollinger 				return err;
269e12229b4SMarkus Bollinger 			chip->capture_stream[j].pipe = pipe;
270e12229b4SMarkus Bollinger 		}
271e12229b4SMarkus Bollinger 	}
272e12229b4SMarkus Bollinger 	return 0;
273e12229b4SMarkus Bollinger }
274e12229b4SMarkus Bollinger 
275e12229b4SMarkus Bollinger static int pcxhr_start_pipes(struct pcxhr_mgr *mgr)
276e12229b4SMarkus Bollinger {
277e12229b4SMarkus Bollinger 	int i, j;
278e12229b4SMarkus Bollinger 	struct snd_pcxhr *chip;
279e12229b4SMarkus Bollinger 	int playback_mask = 0;
280e12229b4SMarkus Bollinger 	int capture_mask = 0;
281e12229b4SMarkus Bollinger 
282e12229b4SMarkus Bollinger 	/* start all the pipes on the dsp */
283e12229b4SMarkus Bollinger 	for (i = 0; i < mgr->num_cards; i++) {
284e12229b4SMarkus Bollinger 		chip = mgr->chip[i];
285e12229b4SMarkus Bollinger 		if (chip->nb_streams_play)
2867628700eSMarkus Bollinger 			playback_mask |= 1 << chip->playback_pipe.first_audio;
287e12229b4SMarkus Bollinger 		for (j = 0; j < chip->nb_streams_capt; j++)
2887628700eSMarkus Bollinger 			capture_mask |= 1 << chip->capture_pipe[j].first_audio;
289e12229b4SMarkus Bollinger 	}
290e12229b4SMarkus Bollinger 	return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
291e12229b4SMarkus Bollinger }
292e12229b4SMarkus Bollinger 
293e12229b4SMarkus Bollinger 
2947628700eSMarkus Bollinger static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
2957628700eSMarkus Bollinger 			  const struct firmware *dsp)
296e12229b4SMarkus Bollinger {
297e12229b4SMarkus Bollinger 	int err, card_index;
298e12229b4SMarkus Bollinger 
299e12229b4SMarkus Bollinger 	snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size);
300e12229b4SMarkus Bollinger 
301e12229b4SMarkus Bollinger 	switch (index) {
302e12229b4SMarkus Bollinger 	case PCXHR_FIRMWARE_XLX_INT_INDEX:
303e12229b4SMarkus Bollinger 		pcxhr_reset_xilinx_com(mgr);
304e12229b4SMarkus Bollinger 		return pcxhr_load_xilinx_binary(mgr, dsp, 0);
305e12229b4SMarkus Bollinger 
306e12229b4SMarkus Bollinger 	case PCXHR_FIRMWARE_XLX_COM_INDEX:
307e12229b4SMarkus Bollinger 		pcxhr_reset_xilinx_com(mgr);
308e12229b4SMarkus Bollinger 		return pcxhr_load_xilinx_binary(mgr, dsp, 1);
309e12229b4SMarkus Bollinger 
310e12229b4SMarkus Bollinger 	case PCXHR_FIRMWARE_DSP_EPRM_INDEX:
311e12229b4SMarkus Bollinger 		pcxhr_reset_dsp(mgr);
312e12229b4SMarkus Bollinger 		return pcxhr_load_eeprom_binary(mgr, dsp);
313e12229b4SMarkus Bollinger 
314e12229b4SMarkus Bollinger 	case PCXHR_FIRMWARE_DSP_BOOT_INDEX:
315e12229b4SMarkus Bollinger 		return pcxhr_load_boot_binary(mgr, dsp);
316e12229b4SMarkus Bollinger 
317e12229b4SMarkus Bollinger 	case PCXHR_FIRMWARE_DSP_MAIN_INDEX:
318e12229b4SMarkus Bollinger 		err = pcxhr_load_dsp_binary(mgr, dsp);
319e12229b4SMarkus Bollinger 		if (err)
320e12229b4SMarkus Bollinger 			return err;
321e12229b4SMarkus Bollinger 		break;	/* continue with first init */
322e12229b4SMarkus Bollinger 	default:
323e12229b4SMarkus Bollinger 		snd_printk(KERN_ERR "wrong file index\n");
324e12229b4SMarkus Bollinger 		return -EFAULT;
325e12229b4SMarkus Bollinger 	} /* end of switch file index*/
326e12229b4SMarkus Bollinger 
327e12229b4SMarkus Bollinger 	/* first communication with embedded */
328e12229b4SMarkus Bollinger 	err = pcxhr_init_board(mgr);
329e12229b4SMarkus Bollinger         if (err < 0) {
330e12229b4SMarkus Bollinger 		snd_printk(KERN_ERR "pcxhr could not be set up\n");
331e12229b4SMarkus Bollinger 		return err;
332e12229b4SMarkus Bollinger 	}
333e12229b4SMarkus Bollinger 	err = pcxhr_config_pipes(mgr);
334e12229b4SMarkus Bollinger         if (err < 0) {
335e12229b4SMarkus Bollinger 		snd_printk(KERN_ERR "pcxhr pipes could not be set up\n");
336e12229b4SMarkus Bollinger 		return err;
337e12229b4SMarkus Bollinger 	}
338e12229b4SMarkus Bollinger        	/* create devices and mixer in accordance with HW options*/
339e12229b4SMarkus Bollinger         for (card_index = 0; card_index < mgr->num_cards; card_index++) {
340e12229b4SMarkus Bollinger 		struct snd_pcxhr *chip = mgr->chip[card_index];
341e12229b4SMarkus Bollinger 
342e12229b4SMarkus Bollinger 		if ((err = pcxhr_create_pcm(chip)) < 0)
343e12229b4SMarkus Bollinger 			return err;
344e12229b4SMarkus Bollinger 
345e12229b4SMarkus Bollinger 		if (card_index == 0) {
346e12229b4SMarkus Bollinger 			if ((err = pcxhr_create_mixer(chip->mgr)) < 0)
347e12229b4SMarkus Bollinger 				return err;
348e12229b4SMarkus Bollinger 		}
349e12229b4SMarkus Bollinger 		if ((err = snd_card_register(chip->card)) < 0)
350e12229b4SMarkus Bollinger 			return err;
351e12229b4SMarkus Bollinger 	}
352e12229b4SMarkus Bollinger 	err = pcxhr_start_pipes(mgr);
353e12229b4SMarkus Bollinger         if (err < 0) {
354e12229b4SMarkus Bollinger 		snd_printk(KERN_ERR "pcxhr pipes could not be started\n");
355e12229b4SMarkus Bollinger 		return err;
356e12229b4SMarkus Bollinger 	}
357e12229b4SMarkus Bollinger 	snd_printdd("pcxhr firmware downloaded and successfully set up\n");
358e12229b4SMarkus Bollinger 
359e12229b4SMarkus Bollinger 	return 0;
360e12229b4SMarkus Bollinger }
361e12229b4SMarkus Bollinger 
362e12229b4SMarkus Bollinger /*
363e12229b4SMarkus Bollinger  * fw loader entry
364e12229b4SMarkus Bollinger  */
365e12229b4SMarkus Bollinger #ifdef SND_PCXHR_FW_LOADER
366e12229b4SMarkus Bollinger 
367e12229b4SMarkus Bollinger int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
368e12229b4SMarkus Bollinger {
3697628700eSMarkus Bollinger 	static char *fw_files[][5] = {
370ade9b2fbSMarkus Bollinger 	[0] = { "xlxint.dat", "xlxc882hr.dat",
371ade9b2fbSMarkus Bollinger 		"dspe882.e56", "dspb882hr.b56", "dspd882.d56" },
372ade9b2fbSMarkus Bollinger 	[1] = { "xlxint.dat", "xlxc882e.dat",
373ade9b2fbSMarkus Bollinger 		"dspe882.e56", "dspb882e.b56", "dspd882.d56" },
374ade9b2fbSMarkus Bollinger 	[2] = { "xlxint.dat", "xlxc1222hr.dat",
375ade9b2fbSMarkus Bollinger 		"dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" },
376ade9b2fbSMarkus Bollinger 	[3] = { "xlxint.dat", "xlxc1222e.dat",
377ade9b2fbSMarkus Bollinger 		"dspe882.e56", "dspb1222e.b56", "dspd1222.d56" },
378ade9b2fbSMarkus Bollinger 	[4] = { NULL, "xlxc222.dat",
379ade9b2fbSMarkus Bollinger 		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
380ade9b2fbSMarkus Bollinger 	[5] = { NULL, "xlxc924.dat",
381ade9b2fbSMarkus Bollinger 		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
382e12229b4SMarkus Bollinger 	};
383e12229b4SMarkus Bollinger 	char path[32];
384e12229b4SMarkus Bollinger 
385e12229b4SMarkus Bollinger 	const struct firmware *fw_entry;
386e12229b4SMarkus Bollinger 	int i, err;
3877628700eSMarkus Bollinger 	int fw_set = mgr->fw_file_set;
388e12229b4SMarkus Bollinger 
3897628700eSMarkus Bollinger 	for (i = 0; i < 5; i++) {
3907628700eSMarkus Bollinger 		if (!fw_files[fw_set][i])
3917628700eSMarkus Bollinger 			continue;
3927628700eSMarkus Bollinger 		sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
393e12229b4SMarkus Bollinger 		if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
3947628700eSMarkus Bollinger 			snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
3957628700eSMarkus Bollinger 				   path);
396e12229b4SMarkus Bollinger 			return -ENOENT;
397e12229b4SMarkus Bollinger 		}
398e12229b4SMarkus Bollinger 		/* fake hwdep dsp record */
399e12229b4SMarkus Bollinger 		err = pcxhr_dsp_load(mgr, i, fw_entry);
400e12229b4SMarkus Bollinger 		release_firmware(fw_entry);
401e12229b4SMarkus Bollinger 		if (err < 0)
402e12229b4SMarkus Bollinger 			return err;
403e12229b4SMarkus Bollinger 		mgr->dsp_loaded |= 1 << i;
404e12229b4SMarkus Bollinger 	}
405e12229b4SMarkus Bollinger 	return 0;
406e12229b4SMarkus Bollinger }
407e12229b4SMarkus Bollinger 
408ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxint.dat");
409ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc882hr.dat");
410ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc882e.dat");
411ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspe882.e56");
412ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspb882hr.b56");
413ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspb882e.b56");
414ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspd882.d56");
4157e0af29dSClemens Ladisch 
416ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat");
417ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc1222e.dat");
418ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspb1222hr.b56");
419ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspb1222e.b56");
420ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspd1222.d56");
4217628700eSMarkus Bollinger 
422ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc222.dat");
423ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/xlxc924.dat");
424ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspe924.e56");
425ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspb924.b56");
426ade9b2fbSMarkus Bollinger MODULE_FIRMWARE("pcxhr/dspd222.d56");
4277628700eSMarkus Bollinger 
4287628700eSMarkus Bollinger 
429e12229b4SMarkus Bollinger #else /* old style firmware loading */
430e12229b4SMarkus Bollinger 
431e12229b4SMarkus Bollinger /* pcxhr hwdep interface id string */
432e12229b4SMarkus Bollinger #define PCXHR_HWDEP_ID       "pcxhr loader"
433e12229b4SMarkus Bollinger 
434e12229b4SMarkus Bollinger 
435e12229b4SMarkus Bollinger static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw,
436e12229b4SMarkus Bollinger 				  struct snd_hwdep_dsp_status *info)
437e12229b4SMarkus Bollinger {
4387628700eSMarkus Bollinger 	struct pcxhr_mgr *mgr = hw->private_data;
4397628700eSMarkus Bollinger 	sprintf(info->id, "pcxhr%d", mgr->fw_file_set);
440e12229b4SMarkus Bollinger         info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX;
441e12229b4SMarkus Bollinger 
442e12229b4SMarkus Bollinger 	if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))
443e12229b4SMarkus Bollinger 		info->chip_ready = 1;
444e12229b4SMarkus Bollinger 
445e12229b4SMarkus Bollinger 	info->version = PCXHR_DRIVER_VERSION;
446e12229b4SMarkus Bollinger 	return 0;
447e12229b4SMarkus Bollinger }
448e12229b4SMarkus Bollinger 
449e12229b4SMarkus Bollinger static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
450e12229b4SMarkus Bollinger 				struct snd_hwdep_dsp_image *dsp)
451e12229b4SMarkus Bollinger {
452e12229b4SMarkus Bollinger 	struct pcxhr_mgr *mgr = hw->private_data;
453e12229b4SMarkus Bollinger 	int err;
454e12229b4SMarkus Bollinger 	struct firmware fw;
455e12229b4SMarkus Bollinger 
456e12229b4SMarkus Bollinger 	fw.size = dsp->length;
457e12229b4SMarkus Bollinger 	fw.data = vmalloc(fw.size);
458e12229b4SMarkus Bollinger 	if (! fw.data) {
4597628700eSMarkus Bollinger 		snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image "
4607628700eSMarkus Bollinger 			   "(%lu bytes)\n", (unsigned long)fw.size);
461e12229b4SMarkus Bollinger 		return -ENOMEM;
462e12229b4SMarkus Bollinger 	}
46367852dc0SDavid Howells 	if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) {
464e12229b4SMarkus Bollinger 		vfree(fw.data);
465e12229b4SMarkus Bollinger 		return -EFAULT;
466e12229b4SMarkus Bollinger 	}
467e12229b4SMarkus Bollinger 	err = pcxhr_dsp_load(mgr, dsp->index, &fw);
468e12229b4SMarkus Bollinger 	vfree(fw.data);
469e12229b4SMarkus Bollinger 	if (err < 0)
470e12229b4SMarkus Bollinger 		return err;
471e12229b4SMarkus Bollinger 	mgr->dsp_loaded |= 1 << dsp->index;
472e12229b4SMarkus Bollinger 	return 0;
473e12229b4SMarkus Bollinger }
474e12229b4SMarkus Bollinger 
475e12229b4SMarkus Bollinger int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
476e12229b4SMarkus Bollinger {
477e12229b4SMarkus Bollinger 	int err;
478e12229b4SMarkus Bollinger 	struct snd_hwdep *hw;
479e12229b4SMarkus Bollinger 
4807628700eSMarkus Bollinger 	/* only create hwdep interface for first cardX
4817628700eSMarkus Bollinger 	 * (see "index" module parameter)
4827628700eSMarkus Bollinger 	 */
4837628700eSMarkus Bollinger 	err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw);
4847628700eSMarkus Bollinger 	if (err < 0)
485e12229b4SMarkus Bollinger 		return err;
486e12229b4SMarkus Bollinger 
487e12229b4SMarkus Bollinger 	hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
488e12229b4SMarkus Bollinger 	hw->private_data = mgr;
489e12229b4SMarkus Bollinger 	hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
490e12229b4SMarkus Bollinger 	hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
491e12229b4SMarkus Bollinger 	hw->exclusive = 1;
4927628700eSMarkus Bollinger 	/* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */
4937628700eSMarkus Bollinger 	hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0;
494e12229b4SMarkus Bollinger 	mgr->dsp_loaded = 0;
495e12229b4SMarkus Bollinger 	sprintf(hw->name, PCXHR_HWDEP_ID);
496e12229b4SMarkus Bollinger 
4977628700eSMarkus Bollinger 	err = snd_card_register(mgr->chip[0]->card);
4987628700eSMarkus Bollinger 	if (err < 0)
499e12229b4SMarkus Bollinger 		return err;
500e12229b4SMarkus Bollinger 	return 0;
501e12229b4SMarkus Bollinger }
502e12229b4SMarkus Bollinger 
503e12229b4SMarkus Bollinger #endif /* SND_PCXHR_FW_LOADER */
504