1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Digital Beep Input Interface for HD-audio codec 4 * 5 * Author: Matt Ranostay <matt.ranostay@konsulko.com> 6 * Copyright (c) 2008 Embedded Alley Solutions Inc 7 */ 8 9 #include <linux/input.h> 10 #include <linux/slab.h> 11 #include <linux/workqueue.h> 12 #include <linux/export.h> 13 #include <sound/core.h> 14 #include "hda_beep.h" 15 #include "hda_local.h" 16 17 enum { 18 DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ 19 DIGBEEP_HZ_MIN = 93750, /* 93.750 Hz */ 20 DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ 21 }; 22 23 /* generate or stop tone */ 24 static void generate_tone(struct hda_beep *beep, int tone) 25 { 26 struct hda_codec *codec = beep->codec; 27 28 if (tone && !beep->playing) { 29 snd_hda_power_up(codec); 30 if (beep->power_hook) 31 beep->power_hook(beep, true); 32 beep->playing = 1; 33 } 34 snd_hda_codec_write(codec, beep->nid, 0, 35 AC_VERB_SET_BEEP_CONTROL, tone); 36 if (!tone && beep->playing) { 37 beep->playing = 0; 38 if (beep->power_hook) 39 beep->power_hook(beep, false); 40 snd_hda_power_down(codec); 41 } 42 } 43 44 static void snd_hda_generate_beep(struct work_struct *work) 45 { 46 struct hda_beep *beep = 47 container_of(work, struct hda_beep, beep_work); 48 49 if (beep->enabled) 50 generate_tone(beep, beep->tone); 51 } 52 53 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 54 * 55 * The tone frequency of beep generator on IDT/STAC codecs is 56 * defined from the 8bit tone parameter, in Hz, 57 * freq = 48000 * (257 - tone) / 1024 58 * that is from 12kHz to 93.75Hz in steps of 46.875 Hz 59 */ 60 static int beep_linear_tone(struct hda_beep *beep, int hz) 61 { 62 if (hz <= 0) 63 return 0; 64 hz *= 1000; /* fixed point */ 65 hz = hz - DIGBEEP_HZ_MIN 66 + DIGBEEP_HZ_STEP / 2; /* round to nearest step */ 67 if (hz < 0) 68 hz = 0; /* turn off PC beep*/ 69 else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) 70 hz = 1; /* max frequency */ 71 else { 72 hz /= DIGBEEP_HZ_STEP; 73 hz = 255 - hz; 74 } 75 return hz; 76 } 77 78 /* HD-audio standard beep tone parameter calculation 79 * 80 * The tone frequency in Hz is calculated as 81 * freq = 48000 / (tone * 4) 82 * from 47Hz to 12kHz 83 */ 84 static int beep_standard_tone(struct hda_beep *beep, int hz) 85 { 86 if (hz <= 0) 87 return 0; /* disabled */ 88 hz = 12000 / hz; 89 if (hz > 0xff) 90 return 0xff; 91 if (hz <= 0) 92 return 1; 93 return hz; 94 } 95 96 static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, 97 unsigned int code, int hz) 98 { 99 struct hda_beep *beep = input_get_drvdata(dev); 100 101 switch (code) { 102 case SND_BELL: 103 if (hz) 104 hz = 1000; 105 /* fallthru */ 106 case SND_TONE: 107 if (beep->linear_tone) 108 beep->tone = beep_linear_tone(beep, hz); 109 else 110 beep->tone = beep_standard_tone(beep, hz); 111 break; 112 default: 113 return -1; 114 } 115 116 /* schedule beep event */ 117 schedule_work(&beep->beep_work); 118 return 0; 119 } 120 121 static void turn_off_beep(struct hda_beep *beep) 122 { 123 cancel_work_sync(&beep->beep_work); 124 if (beep->playing) { 125 /* turn off beep */ 126 generate_tone(beep, 0); 127 } 128 } 129 130 /** 131 * snd_hda_enable_beep_device - Turn on/off beep sound 132 * @codec: the HDA codec 133 * @enable: flag to turn on/off 134 */ 135 int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) 136 { 137 struct hda_beep *beep = codec->beep; 138 if (!beep) 139 return 0; 140 enable = !!enable; 141 if (beep->enabled != enable) { 142 beep->enabled = enable; 143 if (!enable) 144 turn_off_beep(beep); 145 return 1; 146 } 147 return 0; 148 } 149 EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); 150 151 static int beep_dev_register(struct snd_device *device) 152 { 153 struct hda_beep *beep = device->device_data; 154 int err; 155 156 err = input_register_device(beep->dev); 157 if (!err) 158 beep->registered = true; 159 return err; 160 } 161 162 static int beep_dev_disconnect(struct snd_device *device) 163 { 164 struct hda_beep *beep = device->device_data; 165 166 if (beep->registered) 167 input_unregister_device(beep->dev); 168 else 169 input_free_device(beep->dev); 170 turn_off_beep(beep); 171 return 0; 172 } 173 174 static int beep_dev_free(struct snd_device *device) 175 { 176 struct hda_beep *beep = device->device_data; 177 178 beep->codec->beep = NULL; 179 kfree(beep); 180 return 0; 181 } 182 183 /** 184 * snd_hda_attach_beep_device - Attach a beep input device 185 * @codec: the HDA codec 186 * @nid: beep NID 187 * 188 * Attach a beep object to the given widget. If beep hint is turned off 189 * explicitly or beep_mode of the codec is turned off, this doesn't nothing. 190 * 191 * Currently, only one beep device is allowed to each codec. 192 */ 193 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) 194 { 195 static const struct snd_device_ops ops = { 196 .dev_register = beep_dev_register, 197 .dev_disconnect = beep_dev_disconnect, 198 .dev_free = beep_dev_free, 199 }; 200 struct input_dev *input_dev; 201 struct hda_beep *beep; 202 int err; 203 204 if (!snd_hda_get_bool_hint(codec, "beep")) 205 return 0; /* disabled explicitly by hints */ 206 if (codec->beep_mode == HDA_BEEP_MODE_OFF) 207 return 0; /* disabled by module option */ 208 209 beep = kzalloc(sizeof(*beep), GFP_KERNEL); 210 if (beep == NULL) 211 return -ENOMEM; 212 snprintf(beep->phys, sizeof(beep->phys), 213 "card%d/codec#%d/beep0", codec->card->number, codec->addr); 214 /* enable linear scale */ 215 snd_hda_codec_write_cache(codec, nid, 0, 216 AC_VERB_SET_DIGI_CONVERT_2, 0x01); 217 218 beep->nid = nid; 219 beep->codec = codec; 220 codec->beep = beep; 221 222 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); 223 mutex_init(&beep->mutex); 224 225 input_dev = input_allocate_device(); 226 if (!input_dev) { 227 err = -ENOMEM; 228 goto err_free; 229 } 230 231 /* setup digital beep device */ 232 input_dev->name = "HDA Digital PCBeep"; 233 input_dev->phys = beep->phys; 234 input_dev->id.bustype = BUS_PCI; 235 input_dev->dev.parent = &codec->card->card_dev; 236 237 input_dev->id.vendor = codec->core.vendor_id >> 16; 238 input_dev->id.product = codec->core.vendor_id & 0xffff; 239 input_dev->id.version = 0x01; 240 241 input_dev->evbit[0] = BIT_MASK(EV_SND); 242 input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 243 input_dev->event = snd_hda_beep_event; 244 input_set_drvdata(input_dev, beep); 245 246 beep->dev = input_dev; 247 248 err = snd_device_new(codec->card, SNDRV_DEV_JACK, beep, &ops); 249 if (err < 0) 250 goto err_input; 251 252 return 0; 253 254 err_input: 255 input_free_device(beep->dev); 256 err_free: 257 kfree(beep); 258 codec->beep = NULL; 259 return err; 260 } 261 EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); 262 263 /** 264 * snd_hda_detach_beep_device - Detach the beep device 265 * @codec: the HDA codec 266 */ 267 void snd_hda_detach_beep_device(struct hda_codec *codec) 268 { 269 if (!codec->bus->shutdown && codec->beep) 270 snd_device_free(codec->card, codec->beep); 271 } 272 EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); 273 274 static bool ctl_has_mute(struct snd_kcontrol *kcontrol) 275 { 276 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 277 return query_amp_caps(codec, get_amp_nid(kcontrol), 278 get_amp_direction(kcontrol)) & AC_AMPCAP_MUTE; 279 } 280 281 /* get/put callbacks for beep mute mixer switches */ 282 283 /** 284 * snd_hda_mixer_amp_switch_get_beep - Get callback for beep controls 285 * @kcontrol: ctl element 286 * @ucontrol: pointer to get/store the data 287 */ 288 int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, 289 struct snd_ctl_elem_value *ucontrol) 290 { 291 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 292 struct hda_beep *beep = codec->beep; 293 if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) { 294 ucontrol->value.integer.value[0] = 295 ucontrol->value.integer.value[1] = beep->enabled; 296 return 0; 297 } 298 return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 299 } 300 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep); 301 302 /** 303 * snd_hda_mixer_amp_switch_put_beep - Put callback for beep controls 304 * @kcontrol: ctl element 305 * @ucontrol: pointer to get/store the data 306 */ 307 int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, 308 struct snd_ctl_elem_value *ucontrol) 309 { 310 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 311 struct hda_beep *beep = codec->beep; 312 if (beep) { 313 u8 chs = get_amp_channels(kcontrol); 314 int enable = 0; 315 long *valp = ucontrol->value.integer.value; 316 if (chs & 1) { 317 enable |= *valp; 318 valp++; 319 } 320 if (chs & 2) 321 enable |= *valp; 322 snd_hda_enable_beep_device(codec, enable); 323 } 324 if (!ctl_has_mute(kcontrol)) 325 return 0; 326 return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 327 } 328 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put_beep); 329