Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/hda/common/sysfs.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* sysfs interface for HD-audio codec
4
*
5
* Copyright (c) 2014 Takashi Iwai <[email protected]>
6
*
7
* split from hda_hwdep.c
8
*/
9
10
#include <linux/init.h>
11
#include <linux/slab.h>
12
#include <linux/compat.h>
13
#include <linux/mutex.h>
14
#include <linux/ctype.h>
15
#include <linux/string.h>
16
#include <linux/export.h>
17
#include <sound/core.h>
18
#include <sound/hda_codec.h>
19
#include "hda_local.h"
20
#include <sound/hda_hwdep.h>
21
#include <sound/minors.h>
22
23
/* hint string pair */
24
struct hda_hint {
25
const char *key;
26
const char *val; /* contained in the same alloc as key */
27
};
28
29
static ssize_t power_on_acct_show(struct device *dev,
30
struct device_attribute *attr,
31
char *buf)
32
{
33
struct hda_codec *codec = dev_get_drvdata(dev);
34
snd_hda_update_power_acct(codec);
35
return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
36
}
37
38
static ssize_t power_off_acct_show(struct device *dev,
39
struct device_attribute *attr,
40
char *buf)
41
{
42
struct hda_codec *codec = dev_get_drvdata(dev);
43
snd_hda_update_power_acct(codec);
44
return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
45
}
46
47
static DEVICE_ATTR_RO(power_on_acct);
48
static DEVICE_ATTR_RO(power_off_acct);
49
50
#define CODEC_INFO_SHOW(type, field) \
51
static ssize_t type##_show(struct device *dev, \
52
struct device_attribute *attr, \
53
char *buf) \
54
{ \
55
struct hda_codec *codec = dev_get_drvdata(dev); \
56
return sysfs_emit(buf, "0x%x\n", codec->field); \
57
}
58
59
#define CODEC_INFO_STR_SHOW(type, field) \
60
static ssize_t type##_show(struct device *dev, \
61
struct device_attribute *attr, \
62
char *buf) \
63
{ \
64
struct hda_codec *codec = dev_get_drvdata(dev); \
65
return sysfs_emit(buf, "%s\n", \
66
codec->field ? codec->field : ""); \
67
}
68
69
CODEC_INFO_SHOW(vendor_id, core.vendor_id);
70
CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
71
CODEC_INFO_SHOW(revision_id, core.revision_id);
72
CODEC_INFO_SHOW(afg, core.afg);
73
CODEC_INFO_SHOW(mfg, core.mfg);
74
CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
75
CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
76
CODEC_INFO_STR_SHOW(modelname, modelname);
77
78
static ssize_t pin_configs_show(struct hda_codec *codec,
79
struct snd_array *list,
80
char *buf)
81
{
82
const struct hda_pincfg *pin;
83
int i, len = 0;
84
mutex_lock(&codec->user_mutex);
85
snd_array_for_each(list, i, pin) {
86
len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n",
87
pin->nid, pin->cfg);
88
}
89
mutex_unlock(&codec->user_mutex);
90
return len;
91
}
92
93
static ssize_t init_pin_configs_show(struct device *dev,
94
struct device_attribute *attr,
95
char *buf)
96
{
97
struct hda_codec *codec = dev_get_drvdata(dev);
98
return pin_configs_show(codec, &codec->init_pins, buf);
99
}
100
101
static ssize_t driver_pin_configs_show(struct device *dev,
102
struct device_attribute *attr,
103
char *buf)
104
{
105
struct hda_codec *codec = dev_get_drvdata(dev);
106
return pin_configs_show(codec, &codec->driver_pins, buf);
107
}
108
109
#ifdef CONFIG_SND_HDA_RECONFIG
110
111
/*
112
* sysfs interface
113
*/
114
115
static int clear_codec(struct hda_codec *codec)
116
{
117
int err;
118
119
err = snd_hda_codec_reset(codec);
120
if (err < 0) {
121
codec_err(codec, "The codec is being used, can't free.\n");
122
return err;
123
}
124
snd_hda_sysfs_clear(codec);
125
return 0;
126
}
127
128
static int reconfig_codec(struct hda_codec *codec)
129
{
130
int err;
131
132
snd_hda_power_up(codec);
133
codec_info(codec, "hda-codec: reconfiguring\n");
134
err = snd_hda_codec_reset(codec);
135
if (err < 0) {
136
codec_err(codec,
137
"The codec is being used, can't reconfigure.\n");
138
goto error;
139
}
140
err = device_reprobe(hda_codec_dev(codec));
141
if (err < 0)
142
goto error;
143
err = snd_card_register(codec->card);
144
error:
145
snd_hda_power_down(codec);
146
return err;
147
}
148
149
/*
150
* allocate a string at most len chars, and remove the trailing EOL
151
*/
152
static char *kstrndup_noeol(const char *src, size_t len)
153
{
154
char *s = kstrndup(src, len, GFP_KERNEL);
155
char *p;
156
if (!s)
157
return NULL;
158
p = strchr(s, '\n');
159
if (p)
160
*p = 0;
161
return s;
162
}
163
164
#define CODEC_INFO_STORE(type, field) \
165
static ssize_t type##_store(struct device *dev, \
166
struct device_attribute *attr, \
167
const char *buf, size_t count) \
168
{ \
169
struct hda_codec *codec = dev_get_drvdata(dev); \
170
unsigned long val; \
171
int err = kstrtoul(buf, 0, &val); \
172
if (err < 0) \
173
return err; \
174
codec->field = val; \
175
return count; \
176
}
177
178
#define CODEC_INFO_STR_STORE(type, field) \
179
static ssize_t type##_store(struct device *dev, \
180
struct device_attribute *attr, \
181
const char *buf, size_t count) \
182
{ \
183
struct hda_codec *codec = dev_get_drvdata(dev); \
184
char *s = kstrndup_noeol(buf, 64); \
185
if (!s) \
186
return -ENOMEM; \
187
kfree(codec->field); \
188
codec->field = s; \
189
return count; \
190
}
191
192
CODEC_INFO_STORE(vendor_id, core.vendor_id);
193
CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
194
CODEC_INFO_STORE(revision_id, core.revision_id);
195
CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
196
CODEC_INFO_STR_STORE(chip_name, core.chip_name);
197
CODEC_INFO_STR_STORE(modelname, modelname);
198
199
#define CODEC_ACTION_STORE(type) \
200
static ssize_t type##_store(struct device *dev, \
201
struct device_attribute *attr, \
202
const char *buf, size_t count) \
203
{ \
204
struct hda_codec *codec = dev_get_drvdata(dev); \
205
int err = 0; \
206
if (*buf) \
207
err = type##_codec(codec); \
208
return err < 0 ? err : count; \
209
}
210
211
CODEC_ACTION_STORE(reconfig);
212
CODEC_ACTION_STORE(clear);
213
214
static ssize_t init_verbs_show(struct device *dev,
215
struct device_attribute *attr,
216
char *buf)
217
{
218
struct hda_codec *codec = dev_get_drvdata(dev);
219
const struct hda_verb *v;
220
int i, len = 0;
221
mutex_lock(&codec->user_mutex);
222
snd_array_for_each(&codec->init_verbs, i, v) {
223
len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n",
224
v->nid, v->verb, v->param);
225
}
226
mutex_unlock(&codec->user_mutex);
227
return len;
228
}
229
230
static int parse_init_verbs(struct hda_codec *codec, const char *buf)
231
{
232
struct hda_verb *v;
233
int nid, verb, param;
234
235
if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
236
return -EINVAL;
237
if (!nid || !verb)
238
return -EINVAL;
239
mutex_lock(&codec->user_mutex);
240
v = snd_array_new(&codec->init_verbs);
241
if (!v) {
242
mutex_unlock(&codec->user_mutex);
243
return -ENOMEM;
244
}
245
v->nid = nid;
246
v->verb = verb;
247
v->param = param;
248
mutex_unlock(&codec->user_mutex);
249
return 0;
250
}
251
252
static ssize_t init_verbs_store(struct device *dev,
253
struct device_attribute *attr,
254
const char *buf, size_t count)
255
{
256
struct hda_codec *codec = dev_get_drvdata(dev);
257
int err = parse_init_verbs(codec, buf);
258
if (err < 0)
259
return err;
260
return count;
261
}
262
263
static ssize_t hints_show(struct device *dev,
264
struct device_attribute *attr,
265
char *buf)
266
{
267
struct hda_codec *codec = dev_get_drvdata(dev);
268
const struct hda_hint *hint;
269
int i, len = 0;
270
mutex_lock(&codec->user_mutex);
271
snd_array_for_each(&codec->hints, i, hint) {
272
len += sysfs_emit_at(buf, len, "%s = %s\n",
273
hint->key, hint->val);
274
}
275
mutex_unlock(&codec->user_mutex);
276
return len;
277
}
278
279
static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
280
{
281
struct hda_hint *hint;
282
int i;
283
284
snd_array_for_each(&codec->hints, i, hint) {
285
if (!strcmp(hint->key, key))
286
return hint;
287
}
288
return NULL;
289
}
290
291
static void remove_trail_spaces(char *str)
292
{
293
char *p;
294
if (!*str)
295
return;
296
p = str + strlen(str) - 1;
297
for (; isspace(*p); p--) {
298
*p = 0;
299
if (p == str)
300
return;
301
}
302
}
303
304
#define MAX_HINTS 1024
305
306
static int parse_hints(struct hda_codec *codec, const char *buf)
307
{
308
char *key, *val;
309
struct hda_hint *hint;
310
int err = 0;
311
312
buf = skip_spaces(buf);
313
if (!*buf || *buf == '#' || *buf == '\n')
314
return 0;
315
if (*buf == '=')
316
return -EINVAL;
317
key = kstrndup_noeol(buf, 1024);
318
if (!key)
319
return -ENOMEM;
320
/* extract key and val */
321
val = strchr(key, '=');
322
if (!val) {
323
kfree(key);
324
return -EINVAL;
325
}
326
*val++ = 0;
327
val = skip_spaces(val);
328
remove_trail_spaces(key);
329
remove_trail_spaces(val);
330
mutex_lock(&codec->user_mutex);
331
hint = get_hint(codec, key);
332
if (hint) {
333
/* replace */
334
kfree(hint->key);
335
hint->key = key;
336
hint->val = val;
337
goto unlock;
338
}
339
/* allocate a new hint entry */
340
if (codec->hints.used >= MAX_HINTS)
341
hint = NULL;
342
else
343
hint = snd_array_new(&codec->hints);
344
if (hint) {
345
hint->key = key;
346
hint->val = val;
347
} else {
348
err = -ENOMEM;
349
}
350
unlock:
351
mutex_unlock(&codec->user_mutex);
352
if (err)
353
kfree(key);
354
return err;
355
}
356
357
static ssize_t hints_store(struct device *dev,
358
struct device_attribute *attr,
359
const char *buf, size_t count)
360
{
361
struct hda_codec *codec = dev_get_drvdata(dev);
362
int err = parse_hints(codec, buf);
363
if (err < 0)
364
return err;
365
return count;
366
}
367
368
static ssize_t user_pin_configs_show(struct device *dev,
369
struct device_attribute *attr,
370
char *buf)
371
{
372
struct hda_codec *codec = dev_get_drvdata(dev);
373
return pin_configs_show(codec, &codec->user_pins, buf);
374
}
375
376
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
377
{
378
int nid, cfg, err;
379
380
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
381
return -EINVAL;
382
if (!nid)
383
return -EINVAL;
384
mutex_lock(&codec->user_mutex);
385
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
386
mutex_unlock(&codec->user_mutex);
387
return err;
388
}
389
390
static ssize_t user_pin_configs_store(struct device *dev,
391
struct device_attribute *attr,
392
const char *buf, size_t count)
393
{
394
struct hda_codec *codec = dev_get_drvdata(dev);
395
int err = parse_user_pin_configs(codec, buf);
396
if (err < 0)
397
return err;
398
return count;
399
}
400
401
/* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
402
static DEVICE_ATTR_RW(init_verbs);
403
static DEVICE_ATTR_RW(hints);
404
static DEVICE_ATTR_RW(user_pin_configs);
405
static DEVICE_ATTR_WO(reconfig);
406
static DEVICE_ATTR_WO(clear);
407
408
/**
409
* snd_hda_get_hint - Look for hint string
410
* @codec: the HDA codec
411
* @key: the hint key string
412
*
413
* Look for a hint key/value pair matching with the given key string
414
* and returns the value string. If nothing found, returns NULL.
415
*/
416
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
417
{
418
struct hda_hint *hint = get_hint(codec, key);
419
return hint ? hint->val : NULL;
420
}
421
EXPORT_SYMBOL_GPL(snd_hda_get_hint);
422
423
/**
424
* snd_hda_get_bool_hint - Get a boolean hint value
425
* @codec: the HDA codec
426
* @key: the hint key string
427
*
428
* Look for a hint key/value pair matching with the given key string
429
* and returns a boolean value parsed from the value. If no matching
430
* key is found, return a negative value.
431
*/
432
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
433
{
434
const char *p;
435
int ret;
436
437
mutex_lock(&codec->user_mutex);
438
p = snd_hda_get_hint(codec, key);
439
if (!p || !*p)
440
ret = -ENOENT;
441
else {
442
switch (toupper(*p)) {
443
case 'T': /* true */
444
case 'Y': /* yes */
445
case '1':
446
ret = 1;
447
break;
448
default:
449
ret = 0;
450
break;
451
}
452
}
453
mutex_unlock(&codec->user_mutex);
454
return ret;
455
}
456
EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
457
458
/**
459
* snd_hda_get_int_hint - Get an integer hint value
460
* @codec: the HDA codec
461
* @key: the hint key string
462
* @valp: pointer to store a value
463
*
464
* Look for a hint key/value pair matching with the given key string
465
* and stores the integer value to @valp. If no matching key is found,
466
* return a negative error code. Otherwise it returns zero.
467
*/
468
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
469
{
470
const char *p;
471
unsigned long val;
472
int ret;
473
474
mutex_lock(&codec->user_mutex);
475
p = snd_hda_get_hint(codec, key);
476
if (!p)
477
ret = -ENOENT;
478
else if (kstrtoul(p, 0, &val))
479
ret = -EINVAL;
480
else {
481
*valp = val;
482
ret = 0;
483
}
484
mutex_unlock(&codec->user_mutex);
485
return ret;
486
}
487
EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
488
#endif /* CONFIG_SND_HDA_RECONFIG */
489
490
/*
491
* common sysfs attributes
492
*/
493
#ifdef CONFIG_SND_HDA_RECONFIG
494
#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RW(name)
495
#else
496
#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RO(name)
497
#endif
498
static RECONFIG_DEVICE_ATTR(vendor_id);
499
static RECONFIG_DEVICE_ATTR(subsystem_id);
500
static RECONFIG_DEVICE_ATTR(revision_id);
501
static DEVICE_ATTR_RO(afg);
502
static DEVICE_ATTR_RO(mfg);
503
static RECONFIG_DEVICE_ATTR(vendor_name);
504
static RECONFIG_DEVICE_ATTR(chip_name);
505
static RECONFIG_DEVICE_ATTR(modelname);
506
static DEVICE_ATTR_RO(init_pin_configs);
507
static DEVICE_ATTR_RO(driver_pin_configs);
508
509
510
#ifdef CONFIG_SND_HDA_PATCH_LOADER
511
512
/* parser mode */
513
enum {
514
LINE_MODE_NONE,
515
LINE_MODE_CODEC,
516
LINE_MODE_MODEL,
517
LINE_MODE_PINCFG,
518
LINE_MODE_VERB,
519
LINE_MODE_HINT,
520
LINE_MODE_VENDOR_ID,
521
LINE_MODE_SUBSYSTEM_ID,
522
LINE_MODE_REVISION_ID,
523
LINE_MODE_CHIP_NAME,
524
NUM_LINE_MODES,
525
};
526
527
static inline int strmatch(const char *a, const char *b)
528
{
529
return strncasecmp(a, b, strlen(b)) == 0;
530
}
531
532
/* parse the contents after the line "[codec]"
533
* accept only the line with three numbers, and assign the current codec
534
*/
535
static void parse_codec_mode(char *buf, struct hda_bus *bus,
536
struct hda_codec **codecp)
537
{
538
int vendorid, subid, caddr;
539
struct hda_codec *codec;
540
541
*codecp = NULL;
542
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
543
list_for_each_codec(codec, bus) {
544
if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
545
(subid <= 0 || codec->core.subsystem_id == subid) &&
546
codec->core.addr == caddr) {
547
*codecp = codec;
548
break;
549
}
550
}
551
}
552
}
553
554
/* parse the contents after the other command tags, [pincfg], [verb],
555
* [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
556
* just pass to the sysfs helper (only when any codec was specified)
557
*/
558
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
559
struct hda_codec **codecp)
560
{
561
parse_user_pin_configs(*codecp, buf);
562
}
563
564
static void parse_verb_mode(char *buf, struct hda_bus *bus,
565
struct hda_codec **codecp)
566
{
567
parse_init_verbs(*codecp, buf);
568
}
569
570
static void parse_hint_mode(char *buf, struct hda_bus *bus,
571
struct hda_codec **codecp)
572
{
573
parse_hints(*codecp, buf);
574
}
575
576
static void parse_model_mode(char *buf, struct hda_bus *bus,
577
struct hda_codec **codecp)
578
{
579
kfree((*codecp)->modelname);
580
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
581
}
582
583
static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
584
struct hda_codec **codecp)
585
{
586
snd_hda_codec_set_name(*codecp, buf);
587
}
588
589
#define DEFINE_PARSE_ID_MODE(name) \
590
static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
591
struct hda_codec **codecp) \
592
{ \
593
unsigned long val; \
594
if (!kstrtoul(buf, 0, &val)) \
595
(*codecp)->core.name = val; \
596
}
597
598
DEFINE_PARSE_ID_MODE(vendor_id);
599
DEFINE_PARSE_ID_MODE(subsystem_id);
600
DEFINE_PARSE_ID_MODE(revision_id);
601
602
603
struct hda_patch_item {
604
const char *tag;
605
const char *alias;
606
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
607
};
608
609
static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
610
[LINE_MODE_CODEC] = {
611
.tag = "[codec]",
612
.parser = parse_codec_mode,
613
},
614
[LINE_MODE_MODEL] = {
615
.tag = "[model]",
616
.parser = parse_model_mode,
617
},
618
[LINE_MODE_VERB] = {
619
.tag = "[verb]",
620
.alias = "[init_verbs]",
621
.parser = parse_verb_mode,
622
},
623
[LINE_MODE_PINCFG] = {
624
.tag = "[pincfg]",
625
.alias = "[user_pin_configs]",
626
.parser = parse_pincfg_mode,
627
},
628
[LINE_MODE_HINT] = {
629
.tag = "[hint]",
630
.alias = "[hints]",
631
.parser = parse_hint_mode
632
},
633
[LINE_MODE_VENDOR_ID] = {
634
.tag = "[vendor_id]",
635
.parser = parse_vendor_id_mode,
636
},
637
[LINE_MODE_SUBSYSTEM_ID] = {
638
.tag = "[subsystem_id]",
639
.parser = parse_subsystem_id_mode,
640
},
641
[LINE_MODE_REVISION_ID] = {
642
.tag = "[revision_id]",
643
.parser = parse_revision_id_mode,
644
},
645
[LINE_MODE_CHIP_NAME] = {
646
.tag = "[chip_name]",
647
.parser = parse_chip_name_mode,
648
},
649
};
650
651
/* check the line starting with '[' -- change the parser mode accordingly */
652
static int parse_line_mode(char *buf, struct hda_bus *bus)
653
{
654
int i;
655
for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
656
if (!patch_items[i].tag)
657
continue;
658
if (strmatch(buf, patch_items[i].tag))
659
return i;
660
if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
661
return i;
662
}
663
return LINE_MODE_NONE;
664
}
665
666
/* copy one line from the buffer in fw, and update the fields in fw
667
* return zero if it reaches to the end of the buffer, or non-zero
668
* if successfully copied a line
669
*
670
* the spaces at the beginning and the end of the line are stripped
671
*/
672
static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
673
const void **fw_data_p)
674
{
675
int len;
676
size_t fw_size = *fw_size_p;
677
const char *p = *fw_data_p;
678
679
while (isspace(*p) && fw_size) {
680
p++;
681
fw_size--;
682
}
683
if (!fw_size)
684
return 0;
685
686
for (len = 0; len < fw_size; len++) {
687
if (!*p)
688
break;
689
if (*p == '\n') {
690
p++;
691
len++;
692
break;
693
}
694
if (len < size)
695
*buf++ = *p++;
696
}
697
*buf = 0;
698
*fw_size_p = fw_size - len;
699
*fw_data_p = p;
700
remove_trail_spaces(buf);
701
return 1;
702
}
703
704
/**
705
* snd_hda_load_patch - load a "patch" firmware file and parse it
706
* @bus: HD-audio bus
707
* @fw_size: the firmware byte size
708
* @fw_buf: the firmware data
709
*/
710
int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
711
{
712
char buf[128];
713
struct hda_codec *codec;
714
int line_mode;
715
716
line_mode = LINE_MODE_NONE;
717
codec = NULL;
718
while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
719
if (!*buf || *buf == '#' || *buf == '\n')
720
continue;
721
if (*buf == '[')
722
line_mode = parse_line_mode(buf, bus);
723
else if (patch_items[line_mode].parser &&
724
(codec || line_mode <= LINE_MODE_CODEC))
725
patch_items[line_mode].parser(buf, bus, &codec);
726
}
727
return 0;
728
}
729
EXPORT_SYMBOL_GPL(snd_hda_load_patch);
730
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
731
732
/*
733
* sysfs entries
734
*/
735
static struct attribute *hda_dev_attrs[] = {
736
&dev_attr_vendor_id.attr,
737
&dev_attr_subsystem_id.attr,
738
&dev_attr_revision_id.attr,
739
&dev_attr_afg.attr,
740
&dev_attr_mfg.attr,
741
&dev_attr_vendor_name.attr,
742
&dev_attr_chip_name.attr,
743
&dev_attr_modelname.attr,
744
&dev_attr_init_pin_configs.attr,
745
&dev_attr_driver_pin_configs.attr,
746
&dev_attr_power_on_acct.attr,
747
&dev_attr_power_off_acct.attr,
748
#ifdef CONFIG_SND_HDA_RECONFIG
749
&dev_attr_init_verbs.attr,
750
&dev_attr_hints.attr,
751
&dev_attr_user_pin_configs.attr,
752
&dev_attr_reconfig.attr,
753
&dev_attr_clear.attr,
754
#endif
755
NULL
756
};
757
758
static const struct attribute_group hda_dev_attr_group = {
759
.attrs = hda_dev_attrs,
760
};
761
762
const struct attribute_group *snd_hda_dev_attr_groups[] = {
763
&hda_dev_attr_group,
764
NULL
765
};
766
767
void snd_hda_sysfs_init(struct hda_codec *codec)
768
{
769
mutex_init(&codec->user_mutex);
770
#ifdef CONFIG_SND_HDA_RECONFIG
771
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
772
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
773
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
774
#endif
775
}
776
777
void snd_hda_sysfs_clear(struct hda_codec *codec)
778
{
779
#ifdef CONFIG_SND_HDA_RECONFIG
780
struct hda_hint *hint;
781
int i;
782
783
/* clear init verbs */
784
snd_array_free(&codec->init_verbs);
785
/* clear hints */
786
snd_array_for_each(&codec->hints, i, hint) {
787
kfree(hint->key); /* we don't need to free hint->val */
788
}
789
snd_array_free(&codec->hints);
790
snd_array_free(&codec->user_pins);
791
#endif
792
}
793
794