aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/cs46xx/dsp_spos.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/cs46xx/dsp_spos.c')
-rw-r--r--sound/pci/cs46xx/dsp_spos.c531
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