Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: snd-pcsp: add nopcm mode

Currently, if the high-res timers are unavailable, snd-pcsp does not
initialize. People who choose it over pcspkr, loose their console beeps
in that case and get annoyed.
With this patch, the console beeps remain regardless of the high-res
timers. Additionally, the "nopcm" modparam is added to forcibly
disable the PCM capabilities of the driver.

Signed-off-by: Stas Sergeev <stsp@aknet.ru>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Stas Sergeev and committed by
Takashi Iwai
bcc2c6b7 e87a3dd3

+49 -21
+1
Documentation/sound/alsa/ALSA-Configuration.txt
··· 1454 1454 1455 1455 Module for internal PC-Speaker. 1456 1456 1457 + nopcm - Disable PC-Speaker PCM sound. Only beeps remain. 1457 1458 nforce_wa - enable NForce chipset workaround. Expect bad sound. 1458 1459 1459 1460 This module supports system beeps, some kind of PCM playback and
+20 -12
sound/drivers/pcsp/pcsp.c
··· 26 26 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ 27 27 static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ 28 28 static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ 29 + static int nopcm; /* Disable PCM capability of the driver */ 29 30 30 31 module_param(index, int, 0444); 31 32 MODULE_PARM_DESC(index, "Index value for pcsp soundcard."); ··· 34 33 MODULE_PARM_DESC(id, "ID string for pcsp soundcard."); 35 34 module_param(enable, bool, 0444); 36 35 MODULE_PARM_DESC(enable, "Enable PC-Speaker sound."); 36 + module_param(nopcm, bool, 0444); 37 + MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain."); 37 38 38 39 struct snd_pcsp pcsp_chip; 39 40 ··· 46 43 int err; 47 44 int div, min_div, order; 48 45 49 - hrtimer_get_res(CLOCK_MONOTONIC, &tp); 50 - if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { 51 - printk(KERN_ERR "PCSP: Timer resolution is not sufficient " 52 - "(%linS)\n", tp.tv_nsec); 53 - printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " 54 - "enabled.\n"); 55 - return -EIO; 46 + if (!nopcm) { 47 + hrtimer_get_res(CLOCK_MONOTONIC, &tp); 48 + if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { 49 + printk(KERN_ERR "PCSP: Timer resolution is not sufficient " 50 + "(%linS)\n", tp.tv_nsec); 51 + printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " 52 + "enabled.\n"); 53 + printk(KERN_ERR "PCSP: Turned into nopcm mode.\n"); 54 + nopcm = 1; 55 + } 56 56 } 57 57 58 58 if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS) ··· 113 107 snd_card_free(card); 114 108 return err; 115 109 } 116 - err = snd_pcsp_new_pcm(&pcsp_chip); 117 - if (err < 0) { 118 - snd_card_free(card); 119 - return err; 110 + if (!nopcm) { 111 + err = snd_pcsp_new_pcm(&pcsp_chip); 112 + if (err < 0) { 113 + snd_card_free(card); 114 + return err; 115 + } 120 116 } 121 - err = snd_pcsp_new_mixer(&pcsp_chip); 117 + err = snd_pcsp_new_mixer(&pcsp_chip, nopcm); 122 118 if (err < 0) { 123 119 snd_card_free(card); 124 120 return err;
+1 -1
sound/drivers/pcsp/pcsp.h
··· 83 83 extern void pcsp_sync_stop(struct snd_pcsp *chip); 84 84 85 85 extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); 86 - extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); 86 + extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm); 87 87 88 88 #endif
+27 -8
sound/drivers/pcsp/pcsp_mixer.c
··· 119 119 .put = pcsp_##ctl_type##_put, \ 120 120 } 121 121 122 - static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = { 122 + static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { 123 123 PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), 124 124 PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), 125 + }; 126 + 127 + static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { 125 128 PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"), 126 129 }; 127 130 128 - int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip) 131 + static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, 132 + struct snd_kcontrol_new *ctls, int num) 129 133 { 130 - struct snd_card *card = chip->card; 131 134 int i, err; 132 - 133 - for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) { 134 - err = snd_ctl_add(card, 135 - snd_ctl_new1(snd_pcsp_controls + i, 136 - chip)); 135 + struct snd_card *card = chip->card; 136 + for (i = 0; i < num; i++) { 137 + err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip)); 137 138 if (err < 0) 138 139 return err; 139 140 } 141 + return 0; 142 + } 143 + 144 + int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) 145 + { 146 + int err; 147 + struct snd_card *card = chip->card; 148 + 149 + if (!nopcm) { 150 + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm, 151 + ARRAY_SIZE(snd_pcsp_controls_pcm)); 152 + if (err < 0) 153 + return err; 154 + } 155 + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr, 156 + ARRAY_SIZE(snd_pcsp_controls_spkr)); 157 + if (err < 0) 158 + return err; 140 159 141 160 strcpy(card->mixername, "PC-Speaker"); 142 161