~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to sound/pci/cs46xx/dsp_spos.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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