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