1 /* 2 * Digital Beep Input Interface for HD-audio codec 3 * 4 * Author: Matthew Ranostay <mranostay@embeddedalley.com> 5 * Copyright (c) 2008 Embedded Alley Solutions Inc 6 * 7 * This driver is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This driver is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <linux/input.h> 23 #include <linux/slab.h> 24 #include <linux/workqueue.h> 25 #include <linux/export.h> 26 #include <sound/core.h> 27 #include "hda_beep.h" 28 #include "hda_local.h" 29 30 enum { 31 DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ 32 DIGBEEP_HZ_MIN = 93750, /* 93.750 Hz */ 33 DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ 34 }; 35 36 static void snd_hda_generate_beep(struct work_struct *work) 37 { 38 struct hda_beep *beep = 39 container_of(work, struct hda_beep, beep_work); 40 struct hda_codec *codec = beep->codec; 41 int tone; 42 43 if (!beep->enabled) 44 return; 45 46 tone = beep->tone; 47 if (tone && !beep->playing) { 48 snd_hda_power_up(codec); 49 beep->playing = 1; 50 } 51 /* generate tone */ 52 snd_hda_codec_write(codec, beep->nid, 0, 53 AC_VERB_SET_BEEP_CONTROL, tone); 54 if (!tone && beep->playing) { 55 beep->playing = 0; 56 snd_hda_power_down(codec); 57 } 58 } 59 60 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 61 * 62 * The tone frequency of beep generator on IDT/STAC codecs is 63 * defined from the 8bit tone parameter, in Hz, 64 * freq = 48000 * (257 - tone) / 1024 65 * that is from 12kHz to 93.75Hz in steps of 46.875 Hz 66 */ 67 static int beep_linear_tone(struct hda_beep *beep, int hz) 68 { 69 if (hz <= 0) 70 return 0; 71 hz *= 1000; /* fixed point */ 72 hz = hz - DIGBEEP_HZ_MIN 73 + DIGBEEP_HZ_STEP / 2; /* round to nearest step */ 74 if (hz < 0) 75 hz = 0; /* turn off PC beep*/ 76 else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) 77 hz = 1; /* max frequency */ 78 else { 79 hz /= DIGBEEP_HZ_STEP; 80 hz = 255 - hz; 81 } 82 return hz; 83 } 84 85 /* HD-audio standard beep tone parameter calculation 86 * 87 * The tone frequency in Hz is calculated as 88 * freq = 48000 / (tone * 4) 89 * from 47Hz to 12kHz 90 */ 91 static int beep_standard_tone(struct hda_beep *beep, int hz) 92 { 93 if (hz <= 0) 94 return 0; /* disabled */ 95 hz = 12000 / hz; 96 if (hz > 0xff) 97 return 0xff; 98 if (hz <= 0) 99 return 1; 100 return hz; 101 } 102 103 static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, 104 unsigned int code, int hz) 105 { 106 struct hda_beep *beep = input_get_drvdata(dev); 107 108 switch (code) { 109 case SND_BELL: 110 if (hz) 111 hz = 1000; 112 /* fallthru */ 113 case SND_TONE: 114 if (beep->linear_tone) 115 beep->tone = beep_linear_tone(beep, hz); 116 else 117 beep->tone = beep_standard_tone(beep, hz); 118 break; 119 default: 120 return -1; 121 } 122 123 /* schedule beep event */ 124 schedule_work(&beep->beep_work); 125 return 0; 126 } 127 128 static void turn_off_beep(struct hda_beep *beep) 129 { 130 cancel_work_sync(&beep->beep_work); 131 if (beep->playing) { 132 /* turn off beep */ 133 snd_hda_codec_write(beep->codec, beep->nid, 0, 134 AC_VERB_SET_BEEP_CONTROL, 0); 135 beep->playing = 0; 136 snd_hda_power_down(beep->codec); 137 } 138 } 139 140 static void snd_hda_do_detach(struct hda_beep *beep) 141 { 142 if (beep->registered) 143 input_unregister_device(beep->dev); 144 else 145 input_free_device(beep->dev); 146 beep->dev = NULL; 147 turn_off_beep(beep); 148 } 149 150 static int snd_hda_do_attach(struct hda_beep *beep) 151 { 152 struct input_dev *input_dev; 153 struct hda_codec *codec = beep->codec; 154 155 input_dev = input_allocate_device(); 156 if (!input_dev) 157 return -ENOMEM; 158 159 /* setup digital beep device */ 160 input_dev->name = "HDA Digital PCBeep"; 161 input_dev->phys = beep->phys; 162 input_dev->id.bustype = BUS_PCI; 163 164 input_dev->id.vendor = codec->vendor_id >> 16; 165 input_dev->id.product = codec->vendor_id & 0xffff; 166 input_dev->id.version = 0x01; 167 168 input_dev->evbit[0] = BIT_MASK(EV_SND); 169 input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 170 input_dev->event = snd_hda_beep_event; 171 input_dev->dev.parent = &codec->dev; 172 input_set_drvdata(input_dev, beep); 173 174 beep->dev = input_dev; 175 return 0; 176 } 177 178 int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) 179 { 180 struct hda_beep *beep = codec->beep; 181 if (!beep) 182 return 0; 183 enable = !!enable; 184 if (beep->enabled != enable) { 185 beep->enabled = enable; 186 if (!enable) 187 turn_off_beep(beep); 188 return 1; 189 } 190 return 0; 191 } 192 EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); 193 194 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) 195 { 196 struct hda_beep *beep; 197 int err; 198 199 if (!snd_hda_get_bool_hint(codec, "beep")) 200 return 0; /* disabled explicitly by hints */ 201 if (codec->beep_mode == HDA_BEEP_MODE_OFF) 202 return 0; /* disabled by module option */ 203 204 beep = kzalloc(sizeof(*beep), GFP_KERNEL); 205 if (beep == NULL) 206 return -ENOMEM; 207 snprintf(beep->phys, sizeof(beep->phys), 208 "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); 209 /* enable linear scale */ 210 snd_hda_codec_write_cache(codec, nid, 0, 211 AC_VERB_SET_DIGI_CONVERT_2, 0x01); 212 213 beep->nid = nid; 214 beep->codec = codec; 215 codec->beep = beep; 216 217 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); 218 mutex_init(&beep->mutex); 219 220 err = snd_hda_do_attach(beep); 221 if (err < 0) { 222 kfree(beep); 223 codec->beep = NULL; 224 return err; 225 } 226 227 return 0; 228 } 229 EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); 230 231 void snd_hda_detach_beep_device(struct hda_codec *codec) 232 { 233 struct hda_beep *beep = codec->beep; 234 if (beep) { 235 if (beep->dev) 236 snd_hda_do_detach(beep); 237 codec->beep = NULL; 238 kfree(beep); 239 } 240 } 241 EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); 242 243 int snd_hda_register_beep_device(struct hda_codec *codec) 244 { 245 struct hda_beep *beep = codec->beep; 246 int err; 247 248 if (!beep || !beep->dev) 249 return 0; 250 251 err = input_register_device(beep->dev); 252 if (err < 0) { 253 codec_err(codec, "hda_beep: unable to register input device\n"); 254 input_free_device(beep->dev); 255 codec->beep = NULL; 256 kfree(beep); 257 return err; 258 } 259 beep->registered = true; 260 return 0; 261 } 262 EXPORT_SYMBOL_GPL(snd_hda_register_beep_device); 263 264 static bool ctl_has_mute(struct snd_kcontrol *kcontrol) 265 { 266 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 267 return query_amp_caps(codec, get_amp_nid(kcontrol), 268 get_amp_direction(kcontrol)) & AC_AMPCAP_MUTE; 269 } 270 271 /* get/put callbacks for beep mute mixer switches */ 272 int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, 273 struct snd_ctl_elem_value *ucontrol) 274 { 275 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 276 struct hda_beep *beep = codec->beep; 277 if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) { 278 ucontrol->value.integer.value[0] = 279 ucontrol->value.integer.value[1] = beep->enabled; 280 return 0; 281 } 282 return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 283 } 284 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep); 285 286 int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, 287 struct snd_ctl_elem_value *ucontrol) 288 { 289 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 290 struct hda_beep *beep = codec->beep; 291 if (beep) { 292 u8 chs = get_amp_channels(kcontrol); 293 int enable = 0; 294 long *valp = ucontrol->value.integer.value; 295 if (chs & 1) { 296 enable |= *valp; 297 valp++; 298 } 299 if (chs & 2) 300 enable |= *valp; 301 snd_hda_enable_beep_device(codec, enable); 302 } 303 if (!ctl_has_mute(kcontrol)) 304 return 0; 305 return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 306 } 307 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put_beep); 308