aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_codec.c17
-rw-r--r--sound/pci/hda/hda_hwdep.c157
-rw-r--r--sound/pci/hda/hda_local.h5
3 files changed, 177 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 5b54ac07fcbd..0741eda78a5e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device)
393 return snd_hda_bus_free(bus); 393 return snd_hda_bus_free(bus);
394} 394}
395 395
396#ifdef CONFIG_SND_HDA_HWDEP
397static int snd_hda_bus_dev_register(struct snd_device *device)
398{
399 struct hda_bus *bus = device->device_data;
400 struct hda_codec *codec;
401 list_for_each_entry(codec, &bus->codec_list, list) {
402 snd_hda_hwdep_add_sysfs(codec);
403 }
404 return 0;
405}
406#else
407#define snd_hda_bus_dev_register NULL
408#endif
409
396/** 410/**
397 * snd_hda_bus_new - create a HDA bus 411 * snd_hda_bus_new - create a HDA bus
398 * @card: the card entry 412 * @card: the card entry
@@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
408 struct hda_bus *bus; 422 struct hda_bus *bus;
409 int err; 423 int err;
410 static struct snd_device_ops dev_ops = { 424 static struct snd_device_ops dev_ops = {
425 .dev_register = snd_hda_bus_dev_register,
411 .dev_free = snd_hda_bus_dev_free, 426 .dev_free = snd_hda_bus_dev_free,
412 }; 427 };
413 428
@@ -686,9 +701,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
686 } 701 }
687 snd_hda_codec_proc_new(codec); 702 snd_hda_codec_proc_new(codec);
688 703
689#ifdef CONFIG_SND_HDA_HWDEP
690 snd_hda_create_hwdep(codec); 704 snd_hda_create_hwdep(codec);
691#endif
692 705
693 sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, 706 sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
694 codec->subsystem_id, codec->revision_id); 707 codec->subsystem_id, codec->revision_id);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6e18a422d993..214772c8b556 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -27,6 +27,7 @@
27#include "hda_codec.h" 27#include "hda_codec.h"
28#include "hda_local.h" 28#include "hda_local.h"
29#include <sound/hda_hwdep.h> 29#include <sound/hda_hwdep.h>
30#include <sound/minors.h>
30 31
31/* 32/*
32 * write/read an out-of-bound verb 33 * write/read an out-of-bound verb
@@ -119,3 +120,159 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
119 120
120 return 0; 121 return 0;
121} 122}
123
124/*
125 * sysfs interface
126 */
127
128static int clear_codec(struct hda_codec *codec)
129{
130 snd_hda_codec_reset(codec);
131 return 0;
132}
133
134static int reconfig_codec(struct hda_codec *codec)
135{
136 int err;
137
138 snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
139 snd_hda_codec_reset(codec);
140 err = snd_hda_codec_configure(codec);
141 if (err < 0)
142 return err;
143 /* rebuild PCMs */
144 err = snd_hda_build_pcms(codec->bus);
145 if (err < 0)
146 return err;
147 /* rebuild mixers */
148 err = snd_hda_codec_build_controls(codec);
149 if (err < 0)
150 return err;
151 return 0;
152}
153
154/*
155 * allocate a string at most len chars, and remove the trailing EOL
156 */
157static char *kstrndup_noeol(const char *src, size_t len)
158{
159 char *s = kstrndup(src, len, GFP_KERNEL);
160 char *p;
161 if (!s)
162 return NULL;
163 p = strchr(s, '\n');
164 if (p)
165 *p = 0;
166 return s;
167}
168
169#define CODEC_INFO_SHOW(type) \
170static ssize_t type##_show(struct device *dev, \
171 struct device_attribute *attr, \
172 char *buf) \
173{ \
174 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
175 struct hda_codec *codec = hwdep->private_data; \
176 return sprintf(buf, "0x%x\n", codec->type); \
177}
178
179#define CODEC_INFO_STR_SHOW(type) \
180static ssize_t type##_show(struct device *dev, \
181 struct device_attribute *attr, \
182 char *buf) \
183{ \
184 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
185 struct hda_codec *codec = hwdep->private_data; \
186 return sprintf(buf, "%s\n", \
187 codec->type ? codec->type : ""); \
188}
189
190CODEC_INFO_SHOW(vendor_id);
191CODEC_INFO_SHOW(subsystem_id);
192CODEC_INFO_SHOW(revision_id);
193CODEC_INFO_SHOW(afg);
194CODEC_INFO_SHOW(mfg);
195CODEC_INFO_STR_SHOW(name);
196CODEC_INFO_STR_SHOW(modelname);
197
198#define CODEC_INFO_STORE(type) \
199static ssize_t type##_store(struct device *dev, \
200 struct device_attribute *attr, \
201 const char *buf, size_t count) \
202{ \
203 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
204 struct hda_codec *codec = hwdep->private_data; \
205 char *after; \
206 codec->type = simple_strtoul(buf, &after, 0); \
207 return count; \
208}
209
210#define CODEC_INFO_STR_STORE(type) \
211static ssize_t type##_store(struct device *dev, \
212 struct device_attribute *attr, \
213 const char *buf, size_t count) \
214{ \
215 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
216 struct hda_codec *codec = hwdep->private_data; \
217 char *s = kstrndup_noeol(buf, 64); \
218 if (!s) \
219 return -ENOMEM; \
220 kfree(codec->type); \
221 codec->type = s; \
222 return count; \
223}
224
225CODEC_INFO_STORE(vendor_id);
226CODEC_INFO_STORE(subsystem_id);
227CODEC_INFO_STORE(revision_id);
228CODEC_INFO_STR_STORE(name);
229CODEC_INFO_STR_STORE(modelname);
230
231#define CODEC_ACTION_STORE(type) \
232static ssize_t type##_store(struct device *dev, \
233 struct device_attribute *attr, \
234 const char *buf, size_t count) \
235{ \
236 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
237 struct hda_codec *codec = hwdep->private_data; \
238 int err = 0; \
239 if (*buf) \
240 err = type##_codec(codec); \
241 return err < 0 ? err : count; \
242}
243
244CODEC_ACTION_STORE(reconfig);
245CODEC_ACTION_STORE(clear);
246
247#define CODEC_ATTR_RW(type) \
248 __ATTR(type, 0644, type##_show, type##_store)
249#define CODEC_ATTR_RO(type) \
250 __ATTR_RO(type)
251#define CODEC_ATTR_WO(type) \
252 __ATTR(type, 0200, NULL, type##_store)
253
254static struct device_attribute codec_attrs[] = {
255 CODEC_ATTR_RW(vendor_id),
256 CODEC_ATTR_RW(subsystem_id),
257 CODEC_ATTR_RW(revision_id),
258 CODEC_ATTR_RO(afg),
259 CODEC_ATTR_RO(mfg),
260 CODEC_ATTR_RW(name),
261 CODEC_ATTR_RW(modelname),
262 CODEC_ATTR_WO(reconfig),
263 CODEC_ATTR_WO(clear),
264};
265
266/*
267 * create sysfs files on hwdep directory
268 */
269int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
270{
271 struct snd_hwdep *hwdep = codec->hwdep;
272 int i;
273
274 for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
275 snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
276 hwdep->device, &codec_attrs[i]);
277 return 0;
278}
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index d8283f1ab21a..4a08c31b498a 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -401,7 +401,12 @@ void snd_hda_ctls_clear(struct hda_codec *codec);
401/* 401/*
402 * hwdep interface 402 * hwdep interface
403 */ 403 */
404#ifdef CONFIG_SND_HDA_HWDEP
404int snd_hda_create_hwdep(struct hda_codec *codec); 405int snd_hda_create_hwdep(struct hda_codec *codec);
406int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
407#else
408static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
409#endif
405 410
406/* 411/*
407 * power-management 412 * power-management