diff options
| author | Clemens Ladisch <clemens@ladisch.de> | 2009-09-28 05:21:21 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-09-28 05:55:00 -0400 |
| commit | 4852ad02476ab2bbc874f6f8fda9e677e0f09c87 (patch) | |
| tree | 0edcea50bffb7a643e3a72e29bcc920dd7ab71dc | |
| parent | 973dca93a3d46cca7e4743300f8a510b779906af (diff) | |
sound: oxygen: add digital filter control
Add a control to select between sharp and slow roll-of filter responses
of the DACs.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/oxygen/oxygen.c | 65 | ||||
| -rw-r--r-- | sound/pci/oxygen/xonar_cs43xx.c | 82 | ||||
| -rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 85 |
3 files changed, 223 insertions, 9 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index d12fd9efe94e..3ad9eb00aebd 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
| @@ -352,6 +352,70 @@ static void set_ak5385_params(struct oxygen *chip, | |||
| 352 | value, GPIO_AK5385_DFS_MASK); | 352 | value, GPIO_AK5385_DFS_MASK); |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
| 356 | struct snd_ctl_elem_info *info) | ||
| 357 | { | ||
| 358 | static const char *const names[2] = { | ||
| 359 | "Sharp Roll-off", "Slow Roll-off" | ||
| 360 | }; | ||
| 361 | |||
| 362 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 363 | info->count = 1; | ||
| 364 | info->value.enumerated.items = 2; | ||
| 365 | if (info->value.enumerated.item >= 2) | ||
| 366 | info->value.enumerated.item = 1; | ||
| 367 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
| 372 | struct snd_ctl_elem_value *value) | ||
| 373 | { | ||
| 374 | struct oxygen *chip = ctl->private_data; | ||
| 375 | struct generic_data *data = chip->model_data; | ||
| 376 | |||
| 377 | value->value.enumerated.item[0] = | ||
| 378 | (data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0; | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
| 383 | struct snd_ctl_elem_value *value) | ||
| 384 | { | ||
| 385 | struct oxygen *chip = ctl->private_data; | ||
| 386 | struct generic_data *data = chip->model_data; | ||
| 387 | unsigned int i; | ||
| 388 | int changed; | ||
| 389 | u8 reg; | ||
| 390 | |||
| 391 | mutex_lock(&chip->mutex); | ||
| 392 | reg = data->ak4396_regs[0][AK4396_CONTROL_2]; | ||
| 393 | if (value->value.enumerated.item[0]) | ||
| 394 | reg |= AK4396_SLOW; | ||
| 395 | else | ||
| 396 | reg &= ~AK4396_SLOW; | ||
| 397 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; | ||
| 398 | if (changed) { | ||
| 399 | for (i = 0; i < 4; ++i) | ||
| 400 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); | ||
| 401 | } | ||
| 402 | mutex_unlock(&chip->mutex); | ||
| 403 | return changed; | ||
| 404 | } | ||
| 405 | |||
| 406 | static const struct snd_kcontrol_new rolloff_control = { | ||
| 407 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 408 | .name = "DAC Filter Playback Enum", | ||
| 409 | .info = rolloff_info, | ||
| 410 | .get = rolloff_get, | ||
| 411 | .put = rolloff_put, | ||
| 412 | }; | ||
| 413 | |||
| 414 | static int generic_mixer_init(struct oxygen *chip) | ||
| 415 | { | ||
| 416 | return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
| 417 | } | ||
| 418 | |||
| 355 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | 419 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); |
| 356 | 420 | ||
| 357 | static const struct oxygen_model model_generic = { | 421 | static const struct oxygen_model model_generic = { |
| @@ -359,6 +423,7 @@ static const struct oxygen_model model_generic = { | |||
| 359 | .longname = "C-Media Oxygen HD Audio", | 423 | .longname = "C-Media Oxygen HD Audio", |
| 360 | .chip = "CMI8788", | 424 | .chip = "CMI8788", |
| 361 | .init = generic_init, | 425 | .init = generic_init, |
| 426 | .mixer_init = generic_mixer_init, | ||
| 362 | .cleanup = generic_cleanup, | 427 | .cleanup = generic_cleanup, |
| 363 | .resume = generic_resume, | 428 | .resume = generic_resume, |
| 364 | .get_i2s_mclk = oxygen_default_i2s_mclk, | 429 | .get_i2s_mclk = oxygen_default_i2s_mclk, |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index a83f827feb34..16c226bfcd2b 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
| @@ -69,7 +69,7 @@ | |||
| 69 | 69 | ||
| 70 | struct xonar_cs43xx { | 70 | struct xonar_cs43xx { |
| 71 | struct xonar_generic generic; | 71 | struct xonar_generic generic; |
| 72 | u8 cs4398_regs[7]; | 72 | u8 cs4398_regs[8]; |
| 73 | u8 cs4362a_regs[15]; | 73 | u8 cs4362a_regs[15]; |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| @@ -121,12 +121,11 @@ static void cs43xx_registers_init(struct oxygen *chip) | |||
| 121 | cs4398_write(chip, 4, data->cs4398_regs[4]); | 121 | cs4398_write(chip, 4, data->cs4398_regs[4]); |
| 122 | cs4398_write(chip, 5, data->cs4398_regs[5]); | 122 | cs4398_write(chip, 5, data->cs4398_regs[5]); |
| 123 | cs4398_write(chip, 6, data->cs4398_regs[6]); | 123 | cs4398_write(chip, 6, data->cs4398_regs[6]); |
| 124 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | | 124 | cs4398_write(chip, 7, data->cs4398_regs[7]); |
| 125 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | ||
| 126 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); | 125 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); |
| 127 | cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | | 126 | cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | |
| 128 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | 127 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
| 129 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | 128 | cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]); |
| 130 | cs4362a_write(chip, 0x05, 0); | 129 | cs4362a_write(chip, 0x05, 0); |
| 131 | for (i = 6; i <= 14; ++i) | 130 | for (i = 6; i <= 14; ++i) |
| 132 | cs4362a_write(chip, i, data->cs4362a_regs[i]); | 131 | cs4362a_write(chip, i, data->cs4362a_regs[i]); |
| @@ -147,6 +146,9 @@ static void xonar_d1_init(struct oxygen *chip) | |||
| 147 | CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; | 146 | CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; |
| 148 | data->cs4398_regs[5] = 60 * 2; | 147 | data->cs4398_regs[5] = 60 * 2; |
| 149 | data->cs4398_regs[6] = 60 * 2; | 148 | data->cs4398_regs[6] = 60 * 2; |
| 149 | data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP | | ||
| 150 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP; | ||
| 151 | data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE; | ||
| 150 | data->cs4362a_regs[6] = CS4362A_FM_SINGLE | | 152 | data->cs4362a_regs[6] = CS4362A_FM_SINGLE | |
| 151 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 153 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
| 152 | data->cs4362a_regs[7] = 60 | CS4362A_MUTE; | 154 | data->cs4362a_regs[7] = 60 | CS4362A_MUTE; |
| @@ -286,6 +288,68 @@ static const struct snd_kcontrol_new front_panel_switch = { | |||
| 286 | .private_value = GPIO_D1_FRONT_PANEL, | 288 | .private_value = GPIO_D1_FRONT_PANEL, |
| 287 | }; | 289 | }; |
| 288 | 290 | ||
| 291 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
| 292 | struct snd_ctl_elem_info *info) | ||
| 293 | { | ||
| 294 | static const char *const names[2] = { | ||
| 295 | "Fast Roll-off", "Slow Roll-off" | ||
| 296 | }; | ||
| 297 | |||
| 298 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 299 | info->count = 1; | ||
| 300 | info->value.enumerated.items = 2; | ||
| 301 | if (info->value.enumerated.item >= 2) | ||
| 302 | info->value.enumerated.item = 1; | ||
| 303 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
| 308 | struct snd_ctl_elem_value *value) | ||
| 309 | { | ||
| 310 | struct oxygen *chip = ctl->private_data; | ||
| 311 | struct xonar_cs43xx *data = chip->model_data; | ||
| 312 | |||
| 313 | value->value.enumerated.item[0] = | ||
| 314 | (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0; | ||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
| 319 | struct snd_ctl_elem_value *value) | ||
| 320 | { | ||
| 321 | struct oxygen *chip = ctl->private_data; | ||
| 322 | struct xonar_cs43xx *data = chip->model_data; | ||
| 323 | int changed; | ||
| 324 | u8 reg; | ||
| 325 | |||
| 326 | mutex_lock(&chip->mutex); | ||
| 327 | reg = data->cs4398_regs[7]; | ||
| 328 | if (value->value.enumerated.item[0]) | ||
| 329 | reg |= CS4398_FILT_SEL; | ||
| 330 | else | ||
| 331 | reg &= ~CS4398_FILT_SEL; | ||
| 332 | changed = reg != data->cs4398_regs[7]; | ||
| 333 | if (changed) { | ||
| 334 | cs4398_write(chip, 7, reg); | ||
| 335 | if (reg & CS4398_FILT_SEL) | ||
| 336 | reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL; | ||
| 337 | else | ||
| 338 | reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; | ||
| 339 | cs4362a_write(chip, 0x04, reg); | ||
| 340 | } | ||
| 341 | mutex_unlock(&chip->mutex); | ||
| 342 | return changed; | ||
| 343 | } | ||
| 344 | |||
| 345 | static const struct snd_kcontrol_new rolloff_control = { | ||
| 346 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 347 | .name = "DAC Filter Playback Enum", | ||
| 348 | .info = rolloff_info, | ||
| 349 | .get = rolloff_get, | ||
| 350 | .put = rolloff_put, | ||
| 351 | }; | ||
| 352 | |||
| 289 | static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, | 353 | static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, |
| 290 | unsigned int reg, unsigned int mute) | 354 | unsigned int reg, unsigned int mute) |
| 291 | { | 355 | { |
| @@ -309,7 +373,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | |||
| 309 | 373 | ||
| 310 | static int xonar_d1_mixer_init(struct oxygen *chip) | 374 | static int xonar_d1_mixer_init(struct oxygen *chip) |
| 311 | { | 375 | { |
| 312 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | 376 | int err; |
| 377 | |||
| 378 | err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | ||
| 379 | if (err < 0) | ||
| 380 | return err; | ||
| 381 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
| 382 | if (err < 0) | ||
| 383 | return err; | ||
| 384 | return 0; | ||
| 313 | } | 385 | } |
| 314 | 386 | ||
| 315 | static const struct oxygen_model model_xonar_d1 = { | 387 | static const struct oxygen_model model_xonar_d1 = { |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 7f153fb1848d..ba18fb546b4f 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
| @@ -265,7 +265,8 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
| 265 | + gain_offset); | 265 | + gain_offset); |
| 266 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] | 266 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] |
| 267 | + gain_offset); | 267 | + gain_offset); |
| 268 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 268 | pcm1796_write(chip, i, 19, |
| 269 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE]); | ||
| 269 | pcm1796_write(chip, i, 20, | 270 | pcm1796_write(chip, i, 20, |
| 270 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); | 271 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); |
| 271 | pcm1796_write(chip, i, 21, 0); | 272 | pcm1796_write(chip, i, 21, 0); |
| @@ -278,6 +279,8 @@ static void pcm1796_init(struct oxygen *chip) | |||
| 278 | 279 | ||
| 279 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | | 280 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | |
| 280 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 281 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; |
| 282 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = | ||
| 283 | PCM1796_FLT_SHARP | PCM1796_ATS_1; | ||
| 281 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | 284 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; |
| 282 | pcm1796_registers_init(chip); | 285 | pcm1796_registers_init(chip); |
| 283 | data->current_rate = 48000; | 286 | data->current_rate = 48000; |
| @@ -642,6 +645,67 @@ static const struct snd_kcontrol_new alt_switch = { | |||
| 642 | .private_value = GPIO_D2_ALT, | 645 | .private_value = GPIO_D2_ALT, |
| 643 | }; | 646 | }; |
| 644 | 647 | ||
| 648 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
| 649 | struct snd_ctl_elem_info *info) | ||
| 650 | { | ||
| 651 | static const char *const names[2] = { | ||
| 652 | "Sharp Roll-off", "Slow Roll-off" | ||
| 653 | }; | ||
| 654 | |||
| 655 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 656 | info->count = 1; | ||
| 657 | info->value.enumerated.items = 2; | ||
| 658 | if (info->value.enumerated.item >= 2) | ||
| 659 | info->value.enumerated.item = 1; | ||
| 660 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
| 665 | struct snd_ctl_elem_value *value) | ||
| 666 | { | ||
| 667 | struct oxygen *chip = ctl->private_data; | ||
| 668 | struct xonar_pcm179x *data = chip->model_data; | ||
| 669 | |||
| 670 | value->value.enumerated.item[0] = | ||
| 671 | (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] & | ||
| 672 | PCM1796_FLT_MASK) != PCM1796_FLT_SHARP; | ||
| 673 | return 0; | ||
| 674 | } | ||
| 675 | |||
| 676 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
| 677 | struct snd_ctl_elem_value *value) | ||
| 678 | { | ||
| 679 | struct oxygen *chip = ctl->private_data; | ||
| 680 | struct xonar_pcm179x *data = chip->model_data; | ||
| 681 | unsigned int i; | ||
| 682 | int changed; | ||
| 683 | u8 reg; | ||
| 684 | |||
| 685 | mutex_lock(&chip->mutex); | ||
| 686 | reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
| 687 | reg &= ~PCM1796_FLT_MASK; | ||
| 688 | if (!value->value.enumerated.item[0]) | ||
| 689 | reg |= PCM1796_FLT_SHARP; | ||
| 690 | else | ||
| 691 | reg |= PCM1796_FLT_SLOW; | ||
| 692 | changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
| 693 | if (changed) { | ||
| 694 | for (i = 0; i < data->dacs; ++i) | ||
| 695 | pcm1796_write(chip, i, 19, reg); | ||
| 696 | } | ||
| 697 | mutex_unlock(&chip->mutex); | ||
| 698 | return changed; | ||
| 699 | } | ||
| 700 | |||
| 701 | static const struct snd_kcontrol_new rolloff_control = { | ||
| 702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 703 | .name = "DAC Filter Playback Enum", | ||
| 704 | .info = rolloff_info, | ||
| 705 | .get = rolloff_get, | ||
| 706 | .put = rolloff_put, | ||
| 707 | }; | ||
| 708 | |||
| 645 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 709 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) |
| 646 | { | 710 | { |
| 647 | static const char *const names[2] = { "64x", "128x" }; | 711 | static const char *const names[2] = { "64x", "128x" }; |
| @@ -858,6 +922,19 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) | |||
| 858 | return 0; | 922 | return 0; |
| 859 | } | 923 | } |
| 860 | 924 | ||
| 925 | static int add_pcm1796_controls(struct oxygen *chip) | ||
| 926 | { | ||
| 927 | int err; | ||
| 928 | |||
| 929 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
| 930 | if (err < 0) | ||
| 931 | return err; | ||
| 932 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
| 933 | if (err < 0) | ||
| 934 | return err; | ||
| 935 | return 0; | ||
| 936 | } | ||
| 937 | |||
| 861 | static int xonar_d2_mixer_init(struct oxygen *chip) | 938 | static int xonar_d2_mixer_init(struct oxygen *chip) |
| 862 | { | 939 | { |
| 863 | int err; | 940 | int err; |
| @@ -865,7 +942,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
| 865 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 942 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); |
| 866 | if (err < 0) | 943 | if (err < 0) |
| 867 | return err; | 944 | return err; |
| 868 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 945 | err = add_pcm1796_controls(chip); |
| 869 | if (err < 0) | 946 | if (err < 0) |
| 870 | return err; | 947 | return err; |
| 871 | return 0; | 948 | return 0; |
| @@ -873,7 +950,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
| 873 | 950 | ||
| 874 | static int xonar_hdav_mixer_init(struct oxygen *chip) | 951 | static int xonar_hdav_mixer_init(struct oxygen *chip) |
| 875 | { | 952 | { |
| 876 | return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 953 | return add_pcm1796_controls(chip); |
| 877 | } | 954 | } |
| 878 | 955 | ||
| 879 | static int xonar_st_mixer_init(struct oxygen *chip) | 956 | static int xonar_st_mixer_init(struct oxygen *chip) |
| @@ -887,7 +964,7 @@ static int xonar_st_mixer_init(struct oxygen *chip) | |||
| 887 | if (err < 0) | 964 | if (err < 0) |
| 888 | return err; | 965 | return err; |
| 889 | } | 966 | } |
| 890 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 967 | err = add_pcm1796_controls(chip); |
| 891 | if (err < 0) | 968 | if (err < 0) |
| 892 | return err; | 969 | return err; |
| 893 | return 0; | 970 | return 0; |
