diff options
author | Matthew Ranostay <mranostay@embeddedalley.com> | 2008-07-18 12:20:52 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-07-20 13:17:49 -0400 |
commit | 1cd2224cd01898a13138f4ab476932cfb689839e (patch) | |
tree | b482e8f8e6e51fd5143ac9ef7edc88194b031d9c /sound/pci/hda/hda_beep.c | |
parent | 68c072388d2339af504c033a51886ea7c6b8d806 (diff) |
ALSA: hda: digital pc-beep support hd-audio codecs
Added digital pc-beep support using linear tone generation for hd-codecs along
with initial support for several IDT codecs.
Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_beep.c')
-rw-r--r-- | sound/pci/hda/hda_beep.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c new file mode 100644 index 000000000000..5a764c481391 --- /dev/null +++ b/sound/pci/hda/hda_beep.c | |||
@@ -0,0 +1,134 @@ | |||
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/pci.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <sound/core.h> | ||
26 | #include "hda_beep.h" | ||
27 | |||
28 | enum { | ||
29 | DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ | ||
30 | DIGBEEP_HZ_MIN = 93750, /* 93.750 Hz */ | ||
31 | DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ | ||
32 | }; | ||
33 | |||
34 | static void snd_hda_generate_beep(struct work_struct *work) | ||
35 | { | ||
36 | struct hda_beep *beep = | ||
37 | container_of(work, struct hda_beep, beep_work); | ||
38 | struct hda_codec *codec = beep->codec; | ||
39 | |||
40 | /* generate tone */ | ||
41 | snd_hda_codec_write_cache(codec, beep->nid, 0, | ||
42 | AC_VERB_SET_BEEP_CONTROL, beep->tone); | ||
43 | } | ||
44 | |||
45 | static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, | ||
46 | unsigned int code, int hz) | ||
47 | { | ||
48 | struct hda_beep *beep = input_get_drvdata(dev); | ||
49 | |||
50 | switch (code) { | ||
51 | case SND_BELL: | ||
52 | if (hz) | ||
53 | hz = 1000; | ||
54 | case SND_TONE: | ||
55 | hz *= 1000; /* fixed point */ | ||
56 | hz = hz - DIGBEEP_HZ_MIN; | ||
57 | if (hz < 0) | ||
58 | hz = 0; /* turn off PC beep*/ | ||
59 | else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) | ||
60 | hz = 0xff; | ||
61 | else { | ||
62 | hz /= DIGBEEP_HZ_STEP; | ||
63 | hz++; | ||
64 | } | ||
65 | break; | ||
66 | default: | ||
67 | return -1; | ||
68 | } | ||
69 | beep->tone = hz; | ||
70 | |||
71 | /* schedule beep event */ | ||
72 | schedule_work(&beep->beep_work); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | ||
77 | { | ||
78 | struct input_dev *input_dev; | ||
79 | struct hda_beep *beep; | ||
80 | int err; | ||
81 | |||
82 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); | ||
83 | if (beep == NULL) | ||
84 | return -ENOMEM; | ||
85 | snprintf(beep->phys, sizeof(beep->phys), | ||
86 | "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); | ||
87 | input_dev = input_allocate_device(); | ||
88 | |||
89 | /* setup digital beep device */ | ||
90 | input_dev->name = "HDA Digital PCBeep"; | ||
91 | input_dev->phys = beep->phys; | ||
92 | input_dev->id.bustype = BUS_PCI; | ||
93 | |||
94 | input_dev->id.vendor = codec->vendor_id >> 16; | ||
95 | input_dev->id.product = codec->vendor_id & 0xffff; | ||
96 | input_dev->id.version = 0x01; | ||
97 | |||
98 | input_dev->evbit[0] = BIT_MASK(EV_SND); | ||
99 | input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); | ||
100 | input_dev->event = snd_hda_beep_event; | ||
101 | input_dev->dev.parent = &codec->bus->pci->dev; | ||
102 | input_set_drvdata(input_dev, beep); | ||
103 | |||
104 | err = input_register_device(input_dev); | ||
105 | if (err < 0) { | ||
106 | kfree(input_dev); | ||
107 | kfree(beep); | ||
108 | return err; | ||
109 | } | ||
110 | |||
111 | /* enable linear scale */ | ||
112 | snd_hda_codec_write(codec, nid, 0, | ||
113 | AC_VERB_SET_DIGI_CONVERT_2, 0x01); | ||
114 | |||
115 | beep->nid = nid; | ||
116 | beep->dev = input_dev; | ||
117 | beep->codec = codec; | ||
118 | codec->beep = beep; | ||
119 | |||
120 | INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | void snd_hda_detach_beep_device(struct hda_codec *codec) | ||
125 | { | ||
126 | struct hda_beep *beep = codec->beep; | ||
127 | if (beep) { | ||
128 | cancel_work_sync(&beep->beep_work); | ||
129 | flush_scheduled_work(); | ||
130 | |||
131 | input_unregister_device(beep->dev); | ||
132 | kfree(beep); | ||
133 | } | ||
134 | } | ||