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