diff options
Diffstat (limited to 'sound/pci/cs46xx/dsp_spos.c')
| -rw-r--r-- | sound/pci/cs46xx/dsp_spos.c | 531 |
1 files changed, 334 insertions, 197 deletions
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 445a448949e..1c4a0fb3ffe 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -20,19 +20,19 @@ */ -#include <sound/driver.h> #include <asm/io.h> #include <linux/delay.h> -#include <linux/pci.h> #include <linux/pm.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> #include <sound/asoundef.h> -#include <sound/cs46xx.h> +#include "cs46xx.h" #include "cs46xx_lib.h" #include "dsp_spos.h" @@ -63,7 +63,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 u32 mop_operands,mop_type,wide_op; struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert( ((size % 2) == 0), return -EINVAL); + if (snd_BUG_ON(size %2)) + return -EINVAL; while (i < size) { loval = data[i++]; @@ -84,12 +85,15 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 address = (hival & 0x00FFF) << 5; address |= loval >> 15; - snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address); + dev_dbg(chip->card->dev, + "handle_wideop[1]: %05x:%05x addr %04x\n", + hival, loval, address); if ( !(address & 0x8000) ) { address += (ins->code.offset / 2) - overlay_begin_address; } else { - snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n"); + dev_dbg(chip->card->dev, + "handle_wideop[1]: ROM symbol not reallocated\n"); } hival &= 0xFF000; @@ -101,8 +105,9 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 address = (hival & 0x00FFF) << 5; address |= loval >> 15; - snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address); - nreallocated ++; + dev_dbg(chip->card->dev, + "handle_wideop:[2] %05x:%05x addr %04x\n", + hival, loval, address); nreallocated++; } /* wide_opcodes[j] == wide_op */ } /* for */ } /* mod_type == 0 ... */ @@ -112,7 +117,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 ins->code.data[ins->code.size++] = hival; } - snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated); + dev_dbg(chip->card->dev, + "dsp_spos: %d instructions reallocated\n", nreallocated); return nreallocated; } @@ -156,7 +162,8 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul for (i = 0;i < module->symbol_table.nsymbols; ++i) { if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) { - snd_printk(KERN_ERR "dsp_spos: symbol table is full\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol table is full\n"); return -ENOMEM; } @@ -175,8 +182,11 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul ins->symbol_table.nsymbols++; } else { - /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n", - module->symbol_table.symbols[i].symbol_name); */ +#if 0 + dev_dbg(chip->card->dev, + "dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n", + module->symbol_table.symbols[i].symbol_name); */ +#endif } } @@ -191,14 +201,15 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type) int index; if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) { - snd_printk(KERN_ERR "dsp_spos: symbol table is full\n"); + dev_err(chip->card->dev, "dsp_spos: symbol table is full\n"); return NULL; } if (cs46xx_dsp_lookup_symbol(chip, symbol_name, type) != NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name); + dev_err(chip->card->dev, + "dsp_spos: symbol <%s> duplicated\n", symbol_name); return NULL; } @@ -224,39 +235,25 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) { struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL); - if (ins == NULL) + if (ins == NULL) return NULL; /* better to use vmalloc for this big table */ - ins->symbol_table.nsymbols = 0; ins->symbol_table.symbols = vmalloc(sizeof(struct dsp_symbol_entry) * DSP_MAX_SYMBOLS); - ins->symbol_table.highest_frag_index = 0; - - if (ins->symbol_table.symbols == NULL) { + ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL); + ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL); + if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) { cs46xx_dsp_spos_destroy(chip); - return NULL; + goto error; } - + ins->symbol_table.nsymbols = 0; + ins->symbol_table.highest_frag_index = 0; ins->code.offset = 0; ins->code.size = 0; - ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL); - - if (ins->code.data == NULL) { - cs46xx_dsp_spos_destroy(chip); - return NULL; - } - ins->nscb = 0; ins->ntask = 0; - ins->nmodules = 0; - ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL); - - if (ins->modules == NULL) { - cs46xx_dsp_spos_destroy(chip); - return NULL; - } /* default SPDIF input sample rate to 48000 khz */ @@ -270,14 +267,21 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) /* set left and right validity bits and default channel status */ - ins->spdif_csuv_default = - ins->spdif_csuv_stream = + ins->spdif_csuv_default = + ins->spdif_csuv_stream = /* byte 0 */ ((unsigned int)_wrap_all_bits( (SNDRV_PCM_DEFAULT_CON_SPDIF & 0xff)) << 24) | /* byte 1 */ ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) | /* byte 3 */ (unsigned int)_wrap_all_bits( (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) | /* left and right validity bits */ (1 << 13) | (1 << 12); return ins; + +error: + kfree(ins->modules); + kfree(ins->code.data); + vfree(ins->symbol_table.symbols); + kfree(ins); + return NULL; } void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) @@ -285,96 +289,125 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) int i; struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert(ins != NULL, return); + if (snd_BUG_ON(!ins)) + return; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); +#ifdef CONFIG_PM_SLEEP + kfree(ins->scbs[i].data); +#endif } kfree(ins->code.data); vfree(ins->symbol_table.symbols); kfree(ins->modules); kfree(ins); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); +} + +static int dsp_load_parameter(struct snd_cs46xx *chip, + struct dsp_segment_desc *parameter) +{ + u32 doffset, dsize; + + if (!parameter) { + dev_dbg(chip->card->dev, + "dsp_spos: module got no parameter segment\n"); + return 0; + } + + doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET); + dsize = parameter->size * 4; + + dev_dbg(chip->card->dev, + "dsp_spos: downloading parameter data to chip (%08x-%08x)\n", + doffset,doffset + dsize); + if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) { + dev_err(chip->card->dev, + "dsp_spos: failed to download parameter data to DSP\n"); + return -EINVAL; + } + return 0; +} + +static int dsp_load_sample(struct snd_cs46xx *chip, + struct dsp_segment_desc *sample) +{ + u32 doffset, dsize; + + if (!sample) { + dev_dbg(chip->card->dev, + "dsp_spos: module got no sample segment\n"); + return 0; + } + + doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET); + dsize = sample->size * 4; + + dev_dbg(chip->card->dev, + "dsp_spos: downloading sample data to chip (%08x-%08x)\n", + doffset,doffset + dsize); + + if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) { + dev_err(chip->card->dev, + "dsp_spos: failed to sample data to DSP\n"); + return -EINVAL; + } + return 0; } int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM); - struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER); - struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE); u32 doffset, dsize; + int err; if (ins->nmodules == DSP_MAX_MODULES - 1) { - snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: to many modules loaded into DSP\n"); return -ENOMEM; } - snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name); + dev_dbg(chip->card->dev, + "dsp_spos: loading module %s into DSP\n", module->module_name); if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing parameter area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n"); snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE); } - if (parameter == NULL) { - snd_printdd("dsp_spos: module got no parameter segment\n"); - } else { - if (ins->nmodules > 0) { - snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n"); - } - - doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET); - dsize = parameter->size * 4; - - snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n", - doffset,doffset + dsize); - - if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) { - snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n"); - return -EINVAL; - } - } + err = dsp_load_parameter(chip, get_segment_desc(module, + SEGTYPE_SP_PARAMETER)); + if (err < 0) + return err; if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing sample area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n"); snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE); } - if (sample == NULL) { - snd_printdd("dsp_spos: module got no sample segment\n"); - } else { - if (ins->nmodules > 0) { - snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n"); - } - - doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET); - dsize = sample->size * 4; - - snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n", - doffset,doffset + dsize); - - if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) { - snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n"); - return -EINVAL; - } - } - + err = dsp_load_sample(chip, get_segment_desc(module, + SEGTYPE_SP_SAMPLE)); + if (err < 0) + return err; if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing code area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n"); snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE); } if (code == NULL) { - snd_printdd("dsp_spos: module got no code segment\n"); + dev_dbg(chip->card->dev, + "dsp_spos: module got no code segment\n"); } else { if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) { - snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: no space available in DSP\n"); return -ENOMEM; } @@ -383,21 +416,25 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m /* if module has a code segment it must have symbol table */ - snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM); + if (snd_BUG_ON(!module->symbol_table.symbols)) + return -ENOMEM; if (add_symbols(chip,module)) { - snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to load symbol table\n"); return -ENOMEM; } doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET); dsize = code->size * 4; - snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n", + dev_dbg(chip->card->dev, + "dsp_spos: downloading code to chip (%08x-%08x)\n", doffset,doffset + dsize); module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address); if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) { - snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to download code to DSP\n"); return -EINVAL; } @@ -431,7 +468,7 @@ cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symb } #if 0 - printk ("dsp_spos: symbol <%s> type %02x not found\n", + dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n", symbol_name,symbol_type); #endif @@ -497,7 +534,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i,j; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "MODULES:\n"); for ( i = 0; i < ins->nmodules; ++i ) { snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name); @@ -510,7 +547,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, desc->segment_type,desc->offset, desc->size); } } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, @@ -521,7 +558,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, int i, j, col; void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "TASK TREES:\n"); for ( i = 0; i < ins->ntask; ++i) { snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name); @@ -538,7 +575,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, @@ -548,7 +585,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "SCB's:\n"); for ( i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) @@ -571,7 +608,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry, @@ -761,7 +798,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - entry->c.text.read_size = 512; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -778,7 +814,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -791,7 +826,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_modules_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -804,7 +838,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -817,7 +850,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -830,7 +862,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_task_tree_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -843,7 +874,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 1024; entry->c.text.read = cs46xx_dsp_proc_scb_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -852,14 +882,14 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) } ins->proc_scb_info_entry = entry; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* register/update SCB's entries on proc */ for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i)); } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -869,53 +899,38 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i; - if (ins->proc_sym_info_entry) { - snd_info_unregister(ins->proc_sym_info_entry); - ins->proc_sym_info_entry = NULL; - } - - if (ins->proc_modules_info_entry) { - snd_info_unregister(ins->proc_modules_info_entry); - ins->proc_modules_info_entry = NULL; - } - - if (ins->proc_parameter_dump_info_entry) { - snd_info_unregister(ins->proc_parameter_dump_info_entry); - ins->proc_parameter_dump_info_entry = NULL; - } - - if (ins->proc_sample_dump_info_entry) { - snd_info_unregister(ins->proc_sample_dump_info_entry); - ins->proc_sample_dump_info_entry = NULL; - } - - if (ins->proc_scb_info_entry) { - snd_info_unregister(ins->proc_scb_info_entry); - ins->proc_scb_info_entry = NULL; - } - - if (ins->proc_task_info_entry) { - snd_info_unregister(ins->proc_task_info_entry); - ins->proc_task_info_entry = NULL; - } + snd_info_free_entry(ins->proc_sym_info_entry); + ins->proc_sym_info_entry = NULL; + + snd_info_free_entry(ins->proc_modules_info_entry); + ins->proc_modules_info_entry = NULL; + + snd_info_free_entry(ins->proc_parameter_dump_info_entry); + ins->proc_parameter_dump_info_entry = NULL; - down(&chip->spos_mutex); + snd_info_free_entry(ins->proc_sample_dump_info_entry); + ins->proc_sample_dump_info_entry = NULL; + + snd_info_free_entry(ins->proc_scb_info_entry); + ins->proc_scb_info_entry = NULL; + + snd_info_free_entry(ins->proc_task_info_entry); + ins->proc_task_info_entry = NULL; + + mutex_lock(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); - if (ins->proc_dsp_dir) { - snd_info_unregister (ins->proc_dsp_dir); - ins->proc_dsp_dir = NULL; - } + snd_info_free_entry(ins->proc_dsp_dir); + ins->proc_dsp_dir = NULL; return 0; } #endif /* CONFIG_PROC_FS */ -static int debug_tree; static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data, u32 dest, int size) { @@ -924,13 +939,13 @@ static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data, int i; for (i = 0; i < size; ++i) { - if (debug_tree) printk ("addr %p, val %08x\n",spdst,task_data[i]); + dev_dbg(chip->card->dev, "addr %p, val %08x\n", + spdst, task_data[i]); writel(task_data[i],spdst); spdst += sizeof(u32); } } -static int debug_scb; static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest) { void __iomem *spdst = chip->region.idx[1].remap_addr + @@ -938,7 +953,8 @@ static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest) int i; for (i = 0; i < 0x10; ++i) { - if (debug_scb) printk ("addr %p, val %08x\n",spdst,scb_data[i]); + dev_dbg(chip->card->dev, "addr %p, val %08x\n", + spdst, scb_data[i]); writel(scb_data[i],spdst); spdst += sizeof(u32); } @@ -965,19 +981,18 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam int index; if (ins->nscb == DSP_MAX_SCB_DESC - 1) { - snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n"); + dev_err(chip->card->dev, + "dsp_spos: got no place for other SCB\n"); return NULL; } index = find_free_scb_index (ins); + memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); strcpy(ins->scbs[index].scb_name, name); ins->scbs[index].address = dest; ins->scbs[index].index = index; - ins->scbs[index].proc_info = NULL; ins->scbs[index].ref_count = 1; - ins->scbs[index].deleted = 0; - spin_lock_init(&ins->scbs[index].lock); desc = (ins->scbs + index); ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); @@ -998,11 +1013,15 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) struct dsp_task_descriptor * desc = NULL; if (ins->ntask == DSP_MAX_TASK_DESC - 1) { - snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n"); + dev_err(chip->card->dev, + "dsp_spos: got no place for other TASK\n"); return NULL; } - strcpy(ins->tasks[ins->ntask].task_name,name); + if (name) + strcpy(ins->tasks[ins->ntask].task_name, name); + else + strcpy(ins->tasks[ins->ntask].task_name, "(NULL)"); ins->tasks[ins->ntask].address = dest; ins->tasks[ins->ntask].size = size; @@ -1011,20 +1030,34 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) desc = (ins->tasks + ins->ntask); ins->ntask++; - add_symbol (chip,name,dest,SYMBOL_PARAMETER); + if (name) + add_symbol (chip,name,dest,SYMBOL_PARAMETER); return desc; } +#define SCB_BYTES (0x10 * 4) + struct dsp_scb_descriptor * cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) { struct dsp_scb_descriptor * desc; +#ifdef CONFIG_PM_SLEEP + /* copy the data for resume */ + scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL); + if (!scb_data) + return NULL; +#endif + desc = _map_scb (chip,name,dest); if (desc) { + desc->data = scb_data; _dsp_create_scb(chip,scb_data,dest); } else { - snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); + dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n"); +#ifdef CONFIG_PM_SLEEP + kfree(scb_data); +#endif } return desc; @@ -1039,9 +1072,10 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da desc = _map_task_tree (chip,name,dest,size); if (desc) { + desc->data = task_data; _dsp_create_task_tree(chip,task_data,dest,size); } else { - snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n"); + dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n"); } return desc; @@ -1094,31 +1128,36 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) null_algorithm = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE); if (null_algorithm == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol NULLALGORITHM not found\n"); return -EIO; } fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE); if (fg_task_tree_header_code == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n"); return -EIO; } task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE); if (task_tree_header_code == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol TASKTREEHEADERCODE not found\n"); return -EIO; } task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE); if (task_tree_thread == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol TASKTREETHREAD not found\n"); return -EIO; } magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE); if (magic_snoop_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol MAGICSNOOPTASK not found\n"); return -EIO; } @@ -1336,8 +1375,10 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) 0x0000ffff }; - /* dirty hack ... */ - _dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2); + if (!cs46xx_dsp_create_task_tree(chip, NULL, + (u32 *)&mix2_ostream_spb, + WRITE_BACK_SPB, 2)) + goto _fail_end; } /* input sample converter */ @@ -1361,7 +1402,8 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV); - snd_assert (chip->nr_ac97_codecs == 1 || chip->nr_ac97_codecs == 2); + if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2)) + goto _fail_end; if (chip->nr_ac97_codecs == 1) { /* output on slot 5 and 11 @@ -1462,7 +1504,7 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) return 0; _fail_end: - snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n"); + dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n"); return -EINVAL; } @@ -1477,18 +1519,21 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip, s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE); if (s16_async_codec_input_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n"); return -EIO; } spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE); if (spdifo_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol SPDIFOTASK not found\n"); return -EIO; } spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE); if (spdifi_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol SPDIFITASK not found\n"); return -EIO; } @@ -1601,11 +1646,14 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip, spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST); - snd_assert(spdifo_scb_desc, return -EIO); + if (snd_BUG_ON(!spdifo_scb_desc)) + return -EIO; spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST); - snd_assert(spdifi_scb_desc, return -EIO); + if (snd_BUG_ON(!spdifi_scb_desc)) + return -EIO; async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB); - snd_assert(async_codec_scb_desc, return -EIO); + if (snd_BUG_ON(!async_codec_scb_desc)) + return -EIO; async_codec_scb_desc->parent_scb_ptr = NULL; async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc; @@ -1638,7 +1686,6 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip, return 0; } - static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; @@ -1691,10 +1738,12 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) chip->active_ctrl(chip, 1); chip->amplifier_ctrl(chip, 1); - snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL); - snd_assert (ins->spdif_in_src != NULL,return -EINVAL); + if (snd_BUG_ON(ins->asynch_rx_scb)) + return -EINVAL; + if (snd_BUG_ON(!ins->spdif_in_src)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) { /* time countdown enable */ @@ -1738,7 +1787,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) /* monitor state */ ins->spdif_status_in = 1; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1747,10 +1796,12 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL); - snd_assert (ins->spdif_in_src != NULL,return -EINVAL); + if (snd_BUG_ON(!ins->asynch_rx_scb)) + return -EINVAL; + if (snd_BUG_ON(!ins->spdif_in_src)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* Remove the asynchronous receiver SCB */ cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb); @@ -1760,7 +1811,7 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip) /* monitor state */ ins->spdif_status_in = 0; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); /* restore amplifier */ chip->active_ctrl(chip, -1); @@ -1773,13 +1824,15 @@ int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert (ins->pcm_input == NULL,return -EINVAL); - snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL); + if (snd_BUG_ON(ins->pcm_input)) + return -EINVAL; + if (snd_BUG_ON(!ins->ref_snoop_scb)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR, "PCMSerialInput_Wave"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1788,12 +1841,13 @@ int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert (ins->pcm_input != NULL,return -EINVAL); + if (snd_BUG_ON(!ins->pcm_input)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->pcm_input); ins->pcm_input = NULL; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1802,13 +1856,15 @@ int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert (ins->adc_input == NULL,return -EINVAL); - snd_assert (ins->codec_in_scb != NULL,return -EINVAL); + if (snd_BUG_ON(ins->adc_input)) + return -EINVAL; + if (snd_BUG_ON(!ins->codec_in_scb)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR, "PCMSerialInput_ADC"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1817,12 +1873,13 @@ int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - snd_assert (ins->adc_input != NULL,return -EINVAL); + if (snd_BUG_ON(!ins->adc_input)) + return -EINVAL; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->adc_input); ins->adc_input = NULL; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1857,7 +1914,8 @@ int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data) } if (i == 25) { - snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n"); + dev_err(chip->card->dev, + "dsp_spos: SPIOWriteTask not responding\n"); return -EBUSY; } @@ -1869,7 +1927,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_scb_descriptor * scb; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* main output */ scb = ins->master_mix_scb->sub_list_ptr; @@ -1888,7 +1946,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->dac_volume_left = left; ins->dac_volume_right = right; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1897,7 +1955,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if (ins->asynch_rx_scb != NULL) cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb, @@ -1906,7 +1964,86 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->spdif_input_volume_left = left; ins->spdif_input_volume_right = right; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +int cs46xx_dsp_resume(struct snd_cs46xx * chip) +{ + struct dsp_spos_instance * ins = chip->dsp_spos_instance; + int i, err; + + /* clear parameter, sample and code areas */ + snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, + DSP_PARAMETER_BYTE_SIZE); + snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, + DSP_SAMPLE_BYTE_SIZE); + snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE); + + for (i = 0; i < ins->nmodules; i++) { + struct dsp_module_desc *module = &ins->modules[i]; + struct dsp_segment_desc *seg; + u32 doffset, dsize; + + seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER); + err = dsp_load_parameter(chip, seg); + if (err < 0) + return err; + + seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE); + err = dsp_load_sample(chip, seg); + if (err < 0) + return err; + + seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM); + if (!seg) + continue; + + doffset = seg->offset * 4 + module->load_address * 4 + + DSP_CODE_BYTE_OFFSET; + dsize = seg->size * 4; + err = snd_cs46xx_download(chip, + ins->code.data + module->load_address, + doffset, dsize); + if (err < 0) + return err; + } + for (i = 0; i < ins->ntask; i++) { + struct dsp_task_descriptor *t = &ins->tasks[i]; + _dsp_create_task_tree(chip, t->data, t->address, t->size); + } + + for (i = 0; i < ins->nscb; i++) { + struct dsp_scb_descriptor *s = &ins->scbs[i]; + if (s->deleted) + continue; + _dsp_create_scb(chip, s->data, s->address); + } + for (i = 0; i < ins->nscb; i++) { + struct dsp_scb_descriptor *s = &ins->scbs[i]; + if (s->deleted) + continue; + if (s->updated) + cs46xx_dsp_spos_update_scb(chip, s); + if (s->volume_set) + cs46xx_dsp_scb_set_volume(chip, s, + s->volume[0], s->volume[1]); + } + if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { + cs46xx_dsp_enable_spdif_hw(chip); + snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2, + (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10); + if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) + cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV, + ins->spdif_csuv_stream); + } + if (chip->dsp_spos_instance->spdif_status_in) { + cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005); + cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff); + } return 0; } +#endif |
