linux/sound/pci/mixart/mixart_hwdep.c
<<
>>
Prefs
   1/*
   2 * Driver for Digigram miXart soundcards
   3 *
   4 * DSP firmware management
   5 *
   6 * Copyright (c) 2003 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/pci.h>
  25#include <linux/firmware.h>
  26#include <linux/vmalloc.h>
  27#include <linux/slab.h>
  28#include <linux/module.h>
  29#include <linux/io.h>
  30#include <sound/core.h>
  31#include "mixart.h"
  32#include "mixart_mixer.h"
  33#include "mixart_core.h"
  34#include "mixart_hwdep.h"
  35
  36
  37/**
  38 * wait for a value on a peudo register, exit with a timeout
  39 *
  40 * @mgr: pointer to miXart manager structure
  41 * @offset: unsigned pseudo_register base + offset of value
  42 * @is_egal: wait for the equal value
  43 * @value: value
  44 * @timeout: timeout in centisenconds
  45 */
  46static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
  47                                               u32 offset, int is_egal,
  48                                               u32 value, unsigned long timeout)
  49{
  50        unsigned long end_time = jiffies + (timeout * HZ / 100);
  51        u32 read;
  52
  53        do {    /* we may take too long time in this loop.
  54                 * so give controls back to kernel if needed.
  55                 */
  56                cond_resched();
  57
  58                read = readl_be( MIXART_MEM( mgr, offset ));
  59                if(is_egal) {
  60                        if(read == value) return 0;
  61                }
  62                else { /* wait for different value */
  63                        if(read != value) return 0;
  64                }
  65        } while ( time_after_eq(end_time, jiffies) );
  66
  67        return -EBUSY;
  68}
  69
  70
  71/*
  72  structures needed to upload elf code packets 
  73 */
  74struct snd_mixart_elf32_ehdr {
  75        u8      e_ident[16];
  76        __be16  e_type;
  77        __be16  e_machine;
  78        __be32  e_version;
  79        __be32  e_entry;
  80        __be32  e_phoff;
  81        __be32  e_shoff;
  82        __be32  e_flags;
  83        __be16  e_ehsize;
  84        __be16  e_phentsize;
  85        __be16  e_phnum;
  86        __be16  e_shentsize;
  87        __be16  e_shnum;
  88        __be16  e_shstrndx;
  89};
  90
  91struct snd_mixart_elf32_phdr {
  92        __be32  p_type;
  93        __be32  p_offset;
  94        __be32  p_vaddr;
  95        __be32  p_paddr;
  96        __be32  p_filesz;
  97        __be32  p_memsz;
  98        __be32  p_flags;
  99        __be32  p_align;
 100};
 101
 102static int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
 103{
 104        char                    elf32_magic_number[4] = {0x7f,'E','L','F'};
 105        struct snd_mixart_elf32_ehdr *elf_header;
 106        int                     i;
 107
 108        elf_header = (struct snd_mixart_elf32_ehdr *)dsp->data;
 109        for( i=0; i<4; i++ )
 110                if ( elf32_magic_number[i] != elf_header->e_ident[i] )
 111                        return -EINVAL;
 112
 113        if( elf_header->e_phoff != 0 ) {
 114                struct snd_mixart_elf32_phdr     elf_programheader;
 115
 116                for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
 117                        u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
 118
 119                        memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
 120
 121                        if(elf_programheader.p_type != 0) {
 122                                if( elf_programheader.p_filesz != 0 ) {
 123                                        memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
 124                                                     dsp->data + be32_to_cpu( elf_programheader.p_offset ),
 125                                                     be32_to_cpu( elf_programheader.p_filesz ));
 126                                }
 127                        }
 128                }
 129        }
 130        return 0;
 131}
 132
 133/*
 134 * get basic information and init miXart
 135 */
 136
 137/* audio IDs for request to the board */
 138#define MIXART_FIRST_ANA_AUDIO_ID       0
 139#define MIXART_FIRST_DIG_AUDIO_ID       8
 140
 141static int mixart_enum_connectors(struct mixart_mgr *mgr)
 142{
 143        u32 k;
 144        int err;
 145        struct mixart_msg request;
 146        struct mixart_enum_connector_resp *connector;
 147        struct mixart_audio_info_req  *audio_info_req;
 148        struct mixart_audio_info_resp *audio_info;
 149
 150        connector = kmalloc(sizeof(*connector), GFP_KERNEL);
 151        audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
 152        audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
 153        if (! connector || ! audio_info_req || ! audio_info) {
 154                err = -ENOMEM;
 155                goto __error;
 156        }
 157
 158        audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
 159        audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
 160        audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
 161
 162        request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
 163        request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
 164        request.data = NULL;
 165        request.size = 0;
 166
 167        err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
 168        if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
 169                dev_err(&mgr->pci->dev,
 170                        "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
 171                err = -EINVAL;
 172                goto __error;
 173        }
 174
 175        for(k=0; k < connector->uid_count; k++) {
 176                struct mixart_pipe *pipe;
 177
 178                if(k < MIXART_FIRST_DIG_AUDIO_ID) {
 179                        pipe = &mgr->chip[k/2]->pipe_out_ana;
 180                } else {
 181                        pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
 182                }
 183                if(k & 1) {
 184                        pipe->uid_right_connector = connector->uid[k];   /* odd */
 185                } else {
 186                        pipe->uid_left_connector = connector->uid[k];    /* even */
 187                }
 188
 189                /* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 190
 191                /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
 192                request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
 193                request.uid = connector->uid[k];
 194                request.data = audio_info_req;
 195                request.size = sizeof(*audio_info_req);
 196
 197                err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
 198                if( err < 0 ) {
 199                        dev_err(&mgr->pci->dev,
 200                                "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
 201                        goto __error;
 202                }
 203                /*dev_dbg(&mgr->pci->dev, "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
 204        }
 205
 206        request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
 207        request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
 208        request.data = NULL;
 209        request.size = 0;
 210
 211        err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
 212        if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
 213                dev_err(&mgr->pci->dev,
 214                        "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
 215                err = -EINVAL;
 216                goto __error;
 217        }
 218
 219        for(k=0; k < connector->uid_count; k++) {
 220                struct mixart_pipe *pipe;
 221
 222                if(k < MIXART_FIRST_DIG_AUDIO_ID) {
 223                        pipe = &mgr->chip[k/2]->pipe_in_ana;
 224                } else {
 225                        pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
 226                }
 227                if(k & 1) {
 228                        pipe->uid_right_connector = connector->uid[k];   /* odd */
 229                } else {
 230                        pipe->uid_left_connector = connector->uid[k];    /* even */
 231                }
 232
 233                /* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 234
 235                /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
 236                request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
 237                request.uid = connector->uid[k];
 238                request.data = audio_info_req;
 239                request.size = sizeof(*audio_info_req);
 240
 241                err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
 242                if( err < 0 ) {
 243                        dev_err(&mgr->pci->dev,
 244                                "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
 245                        goto __error;
 246                }
 247                /*dev_dbg(&mgr->pci->dev, "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
 248        }
 249        err = 0;
 250
 251 __error:
 252        kfree(connector);
 253        kfree(audio_info_req);
 254        kfree(audio_info);
 255
 256        return err;
 257}
 258
 259static int mixart_enum_physio(struct mixart_mgr *mgr)
 260{
 261        u32 k;
 262        int err;
 263        struct mixart_msg request;
 264        struct mixart_uid get_console_mgr;
 265        struct mixart_return_uid console_mgr;
 266        struct mixart_uid_enumeration phys_io;
 267
 268        /* get the uid for the console manager */
 269        get_console_mgr.object_id = 0;
 270        get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
 271
 272        request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
 273        request.uid = get_console_mgr;
 274        request.data = &get_console_mgr;
 275        request.size = sizeof(get_console_mgr);
 276
 277        err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
 278
 279        if( (err < 0) || (console_mgr.error_code != 0) ) {
 280                dev_dbg(&mgr->pci->dev,
 281                        "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n",
 282                        console_mgr.error_code);
 283                return -EINVAL;
 284        }
 285
 286        /* used later for clock issues ! */
 287        mgr->uid_console_manager = console_mgr.uid;
 288
 289        request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
 290        request.uid = (struct mixart_uid){0,0};
 291        request.data = &console_mgr.uid;
 292        request.size = sizeof(console_mgr.uid);
 293
 294        err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
 295        if( (err < 0) || ( phys_io.error_code != 0 ) ) {
 296                dev_err(&mgr->pci->dev,
 297                        "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n",
 298                        err, phys_io.error_code);
 299                return -EINVAL;
 300        }
 301
 302        /* min 2 phys io per card (analog in + analog out) */
 303        if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
 304                return -EINVAL;
 305
 306        for(k=0; k<mgr->num_cards; k++) {
 307                mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
 308                mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; 
 309        }
 310
 311        return 0;
 312}
 313
 314
 315static int mixart_first_init(struct mixart_mgr *mgr)
 316{
 317        u32 k;
 318        int err;
 319        struct mixart_msg request;
 320
 321        if((err = mixart_enum_connectors(mgr)) < 0) return err;
 322
 323        if((err = mixart_enum_physio(mgr)) < 0) return err;
 324
 325        /* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
 326        /* though why not here */
 327        request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
 328        request.uid = (struct mixart_uid){0,0};
 329        request.data = NULL;
 330        request.size = 0;
 331        /* this command has no data. response is a 32 bit status */
 332        err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
 333        if( (err < 0) || (k != 0) ) {
 334                dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
 335                return err == 0 ? -EINVAL : err;
 336        }
 337
 338        return 0;
 339}
 340
 341
 342/* firmware base addresses (when hard coded) */
 343#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS   0x00600000
 344
 345static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmware *dsp)
 346{
 347        int           err, card_index;
 348        u32           status_xilinx, status_elf, status_daught;
 349        u32           val;
 350
 351        /* read motherboard xilinx status */
 352        status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
 353        /* read elf status */
 354        status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
 355        /* read daughterboard xilinx status */
 356        status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
 357
 358        /* motherboard xilinx status 5 will say that the board is performing a reset */
 359        if (status_xilinx == 5) {
 360                dev_err(&mgr->pci->dev, "miXart is resetting !\n");
 361                return -EAGAIN; /* try again later */
 362        }
 363
 364        switch (index)   {
 365        case MIXART_MOTHERBOARD_XLX_INDEX:
 366
 367                /* xilinx already loaded ? */ 
 368                if (status_xilinx == 4) {
 369                        dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n");
 370                        return 0;
 371                }
 372                /* the status should be 0 == "idle" */
 373                if (status_xilinx != 0) {
 374                        dev_err(&mgr->pci->dev,
 375                                "xilinx load error ! status = %d\n",
 376                                   status_xilinx);
 377                        return -EIO; /* modprob -r may help ? */
 378                }
 379
 380                /* check xilinx validity */
 381                if (((u32*)(dsp->data))[0] == 0xffffffff)
 382                        return -EINVAL;
 383                if (dsp->size % 4)
 384                        return -EINVAL;
 385
 386                /* set xilinx status to copying */
 387                writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
 388
 389                /* setup xilinx base address */
 390                writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
 391                /* setup code size for xilinx file */
 392                writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
 393
 394                /* copy xilinx code */
 395                memcpy_toio(  MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS),  dsp->data,  dsp->size);
 396    
 397                /* set xilinx status to copy finished */
 398                writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
 399
 400                /* return, because no further processing needed */
 401                return 0;
 402
 403        case MIXART_MOTHERBOARD_ELF_INDEX:
 404
 405                if (status_elf == 4) {
 406                        dev_dbg(&mgr->pci->dev, "elf file already loaded !\n");
 407                        return 0;
 408                }
 409
 410                /* the status should be 0 == "idle" */
 411                if (status_elf != 0) {
 412                        dev_err(&mgr->pci->dev,
 413                                "elf load error ! status = %d\n",
 414                                   status_elf);
 415                        return -EIO; /* modprob -r may help ? */
 416                }
 417
 418                /* wait for xilinx status == 4 */
 419                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
 420                if (err < 0) {
 421                        dev_err(&mgr->pci->dev, "xilinx was not loaded or "
 422                                   "could not be started\n");
 423                        return err;
 424                }
 425
 426                /* init some data on the card */
 427                writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
 428                writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );         /* reset pointer to flow table on miXart */
 429
 430                /* set elf status to copying */
 431                writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
 432
 433                /* process the copying of the elf packets */
 434                err = mixart_load_elf( mgr, dsp );
 435                if (err < 0) return err;
 436
 437                /* set elf status to copy finished */
 438                writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
 439
 440                /* wait for elf status == 4 */
 441                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
 442                if (err < 0) {
 443                        dev_err(&mgr->pci->dev, "elf could not be started\n");
 444                        return err;
 445                }
 446
 447                /* miXart waits at this point on the pointer to the flow table */
 448                writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
 449
 450                return 0;  /* return, another xilinx file has to be loaded before */
 451
 452        case MIXART_AESEBUBOARD_XLX_INDEX:
 453        default:
 454
 455                /* elf and xilinx should be loaded */
 456                if (status_elf != 4 || status_xilinx != 4) {
 457                        dev_err(&mgr->pci->dev, "xilinx or elf not "
 458                               "successfully loaded\n");
 459                        return -EIO; /* modprob -r may help ? */
 460                }
 461
 462                /* wait for daughter detection != 0 */
 463                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
 464                if (err < 0) {
 465                        dev_err(&mgr->pci->dev, "error starting elf file\n");
 466                        return err;
 467                }
 468
 469                /* the board type can now be retrieved */
 470                mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
 471
 472                if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
 473                        break;  /* no daughter board; the file does not have to be loaded, continue after the switch */
 474
 475                /* only if aesebu daughter board presence (elf code must run)  */ 
 476                if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
 477                        return -EINVAL;
 478
 479                /* daughter should be idle */
 480                if (status_daught != 0) {
 481                        dev_err(&mgr->pci->dev,
 482                                "daughter load error ! status = %d\n",
 483                               status_daught);
 484                        return -EIO; /* modprob -r may help ? */
 485                }
 486 
 487                /* check daughterboard xilinx validity */
 488                if (((u32*)(dsp->data))[0] == 0xffffffff)
 489                        return -EINVAL;
 490                if (dsp->size % 4)
 491                        return -EINVAL;
 492
 493                /* inform mixart about the size of the file */
 494                writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
 495
 496                /* set daughterboard status to 1 */
 497                writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
 498
 499                /* wait for status == 2 */
 500                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
 501                if (err < 0) {
 502                        dev_err(&mgr->pci->dev, "daughter board load error\n");
 503                        return err;
 504                }
 505
 506                /* get the address where to write the file */
 507                val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
 508                if (!val)
 509                        return -EINVAL;
 510
 511                /* copy daughterboard xilinx code */
 512                memcpy_toio(  MIXART_MEM( mgr, val),  dsp->data,  dsp->size);
 513
 514                /* set daughterboard status to 4 */
 515                writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
 516
 517                /* continue with init */
 518                break;
 519        } /* end of switch file index*/
 520
 521        /* wait for daughter status == 3 */
 522        err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
 523        if (err < 0) {
 524                dev_err(&mgr->pci->dev,
 525                           "daughter board could not be initialised\n");
 526                return err;
 527        }
 528
 529        /* init mailbox (communication with embedded) */
 530        snd_mixart_init_mailbox(mgr);
 531
 532        /* first communication with embedded */
 533        err = mixart_first_init(mgr);
 534        if (err < 0) {
 535                dev_err(&mgr->pci->dev, "miXart could not be set up\n");
 536                return err;
 537        }
 538
 539        /* create devices and mixer in accordance with HW options*/
 540        for (card_index = 0; card_index < mgr->num_cards; card_index++) {
 541                struct snd_mixart *chip = mgr->chip[card_index];
 542
 543                if ((err = snd_mixart_create_pcm(chip)) < 0)
 544                        return err;
 545
 546                if (card_index == 0) {
 547                        if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
 548                                return err;
 549                }
 550
 551                if ((err = snd_card_register(chip->card)) < 0)
 552                        return err;
 553        }
 554
 555        dev_dbg(&mgr->pci->dev,
 556                "miXart firmware downloaded and successfully set up\n");
 557
 558        return 0;
 559}
 560
 561
 562int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
 563{
 564        static char *fw_files[3] = {
 565                "miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
 566        };
 567        char path[32];
 568
 569        const struct firmware *fw_entry;
 570        int i, err;
 571
 572        for (i = 0; i < 3; i++) {
 573                sprintf(path, "mixart/%s", fw_files[i]);
 574                if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
 575                        dev_err(&mgr->pci->dev,
 576                                "miXart: can't load firmware %s\n", path);
 577                        return -ENOENT;
 578                }
 579                /* fake hwdep dsp record */
 580                err = mixart_dsp_load(mgr, i, fw_entry);
 581                release_firmware(fw_entry);
 582                if (err < 0)
 583                        return err;
 584                mgr->dsp_loaded |= 1 << i;
 585        }
 586        return 0;
 587}
 588
 589MODULE_FIRMWARE("mixart/miXart8.xlx");
 590MODULE_FIRMWARE("mixart/miXart8.elf");
 591MODULE_FIRMWARE("mixart/miXart8AES.xlx");
 592