linux/sound/pci/cs46xx/dsp_spos.c
<<
>>
Prefs
   1/*
   2 *   This program is free software; you can redistribute it and/or modify
   3 *   it under the terms of the GNU General Public License as published by
   4 *   the Free Software Foundation; either version 2 of the License, or
   5 *   (at your option) any later version.
   6 *
   7 *   This program is distributed in the hope that it will be useful,
   8 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 *   GNU General Public License for more details.
  11 *
  12 *   You should have received a copy of the GNU General Public License
  13 *   along with this program; if not, write to the Free Software
  14 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  15 *
  16 */
  17
  18/*
  19 * 2002-07 Benny Sjostrand benny@hostmobility.com
  20 */
  21
  22
  23#include <linux/io.h>
  24#include <linux/delay.h>
  25#include <linux/pm.h>
  26#include <linux/init.h>
  27#include <linux/slab.h>
  28#include <linux/vmalloc.h>
  29#include <linux/mutex.h>
  30
  31#include <sound/core.h>
  32#include <sound/control.h>
  33#include <sound/info.h>
  34#include <sound/asoundef.h>
  35#include "cs46xx.h"
  36
  37#include "cs46xx_lib.h"
  38#include "dsp_spos.h"
  39
  40static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
  41                                  struct dsp_scb_descriptor * fg_entry);
  42
  43static enum wide_opcode wide_opcodes[] = { 
  44        WIDE_FOR_BEGIN_LOOP,
  45        WIDE_FOR_BEGIN_LOOP2,
  46        WIDE_COND_GOTO_ADDR,
  47        WIDE_COND_GOTO_CALL,
  48        WIDE_TBEQ_COND_GOTO_ADDR,
  49        WIDE_TBEQ_COND_CALL_ADDR,
  50        WIDE_TBEQ_NCOND_GOTO_ADDR,
  51        WIDE_TBEQ_NCOND_CALL_ADDR,
  52        WIDE_TBEQ_COND_GOTO1_ADDR,
  53        WIDE_TBEQ_COND_CALL1_ADDR,
  54        WIDE_TBEQ_NCOND_GOTOI_ADDR,
  55        WIDE_TBEQ_NCOND_CALL1_ADDR
  56};
  57
  58static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 size,
  59                                       u32 overlay_begin_address)
  60{
  61        unsigned int i = 0, j, nreallocated = 0;
  62        u32 hival,loval,address;
  63        u32 mop_operands,mop_type,wide_op;
  64        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
  65
  66        if (snd_BUG_ON(size %2))
  67                return -EINVAL;
  68  
  69        while (i < size) {
  70                loval = data[i++];
  71                hival = data[i++];
  72
  73                if (ins->code.offset > 0) {
  74                        mop_operands = (hival >> 6) & 0x03fff;
  75                        mop_type = mop_operands >> 10;
  76      
  77                        /* check for wide type instruction */
  78                        if (mop_type == 0 &&
  79                            (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&
  80                            (mop_operands & WIDE_INSTR_MASK) != 0) {
  81                                wide_op = loval & 0x7f;
  82                                for (j = 0;j < ARRAY_SIZE(wide_opcodes); ++j) {
  83                                        if (wide_opcodes[j] == wide_op) {
  84                                                /* need to reallocate instruction */
  85                                                address  = (hival & 0x00FFF) << 5;
  86                                                address |=  loval >> 15;
  87            
  88                                                dev_dbg(chip->card->dev,
  89                                                        "handle_wideop[1]: %05x:%05x addr %04x\n",
  90                                                        hival, loval, address);
  91            
  92                                                if ( !(address & 0x8000) ) {
  93                                                        address += (ins->code.offset / 2) - overlay_begin_address;
  94                                                } else {
  95                                                        dev_dbg(chip->card->dev,
  96                                                                "handle_wideop[1]: ROM symbol not reallocated\n");
  97                                                }
  98            
  99                                                hival &= 0xFF000;
 100                                                loval &= 0x07FFF;
 101            
 102                                                hival |= ( (address >> 5)  & 0x00FFF);
 103                                                loval |= ( (address << 15) & 0xF8000);
 104            
 105                                                address  = (hival & 0x00FFF) << 5;
 106                                                address |=  loval >> 15;
 107            
 108                                                dev_dbg(chip->card->dev,
 109                                                        "handle_wideop:[2] %05x:%05x addr %04x\n",
 110                                                        hival, loval, address);
 111                                                nreallocated++;
 112                                        } /* wide_opcodes[j] == wide_op */
 113                                } /* for */
 114                        } /* mod_type == 0 ... */
 115                } /* ins->code.offset > 0 */
 116
 117                ins->code.data[ins->code.size++] = loval;
 118                ins->code.data[ins->code.size++] = hival;
 119        }
 120
 121        dev_dbg(chip->card->dev,
 122                "dsp_spos: %d instructions reallocated\n", nreallocated);
 123        return nreallocated;
 124}
 125
 126static struct dsp_segment_desc * get_segment_desc (struct dsp_module_desc * module, int seg_type)
 127{
 128        int i;
 129        for (i = 0;i < module->nsegments; ++i) {
 130                if (module->segments[i].segment_type == seg_type) {
 131                        return (module->segments + i);
 132                }
 133        }
 134
 135        return NULL;
 136};
 137
 138static int find_free_symbol_index (struct dsp_spos_instance * ins)
 139{
 140        int index = ins->symbol_table.nsymbols,i;
 141
 142        for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {
 143                if (ins->symbol_table.symbols[i].deleted) {
 144                        index = i;
 145                        break;
 146                }
 147        }
 148
 149        return index;
 150}
 151
 152static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * module)
 153{
 154        int i;
 155        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 156
 157        if (module->symbol_table.nsymbols > 0) {
 158                if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&
 159                    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {
 160                        module->overlay_begin_address = module->symbol_table.symbols[0].address;
 161                }
 162        }
 163
 164        for (i = 0;i < module->symbol_table.nsymbols; ++i) {
 165                if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
 166                        dev_err(chip->card->dev,
 167                                "dsp_spos: symbol table is full\n");
 168                        return -ENOMEM;
 169                }
 170
 171
 172                if (cs46xx_dsp_lookup_symbol(chip,
 173                                             module->symbol_table.symbols[i].symbol_name,
 174                                             module->symbol_table.symbols[i].symbol_type) == NULL) {
 175
 176                        ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];
 177                        ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);
 178                        ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;
 179                        ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;
 180
 181                        if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index) 
 182                                ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
 183
 184                        ins->symbol_table.nsymbols++;
 185                } else {
 186#if 0
 187                        dev_dbg(chip->card->dev,
 188                                "dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
 189                                module->symbol_table.symbols[i].symbol_name); */
 190#endif
 191                }
 192        }
 193
 194        return 0;
 195}
 196
 197static struct dsp_symbol_entry *
 198add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
 199{
 200        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 201        struct dsp_symbol_entry * symbol = NULL;
 202        int index;
 203
 204        if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
 205                dev_err(chip->card->dev, "dsp_spos: symbol table is full\n");
 206                return NULL;
 207        }
 208  
 209        if (cs46xx_dsp_lookup_symbol(chip,
 210                                     symbol_name,
 211                                     type) != NULL) {
 212                dev_err(chip->card->dev,
 213                        "dsp_spos: symbol <%s> duplicated\n", symbol_name);
 214                return NULL;
 215        }
 216
 217        index = find_free_symbol_index (ins);
 218
 219        strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
 220        ins->symbol_table.symbols[index].address = address;
 221        ins->symbol_table.symbols[index].symbol_type = type;
 222        ins->symbol_table.symbols[index].module = NULL;
 223        ins->symbol_table.symbols[index].deleted = 0;
 224        symbol = (ins->symbol_table.symbols + index);
 225
 226        if (index > ins->symbol_table.highest_frag_index) 
 227                ins->symbol_table.highest_frag_index = index;
 228
 229        if (index == ins->symbol_table.nsymbols)
 230                ins->symbol_table.nsymbols++; /* no frag. in list */
 231
 232        return symbol;
 233}
 234
 235struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 236{
 237        struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
 238
 239        if (ins == NULL)
 240                return NULL;
 241
 242        /* better to use vmalloc for this big table */
 243        ins->symbol_table.symbols =
 244                vmalloc(array_size(DSP_MAX_SYMBOLS,
 245                                   sizeof(struct dsp_symbol_entry)));
 246        ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
 247        ins->modules = kmalloc_array(DSP_MAX_MODULES,
 248                                     sizeof(struct dsp_module_desc),
 249                                     GFP_KERNEL);
 250        if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
 251                cs46xx_dsp_spos_destroy(chip);
 252                goto error;
 253        }
 254        ins->symbol_table.nsymbols = 0;
 255        ins->symbol_table.highest_frag_index = 0;
 256        ins->code.offset = 0;
 257        ins->code.size = 0;
 258        ins->nscb = 0;
 259        ins->ntask = 0;
 260        ins->nmodules = 0;
 261
 262        /* default SPDIF input sample rate
 263           to 48000 khz */
 264        ins->spdif_in_sample_rate = 48000;
 265
 266        /* maximize volume */
 267        ins->dac_volume_right = 0x8000;
 268        ins->dac_volume_left = 0x8000;
 269        ins->spdif_input_volume_right = 0x8000;
 270        ins->spdif_input_volume_left = 0x8000;
 271
 272        /* set left and right validity bits and
 273           default channel status */
 274        ins->spdif_csuv_default =
 275                ins->spdif_csuv_stream =
 276         /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
 277         /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
 278         /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
 279         /* left and right validity bits */ (1 << 13) | (1 << 12);
 280
 281        return ins;
 282
 283error:
 284        kfree(ins->modules);
 285        kfree(ins->code.data);
 286        vfree(ins->symbol_table.symbols);
 287        kfree(ins);
 288        return NULL;
 289}
 290
 291void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
 292{
 293        int i;
 294        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 295
 296        if (snd_BUG_ON(!ins))
 297                return;
 298
 299        mutex_lock(&chip->spos_mutex);
 300        for (i = 0; i < ins->nscb; ++i) {
 301                if (ins->scbs[i].deleted) continue;
 302
 303                cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
 304#ifdef CONFIG_PM_SLEEP
 305                kfree(ins->scbs[i].data);
 306#endif
 307        }
 308
 309        kfree(ins->code.data);
 310        vfree(ins->symbol_table.symbols);
 311        kfree(ins->modules);
 312        kfree(ins);
 313        mutex_unlock(&chip->spos_mutex);
 314}
 315
 316static int dsp_load_parameter(struct snd_cs46xx *chip,
 317                              struct dsp_segment_desc *parameter)
 318{
 319        u32 doffset, dsize;
 320
 321        if (!parameter) {
 322                dev_dbg(chip->card->dev,
 323                        "dsp_spos: module got no parameter segment\n");
 324                return 0;
 325        }
 326
 327        doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
 328        dsize   = parameter->size * 4;
 329
 330        dev_dbg(chip->card->dev,
 331                "dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
 332                    doffset,doffset + dsize);
 333        if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
 334                dev_err(chip->card->dev,
 335                        "dsp_spos: failed to download parameter data to DSP\n");
 336                return -EINVAL;
 337        }
 338        return 0;
 339}
 340
 341static int dsp_load_sample(struct snd_cs46xx *chip,
 342                           struct dsp_segment_desc *sample)
 343{
 344        u32 doffset, dsize;
 345
 346        if (!sample) {
 347                dev_dbg(chip->card->dev,
 348                        "dsp_spos: module got no sample segment\n");
 349                return 0;
 350        }
 351
 352        doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
 353        dsize   =  sample->size * 4;
 354
 355        dev_dbg(chip->card->dev,
 356                "dsp_spos: downloading sample data to chip (%08x-%08x)\n",
 357                    doffset,doffset + dsize);
 358
 359        if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
 360                dev_err(chip->card->dev,
 361                        "dsp_spos: failed to sample data to DSP\n");
 362                return -EINVAL;
 363        }
 364        return 0;
 365}
 366
 367int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
 368{
 369        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 370        struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
 371        u32 doffset, dsize;
 372        int err;
 373
 374        if (ins->nmodules == DSP_MAX_MODULES - 1) {
 375                dev_err(chip->card->dev,
 376                        "dsp_spos: to many modules loaded into DSP\n");
 377                return -ENOMEM;
 378        }
 379
 380        dev_dbg(chip->card->dev,
 381                "dsp_spos: loading module %s into DSP\n", module->module_name);
 382  
 383        if (ins->nmodules == 0) {
 384                dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n");
 385                snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
 386        }
 387  
 388        err = dsp_load_parameter(chip, get_segment_desc(module,
 389                                                        SEGTYPE_SP_PARAMETER));
 390        if (err < 0)
 391                return err;
 392
 393        if (ins->nmodules == 0) {
 394                dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n");
 395                snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
 396        }
 397
 398        err = dsp_load_sample(chip, get_segment_desc(module,
 399                                                     SEGTYPE_SP_SAMPLE));
 400        if (err < 0)
 401                return err;
 402
 403        if (ins->nmodules == 0) {
 404                dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n");
 405                snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
 406        }
 407
 408        if (code == NULL) {
 409                dev_dbg(chip->card->dev,
 410                        "dsp_spos: module got no code segment\n");
 411        } else {
 412                if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
 413                        dev_err(chip->card->dev,
 414                                "dsp_spos: no space available in DSP\n");
 415                        return -ENOMEM;
 416                }
 417
 418                module->load_address = ins->code.offset;
 419                module->overlay_begin_address = 0x000;
 420
 421                /* if module has a code segment it must have
 422                   symbol table */
 423                if (snd_BUG_ON(!module->symbol_table.symbols))
 424                        return -ENOMEM;
 425                if (add_symbols(chip,module)) {
 426                        dev_err(chip->card->dev,
 427                                "dsp_spos: failed to load symbol table\n");
 428                        return -ENOMEM;
 429                }
 430    
 431                doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
 432                dsize   = code->size * 4;
 433                dev_dbg(chip->card->dev,
 434                        "dsp_spos: downloading code to chip (%08x-%08x)\n",
 435                            doffset,doffset + dsize);   
 436
 437                module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
 438
 439                if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
 440                        dev_err(chip->card->dev,
 441                                "dsp_spos: failed to download code to DSP\n");
 442                        return -EINVAL;
 443                }
 444
 445                ins->code.offset += code->size;
 446        }
 447
 448        /* NOTE: module segments and symbol table must be
 449           statically allocated. Case that module data is
 450           not generated by the ospparser */
 451        ins->modules[ins->nmodules] = *module;
 452        ins->nmodules++;
 453
 454        return 0;
 455}
 456
 457struct dsp_symbol_entry *
 458cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symbol_type)
 459{
 460        int i;
 461        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 462
 463        for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
 464
 465                if (ins->symbol_table.symbols[i].deleted)
 466                        continue;
 467
 468                if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&
 469                    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
 470                        return (ins->symbol_table.symbols + i);
 471                }
 472        }
 473
 474#if 0
 475        dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n",
 476                symbol_name,symbol_type);
 477#endif
 478
 479        return NULL;
 480}
 481
 482
 483#ifdef CONFIG_SND_PROC_FS
 484static struct dsp_symbol_entry *
 485cs46xx_dsp_lookup_symbol_addr (struct snd_cs46xx * chip, u32 address, int symbol_type)
 486{
 487        int i;
 488        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 489
 490        for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
 491
 492                if (ins->symbol_table.symbols[i].deleted)
 493                        continue;
 494
 495                if (ins->symbol_table.symbols[i].address == address &&
 496                    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
 497                        return (ins->symbol_table.symbols + i);
 498                }
 499        }
 500
 501
 502        return NULL;
 503}
 504
 505
 506static void cs46xx_dsp_proc_symbol_table_read (struct snd_info_entry *entry,
 507                                               struct snd_info_buffer *buffer)
 508{
 509        struct snd_cs46xx *chip = entry->private_data;
 510        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 511        int i;
 512
 513        snd_iprintf(buffer, "SYMBOLS:\n");
 514        for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
 515                char *module_str = "system";
 516
 517                if (ins->symbol_table.symbols[i].deleted)
 518                        continue;
 519
 520                if (ins->symbol_table.symbols[i].module != NULL) {
 521                        module_str = ins->symbol_table.symbols[i].module->module_name;
 522                }
 523
 524    
 525                snd_iprintf(buffer, "%04X <%02X> %s [%s]\n",
 526                            ins->symbol_table.symbols[i].address,
 527                            ins->symbol_table.symbols[i].symbol_type,
 528                            ins->symbol_table.symbols[i].symbol_name,
 529                            module_str);    
 530        }
 531}
 532
 533
 534static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry,
 535                                          struct snd_info_buffer *buffer)
 536{
 537        struct snd_cs46xx *chip = entry->private_data;
 538        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 539        int i,j;
 540
 541        mutex_lock(&chip->spos_mutex);
 542        snd_iprintf(buffer, "MODULES:\n");
 543        for ( i = 0; i < ins->nmodules; ++i ) {
 544                snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
 545                snd_iprintf(buffer, "   %d symbols\n", ins->modules[i].symbol_table.nsymbols);
 546                snd_iprintf(buffer, "   %d fixups\n", ins->modules[i].nfixups);
 547
 548                for (j = 0; j < ins->modules[i].nsegments; ++ j) {
 549                        struct dsp_segment_desc * desc = (ins->modules[i].segments + j);
 550                        snd_iprintf(buffer, "   segment %02x offset %08x size %08x\n",
 551                                    desc->segment_type,desc->offset, desc->size);
 552                }
 553        }
 554        mutex_unlock(&chip->spos_mutex);
 555}
 556
 557static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
 558                                            struct snd_info_buffer *buffer)
 559{
 560        struct snd_cs46xx *chip = entry->private_data;
 561        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 562        int i, j, col;
 563        void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
 564
 565        mutex_lock(&chip->spos_mutex);
 566        snd_iprintf(buffer, "TASK TREES:\n");
 567        for ( i = 0; i < ins->ntask; ++i) {
 568                snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
 569
 570                for (col = 0,j = 0;j < ins->tasks[i].size; j++,col++) {
 571                        u32 val;
 572                        if (col == 4) {
 573                                snd_iprintf(buffer,"\n");
 574                                col = 0;
 575                        }
 576                        val = readl(dst + (ins->tasks[i].address + j) * sizeof(u32));
 577                        snd_iprintf(buffer,"%08x ",val);
 578                }
 579        }
 580
 581        snd_iprintf(buffer,"\n");  
 582        mutex_unlock(&chip->spos_mutex);
 583}
 584
 585static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
 586                                      struct snd_info_buffer *buffer)
 587{
 588        struct snd_cs46xx *chip = entry->private_data;
 589        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 590        int i;
 591
 592        mutex_lock(&chip->spos_mutex);
 593        snd_iprintf(buffer, "SCB's:\n");
 594        for ( i = 0; i < ins->nscb; ++i) {
 595                if (ins->scbs[i].deleted)
 596                        continue;
 597                snd_iprintf(buffer,"\n%04x %s:\n\n",ins->scbs[i].address,ins->scbs[i].scb_name);
 598
 599                if (ins->scbs[i].parent_scb_ptr != NULL) {
 600                        snd_iprintf(buffer,"parent [%s:%04x] ", 
 601                                    ins->scbs[i].parent_scb_ptr->scb_name,
 602                                    ins->scbs[i].parent_scb_ptr->address);
 603                } else snd_iprintf(buffer,"parent [none] ");
 604
 605                snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
 606                            ins->scbs[i].sub_list_ptr->scb_name,
 607                            ins->scbs[i].sub_list_ptr->address,
 608                            ins->scbs[i].next_scb_ptr->scb_name,
 609                            ins->scbs[i].next_scb_ptr->address,
 610                            ins->scbs[i].task_entry->symbol_name,
 611                            ins->scbs[i].task_entry->address);
 612        }
 613
 614        snd_iprintf(buffer,"\n");
 615        mutex_unlock(&chip->spos_mutex);
 616}
 617
 618static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
 619                                                 struct snd_info_buffer *buffer)
 620{
 621        struct snd_cs46xx *chip = entry->private_data;
 622        /*struct dsp_spos_instance * ins = chip->dsp_spos_instance; */
 623        unsigned int i, col = 0;
 624        void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
 625        struct dsp_symbol_entry * symbol; 
 626
 627        for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
 628                if (col == 4) {
 629                        snd_iprintf(buffer,"\n");
 630                        col = 0;
 631                }
 632
 633                if ( (symbol = cs46xx_dsp_lookup_symbol_addr (chip,i / sizeof(u32), SYMBOL_PARAMETER)) != NULL) {
 634                        col = 0;
 635                        snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name);
 636                }
 637
 638                if (col == 0) {
 639                        snd_iprintf(buffer, "%04X ", i / (unsigned int)sizeof(u32));
 640                }
 641
 642                snd_iprintf(buffer,"%08X ",readl(dst + i));
 643        }
 644}
 645
 646static void cs46xx_dsp_proc_sample_dump_read (struct snd_info_entry *entry,
 647                                              struct snd_info_buffer *buffer)
 648{
 649        struct snd_cs46xx *chip = entry->private_data;
 650        int i,col = 0;
 651        void __iomem *dst = chip->region.idx[2].remap_addr;
 652
 653        snd_iprintf(buffer,"PCMREADER:\n");
 654        for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
 655                if (col == 4) {
 656                        snd_iprintf(buffer,"\n");
 657                        col = 0;
 658                }
 659
 660                if (col == 0) {
 661                        snd_iprintf(buffer, "%04X ",i);
 662                }
 663
 664                snd_iprintf(buffer,"%08X ",readl(dst + i));
 665        }
 666
 667        snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
 668
 669        col = 0;
 670        for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x40; i += sizeof(u32),col ++) {
 671                if (col == 4) {
 672                        snd_iprintf(buffer,"\n");
 673                        col = 0;
 674                }
 675
 676                if (col == 0) {
 677                        snd_iprintf(buffer, "%04X ",i);
 678                }
 679
 680                snd_iprintf(buffer,"%08X ",readl(dst + i));
 681        }
 682
 683        snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
 684        col = 0;
 685        for (i = 0x2480 ; i < 0x2480 + 0x40 ; i += sizeof(u32),col ++) {
 686                if (col == 4) {
 687                        snd_iprintf(buffer,"\n");
 688                        col = 0;
 689                }
 690                
 691                if (col == 0) {
 692                        snd_iprintf(buffer, "%04X ",i);
 693                }
 694
 695                snd_iprintf(buffer,"%08X ",readl(dst + i));
 696        }
 697
 698
 699        snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
 700        col = 0;
 701        for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30; i += sizeof(u32),col ++) {
 702                if (col == 4) {
 703                        snd_iprintf(buffer,"\n");
 704                        col = 0;
 705                }
 706
 707                if (col == 0) {
 708                        snd_iprintf(buffer, "%04X ",i);
 709                }
 710
 711                snd_iprintf(buffer,"%08X ",readl(dst + i));
 712        }
 713
 714        snd_iprintf(buffer,"\n...\n");
 715        col = 0;
 716
 717        for (i = SPDIFO_IP_OUTPUT_BUFFER1+0xD0;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110; i += sizeof(u32),col ++) {
 718                if (col == 4) {
 719                        snd_iprintf(buffer,"\n");
 720                        col = 0;
 721                }
 722
 723                if (col == 0) {
 724                        snd_iprintf(buffer, "%04X ",i);
 725                }
 726
 727                snd_iprintf(buffer,"%08X ",readl(dst + i));
 728        }
 729
 730
 731        snd_iprintf(buffer,"\nOUTPUT_SNOOP:\n");
 732        col = 0;
 733        for (i = OUTPUT_SNOOP_BUFFER;i < OUTPUT_SNOOP_BUFFER + 0x40; i += sizeof(u32),col ++) {
 734                if (col == 4) {
 735                        snd_iprintf(buffer,"\n");
 736                        col = 0;
 737                }
 738
 739                if (col == 0) {
 740                        snd_iprintf(buffer, "%04X ",i);
 741                }
 742
 743                snd_iprintf(buffer,"%08X ",readl(dst + i));
 744        }
 745
 746        snd_iprintf(buffer,"\nCODEC_INPUT_BUF1: \n");
 747        col = 0;
 748        for (i = CODEC_INPUT_BUF1;i < CODEC_INPUT_BUF1 + 0x40; i += sizeof(u32),col ++) {
 749                if (col == 4) {
 750                        snd_iprintf(buffer,"\n");
 751                        col = 0;
 752                }
 753
 754                if (col == 0) {
 755                        snd_iprintf(buffer, "%04X ",i);
 756                }
 757
 758                snd_iprintf(buffer,"%08X ",readl(dst + i));
 759        }
 760#if 0
 761        snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
 762        col = 0;
 763        for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
 764                if (col == 4) {
 765                        snd_iprintf(buffer,"\n");
 766                        col = 0;
 767                }
 768
 769                if (col == 0) {
 770                        snd_iprintf(buffer, "%04X ",i);
 771                }
 772
 773                snd_iprintf(buffer,"%08X ",readl(dst + i));
 774        }
 775#endif
 776
 777        snd_iprintf(buffer,"\nSPDIFI_IP_OUTPUT_BUFFER1: \n");
 778        col = 0;
 779        for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80; i += sizeof(u32),col ++) {
 780                if (col == 4) {
 781                        snd_iprintf(buffer,"\n");
 782                        col = 0;
 783                }
 784
 785                if (col == 0) {
 786                        snd_iprintf(buffer, "%04X ",i);
 787                }
 788                
 789                snd_iprintf(buffer,"%08X ",readl(dst + i));
 790        }
 791        snd_iprintf(buffer,"\n");
 792}
 793
 794int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
 795{
 796        struct snd_info_entry *entry;
 797        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 798        int i;
 799
 800        ins->snd_card = card;
 801
 802        entry = snd_info_create_card_entry(card, "dsp", card->proc_root);
 803        if (entry)
 804                entry->mode = S_IFDIR | 0555;
 805        ins->proc_dsp_dir = entry;
 806
 807        if (!ins->proc_dsp_dir)
 808                return -ENOMEM;
 809
 810        entry = snd_info_create_card_entry(card, "spos_symbols",
 811                                           ins->proc_dsp_dir);
 812        if (entry)
 813                snd_info_set_text_ops(entry, chip,
 814                                      cs46xx_dsp_proc_symbol_table_read);
 815    
 816        entry = snd_info_create_card_entry(card, "spos_modules",
 817                                           ins->proc_dsp_dir);
 818        if (entry)
 819                snd_info_set_text_ops(entry, chip,
 820                                      cs46xx_dsp_proc_modules_read);
 821
 822        entry = snd_info_create_card_entry(card, "parameter",
 823                                           ins->proc_dsp_dir);
 824        if (entry)
 825                snd_info_set_text_ops(entry, chip,
 826                                      cs46xx_dsp_proc_parameter_dump_read);
 827
 828        entry = snd_info_create_card_entry(card, "sample",
 829                                           ins->proc_dsp_dir);
 830        if (entry)
 831                snd_info_set_text_ops(entry, chip,
 832                                      cs46xx_dsp_proc_sample_dump_read);
 833
 834        entry = snd_info_create_card_entry(card, "task_tree",
 835                                           ins->proc_dsp_dir);
 836        if (entry)
 837                snd_info_set_text_ops(entry, chip,
 838                                      cs46xx_dsp_proc_task_tree_read);
 839
 840        entry = snd_info_create_card_entry(card, "scb_info",
 841                                           ins->proc_dsp_dir);
 842        if (entry)
 843                snd_info_set_text_ops(entry, chip,
 844                                      cs46xx_dsp_proc_scb_read);
 845
 846        mutex_lock(&chip->spos_mutex);
 847        /* register/update SCB's entries on proc */
 848        for (i = 0; i < ins->nscb; ++i) {
 849                if (ins->scbs[i].deleted) continue;
 850
 851                cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
 852        }
 853        mutex_unlock(&chip->spos_mutex);
 854
 855        return 0;
 856}
 857
 858int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
 859{
 860        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 861        int i;
 862
 863        if (!ins)
 864                return 0;
 865
 866        mutex_lock(&chip->spos_mutex);
 867        for (i = 0; i < ins->nscb; ++i) {
 868                if (ins->scbs[i].deleted) continue;
 869                cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
 870        }
 871        mutex_unlock(&chip->spos_mutex);
 872
 873        snd_info_free_entry(ins->proc_dsp_dir);
 874        ins->proc_dsp_dir = NULL;
 875
 876        return 0;
 877}
 878#endif /* CONFIG_SND_PROC_FS */
 879
 880static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
 881                                   u32  dest, int size)
 882{
 883        void __iomem *spdst = chip->region.idx[1].remap_addr + 
 884                DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
 885        int i;
 886
 887        for (i = 0; i < size; ++i) {
 888                dev_dbg(chip->card->dev, "addr %p, val %08x\n",
 889                        spdst, task_data[i]);
 890                writel(task_data[i],spdst);
 891                spdst += sizeof(u32);
 892        }
 893}
 894
 895static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
 896{
 897        void __iomem *spdst = chip->region.idx[1].remap_addr + 
 898                DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
 899        int i;
 900
 901        for (i = 0; i < 0x10; ++i) {
 902                dev_dbg(chip->card->dev, "addr %p, val %08x\n",
 903                        spdst, scb_data[i]);
 904                writel(scb_data[i],spdst);
 905                spdst += sizeof(u32);
 906        }
 907}
 908
 909static int find_free_scb_index (struct dsp_spos_instance * ins)
 910{
 911        int index = ins->nscb, i;
 912
 913        for (i = ins->scb_highest_frag_index; i < ins->nscb; ++i) {
 914                if (ins->scbs[i].deleted) {
 915                        index = i;
 916                        break;
 917                }
 918        }
 919
 920        return index;
 921}
 922
 923static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * name, u32 dest)
 924{
 925        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 926        struct dsp_scb_descriptor * desc = NULL;
 927        int index;
 928
 929        if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
 930                dev_err(chip->card->dev,
 931                        "dsp_spos: got no place for other SCB\n");
 932                return NULL;
 933        }
 934
 935        index = find_free_scb_index (ins);
 936
 937        memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
 938        strcpy(ins->scbs[index].scb_name, name);
 939        ins->scbs[index].address = dest;
 940        ins->scbs[index].index = index;
 941        ins->scbs[index].ref_count = 1;
 942
 943        desc = (ins->scbs + index);
 944        ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
 945
 946        if (index > ins->scb_highest_frag_index)
 947                ins->scb_highest_frag_index = index;
 948
 949        if (index == ins->nscb)
 950                ins->nscb++;
 951
 952        return desc;
 953}
 954
 955static struct dsp_task_descriptor *
 956_map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
 957{
 958        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 959        struct dsp_task_descriptor * desc = NULL;
 960
 961        if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
 962                dev_err(chip->card->dev,
 963                        "dsp_spos: got no place for other TASK\n");
 964                return NULL;
 965        }
 966
 967        if (name)
 968                strcpy(ins->tasks[ins->ntask].task_name, name);
 969        else
 970                strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
 971        ins->tasks[ins->ntask].address = dest;
 972        ins->tasks[ins->ntask].size = size;
 973
 974        /* quick find in list */
 975        ins->tasks[ins->ntask].index = ins->ntask;
 976        desc = (ins->tasks + ins->ntask);
 977        ins->ntask++;
 978
 979        if (name)
 980                add_symbol (chip,name,dest,SYMBOL_PARAMETER);
 981        return desc;
 982}
 983
 984#define SCB_BYTES       (0x10 * 4)
 985
 986struct dsp_scb_descriptor *
 987cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
 988{
 989        struct dsp_scb_descriptor * desc;
 990
 991#ifdef CONFIG_PM_SLEEP
 992        /* copy the data for resume */
 993        scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
 994        if (!scb_data)
 995                return NULL;
 996#endif
 997
 998        desc = _map_scb (chip,name,dest);
 999        if (desc) {
1000                desc->data = scb_data;
1001                _dsp_create_scb(chip,scb_data,dest);
1002        } else {
1003                dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n");
1004#ifdef CONFIG_PM_SLEEP
1005                kfree(scb_data);
1006#endif
1007        }
1008
1009        return desc;
1010}
1011
1012
1013static struct dsp_task_descriptor *
1014cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_data,
1015                             u32 dest, int size)
1016{
1017        struct dsp_task_descriptor * desc;
1018
1019        desc = _map_task_tree (chip,name,dest,size);
1020        if (desc) {
1021                desc->data = task_data;
1022                _dsp_create_task_tree(chip,task_data,dest,size);
1023        } else {
1024                dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n");
1025        }
1026
1027        return desc;
1028}
1029
1030int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
1031{
1032        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1033        struct dsp_symbol_entry * fg_task_tree_header_code;
1034        struct dsp_symbol_entry * task_tree_header_code;
1035        struct dsp_symbol_entry * task_tree_thread;
1036        struct dsp_symbol_entry * null_algorithm;
1037        struct dsp_symbol_entry * magic_snoop_task;
1038
1039        struct dsp_scb_descriptor * timing_master_scb;
1040        struct dsp_scb_descriptor * codec_out_scb;
1041        struct dsp_scb_descriptor * codec_in_scb;
1042        struct dsp_scb_descriptor * src_task_scb;
1043        struct dsp_scb_descriptor * master_mix_scb;
1044        struct dsp_scb_descriptor * rear_mix_scb;
1045        struct dsp_scb_descriptor * record_mix_scb;
1046        struct dsp_scb_descriptor * write_back_scb;
1047        struct dsp_scb_descriptor * vari_decimate_scb;
1048        struct dsp_scb_descriptor * rear_codec_out_scb;
1049        struct dsp_scb_descriptor * clfe_codec_out_scb;
1050        struct dsp_scb_descriptor * magic_snoop_scb;
1051        
1052        int fifo_addr, fifo_span, valid_slots;
1053
1054        static struct dsp_spos_control_block sposcb = {
1055                /* 0 */ HFG_TREE_SCB,HFG_STACK,
1056                /* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR,
1057                /* 2 */ DSP_SPOS_DC,0,
1058                /* 3 */ DSP_SPOS_DC,DSP_SPOS_DC,
1059                /* 4 */ 0,0,
1060                /* 5 */ DSP_SPOS_UU,0,
1061                /* 6 */ FG_TASK_HEADER_ADDR,0,
1062                /* 7 */ 0,0,
1063                /* 8 */ DSP_SPOS_UU,DSP_SPOS_DC,
1064                /* 9 */ 0,
1065                /* A */ 0,HFG_FIRST_EXECUTE_MODE,
1066                /* B */ DSP_SPOS_UU,DSP_SPOS_UU,
1067                /* C */ DSP_SPOS_DC_DC,
1068                /* D */ DSP_SPOS_DC_DC,
1069                /* E */ DSP_SPOS_DC_DC,
1070                /* F */ DSP_SPOS_DC_DC
1071        };
1072
1073        cs46xx_dsp_create_task_tree(chip, "sposCB", (u32 *)&sposcb, SPOSCB_ADDR, 0x10);
1074
1075        null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
1076        if (null_algorithm == NULL) {
1077                dev_err(chip->card->dev,
1078                        "dsp_spos: symbol NULLALGORITHM not found\n");
1079                return -EIO;
1080        }
1081
1082        fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);  
1083        if (fg_task_tree_header_code == NULL) {
1084                dev_err(chip->card->dev,
1085                        "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
1086                return -EIO;
1087        }
1088
1089        task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);  
1090        if (task_tree_header_code == NULL) {
1091                dev_err(chip->card->dev,
1092                        "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
1093                return -EIO;
1094        }
1095  
1096        task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
1097        if (task_tree_thread == NULL) {
1098                dev_err(chip->card->dev,
1099                        "dsp_spos: symbol TASKTREETHREAD not found\n");
1100                return -EIO;
1101        }
1102
1103        magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
1104        if (magic_snoop_task == NULL) {
1105                dev_err(chip->card->dev,
1106                        "dsp_spos: symbol MAGICSNOOPTASK not found\n");
1107                return -EIO;
1108        }
1109  
1110        {
1111                /* create the null SCB */
1112                static struct dsp_generic_scb null_scb = {
1113                        { 0, 0, 0, 0 },
1114                        { 0, 0, 0, 0, 0 },
1115                        NULL_SCB_ADDR, NULL_SCB_ADDR,
1116                        0, 0, 0, 0, 0,
1117                        {
1118                                0,0,
1119                                0,0,
1120                        }
1121                };
1122
1123                null_scb.entry_point = null_algorithm->address;
1124                ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR);
1125                ins->the_null_scb->task_entry = null_algorithm;
1126                ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
1127                ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
1128                ins->the_null_scb->parent_scb_ptr = NULL;
1129                cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
1130        }
1131
1132        {
1133                /* setup foreground task tree */
1134                static struct dsp_task_tree_control_block fg_task_tree_hdr =  {
1135                        { FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10),
1136                          DSP_SPOS_DC_DC,
1137                          DSP_SPOS_DC_DC,
1138                          0x0000,DSP_SPOS_DC,
1139                          DSP_SPOS_DC, DSP_SPOS_DC,
1140                          DSP_SPOS_DC_DC,
1141                          DSP_SPOS_DC_DC,
1142                          DSP_SPOS_DC_DC,
1143                          DSP_SPOS_DC,DSP_SPOS_DC },
1144    
1145                        {
1146                                BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR, 
1147                                0,
1148                                FG_TASK_HEADER_ADDR + TCBData,                  
1149                        },
1150
1151                        {    
1152                                4,0,
1153                                1,0,
1154                                2,SPOSCB_ADDR + HFGFlags,
1155                                0,0,
1156                                FG_TASK_HEADER_ADDR + TCBContextBlk,FG_STACK
1157                        },
1158
1159                        {
1160                                DSP_SPOS_DC,0,
1161                                DSP_SPOS_DC,DSP_SPOS_DC,
1162                                DSP_SPOS_DC,DSP_SPOS_DC,
1163                                DSP_SPOS_DC,DSP_SPOS_DC,
1164                                DSP_SPOS_DC,DSP_SPOS_DC,
1165                                DSP_SPOS_DCDC,
1166                                DSP_SPOS_UU,1,
1167                                DSP_SPOS_DCDC,
1168                                DSP_SPOS_DCDC,
1169                                DSP_SPOS_DCDC,
1170                                DSP_SPOS_DCDC,
1171                                DSP_SPOS_DCDC,
1172                                DSP_SPOS_DCDC,
1173                                DSP_SPOS_DCDC,
1174                                DSP_SPOS_DCDC,
1175                                DSP_SPOS_DCDC,
1176                                DSP_SPOS_DCDC,
1177                                DSP_SPOS_DCDC,
1178                                DSP_SPOS_DCDC,
1179                                DSP_SPOS_DCDC,
1180                                DSP_SPOS_DCDC,
1181                                DSP_SPOS_DCDC,
1182                                DSP_SPOS_DCDC,
1183                                DSP_SPOS_DCDC,
1184                                DSP_SPOS_DCDC,
1185                                DSP_SPOS_DCDC,
1186                                DSP_SPOS_DCDC,
1187                                DSP_SPOS_DCDC,
1188                                DSP_SPOS_DCDC,
1189                                DSP_SPOS_DCDC,
1190                                DSP_SPOS_DCDC,
1191                                DSP_SPOS_DCDC,
1192                                DSP_SPOS_DCDC,
1193                                DSP_SPOS_DCDC,
1194                                DSP_SPOS_DCDC 
1195                        },                                               
1196                        { 
1197                                FG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1198                                0,0
1199                        }
1200                };
1201
1202                fg_task_tree_hdr.links.entry_point = fg_task_tree_header_code->address;
1203                fg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1204                cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35);
1205        }
1206
1207
1208        {
1209                /* setup foreground task tree */
1210                static struct dsp_task_tree_control_block bg_task_tree_hdr =  {
1211                        { DSP_SPOS_DC_DC,
1212                          DSP_SPOS_DC_DC,
1213                          DSP_SPOS_DC_DC,
1214                          DSP_SPOS_DC, DSP_SPOS_DC,
1215                          DSP_SPOS_DC, DSP_SPOS_DC,
1216                          DSP_SPOS_DC_DC,
1217                          DSP_SPOS_DC_DC,
1218                          DSP_SPOS_DC_DC,
1219                          DSP_SPOS_DC,DSP_SPOS_DC },
1220    
1221                        {
1222                                NULL_SCB_ADDR,NULL_SCB_ADDR,  /* Set up the background to do nothing */
1223                                0,
1224                                BG_TREE_SCB_ADDR + TCBData,
1225                        },
1226
1227                        {    
1228                                9999,0,
1229                                0,1,
1230                                0,SPOSCB_ADDR + HFGFlags,
1231                                0,0,
1232                                BG_TREE_SCB_ADDR + TCBContextBlk,BG_STACK
1233                        },
1234
1235                        {
1236                                DSP_SPOS_DC,0,
1237                                DSP_SPOS_DC,DSP_SPOS_DC,
1238                                DSP_SPOS_DC,DSP_SPOS_DC,
1239                                DSP_SPOS_DC,DSP_SPOS_DC,
1240                                DSP_SPOS_DC,DSP_SPOS_DC,
1241                                DSP_SPOS_DCDC,
1242                                DSP_SPOS_UU,1,
1243                                DSP_SPOS_DCDC,
1244                                DSP_SPOS_DCDC,
1245                                DSP_SPOS_DCDC,
1246                                DSP_SPOS_DCDC,
1247                                DSP_SPOS_DCDC,
1248                                DSP_SPOS_DCDC,
1249                                DSP_SPOS_DCDC,
1250                                DSP_SPOS_DCDC,
1251                                DSP_SPOS_DCDC,
1252                                DSP_SPOS_DCDC,
1253                                DSP_SPOS_DCDC,
1254                                DSP_SPOS_DCDC,
1255                                DSP_SPOS_DCDC,
1256                                DSP_SPOS_DCDC,
1257                                DSP_SPOS_DCDC,
1258                                DSP_SPOS_DCDC,
1259                                DSP_SPOS_DCDC,
1260                                DSP_SPOS_DCDC,
1261                                DSP_SPOS_DCDC,
1262                                DSP_SPOS_DCDC,
1263                                DSP_SPOS_DCDC,
1264                                DSP_SPOS_DCDC,
1265                                DSP_SPOS_DCDC,
1266                                DSP_SPOS_DCDC,
1267                                DSP_SPOS_DCDC,
1268                                DSP_SPOS_DCDC,
1269                                DSP_SPOS_DCDC,
1270                                DSP_SPOS_DCDC 
1271                        },                                               
1272                        { 
1273                                BG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1274                                0,0
1275                        }
1276                };
1277
1278                bg_task_tree_hdr.links.entry_point = task_tree_header_code->address;
1279                bg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1280                cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35);
1281        }
1282
1283        /* create timing master SCB */
1284        timing_master_scb = cs46xx_dsp_create_timing_master_scb(chip);
1285
1286        /* create the CODEC output task */
1287        codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_I",0x0010,0x0000,
1288                                                        MASTERMIX_SCB_ADDR,
1289                                                        CODECOUT_SCB_ADDR,timing_master_scb,
1290                                                        SCB_ON_PARENT_SUBLIST_SCB);
1291
1292        if (!codec_out_scb) goto _fail_end;
1293        /* create the master mix SCB */
1294        master_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"MasterMixSCB",
1295                                                        MIX_SAMPLE_BUF1,MASTERMIX_SCB_ADDR,
1296                                                        codec_out_scb,
1297                                                        SCB_ON_PARENT_SUBLIST_SCB);
1298        ins->master_mix_scb = master_mix_scb;
1299
1300        if (!master_mix_scb) goto _fail_end;
1301
1302        /* create codec in */
1303        codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
1304                                                      CODEC_INPUT_BUF1,
1305                                                      CODECIN_SCB_ADDR,codec_out_scb,
1306                                                      SCB_ON_PARENT_NEXT_SCB);
1307        if (!codec_in_scb) goto _fail_end;
1308        ins->codec_in_scb = codec_in_scb;
1309
1310        /* create write back scb */
1311        write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb(chip,"WriteBackSCB",
1312                                                              WRITE_BACK_BUF1,WRITE_BACK_SPB,
1313                                                              WRITEBACK_SCB_ADDR,
1314                                                              timing_master_scb,
1315                                                              SCB_ON_PARENT_NEXT_SCB);
1316        if (!write_back_scb) goto _fail_end;
1317
1318        {
1319                static struct dsp_mix2_ostream_spb mix2_ostream_spb = {
1320                        0x00020000,
1321                        0x0000ffff
1322                };
1323    
1324                if (!cs46xx_dsp_create_task_tree(chip, NULL,
1325                                                 (u32 *)&mix2_ostream_spb,
1326                                                 WRITE_BACK_SPB, 2))
1327                        goto _fail_end;
1328        }
1329
1330        /* input sample converter */
1331        vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb(chip,"VariDecimateSCB",
1332                                                                VARI_DECIMATE_BUF0,
1333                                                                VARI_DECIMATE_BUF1,
1334                                                                VARIDECIMATE_SCB_ADDR,
1335                                                                write_back_scb,
1336                                                                SCB_ON_PARENT_SUBLIST_SCB);
1337        if (!vari_decimate_scb) goto _fail_end;
1338
1339        /* create the record mixer SCB */
1340        record_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RecordMixerSCB",
1341                                                        MIX_SAMPLE_BUF2,
1342                                                        RECORD_MIXER_SCB_ADDR,
1343                                                        vari_decimate_scb,
1344                                                        SCB_ON_PARENT_SUBLIST_SCB);
1345        ins->record_mixer_scb = record_mix_scb;
1346
1347        if (!record_mix_scb) goto _fail_end;
1348
1349        valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
1350
1351        if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2))
1352                goto _fail_end;
1353
1354        if (chip->nr_ac97_codecs == 1) {
1355                /* output on slot 5 and 11 
1356                   on primary CODEC */
1357                fifo_addr = 0x20;
1358                fifo_span = 0x60;
1359
1360                /* enable slot 5 and 11 */
1361                valid_slots |= ACOSV_SLV5 | ACOSV_SLV11;
1362        } else {
1363                /* output on slot 7 and 8 
1364                   on secondary CODEC */
1365                fifo_addr = 0x40;
1366                fifo_span = 0x10;
1367
1368                /* enable slot 7 and 8 */
1369                valid_slots |= ACOSV_SLV7 | ACOSV_SLV8;
1370        }
1371        /* create CODEC tasklet for rear speakers output*/
1372        rear_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_Rear",fifo_span,fifo_addr,
1373                                                             REAR_MIXER_SCB_ADDR,
1374                                                             REAR_CODECOUT_SCB_ADDR,codec_in_scb,
1375                                                             SCB_ON_PARENT_NEXT_SCB);
1376        if (!rear_codec_out_scb) goto _fail_end;
1377        
1378        
1379        /* create the rear PCM channel  mixer SCB */
1380        rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
1381                                                      MIX_SAMPLE_BUF3,
1382                                                      REAR_MIXER_SCB_ADDR,
1383                                                      rear_codec_out_scb,
1384                                                      SCB_ON_PARENT_SUBLIST_SCB);
1385        ins->rear_mix_scb = rear_mix_scb;
1386        if (!rear_mix_scb) goto _fail_end;
1387        
1388        if (chip->nr_ac97_codecs == 2) {
1389                /* create CODEC tasklet for rear Center/LFE output 
1390                   slot 6 and 9 on secondary CODEC */
1391                clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_CLFE",0x0030,0x0030,
1392                                                                     CLFE_MIXER_SCB_ADDR,
1393                                                                     CLFE_CODEC_SCB_ADDR,
1394                                                                     rear_codec_out_scb,
1395                                                                     SCB_ON_PARENT_NEXT_SCB);
1396                if (!clfe_codec_out_scb) goto _fail_end;
1397                
1398                
1399                /* create the rear PCM channel  mixer SCB */
1400                ins->center_lfe_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"CLFEMixerSCB",
1401                                                                         MIX_SAMPLE_BUF4,
1402                                                                         CLFE_MIXER_SCB_ADDR,
1403                                                                         clfe_codec_out_scb,
1404                                                                         SCB_ON_PARENT_SUBLIST_SCB);
1405                if (!ins->center_lfe_mix_scb) goto _fail_end;
1406
1407                /* enable slot 6 and 9 */
1408                valid_slots |= ACOSV_SLV6 | ACOSV_SLV9;
1409        } else {
1410                clfe_codec_out_scb = rear_codec_out_scb;
1411                ins->center_lfe_mix_scb = rear_mix_scb;
1412        }
1413
1414        /* enable slots depending on CODEC configuration */
1415        snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
1416
1417        /* the magic snooper */
1418        magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
1419                                                             OUTPUT_SNOOP_BUFFER,
1420                                                             codec_out_scb,
1421                                                             clfe_codec_out_scb,
1422                                                             SCB_ON_PARENT_NEXT_SCB);
1423
1424    
1425        if (!magic_snoop_scb) goto _fail_end;
1426        ins->ref_snoop_scb = magic_snoop_scb;
1427
1428        /* SP IO access */
1429        if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
1430                                              magic_snoop_scb,
1431                                              SCB_ON_PARENT_NEXT_SCB))
1432                goto _fail_end;
1433
1434        /* SPDIF input sampel rate converter */
1435        src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
1436                                                      ins->spdif_in_sample_rate,
1437                                                      SRC_OUTPUT_BUF1,
1438                                                      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
1439                                                      master_mix_scb,
1440                                                      SCB_ON_PARENT_SUBLIST_SCB,1);
1441
1442        if (!src_task_scb) goto _fail_end;
1443        cs46xx_src_unlink(chip,src_task_scb);
1444
1445        /* NOTE: when we now how to detect the SPDIF input
1446           sample rate we will use this SRC to adjust it */
1447        ins->spdif_in_src = src_task_scb;
1448
1449        cs46xx_dsp_async_init(chip,timing_master_scb);
1450        return 0;
1451
1452 _fail_end:
1453        dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n");
1454        return -EINVAL;
1455}
1456
1457static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
1458                                  struct dsp_scb_descriptor * fg_entry)
1459{
1460        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1461        struct dsp_symbol_entry * s16_async_codec_input_task;
1462        struct dsp_symbol_entry * spdifo_task;
1463        struct dsp_symbol_entry * spdifi_task;
1464        struct dsp_scb_descriptor * spdifi_scb_desc, * spdifo_scb_desc, * async_codec_scb_desc;
1465
1466        s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
1467        if (s16_async_codec_input_task == NULL) {
1468                dev_err(chip->card->dev,
1469                        "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
1470                return -EIO;
1471        }
1472        spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
1473        if (spdifo_task == NULL) {
1474                dev_err(chip->card->dev,
1475                        "dsp_spos: symbol SPDIFOTASK not found\n");
1476                return -EIO;
1477        }
1478
1479        spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
1480        if (spdifi_task == NULL) {
1481                dev_err(chip->card->dev,
1482                        "dsp_spos: symbol SPDIFITASK not found\n");
1483                return -EIO;
1484        }
1485
1486        {
1487                /* 0xBC0 */
1488                struct dsp_spdifoscb spdifo_scb = {
1489                        /* 0 */ DSP_SPOS_UUUU,
1490                        {
1491                                /* 1 */ 0xb0, 
1492                                /* 2 */ 0, 
1493                                /* 3 */ 0, 
1494                                /* 4 */ 0, 
1495                        },
1496                        /* NOTE: the SPDIF output task read samples in mono
1497                           format, the AsynchFGTxSCB task writes to buffer
1498                           in stereo format
1499                        */
1500                        /* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256,
1501                        /* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 )  |  0xFFFC,
1502                        /* 7 */ 0,0, 
1503                        /* 8 */ 0, 
1504                        /* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR, 
1505                        /* A */ spdifo_task->address,
1506                        SPDIFO_SCB_INST + SPDIFOFIFOPointer,
1507                        {
1508                                /* B */ 0x0040, /*DSP_SPOS_UUUU,*/
1509                                /* C */ 0x20ff, /*DSP_SPOS_UUUU,*/
1510                        },
1511                        /* D */ 0x804c,0,                                                         /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
1512                        /* E */ 0x0108,0x0001,                                    /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
1513                        /* F */ DSP_SPOS_UUUU                                     /* SPDIFOFree; */
1514                };
1515
1516                /* 0xBB0 */
1517                struct dsp_spdifiscb spdifi_scb = {
1518                        /* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
1519                        /* 1 */ 0,
1520                        /* 2 */ 0,
1521                        /* 3 */ 1,4000,        /* SPDIFICountLimit SPDIFICount */ 
1522                        /* 4 */ DSP_SPOS_UUUU, /* SPDIFIStatusData */
1523                        /* 5 */ 0,DSP_SPOS_UUHI, /* StatusData, Free4 */
1524                        /* 6 */ DSP_SPOS_UUUU,  /* Free3 */
1525                        /* 7 */ DSP_SPOS_UU,DSP_SPOS_DC,  /* Free2 BitCount*/
1526                        /* 8 */ DSP_SPOS_UUUU,  /* TempStatus */
1527                        /* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR,
1528                        /* A */ spdifi_task->address,
1529                        SPDIFI_SCB_INST + SPDIFIFIFOPointer,
1530                        /* NOTE: The SPDIF input task write the sample in mono
1531                           format from the HW FIFO, the AsynchFGRxSCB task  reads 
1532                           them in stereo 
1533                        */
1534                        /* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128,
1535                        /* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1536                        /* D */ 0x8048,0,
1537                        /* E */ 0x01f0,0x0001,
1538                        /* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */
1539                };
1540
1541                /* 0xBA0 */
1542                struct dsp_async_codec_input_scb async_codec_input_scb = {
1543                        /* 0 */ DSP_SPOS_UUUU,
1544                        /* 1 */ 0,
1545                        /* 2 */ 0,
1546                        /* 3 */ 1,4000,
1547                        /* 4 */ 0x0118,0x0001,
1548                        /* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64,
1549                        /* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1550                        /* 7 */ DSP_SPOS_UU,0x3,
1551                        /* 8 */ DSP_SPOS_UUUU,
1552                        /* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR,
1553                        /* A */ s16_async_codec_input_task->address,
1554                        HFG_TREE_SCB + AsyncCIOFIFOPointer,
1555              
1556                        /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1557                        /* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10),  /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
1558      
1559#ifdef UseASER1Input
1560                        /* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;        
1561                           Init. 0000:8042: for ASER1
1562                           0000:8044: for ASER2 */
1563                        /* D */ 0x8042,0,
1564      
1565                        /* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1566                           Init 1 stero:8050 ASER1
1567                           Init 0  mono:8070 ASER2
1568                           Init 1 Stereo : 0100 ASER1 (Set by script) */
1569                        /* E */ 0x0100,0x0001,
1570      
1571#endif
1572      
1573#ifdef UseASER2Input
1574                        /* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
1575                           Init. 0000:8042: for ASER1
1576                           0000:8044: for ASER2 */
1577                        /* D */ 0x8044,0,
1578      
1579                        /* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1580                           Init 1 stero:8050 ASER1
1581                           Init 0  mono:8070 ASER2
1582                           Init 1 Stereo : 0100 ASER1 (Set by script) */
1583                        /* E */ 0x0110,0x0001,
1584      
1585#endif
1586      
1587                        /* short AsyncCIOutputBufModulo:AsyncCIFree;
1588                           AsyncCIOutputBufModulo: The modulo size for   
1589                           the output buffer of this task */
1590                        /* F */ 0, /* DSP_SPOS_UUUU */
1591                };
1592
1593                spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
1594
1595                if (snd_BUG_ON(!spdifo_scb_desc))
1596                        return -EIO;
1597                spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
1598                if (snd_BUG_ON(!spdifi_scb_desc))
1599                        return -EIO;
1600                async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
1601                if (snd_BUG_ON(!async_codec_scb_desc))
1602                        return -EIO;
1603
1604                async_codec_scb_desc->parent_scb_ptr = NULL;
1605                async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
1606                async_codec_scb_desc->sub_list_ptr = ins->the_null_scb;
1607                async_codec_scb_desc->task_entry = s16_async_codec_input_task;
1608
1609                spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc;
1610                spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc;
1611                spdifi_scb_desc->sub_list_ptr = ins->the_null_scb;
1612                spdifi_scb_desc->task_entry = spdifi_task;
1613
1614                spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc;
1615                spdifo_scb_desc->next_scb_ptr = fg_entry;
1616                spdifo_scb_desc->sub_list_ptr = ins->the_null_scb;
1617                spdifo_scb_desc->task_entry = spdifo_task;
1618
1619                /* this one is faked, as the parnet of SPDIFO task
1620                   is the FG task tree */
1621                fg_entry->parent_scb_ptr = spdifo_scb_desc;
1622
1623                /* for proc fs */
1624                cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
1625                cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
1626                cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
1627
1628                /* Async MASTER ENABLE, affects both SPDIF input and output */
1629                snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
1630        }
1631
1632        return 0;
1633}
1634
1635static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
1636{
1637        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1638
1639        /* set SPDIF output FIFO slot */
1640        snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
1641
1642        /* SPDIF output MASTER ENABLE */
1643        cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0);
1644
1645        /* right and left validate bit */
1646        /*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
1647        cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0);
1648
1649        /* clear fifo pointer */
1650        cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
1651
1652        /* monitor state */
1653        ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;
1654}
1655
1656int cs46xx_dsp_enable_spdif_hw (struct snd_cs46xx *chip)
1657{
1658        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1659
1660        /* if hw-ctrl already enabled, turn off to reset logic ... */
1661        cs46xx_dsp_disable_spdif_hw (chip);
1662        udelay(50);
1663
1664        /* set SPDIF output FIFO slot */
1665        snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
1666
1667        /* SPDIF output MASTER ENABLE */
1668        cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
1669
1670        /* right and left validate bit */
1671        cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1672
1673        /* monitor state */
1674        ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
1675
1676        return 0;
1677}
1678
1679int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
1680{
1681        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1682
1683        /* turn on amplifier */
1684        chip->active_ctrl(chip, 1);
1685        chip->amplifier_ctrl(chip, 1);
1686
1687        if (snd_BUG_ON(ins->asynch_rx_scb))
1688                return -EINVAL;
1689        if (snd_BUG_ON(!ins->spdif_in_src))
1690                return -EINVAL;
1691
1692        mutex_lock(&chip->spos_mutex);
1693
1694        if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
1695                /* time countdown enable */
1696                cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000005);
1697                /* NOTE: 80000005 value is just magic. With all values
1698                   that I've tested this one seem to give the best result.
1699                   Got no explication why. (Benny) */
1700
1701                /* SPDIF input MASTER ENABLE */
1702                cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
1703
1704                ins->spdif_status_out |= DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED;
1705        }
1706
1707        /* create and start the asynchronous receiver SCB */
1708        ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
1709                                                                ASYNCRX_SCB_ADDR,
1710                                                                SPDIFI_SCB_INST,
1711                                                                SPDIFI_IP_OUTPUT_BUFFER1,
1712                                                                ins->spdif_in_src,
1713                                                                SCB_ON_PARENT_SUBLIST_SCB);
1714
1715        spin_lock_irq(&chip->reg_lock);
1716
1717        /* reset SPDIF input sample buffer pointer */
1718        /*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
1719          (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);*/
1720
1721        /* reset FIFO ptr */
1722        /*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/
1723        cs46xx_src_link(chip,ins->spdif_in_src);
1724
1725        /* unmute SRC volume */
1726        cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
1727
1728        spin_unlock_irq(&chip->reg_lock);
1729
1730        /* set SPDIF input sample rate and unmute
1731           NOTE: only 48khz support for SPDIF input this time */
1732        /* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
1733
1734        /* monitor state */
1735        ins->spdif_status_in = 1;
1736        mutex_unlock(&chip->spos_mutex);
1737
1738        return 0;
1739}
1740
1741int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip)
1742{
1743        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1744
1745        if (snd_BUG_ON(!ins->asynch_rx_scb))
1746                return -EINVAL;
1747        if (snd_BUG_ON(!ins->spdif_in_src))
1748                return -EINVAL;
1749
1750        mutex_lock(&chip->spos_mutex);
1751
1752        /* Remove the asynchronous receiver SCB */
1753        cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
1754        ins->asynch_rx_scb = NULL;
1755
1756        cs46xx_src_unlink(chip,ins->spdif_in_src);
1757
1758        /* monitor state */
1759        ins->spdif_status_in = 0;
1760        mutex_unlock(&chip->spos_mutex);
1761
1762        /* restore amplifier */
1763        chip->active_ctrl(chip, -1);
1764        chip->amplifier_ctrl(chip, -1);
1765
1766        return 0;
1767}
1768
1769int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip)
1770{
1771        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1772
1773        if (snd_BUG_ON(ins->pcm_input))
1774                return -EINVAL;
1775        if (snd_BUG_ON(!ins->ref_snoop_scb))
1776                return -EINVAL;
1777
1778        mutex_lock(&chip->spos_mutex);
1779        ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
1780                                                  "PCMSerialInput_Wave");
1781        mutex_unlock(&chip->spos_mutex);
1782
1783        return 0;
1784}
1785
1786int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip)
1787{
1788        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1789
1790        if (snd_BUG_ON(!ins->pcm_input))
1791                return -EINVAL;
1792
1793        mutex_lock(&chip->spos_mutex);
1794        cs46xx_dsp_remove_scb (chip,ins->pcm_input);
1795        ins->pcm_input = NULL;
1796        mutex_unlock(&chip->spos_mutex);
1797
1798        return 0;
1799}
1800
1801int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip)
1802{
1803        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1804
1805        if (snd_BUG_ON(ins->adc_input))
1806                return -EINVAL;
1807        if (snd_BUG_ON(!ins->codec_in_scb))
1808                return -EINVAL;
1809
1810        mutex_lock(&chip->spos_mutex);
1811        ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
1812                                                  "PCMSerialInput_ADC");
1813        mutex_unlock(&chip->spos_mutex);
1814
1815        return 0;
1816}
1817
1818int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip)
1819{
1820        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1821
1822        if (snd_BUG_ON(!ins->adc_input))
1823                return -EINVAL;
1824
1825        mutex_lock(&chip->spos_mutex);
1826        cs46xx_dsp_remove_scb (chip,ins->adc_input);
1827        ins->adc_input = NULL;
1828        mutex_unlock(&chip->spos_mutex);
1829
1830        return 0;
1831}
1832
1833int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data)
1834{
1835        u32 temp;
1836        int  i;
1837
1838        /* santiy check the parameters.  (These numbers are not 100% correct.  They are
1839           a rough guess from looking at the controller spec.) */
1840        if (address < 0x8000 || address >= 0x9000)
1841                return -EINVAL;
1842        
1843        /* initialize the SP_IO_WRITE SCB with the data. */
1844        temp = ( address << 16 ) | ( address & 0x0000FFFF);   /* offset 0 <-- address2 : address1 */
1845
1846        snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR      << 2), temp);
1847        snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
1848        snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */
1849    
1850        /* Poke this location to tell the task to start */
1851        snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
1852
1853        /* Verify that the task ran */
1854        for (i=0; i<25; i++) {
1855                udelay(125);
1856
1857                temp =  snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2));
1858                if (temp == 0x00000000)
1859                        break;
1860        }
1861
1862        if (i == 25) {
1863                dev_err(chip->card->dev,
1864                        "dsp_spos: SPIOWriteTask not responding\n");
1865                return -EBUSY;
1866        }
1867
1868        return 0;
1869}
1870
1871int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right)
1872{
1873        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1874        struct dsp_scb_descriptor * scb; 
1875
1876        mutex_lock(&chip->spos_mutex);
1877        
1878        /* main output */
1879        scb = ins->master_mix_scb->sub_list_ptr;
1880        while (scb != ins->the_null_scb) {
1881                cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1882                scb = scb->next_scb_ptr;
1883        }
1884
1885        /* rear output */
1886        scb = ins->rear_mix_scb->sub_list_ptr;
1887        while (scb != ins->the_null_scb) {
1888                cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1889                scb = scb->next_scb_ptr;
1890        }
1891
1892        ins->dac_volume_left = left;
1893        ins->dac_volume_right = right;
1894
1895        mutex_unlock(&chip->spos_mutex);
1896
1897        return 0;
1898}
1899
1900int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
1901{
1902        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1903
1904        mutex_lock(&chip->spos_mutex);
1905
1906        if (ins->asynch_rx_scb != NULL)
1907                cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
1908                                           left,right);
1909
1910        ins->spdif_input_volume_left = left;
1911        ins->spdif_input_volume_right = right;
1912
1913        mutex_unlock(&chip->spos_mutex);
1914
1915        return 0;
1916}
1917
1918#ifdef CONFIG_PM_SLEEP
1919int cs46xx_dsp_resume(struct snd_cs46xx * chip)
1920{
1921        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1922        int i, err;
1923
1924        /* clear parameter, sample and code areas */
1925        snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
1926                             DSP_PARAMETER_BYTE_SIZE);
1927        snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
1928                             DSP_SAMPLE_BYTE_SIZE);
1929        snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
1930
1931        for (i = 0; i < ins->nmodules; i++) {
1932                struct dsp_module_desc *module = &ins->modules[i];
1933                struct dsp_segment_desc *seg;
1934                u32 doffset, dsize;
1935
1936                seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
1937                err = dsp_load_parameter(chip, seg);
1938                if (err < 0)
1939                        return err;
1940
1941                seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
1942                err = dsp_load_sample(chip, seg);
1943                if (err < 0)
1944                        return err;
1945
1946                seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
1947                if (!seg)
1948                        continue;
1949
1950                doffset = seg->offset * 4 + module->load_address * 4
1951                        + DSP_CODE_BYTE_OFFSET;
1952                dsize   = seg->size * 4;
1953                err = snd_cs46xx_download(chip,
1954                                          ins->code.data + module->load_address,
1955                                          doffset, dsize);
1956                if (err < 0)
1957                        return err;
1958        }
1959
1960        for (i = 0; i < ins->ntask; i++) {
1961                struct dsp_task_descriptor *t = &ins->tasks[i];
1962                _dsp_create_task_tree(chip, t->data, t->address, t->size);
1963        }
1964
1965        for (i = 0; i < ins->nscb; i++) {
1966                struct dsp_scb_descriptor *s = &ins->scbs[i];
1967                if (s->deleted)
1968                        continue;
1969                _dsp_create_scb(chip, s->data, s->address);
1970        }
1971        for (i = 0; i < ins->nscb; i++) {
1972                struct dsp_scb_descriptor *s = &ins->scbs[i];
1973                if (s->deleted)
1974                        continue;
1975                if (s->updated)
1976                        cs46xx_dsp_spos_update_scb(chip, s);
1977                if (s->volume_set)
1978                        cs46xx_dsp_scb_set_volume(chip, s,
1979                                                  s->volume[0], s->volume[1]);
1980        }
1981        if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
1982                cs46xx_dsp_enable_spdif_hw(chip);
1983                snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
1984                                (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
1985                if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
1986                        cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
1987                                            ins->spdif_csuv_stream);
1988        }
1989        if (chip->dsp_spos_instance->spdif_status_in) {
1990                cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
1991                cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
1992        }
1993        return 0;
1994}
1995#endif
1996