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