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