aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-07-19 05:23:21 -0400
committerJaroslav Kysela <perex@suse.cz>2007-07-20 05:11:57 -0400
commit89f157d9e6bf08b65f93dcb1dca1de037079885f (patch)
treecd828ea196a97f13216bb1af2da68901a079f6c5 /sound
parent87d483630a4bd5af2beb2155c7ae8c408729a1a6 (diff)
[ALSA] cs46xx - Fix PM resume
Fixed PM resume of cs46xx devices. It now restores properly the DSP image and kick-off the DSP. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c77
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.h3
-rw-r--r--sound/pci/cs46xx/dsp_spos.c170
3 files changed, 191 insertions, 59 deletions
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index bef1f6d1859c..71d7aab9d869 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2897,6 +2897,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
2897 } 2897 }
2898#endif 2898#endif
2899 2899
2900#ifdef CONFIG_PM
2901 kfree(chip->saved_regs);
2902#endif
2903
2900 pci_disable_device(chip->pci); 2904 pci_disable_device(chip->pci);
2901 kfree(chip); 2905 kfree(chip);
2902 return 0; 2906 return 0;
@@ -3140,6 +3144,23 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
3140/* 3144/*
3141 * start and load DSP 3145 * start and load DSP
3142 */ 3146 */
3147
3148static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
3149{
3150 unsigned int tmp;
3151
3152 snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
3153
3154 tmp = snd_cs46xx_peek(chip, BA1_PFIE);
3155 tmp &= ~0x0000f03f;
3156 snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */
3157
3158 tmp = snd_cs46xx_peek(chip, BA1_CIE);
3159 tmp &= ~0x0000003f;
3160 tmp |= 0x00000001;
3161 snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */
3162}
3163
3143int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) 3164int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
3144{ 3165{
3145 unsigned int tmp; 3166 unsigned int tmp;
@@ -3214,19 +3235,7 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
3214 3235
3215 snd_cs46xx_proc_start(chip); 3236 snd_cs46xx_proc_start(chip);
3216 3237
3217 /* 3238 cs46xx_enable_stream_irqs(chip);
3218 * Enable interrupts on the part.
3219 */
3220 snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
3221
3222 tmp = snd_cs46xx_peek(chip, BA1_PFIE);
3223 tmp &= ~0x0000f03f;
3224 snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */
3225
3226 tmp = snd_cs46xx_peek(chip, BA1_CIE);
3227 tmp &= ~0x0000003f;
3228 tmp |= 0x00000001;
3229 snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */
3230 3239
3231#ifndef CONFIG_SND_CS46XX_NEW_DSP 3240#ifndef CONFIG_SND_CS46XX_NEW_DSP
3232 /* set the attenuation to 0dB */ 3241 /* set the attenuation to 0dB */
@@ -3665,11 +3674,19 @@ static struct cs_card_type __devinitdata cards[] = {
3665 * APM support 3674 * APM support
3666 */ 3675 */
3667#ifdef CONFIG_PM 3676#ifdef CONFIG_PM
3677static unsigned int saved_regs[] = {
3678 BA0_ACOSV,
3679 BA0_ASER_FADDR,
3680 BA0_ASER_MASTER,
3681 BA1_PVOL,
3682 BA1_CVOL,
3683};
3684
3668int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state) 3685int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
3669{ 3686{
3670 struct snd_card *card = pci_get_drvdata(pci); 3687 struct snd_card *card = pci_get_drvdata(pci);
3671 struct snd_cs46xx *chip = card->private_data; 3688 struct snd_cs46xx *chip = card->private_data;
3672 int amp_saved; 3689 int i, amp_saved;
3673 3690
3674 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 3691 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
3675 chip->in_suspend = 1; 3692 chip->in_suspend = 1;
@@ -3680,6 +3697,10 @@ int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
3680 snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); 3697 snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
3681 snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); 3698 snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
3682 3699
3700 /* save some registers */
3701 for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
3702 chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]);
3703
3683 amp_saved = chip->amplifier; 3704 amp_saved = chip->amplifier;
3684 /* turn off amp */ 3705 /* turn off amp */
3685 chip->amplifier_ctrl(chip, -chip->amplifier); 3706 chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3698,7 +3719,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
3698{ 3719{
3699 struct snd_card *card = pci_get_drvdata(pci); 3720 struct snd_card *card = pci_get_drvdata(pci);
3700 struct snd_cs46xx *chip = card->private_data; 3721 struct snd_cs46xx *chip = card->private_data;
3701 int amp_saved; 3722 int i, amp_saved;
3702 3723
3703 pci_set_power_state(pci, PCI_D0); 3724 pci_set_power_state(pci, PCI_D0);
3704 pci_restore_state(pci); 3725 pci_restore_state(pci);
@@ -3716,6 +3737,16 @@ int snd_cs46xx_resume(struct pci_dev *pci)
3716 3737
3717 snd_cs46xx_chip_init(chip); 3738 snd_cs46xx_chip_init(chip);
3718 3739
3740 snd_cs46xx_reset(chip);
3741#ifdef CONFIG_SND_CS46XX_NEW_DSP
3742 cs46xx_dsp_resume(chip);
3743 /* restore some registers */
3744 for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
3745 snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]);
3746#else
3747 snd_cs46xx_download_image(chip);
3748#endif
3749
3719#if 0 3750#if 0
3720 snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 3751 snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE,
3721 chip->ac97_general_purpose); 3752 chip->ac97_general_purpose);
@@ -3730,6 +3761,13 @@ int snd_cs46xx_resume(struct pci_dev *pci)
3730 snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); 3761 snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
3731 snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); 3762 snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
3732 3763
3764 /* reset playback/capture */
3765 snd_cs46xx_set_play_sample_rate(chip, 8000);
3766 snd_cs46xx_set_capture_sample_rate(chip, 8000);
3767 snd_cs46xx_proc_start(chip);
3768
3769 cs46xx_enable_stream_irqs(chip);
3770
3733 if (amp_saved) 3771 if (amp_saved)
3734 chip->amplifier_ctrl(chip, 1); /* turn amp on */ 3772 chip->amplifier_ctrl(chip, 1); /* turn amp on */
3735 else 3773 else
@@ -3896,6 +3934,15 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
3896 3934
3897 snd_cs46xx_proc_init(card, chip); 3935 snd_cs46xx_proc_init(card, chip);
3898 3936
3937#ifdef CONFIG_PM
3938 chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
3939 ARRAY_SIZE(saved_regs), GFP_KERNEL);
3940 if (!chip->saved_regs) {
3941 snd_cs46xx_free(chip);
3942 return -ENOMEM;
3943 }
3944#endif
3945
3899 chip->active_ctrl(chip, -1); /* disable CLKRUN */ 3946 chip->active_ctrl(chip, -1); /* disable CLKRUN */
3900 3947
3901 snd_card_set_dev(card, &pci->dev); 3948 snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index f75750c2bd24..20dcd72f06c1 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -86,6 +86,9 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
86struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip); 86struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
87void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip); 87void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
88int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module); 88int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
89#ifdef CONFIG_PM
90int cs46xx_dsp_resume(struct snd_cs46xx * chip);
91#endif
89struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, 92struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
90 int symbol_type); 93 int symbol_type);
91#ifdef CONFIG_PROC_FS 94#ifdef CONFIG_PROC_FS
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
309static 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
333static 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
309int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module) 356int 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
1626static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip) 1650static 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
1923int 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