1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <getopt.h>
36 #include <ctype.h>
37 #include <aw-alsa-lib/control.h>
38 #include <aw-alsa-lib/common.h>
39 #include <hal_cmd.h>
40 
41 
amixer_ctl_info_print(snd_ctl_info_t * info)42 static void amixer_ctl_info_print(snd_ctl_info_t *info)
43 {
44     if (info->type == SND_CTL_ELEM_TYPE_INTEGER) {
45         printf("numid=%u, name=\'%s\'\n", info->id, info->name);
46         printf("\t value=%lu, min=%u, max=%u\n",
47             info->value, info->min, info->max);
48     } else if (info->type == SND_CTL_ELEM_TYPE_ENUMERATED) {
49         printf("numid=%u, name=\'%s\'\n", info->id, info->name);
50         printf("\t value=%s, enum=", info->texts[info->value]);
51         int i = 0;
52         for (i = 0; i < info->items; i++) {
53             printf("%s ", info->texts[i]);
54         }
55         printf("\n");
56     } else {
57         printf("numid=%u, name=\'%s\' type error:%d\n",
58             info->id, info->name, info->type);
59     }
60 }
61 
amixer_controls(const char * card_name)62 static int amixer_controls(const char *card_name)
63 {
64     int num, ret, i, count = 0;
65     snd_ctl_info_t info;
66 
67     if ((card_name == NULL) || (!strcmp(card_name, "default")))
68         card_name = "audiocodec";
69 
70     num = snd_ctl_num(card_name);
71     if (num == 0) {
72         printf("The card didn't have ctl.\n");
73         return 0;
74     } else if (num < 0)
75         return -1;
76 
77     for (i = 0; i < num;i ++) {
78         memset(&info, 0, sizeof(snd_ctl_info_t));
79         ret = snd_ctl_get_bynum(card_name, i, &info);
80         if (ret < 0) {
81             printf("get %d elem failed\n", i);
82             return ret;
83         }
84         amixer_ctl_info_print(&info);
85     }
86     return 0;
87 }
88 
parser_ctl_numid(const char * cmd,int * id)89 static int parser_ctl_numid(const char *cmd, int *id)
90 {
91     char *id_str = "numid=";
92 
93     if (strncmp(cmd, id_str, strlen(id_str)) != 0)
94         return -1;
95     *id = atoi(cmd+strlen(id_str));
96     return 0;
97 }
98 
amixer_usage(void)99 static void amixer_usage(void)
100 {
101     printf("Usage: amixer <options> [command]\n");
102     printf("\nAvailable options:\n");
103     printf("  -c,--card N       select the card\n");
104     printf("\nAvailable commands:\n");
105     printf("  amixer        show all controls for default card\n");
106     printf("  amixer set numid val  set control contents for one control\n");
107     printf("  amixer get numid  get control contents for one control\n");
108 }
109 
amixer(int argc,char * argv[])110 static int amixer(int argc, char *argv[])
111 {
112     static char g_card_name[64] = "audiocodec";
113     int ret = 0;
114     int numid = 0;
115     char *ctl_name = NULL;
116     const char *card_name = NULL;
117     snd_ctl_info_t info;
118     int morehelp = 0;
119     const struct option long_option[] = {
120         {"help", 0, NULL, 'h'},
121         {"list", 0, NULL, 'l'},
122         {"card", 1, NULL, 'c'},
123         {NULL, 0, NULL, 0},
124     };
125 
126     while (1) {
127         int c;
128 
129         if ((c = getopt_long(argc, argv, "hlc:", long_option, NULL)) < 0)
130             break;
131         switch (c) {
132         case 'h':
133             amixer_usage();
134             return 0;
135         case 'l':
136             asound_list();
137             return 0;
138         case 'c': {
139                 int card_index = 0;
140 
141                 if (isdigit((unsigned char)(*optarg))) {
142                     sscanf(optarg, "%d", &card_index);
143                     card_name = snd_card_name(card_index);
144                     if (card_name == NULL) {
145                         fprintf(stderr, "Invalid card number.\n");
146                         morehelp++;
147                     } else {
148                         strncpy(g_card_name, card_name, 64);
149                     }
150                 } else
151                     strncpy(g_card_name, optarg, 64);
152                 fprintf(stderr, "Card Name:%s.\n", g_card_name);
153             }
154             break;
155         default:
156             fprintf(stderr, "Invalid switch or option needs an argument.\n");
157             morehelp++;
158         }
159     }
160 
161     if (morehelp) {
162         amixer_usage();
163         return 1;
164     }
165 
166     if ((argc == 1) || ((argc - optind) <= 0)) {
167         return amixer_controls(g_card_name);
168     }
169 
170     if (!strcmp("get", argv[optind])) {
171         if (!snd_ctl_get_bynum(g_card_name, atoi(argv[optind + 1]), &info)) {
172             amixer_ctl_info_print(&info);
173             return 0;
174         }
175     } else if (!strcmp("set", argv[optind])) {
176         int value = -1;
177         numid = atoi(argv[optind + 1]);
178         if (argc >= 4)
179             value = atoi(argv[optind + 2]);
180 
181         if (value >= 0) {
182             if (snd_ctl_get_bynum(g_card_name, numid, &info) != 0) {
183                 printf("snd_ctl_get failed\n");
184                 return -1;
185             }
186             snd_ctl_set_bynum(g_card_name, numid, value);
187         }
188         if (!snd_ctl_get_bynum(g_card_name, numid, &info)) {
189             amixer_ctl_info_print(&info);
190             return 0;
191         }
192     } else {
193         amixer_usage();
194     }
195 
196     return 0;
197 }
198 
cmd_amixer(int argc,char ** argv)199 int cmd_amixer(int argc, char ** argv)
200 {
201     amixer(argc, argv);
202     return 0;
203 }
204 FINSH_FUNCTION_EXPORT_CMD(cmd_amixer, amixer, amixer utils);
205