1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Information interface for ALSA driver |
4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
5 | */ |
6 | |
7 | #include <linux/slab.h> |
8 | #include <linux/time.h> |
9 | #include <linux/string.h> |
10 | #include <linux/export.h> |
11 | #include <sound/core.h> |
12 | #include <sound/minors.h> |
13 | #include <sound/info.h> |
14 | #include <linux/utsname.h> |
15 | #include <linux/mutex.h> |
16 | |
17 | /* |
18 | * OSS compatible part |
19 | */ |
20 | |
21 | static DEFINE_MUTEX(strings); |
22 | static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT]; |
23 | |
24 | int snd_oss_info_register(int dev, int num, char *string) |
25 | { |
26 | char *x; |
27 | |
28 | if (snd_BUG_ON(dev < 0 || dev >= SNDRV_OSS_INFO_DEV_COUNT)) |
29 | return -ENXIO; |
30 | if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS)) |
31 | return -ENXIO; |
32 | guard(mutex)(T: &strings); |
33 | if (string == NULL) { |
34 | x = snd_sndstat_strings[num][dev]; |
35 | kfree(objp: x); |
36 | x = NULL; |
37 | } else { |
38 | x = kstrdup(s: string, GFP_KERNEL); |
39 | if (x == NULL) |
40 | return -ENOMEM; |
41 | } |
42 | snd_sndstat_strings[num][dev] = x; |
43 | return 0; |
44 | } |
45 | EXPORT_SYMBOL(snd_oss_info_register); |
46 | |
47 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) |
48 | { |
49 | int idx, ok = -1; |
50 | char *str; |
51 | |
52 | snd_iprintf(buf, "\n%s:" , id); |
53 | guard(mutex)(T: &strings); |
54 | for (idx = 0; idx < SNDRV_CARDS; idx++) { |
55 | str = snd_sndstat_strings[idx][dev]; |
56 | if (str) { |
57 | if (ok < 0) { |
58 | snd_iprintf(buf, "\n" ); |
59 | ok++; |
60 | } |
61 | snd_iprintf(buf, "%i: %s\n" , idx, str); |
62 | } |
63 | } |
64 | if (ok < 0) |
65 | snd_iprintf(buf, " NOT ENABLED IN CONFIG\n" ); |
66 | return ok; |
67 | } |
68 | |
69 | static void snd_sndstat_proc_read(struct snd_info_entry *entry, |
70 | struct snd_info_buffer *buffer) |
71 | { |
72 | snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n" ); |
73 | snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n" , |
74 | init_utsname()->sysname, |
75 | init_utsname()->nodename, |
76 | init_utsname()->release, |
77 | init_utsname()->version, |
78 | init_utsname()->machine); |
79 | snd_iprintf(buffer, "Config options: 0\n" ); |
80 | snd_iprintf(buffer, "\nInstalled drivers: \n" ); |
81 | snd_iprintf(buffer, "Type 10: ALSA emulation\n" ); |
82 | snd_iprintf(buffer, "\nCard config: \n" ); |
83 | snd_card_info_read_oss(buffer); |
84 | snd_sndstat_show_strings(buf: buffer, id: "Audio devices" , SNDRV_OSS_INFO_DEV_AUDIO); |
85 | snd_sndstat_show_strings(buf: buffer, id: "Synth devices" , SNDRV_OSS_INFO_DEV_SYNTH); |
86 | snd_sndstat_show_strings(buf: buffer, id: "Midi devices" , SNDRV_OSS_INFO_DEV_MIDI); |
87 | snd_sndstat_show_strings(buf: buffer, id: "Timers" , SNDRV_OSS_INFO_DEV_TIMERS); |
88 | snd_sndstat_show_strings(buf: buffer, id: "Mixers" , SNDRV_OSS_INFO_DEV_MIXERS); |
89 | } |
90 | |
91 | int __init snd_info_minor_register(void) |
92 | { |
93 | struct snd_info_entry *entry; |
94 | |
95 | memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); |
96 | entry = snd_info_create_module_entry(THIS_MODULE, name: "sndstat" , |
97 | parent: snd_oss_root); |
98 | if (!entry) |
99 | return -ENOMEM; |
100 | entry->c.text.read = snd_sndstat_proc_read; |
101 | return snd_info_register(entry); /* freed in error path */ |
102 | } |
103 | |