root/sound/pci/pcxhr/pcxhr_hwdep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcxhr_init_board
  2. pcxhr_sub_init
  3. pcxhr_reset_board
  4. pcxhr_dsp_allocate_pipe
  5. pcxhr_dsp_free_pipe
  6. pcxhr_config_pipes
  7. pcxhr_start_pipes
  8. pcxhr_dsp_load
  9. pcxhr_setup_firmware

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for Digigram pcxhr compatible soundcards
   4  *
   5  * hwdep device manager
   6  *
   7  * Copyright (c) 2004 by Digigram <alsa@digigram.com>
   8  */
   9 
  10 #include <linux/interrupt.h>
  11 #include <linux/vmalloc.h>
  12 #include <linux/firmware.h>
  13 #include <linux/pci.h>
  14 #include <linux/module.h>
  15 #include <linux/io.h>
  16 #include <sound/core.h>
  17 #include <sound/hwdep.h>
  18 #include "pcxhr.h"
  19 #include "pcxhr_mixer.h"
  20 #include "pcxhr_hwdep.h"
  21 #include "pcxhr_core.h"
  22 #include "pcxhr_mix22.h"
  23 
  24 
  25 static int pcxhr_sub_init(struct pcxhr_mgr *mgr);
  26 /*
  27  * get basic information and init pcxhr card
  28  */
  29 static int pcxhr_init_board(struct pcxhr_mgr *mgr)
  30 {
  31         int err;
  32         struct pcxhr_rmh rmh;
  33         int card_streams;
  34 
  35         /* calc the number of all streams used */
  36         if (mgr->mono_capture)
  37                 card_streams = mgr->capture_chips * 2;
  38         else
  39                 card_streams = mgr->capture_chips;
  40         card_streams += mgr->playback_chips * PCXHR_PLAYBACK_STREAMS;
  41 
  42         /* enable interrupts */
  43         pcxhr_enable_dsp(mgr);
  44 
  45         pcxhr_init_rmh(&rmh, CMD_SUPPORTED);
  46         err = pcxhr_send_msg(mgr, &rmh);
  47         if (err)
  48                 return err;
  49         /* test 4, 8 or 12 phys out */
  50         if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)
  51                 return -EINVAL;
  52         /* test 4, 8 or 2 phys in */
  53         if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
  54             mgr->capture_chips * 2)
  55                 return -EINVAL;
  56         /* test max nb substream per board */
  57         if ((rmh.stat[1] & 0x5F) < card_streams)
  58                 return -EINVAL;
  59         /* test max nb substream per pipe */
  60         if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
  61                 return -EINVAL;
  62         dev_dbg(&mgr->pci->dev,
  63                 "supported formats : playback=%x capture=%x\n",
  64                     rmh.stat[2], rmh.stat[3]);
  65 
  66         pcxhr_init_rmh(&rmh, CMD_VERSION);
  67         /* firmware num for DSP */
  68         rmh.cmd[0] |= mgr->firmware_num;
  69         /* transfer granularity in samples (should be multiple of 48) */
  70         rmh.cmd[1] = (1<<23) + mgr->granularity;
  71         rmh.cmd_len = 2;
  72         err = pcxhr_send_msg(mgr, &rmh);
  73         if (err)
  74                 return err;
  75         dev_dbg(&mgr->pci->dev,
  76                 "PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
  77                     (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
  78         mgr->dsp_version = rmh.stat[0];
  79 
  80         if (mgr->is_hr_stereo)
  81                 err = hr222_sub_init(mgr);
  82         else
  83                 err = pcxhr_sub_init(mgr);
  84         return err;
  85 }
  86 
  87 static int pcxhr_sub_init(struct pcxhr_mgr *mgr)
  88 {
  89         int err;
  90         struct pcxhr_rmh rmh;
  91 
  92         /* get options */
  93         pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
  94         rmh.cmd[0] |= IO_NUM_REG_STATUS;
  95         rmh.cmd[1]  = REG_STATUS_OPTIONS;
  96         rmh.cmd_len = 2;
  97         err = pcxhr_send_msg(mgr, &rmh);
  98         if (err)
  99                 return err;
 100 
 101         if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) ==
 102             REG_STATUS_OPT_ANALOG_BOARD)
 103                 mgr->board_has_analog = 1;      /* analog addon board found */
 104 
 105         /* unmute inputs */
 106         err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
 107                                           REG_CONT_UNMUTE_INPUTS, NULL);
 108         if (err)
 109                 return err;
 110         /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */
 111         pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
 112         rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
 113         if (DSP_EXT_CMD_SET(mgr)) {
 114                 rmh.cmd[1]  = 1;        /* unmute digital plugs */
 115                 rmh.cmd_len = 2;
 116         }
 117         err = pcxhr_send_msg(mgr, &rmh);
 118         return err;
 119 }
 120 
 121 void pcxhr_reset_board(struct pcxhr_mgr *mgr)
 122 {
 123         struct pcxhr_rmh rmh;
 124 
 125         if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
 126                 /* mute outputs */
 127             if (!mgr->is_hr_stereo) {
 128                 /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
 129                 pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
 130                 rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
 131                 pcxhr_send_msg(mgr, &rmh);
 132                 /* mute inputs */
 133                 pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
 134                                             0, NULL);
 135             }
 136                 /* stereo cards mute with reset of dsp */
 137         }
 138         /* reset pcxhr dsp */
 139         if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
 140                 pcxhr_reset_dsp(mgr);
 141         /* reset second xilinx */
 142         if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) {
 143                 pcxhr_reset_xilinx_com(mgr);
 144                 mgr->dsp_loaded = 1;
 145         }
 146         return;
 147 }
 148 
 149 
 150 /*
 151  *  allocate a playback/capture pipe (pcmp0/pcmc0)
 152  */
 153 static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
 154                                    struct pcxhr_pipe *pipe,
 155                                    int is_capture, int pin)
 156 {
 157         int stream_count, audio_count;
 158         int err;
 159         struct pcxhr_rmh rmh;
 160 
 161         if (is_capture) {
 162                 stream_count = 1;
 163                 if (mgr->mono_capture)
 164                         audio_count = 1;
 165                 else
 166                         audio_count = 2;
 167         } else {
 168                 stream_count = PCXHR_PLAYBACK_STREAMS;
 169                 audio_count = 2;        /* always stereo */
 170         }
 171         dev_dbg(&mgr->pci->dev, "snd_add_ref_pipe pin(%d) pcm%c0\n",
 172                     pin, is_capture ? 'c' : 'p');
 173         pipe->is_capture = is_capture;
 174         pipe->first_audio = pin;
 175         /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
 176         pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
 177         pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin,
 178                                   audio_count, stream_count);
 179         rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */
 180         if (DSP_EXT_CMD_SET(mgr)) {
 181                 /* add channel mask to command */
 182           rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03;
 183         }
 184         err = pcxhr_send_msg(mgr, &rmh);
 185         if (err < 0) {
 186                 dev_err(&mgr->pci->dev, "error pipe allocation "
 187                            "(CMD_RES_PIPE) err=%x!\n", err);
 188                 return err;
 189         }
 190         pipe->status = PCXHR_PIPE_DEFINED;
 191 
 192         return 0;
 193 }
 194 
 195 /*
 196  *  free playback/capture pipe (pcmp0/pcmc0)
 197  */
 198 #if 0
 199 static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
 200 {
 201         struct pcxhr_rmh rmh;
 202         int capture_mask = 0;
 203         int playback_mask = 0;
 204         int err = 0;
 205 
 206         if (pipe->is_capture)
 207                 capture_mask  = (1 << pipe->first_audio);
 208         else
 209                 playback_mask = (1 << pipe->first_audio);
 210 
 211         /* stop one pipe */
 212         err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
 213         if (err < 0)
 214                 dev_err(&mgr->pci->dev, "error stopping pipe!\n");
 215         /* release the pipe */
 216         pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
 217         pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
 218                                   0, 0);
 219         err = pcxhr_send_msg(mgr, &rmh);
 220         if (err < 0)
 221                 dev_err(&mgr->pci->dev, "error pipe release "
 222                            "(CMD_FREE_PIPE) err(%x)\n", err);
 223         pipe->status = PCXHR_PIPE_UNDEFINED;
 224         return err;
 225 }
 226 #endif
 227 
 228 
 229 static int pcxhr_config_pipes(struct pcxhr_mgr *mgr)
 230 {
 231         int err, i, j;
 232         struct snd_pcxhr *chip;
 233         struct pcxhr_pipe *pipe;
 234 
 235         /* allocate the pipes on the dsp */
 236         for (i = 0; i < mgr->num_cards; i++) {
 237                 chip = mgr->chip[i];
 238                 if (chip->nb_streams_play) {
 239                         pipe = &chip->playback_pipe;
 240                         err = pcxhr_dsp_allocate_pipe( mgr, pipe, 0, i*2);
 241                         if (err)
 242                                 return err;
 243                         for(j = 0; j < chip->nb_streams_play; j++)
 244                                 chip->playback_stream[j].pipe = pipe;
 245                 }
 246                 for (j = 0; j < chip->nb_streams_capt; j++) {
 247                         pipe = &chip->capture_pipe[j];
 248                         err = pcxhr_dsp_allocate_pipe(mgr, pipe, 1, i*2 + j);
 249                         if (err)
 250                                 return err;
 251                         chip->capture_stream[j].pipe = pipe;
 252                 }
 253         }
 254         return 0;
 255 }
 256 
 257 static int pcxhr_start_pipes(struct pcxhr_mgr *mgr)
 258 {
 259         int i, j;
 260         struct snd_pcxhr *chip;
 261         int playback_mask = 0;
 262         int capture_mask = 0;
 263 
 264         /* start all the pipes on the dsp */
 265         for (i = 0; i < mgr->num_cards; i++) {
 266                 chip = mgr->chip[i];
 267                 if (chip->nb_streams_play)
 268                         playback_mask |= 1 << chip->playback_pipe.first_audio;
 269                 for (j = 0; j < chip->nb_streams_capt; j++)
 270                         capture_mask |= 1 << chip->capture_pipe[j].first_audio;
 271         }
 272         return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 273 }
 274 
 275 
 276 static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
 277                           const struct firmware *dsp)
 278 {
 279         int err, card_index;
 280 
 281         dev_dbg(&mgr->pci->dev,
 282                 "loading dsp [%d] size = %zd\n", index, dsp->size);
 283 
 284         switch (index) {
 285         case PCXHR_FIRMWARE_XLX_INT_INDEX:
 286                 pcxhr_reset_xilinx_com(mgr);
 287                 return pcxhr_load_xilinx_binary(mgr, dsp, 0);
 288 
 289         case PCXHR_FIRMWARE_XLX_COM_INDEX:
 290                 pcxhr_reset_xilinx_com(mgr);
 291                 return pcxhr_load_xilinx_binary(mgr, dsp, 1);
 292 
 293         case PCXHR_FIRMWARE_DSP_EPRM_INDEX:
 294                 pcxhr_reset_dsp(mgr);
 295                 return pcxhr_load_eeprom_binary(mgr, dsp);
 296 
 297         case PCXHR_FIRMWARE_DSP_BOOT_INDEX:
 298                 return pcxhr_load_boot_binary(mgr, dsp);
 299 
 300         case PCXHR_FIRMWARE_DSP_MAIN_INDEX:
 301                 err = pcxhr_load_dsp_binary(mgr, dsp);
 302                 if (err)
 303                         return err;
 304                 break;  /* continue with first init */
 305         default:
 306                 dev_err(&mgr->pci->dev, "wrong file index\n");
 307                 return -EFAULT;
 308         } /* end of switch file index*/
 309 
 310         /* first communication with embedded */
 311         err = pcxhr_init_board(mgr);
 312         if (err < 0) {
 313                 dev_err(&mgr->pci->dev, "pcxhr could not be set up\n");
 314                 return err;
 315         }
 316         err = pcxhr_config_pipes(mgr);
 317         if (err < 0) {
 318                 dev_err(&mgr->pci->dev, "pcxhr pipes could not be set up\n");
 319                 return err;
 320         }
 321         /* create devices and mixer in accordance with HW options*/
 322         for (card_index = 0; card_index < mgr->num_cards; card_index++) {
 323                 struct snd_pcxhr *chip = mgr->chip[card_index];
 324 
 325                 if ((err = pcxhr_create_pcm(chip)) < 0)
 326                         return err;
 327 
 328                 if (card_index == 0) {
 329                         if ((err = pcxhr_create_mixer(chip->mgr)) < 0)
 330                                 return err;
 331                 }
 332                 if ((err = snd_card_register(chip->card)) < 0)
 333                         return err;
 334         }
 335         err = pcxhr_start_pipes(mgr);
 336         if (err < 0) {
 337                 dev_err(&mgr->pci->dev, "pcxhr pipes could not be started\n");
 338                 return err;
 339         }
 340         dev_dbg(&mgr->pci->dev,
 341                 "pcxhr firmware downloaded and successfully set up\n");
 342 
 343         return 0;
 344 }
 345 
 346 /*
 347  * fw loader entry
 348  */
 349 int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
 350 {
 351         static char *fw_files[][5] = {
 352         [0] = { "xlxint.dat", "xlxc882hr.dat",
 353                 "dspe882.e56", "dspb882hr.b56", "dspd882.d56" },
 354         [1] = { "xlxint.dat", "xlxc882e.dat",
 355                 "dspe882.e56", "dspb882e.b56", "dspd882.d56" },
 356         [2] = { "xlxint.dat", "xlxc1222hr.dat",
 357                 "dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" },
 358         [3] = { "xlxint.dat", "xlxc1222e.dat",
 359                 "dspe882.e56", "dspb1222e.b56", "dspd1222.d56" },
 360         [4] = { NULL, "xlxc222.dat",
 361                 "dspe924.e56", "dspb924.b56", "dspd222.d56" },
 362         [5] = { NULL, "xlxc924.dat",
 363                 "dspe924.e56", "dspb924.b56", "dspd222.d56" },
 364         };
 365         char path[32];
 366 
 367         const struct firmware *fw_entry;
 368         int i, err;
 369         int fw_set = mgr->fw_file_set;
 370 
 371         for (i = 0; i < 5; i++) {
 372                 if (!fw_files[fw_set][i])
 373                         continue;
 374                 sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
 375                 if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
 376                         dev_err(&mgr->pci->dev,
 377                                 "pcxhr: can't load firmware %s\n",
 378                                    path);
 379                         return -ENOENT;
 380                 }
 381                 /* fake hwdep dsp record */
 382                 err = pcxhr_dsp_load(mgr, i, fw_entry);
 383                 release_firmware(fw_entry);
 384                 if (err < 0)
 385                         return err;
 386                 mgr->dsp_loaded |= 1 << i;
 387         }
 388         return 0;
 389 }
 390 
 391 MODULE_FIRMWARE("pcxhr/xlxint.dat");
 392 MODULE_FIRMWARE("pcxhr/xlxc882hr.dat");
 393 MODULE_FIRMWARE("pcxhr/xlxc882e.dat");
 394 MODULE_FIRMWARE("pcxhr/dspe882.e56");
 395 MODULE_FIRMWARE("pcxhr/dspb882hr.b56");
 396 MODULE_FIRMWARE("pcxhr/dspb882e.b56");
 397 MODULE_FIRMWARE("pcxhr/dspd882.d56");
 398 
 399 MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat");
 400 MODULE_FIRMWARE("pcxhr/xlxc1222e.dat");
 401 MODULE_FIRMWARE("pcxhr/dspb1222hr.b56");
 402 MODULE_FIRMWARE("pcxhr/dspb1222e.b56");
 403 MODULE_FIRMWARE("pcxhr/dspd1222.d56");
 404 
 405 MODULE_FIRMWARE("pcxhr/xlxc222.dat");
 406 MODULE_FIRMWARE("pcxhr/xlxc924.dat");
 407 MODULE_FIRMWARE("pcxhr/dspe924.e56");
 408 MODULE_FIRMWARE("pcxhr/dspb924.b56");
 409 MODULE_FIRMWARE("pcxhr/dspd222.d56");

/* [<][>][^][v][top][bottom][index][help] */