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