diff options
Diffstat (limited to 'sound/pci/cs46xx/dsp_spos.c')
-rw-r--r-- | sound/pci/cs46xx/dsp_spos.c | 170 |
1 files changed, 126 insertions, 44 deletions
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 336e77e2600c..590b35d91df2 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -306,13 +306,59 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) | |||
306 | mutex_unlock(&chip->spos_mutex); | 306 | mutex_unlock(&chip->spos_mutex); |
307 | } | 307 | } |
308 | 308 | ||
309 | static int dsp_load_parameter(struct snd_cs46xx *chip, | ||
310 | struct dsp_segment_desc *parameter) | ||
311 | { | ||
312 | u32 doffset, dsize; | ||
313 | |||
314 | if (!parameter) { | ||
315 | snd_printdd("dsp_spos: module got no parameter segment\n"); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET); | ||
320 | dsize = parameter->size * 4; | ||
321 | |||
322 | snd_printdd("dsp_spos: " | ||
323 | "downloading parameter data to chip (%08x-%08x)\n", | ||
324 | doffset,doffset + dsize); | ||
325 | if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) { | ||
326 | snd_printk(KERN_ERR "dsp_spos: " | ||
327 | "failed to download parameter data to DSP\n"); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int dsp_load_sample(struct snd_cs46xx *chip, | ||
334 | struct dsp_segment_desc *sample) | ||
335 | { | ||
336 | u32 doffset, dsize; | ||
337 | |||
338 | if (!sample) { | ||
339 | snd_printdd("dsp_spos: module got no sample segment\n"); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET); | ||
344 | dsize = sample->size * 4; | ||
345 | |||
346 | snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n", | ||
347 | doffset,doffset + dsize); | ||
348 | |||
349 | if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) { | ||
350 | snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n"); | ||
351 | return -EINVAL; | ||
352 | } | ||
353 | return 0; | ||
354 | } | ||
355 | |||
309 | int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module) | 356 | int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module) |
310 | { | 357 | { |
311 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 358 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
312 | struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM); | 359 | struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM); |
313 | struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER); | ||
314 | struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE); | ||
315 | u32 doffset, dsize; | 360 | u32 doffset, dsize; |
361 | int err; | ||
316 | 362 | ||
317 | if (ins->nmodules == DSP_MAX_MODULES - 1) { | 363 | if (ins->nmodules == DSP_MAX_MODULES - 1) { |
318 | snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n"); | 364 | snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n"); |
@@ -326,49 +372,20 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m | |||
326 | snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE); | 372 | snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE); |
327 | } | 373 | } |
328 | 374 | ||
329 | if (parameter == NULL) { | 375 | err = dsp_load_parameter(chip, get_segment_desc(module, |
330 | snd_printdd("dsp_spos: module got no parameter segment\n"); | 376 | SEGTYPE_SP_PARAMETER)); |
331 | } else { | 377 | if (err < 0) |
332 | if (ins->nmodules > 0) { | 378 | return err; |
333 | snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n"); | ||
334 | } | ||
335 | |||
336 | doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET); | ||
337 | dsize = parameter->size * 4; | ||
338 | |||
339 | snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n", | ||
340 | doffset,doffset + dsize); | ||
341 | |||
342 | if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) { | ||
343 | snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n"); | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | } | ||
347 | 379 | ||
348 | if (ins->nmodules == 0) { | 380 | if (ins->nmodules == 0) { |
349 | snd_printdd("dsp_spos: clearing sample area\n"); | 381 | snd_printdd("dsp_spos: clearing sample area\n"); |
350 | snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE); | 382 | snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE); |
351 | } | 383 | } |
352 | 384 | ||
353 | if (sample == NULL) { | 385 | err = dsp_load_sample(chip, get_segment_desc(module, |
354 | snd_printdd("dsp_spos: module got no sample segment\n"); | 386 | SEGTYPE_SP_SAMPLE)); |
355 | } else { | 387 | if (err < 0) |
356 | if (ins->nmodules > 0) { | 388 | return err; |
357 | snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n"); | ||
358 | } | ||
359 | |||
360 | doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET); | ||
361 | dsize = sample->size * 4; | ||
362 | |||
363 | snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n", | ||
364 | doffset,doffset + dsize); | ||
365 | |||
366 | if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) { | ||
367 | snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n"); | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | 389 | ||
373 | if (ins->nmodules == 0) { | 390 | if (ins->nmodules == 0) { |
374 | snd_printdd("dsp_spos: clearing code area\n"); | 391 | snd_printdd("dsp_spos: clearing code area\n"); |
@@ -986,7 +1003,10 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) | |||
986 | return NULL; | 1003 | return NULL; |
987 | } | 1004 | } |
988 | 1005 | ||
989 | strcpy(ins->tasks[ins->ntask].task_name,name); | 1006 | if (name) |
1007 | strcpy(ins->tasks[ins->ntask].task_name, name); | ||
1008 | else | ||
1009 | strcpy(ins->tasks[ins->ntask].task_name, "(NULL)"); | ||
990 | ins->tasks[ins->ntask].address = dest; | 1010 | ins->tasks[ins->ntask].address = dest; |
991 | ins->tasks[ins->ntask].size = size; | 1011 | ins->tasks[ins->ntask].size = size; |
992 | 1012 | ||
@@ -995,7 +1015,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) | |||
995 | desc = (ins->tasks + ins->ntask); | 1015 | desc = (ins->tasks + ins->ntask); |
996 | ins->ntask++; | 1016 | ins->ntask++; |
997 | 1017 | ||
998 | add_symbol (chip,name,dest,SYMBOL_PARAMETER); | 1018 | if (name) |
1019 | add_symbol (chip,name,dest,SYMBOL_PARAMETER); | ||
999 | return desc; | 1020 | return desc; |
1000 | } | 1021 | } |
1001 | 1022 | ||
@@ -1006,6 +1027,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 | |||
1006 | 1027 | ||
1007 | desc = _map_scb (chip,name,dest); | 1028 | desc = _map_scb (chip,name,dest); |
1008 | if (desc) { | 1029 | if (desc) { |
1030 | desc->data = scb_data; | ||
1009 | _dsp_create_scb(chip,scb_data,dest); | 1031 | _dsp_create_scb(chip,scb_data,dest); |
1010 | } else { | 1032 | } else { |
1011 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); | 1033 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); |
@@ -1023,6 +1045,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da | |||
1023 | 1045 | ||
1024 | desc = _map_task_tree (chip,name,dest,size); | 1046 | desc = _map_task_tree (chip,name,dest,size); |
1025 | if (desc) { | 1047 | if (desc) { |
1048 | desc->data = task_data; | ||
1026 | _dsp_create_task_tree(chip,task_data,dest,size); | 1049 | _dsp_create_task_tree(chip,task_data,dest,size); |
1027 | } else { | 1050 | } else { |
1028 | snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n"); | 1051 | snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n"); |
@@ -1320,8 +1343,10 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) | |||
1320 | 0x0000ffff | 1343 | 0x0000ffff |
1321 | }; | 1344 | }; |
1322 | 1345 | ||
1323 | /* dirty hack ... */ | 1346 | if (!cs46xx_dsp_create_task_tree(chip, NULL, |
1324 | _dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2); | 1347 | (u32 *)&mix2_ostream_spb, |
1348 | WRITE_BACK_SPB, 2)) | ||
1349 | goto _fail_end; | ||
1325 | } | 1350 | } |
1326 | 1351 | ||
1327 | /* input sample converter */ | 1352 | /* input sample converter */ |
@@ -1622,7 +1647,6 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip, | |||
1622 | return 0; | 1647 | return 0; |
1623 | } | 1648 | } |
1624 | 1649 | ||
1625 | |||
1626 | static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip) | 1650 | static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip) |
1627 | { | 1651 | { |
1628 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 1652 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
@@ -1894,3 +1918,61 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) | |||
1894 | 1918 | ||
1895 | return 0; | 1919 | return 0; |
1896 | } | 1920 | } |
1921 | |||
1922 | #ifdef CONFIG_PM | ||
1923 | int cs46xx_dsp_resume(struct snd_cs46xx * chip) | ||
1924 | { | ||
1925 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | ||
1926 | int i, err; | ||
1927 | |||
1928 | /* clear parameter, sample and code areas */ | ||
1929 | snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, | ||
1930 | DSP_PARAMETER_BYTE_SIZE); | ||
1931 | snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, | ||
1932 | DSP_SAMPLE_BYTE_SIZE); | ||
1933 | snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE); | ||
1934 | |||
1935 | for (i = 0; i < ins->nmodules; i++) { | ||
1936 | struct dsp_module_desc *module = &ins->modules[i]; | ||
1937 | struct dsp_segment_desc *seg; | ||
1938 | u32 doffset, dsize; | ||
1939 | |||
1940 | seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER); | ||
1941 | err = dsp_load_parameter(chip, seg); | ||
1942 | if (err < 0) | ||
1943 | return err; | ||
1944 | |||
1945 | seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE); | ||
1946 | err = dsp_load_sample(chip, seg); | ||
1947 | if (err < 0) | ||
1948 | return err; | ||
1949 | |||
1950 | seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM); | ||
1951 | if (!seg) | ||
1952 | continue; | ||
1953 | |||
1954 | doffset = seg->offset * 4 + module->load_address * 4 | ||
1955 | + DSP_CODE_BYTE_OFFSET; | ||
1956 | dsize = seg->size * 4; | ||
1957 | err = snd_cs46xx_download(chip, | ||
1958 | ins->code.data + module->load_address, | ||
1959 | doffset, dsize); | ||
1960 | if (err < 0) | ||
1961 | return err; | ||
1962 | } | ||
1963 | |||
1964 | for (i = 0; i < ins->ntask; i++) { | ||
1965 | struct dsp_task_descriptor *t = &ins->tasks[i]; | ||
1966 | _dsp_create_task_tree(chip, t->data, t->address, t->size); | ||
1967 | } | ||
1968 | |||
1969 | for (i = 0; i < ins->nscb; i++) { | ||
1970 | struct dsp_scb_descriptor *s = &ins->scbs[i]; | ||
1971 | if (s->deleted) | ||
1972 | continue; | ||
1973 | _dsp_create_scb(chip, s->data, s->address); | ||
1974 | } | ||
1975 | |||
1976 | return 0; | ||
1977 | } | ||
1978 | #endif | ||