1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PC-Speaker driver for Linux 4 * 5 * Mixer implementation. 6 * Copyright (C) 2001-2008 Stas Sergeev 7 */ 8 9 #include <sound/core.h> 10 #include <sound/control.h> 11 #include "pcsp.h" 12 13 14 static int pcsp_enable_info(struct snd_kcontrol *kcontrol, 15 struct snd_ctl_elem_info *uinfo) 16 { 17 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 18 uinfo->count = 1; 19 uinfo->value.integer.min = 0; 20 uinfo->value.integer.max = 1; 21 return 0; 22 } 23 24 static int pcsp_enable_get(struct snd_kcontrol *kcontrol, 25 struct snd_ctl_elem_value *ucontrol) 26 { 27 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 28 ucontrol->value.integer.value[0] = chip->enable; 29 return 0; 30 } 31 32 static int pcsp_enable_put(struct snd_kcontrol *kcontrol, 33 struct snd_ctl_elem_value *ucontrol) 34 { 35 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 36 int changed = 0; 37 int enab = ucontrol->value.integer.value[0]; 38 if (enab != chip->enable) { 39 chip->enable = enab; 40 changed = 1; 41 } 42 return changed; 43 } 44 45 static int pcsp_treble_info(struct snd_kcontrol *kcontrol, 46 struct snd_ctl_elem_info *uinfo) 47 { 48 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 49 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 50 uinfo->count = 1; 51 uinfo->value.enumerated.items = chip->max_treble + 1; 52 if (uinfo->value.enumerated.item > chip->max_treble) 53 uinfo->value.enumerated.item = chip->max_treble; 54 sprintf(uinfo->value.enumerated.name, "%lu", 55 (unsigned long)PCSP_CALC_RATE(uinfo->value.enumerated.item)); 56 return 0; 57 } 58 59 static int pcsp_treble_get(struct snd_kcontrol *kcontrol, 60 struct snd_ctl_elem_value *ucontrol) 61 { 62 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 63 ucontrol->value.enumerated.item[0] = chip->treble; 64 return 0; 65 } 66 67 static int pcsp_treble_put(struct snd_kcontrol *kcontrol, 68 struct snd_ctl_elem_value *ucontrol) 69 { 70 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 71 int changed = 0; 72 int treble = ucontrol->value.enumerated.item[0]; 73 if (treble != chip->treble) { 74 chip->treble = treble; 75 #if PCSP_DEBUG 76 dev_dbg(chip->card->dev, "PCSP: rate set to %li\n", PCSP_RATE()); 77 #endif 78 changed = 1; 79 } 80 return changed; 81 } 82 83 static int pcsp_pcspkr_info(struct snd_kcontrol *kcontrol, 84 struct snd_ctl_elem_info *uinfo) 85 { 86 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 87 uinfo->count = 1; 88 uinfo->value.integer.min = 0; 89 uinfo->value.integer.max = 1; 90 return 0; 91 } 92 93 static int pcsp_pcspkr_get(struct snd_kcontrol *kcontrol, 94 struct snd_ctl_elem_value *ucontrol) 95 { 96 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 97 ucontrol->value.integer.value[0] = chip->pcspkr; 98 return 0; 99 } 100 101 static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol, 102 struct snd_ctl_elem_value *ucontrol) 103 { 104 struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol); 105 int changed = 0; 106 int spkr = ucontrol->value.integer.value[0]; 107 if (spkr != chip->pcspkr) { 108 chip->pcspkr = spkr; 109 changed = 1; 110 } 111 return changed; 112 } 113 114 #define PCSP_MIXER_CONTROL(ctl_type, ctl_name) \ 115 { \ 116 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 117 .name = ctl_name, \ 118 .info = pcsp_##ctl_type##_info, \ 119 .get = pcsp_##ctl_type##_get, \ 120 .put = pcsp_##ctl_type##_put, \ 121 } 122 123 static const struct snd_kcontrol_new snd_pcsp_controls_pcm[] = { 124 PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), 125 PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), 126 }; 127 128 static const struct snd_kcontrol_new snd_pcsp_controls_spkr[] = { 129 PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"), 130 }; 131 132 static int snd_pcsp_ctls_add(struct snd_pcsp *chip, 133 const struct snd_kcontrol_new *ctls, int num) 134 { 135 int i, err; 136 struct snd_card *card = chip->card; 137 for (i = 0; i < num; i++) { 138 err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip)); 139 if (err < 0) 140 return err; 141 } 142 return 0; 143 } 144 145 int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) 146 { 147 int err; 148 struct snd_card *card = chip->card; 149 150 if (!nopcm) { 151 err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm, 152 ARRAY_SIZE(snd_pcsp_controls_pcm)); 153 if (err < 0) 154 return err; 155 } 156 err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr, 157 ARRAY_SIZE(snd_pcsp_controls_spkr)); 158 if (err < 0) 159 return err; 160 161 strcpy(card->mixername, "PC-Speaker"); 162 163 return 0; 164 } 165