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