hdaudioctl.c revision 1.3 1 1.3 sborrill /* $NetBSD: hdaudioctl.c,v 1.3 2020/06/15 13:06:39 sborrill Exp $ */
2 1.1 sborrill
3 1.1 sborrill /*
4 1.1 sborrill * Copyright (c) 2009 Precedence Technologies Ltd <support (at) precedence.co.uk>
5 1.1 sborrill * Copyright (c) 2009 Jared D. McNeill <jmcneill (at) invisible.ca>
6 1.1 sborrill * All rights reserved.
7 1.1 sborrill *
8 1.1 sborrill * This code is derived from software contributed to The NetBSD Foundation
9 1.1 sborrill * by Precedence Technologies Ltd
10 1.1 sborrill *
11 1.1 sborrill * Redistribution and use in source and binary forms, with or without
12 1.1 sborrill * modification, are permitted provided that the following conditions
13 1.1 sborrill * are met:
14 1.1 sborrill * 1. Redistributions of source code must retain the above copyright
15 1.1 sborrill * notice, this list of conditions and the following disclaimer.
16 1.1 sborrill * 2. The name of the author may not be used to endorse or promote products
17 1.1 sborrill * derived from this software without specific prior written permission.
18 1.1 sborrill *
19 1.1 sborrill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 1.1 sborrill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 1.1 sborrill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 1.1 sborrill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 1.1 sborrill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 1.1 sborrill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 1.1 sborrill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 1.1 sborrill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 1.1 sborrill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 sborrill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 sborrill * SUCH DAMAGE.
30 1.1 sborrill */
31 1.1 sborrill
32 1.1 sborrill #include <sys/types.h>
33 1.1 sborrill #include <sys/ioctl.h>
34 1.1 sborrill
35 1.1 sborrill #include <prop/proplib.h>
36 1.1 sborrill
37 1.1 sborrill #include <errno.h>
38 1.1 sborrill #include <fcntl.h>
39 1.1 sborrill #include <stdio.h>
40 1.1 sborrill #include <stdlib.h>
41 1.1 sborrill #include <string.h>
42 1.1 sborrill #include <unistd.h>
43 1.1 sborrill #include <ctype.h>
44 1.1 sborrill
45 1.2 jmcneill #include <dev/hdaudio/hdaudioio.h>
46 1.2 jmcneill #include <dev/hdaudio/hdaudioreg.h>
47 1.1 sborrill
48 1.1 sborrill #include "hdaudioctl.h"
49 1.1 sborrill
50 1.1 sborrill #define DEVPATH_HDAUDIO "/dev/hdaudio0"
51 1.1 sborrill
52 1.3 sborrill const char *pin_devices[16] = {
53 1.3 sborrill "Line out", "Speaker", "Headphones", "CD",
54 1.3 sborrill "SPDIF Out", "Digital Out", "Modem Line", "Modem Handset",
55 1.3 sborrill "Line In", "AUX", "Mic In", "Telephony",
56 1.3 sborrill "SPDIF In", "Digital In", "Reserved", "Other"
57 1.3 sborrill };
58 1.3 sborrill static const char *pin_jacks[16] = {
59 1.3 sborrill "Unknown", "1/8\"", "1/4\"", "ATAPI",
60 1.3 sborrill "RCA", "Optic", "Digital", "Analog",
61 1.3 sborrill "DIN", "XLR", "RJ-11", "Combo",
62 1.3 sborrill "0xC", "0xD", "0xE", "Other"
63 1.3 sborrill };
64 1.3 sborrill static const char *pin_connections[4] = {
65 1.3 sborrill "Jack", "None", "Fixed", "Both"
66 1.3 sborrill };
67 1.3 sborrill static const char *pin_colors[16] = {
68 1.3 sborrill "Unknown", "Black", "Grey", "Blue",
69 1.3 sborrill "Green", "Red", "Orange", "Yellow",
70 1.3 sborrill "Purple", "Pink", "Res. A", "Res. B",
71 1.3 sborrill "Res. C", "Res. D", "White", "Other"
72 1.3 sborrill };
73 1.3 sborrill static const char *pin_locations[64] = {
74 1.3 sborrill "0x00", "Rear", "Front", "Left",
75 1.3 sborrill "Right", "Top", "Bottom", "Rear-panel",
76 1.3 sborrill "Drive-bay", "0x09", "0x0a", "0x0b",
77 1.3 sborrill "0x0c", "0x0d", "0x0e", "0x0f",
78 1.3 sborrill "Internal", "0x11", "0x12", "0x13",
79 1.3 sborrill "0x14", "0x15", "0x16", "Riser",
80 1.3 sborrill "0x18", "Onboard", "0x1a", "0x1b",
81 1.3 sborrill "0x1c", "0x1d", "0x1e", "0x1f",
82 1.3 sborrill "External", "Ext-Rear", "Ext-Front", "Ext-Left",
83 1.3 sborrill "Ext-Right", "Ext-Top", "Ext-Bottom", "0x07",
84 1.3 sborrill "0x28", "0x29", "0x2a", "0x2b",
85 1.3 sborrill "0x2c", "0x2d", "0x2e", "0x2f",
86 1.3 sborrill "Other", "0x31", "0x32", "0x33",
87 1.3 sborrill "0x34", "0x35", "Other-Bott", "Lid-In",
88 1.3 sborrill "Lid-Out", "0x39", "0x3a", "0x3b",
89 1.3 sborrill "0x3c", "0x3d", "0x3e", "0x3f"
90 1.3 sborrill };
91 1.3 sborrill
92 1.1 sborrill void
93 1.1 sborrill usage(void)
94 1.1 sborrill {
95 1.1 sborrill const char *prog;
96 1.1 sborrill prog = getprogname();
97 1.1 sborrill
98 1.1 sborrill fprintf(stderr, "usage: %s [-f dev] list\n", prog);
99 1.3 sborrill fprintf(stderr, " %s [-f dev] show <codecid> <nid>\n", prog);
100 1.1 sborrill fprintf(stderr, " %s [-f dev] get <codecid> <nid>\n", prog);
101 1.1 sborrill fprintf(stderr, " %s [-f dev] set <codecid> <nid> [plist]\n",
102 1.1 sborrill prog);
103 1.1 sborrill fprintf(stderr, " %s [-f dev] graph <codecid> <nid>\n", prog);
104 1.1 sborrill exit(EXIT_FAILURE);
105 1.1 sborrill }
106 1.1 sborrill
107 1.1 sborrill static int
108 1.1 sborrill hdaudioctl_list(int fd)
109 1.1 sborrill {
110 1.1 sborrill prop_dictionary_t request, response;
111 1.1 sborrill prop_dictionary_t dict;
112 1.1 sborrill prop_object_iterator_t iter;
113 1.1 sborrill prop_object_t obj;
114 1.1 sborrill prop_array_t array;
115 1.1 sborrill uint16_t nid, codecid;
116 1.1 sborrill uint16_t vendor, product;
117 1.1 sborrill uint32_t subsystem;
118 1.1 sborrill const char *device = NULL;
119 1.1 sborrill int error;
120 1.1 sborrill
121 1.1 sborrill request = prop_dictionary_create();
122 1.1 sborrill if (request == NULL) {
123 1.1 sborrill fprintf(stderr, "out of memory\n");
124 1.1 sborrill return ENOMEM;
125 1.1 sborrill }
126 1.1 sborrill
127 1.1 sborrill error = prop_dictionary_sendrecv_ioctl(request, fd,
128 1.1 sborrill HDAUDIO_FGRP_INFO, &response);
129 1.1 sborrill if (error != 0) {
130 1.1 sborrill perror("HDAUDIO_FGRP_INFO failed");
131 1.1 sborrill return error;
132 1.1 sborrill }
133 1.1 sborrill
134 1.1 sborrill array = prop_dictionary_get(response, "function-group-info");
135 1.1 sborrill iter = prop_array_iterator(array);
136 1.1 sborrill prop_object_iterator_reset(iter);
137 1.1 sborrill while ((obj = prop_object_iterator_next(iter)) != NULL) {
138 1.1 sborrill dict = (prop_dictionary_t)obj;
139 1.1 sborrill prop_dictionary_get_uint16(dict, "codecid", &codecid);
140 1.1 sborrill prop_dictionary_get_uint16(dict, "nid", &nid);
141 1.1 sborrill prop_dictionary_get_uint16(dict, "vendor-id", &vendor);
142 1.1 sborrill prop_dictionary_get_uint16(dict, "product-id", &product);
143 1.1 sborrill prop_dictionary_get_uint32(dict, "subsystem-id", &subsystem);
144 1.1 sborrill prop_dictionary_get_cstring_nocopy(dict, "device", &device);
145 1.1 sborrill
146 1.1 sborrill printf("codecid 0x%02X nid 0x%02X vendor 0x%04X "
147 1.1 sborrill "product 0x%04X subsystem 0x%08X device %s\n",
148 1.1 sborrill codecid, nid, vendor, product, subsystem,
149 1.1 sborrill device ? device : "<none>");
150 1.1 sborrill }
151 1.1 sborrill
152 1.1 sborrill prop_object_release(array);
153 1.1 sborrill prop_object_release(response);
154 1.1 sborrill prop_object_release(request);
155 1.1 sborrill
156 1.1 sborrill return 0;
157 1.1 sborrill }
158 1.1 sborrill
159 1.1 sborrill static int
160 1.1 sborrill hdaudioctl_get(int fd, int argc, char *argv[])
161 1.1 sborrill {
162 1.1 sborrill prop_dictionary_t request, response;
163 1.1 sborrill prop_array_t config;
164 1.1 sborrill uint16_t nid, codecid;
165 1.1 sborrill const char *xml;
166 1.1 sborrill int error;
167 1.1 sborrill
168 1.1 sborrill if (argc != 2)
169 1.1 sborrill usage();
170 1.1 sborrill
171 1.1 sborrill codecid = strtol(argv[0], NULL, 0);
172 1.1 sborrill nid = strtol(argv[1], NULL, 0);
173 1.1 sborrill
174 1.1 sborrill request = prop_dictionary_create();
175 1.1 sborrill if (request == NULL) {
176 1.1 sborrill fprintf(stderr, "out of memory\n");
177 1.1 sborrill return ENOMEM;
178 1.1 sborrill }
179 1.1 sborrill
180 1.1 sborrill prop_dictionary_set_uint16(request, "codecid", codecid);
181 1.1 sborrill prop_dictionary_set_uint16(request, "nid", nid);
182 1.1 sborrill
183 1.1 sborrill error = prop_dictionary_sendrecv_ioctl(request, fd,
184 1.1 sborrill HDAUDIO_FGRP_GETCONFIG, &response);
185 1.1 sborrill if (error != 0) {
186 1.1 sborrill perror("HDAUDIO_FGRP_GETCONFIG failed");
187 1.1 sborrill return error;
188 1.1 sborrill }
189 1.1 sborrill
190 1.1 sborrill config = prop_dictionary_get(response, "pin-config");
191 1.1 sborrill xml = prop_array_externalize(config);
192 1.1 sborrill
193 1.1 sborrill printf("%s\n", xml);
194 1.1 sborrill
195 1.1 sborrill prop_object_release(response);
196 1.1 sborrill prop_object_release(request);
197 1.1 sborrill
198 1.1 sborrill return 0;
199 1.1 sborrill }
200 1.1 sborrill
201 1.1 sborrill static int
202 1.1 sborrill hdaudioctl_set(int fd, int argc, char *argv[])
203 1.1 sborrill {
204 1.1 sborrill prop_dictionary_t request, response;
205 1.1 sborrill prop_array_t config = NULL;
206 1.1 sborrill uint16_t nid, codecid;
207 1.1 sborrill int error;
208 1.1 sborrill
209 1.1 sborrill if (argc < 2 || argc > 3)
210 1.1 sborrill usage();
211 1.1 sborrill
212 1.1 sborrill codecid = strtol(argv[0], NULL, 0);
213 1.1 sborrill nid = strtol(argv[1], NULL, 0);
214 1.1 sborrill if (argc == 3) {
215 1.1 sborrill config = prop_array_internalize_from_file(argv[2]);
216 1.1 sborrill if (config == NULL) {
217 1.1 sborrill fprintf(stderr,
218 1.1 sborrill "couldn't load configuration from %s\n", argv[2]);
219 1.1 sborrill return EIO;
220 1.1 sborrill }
221 1.1 sborrill }
222 1.1 sborrill
223 1.1 sborrill request = prop_dictionary_create();
224 1.1 sborrill if (request == NULL) {
225 1.1 sborrill fprintf(stderr, "out of memory\n");
226 1.1 sborrill return ENOMEM;
227 1.1 sborrill }
228 1.1 sborrill
229 1.1 sborrill prop_dictionary_set_uint16(request, "codecid", codecid);
230 1.1 sborrill prop_dictionary_set_uint16(request, "nid", nid);
231 1.1 sborrill if (config)
232 1.1 sborrill prop_dictionary_set(request, "pin-config", config);
233 1.1 sborrill
234 1.1 sborrill error = prop_dictionary_sendrecv_ioctl(request, fd,
235 1.1 sborrill HDAUDIO_FGRP_SETCONFIG, &response);
236 1.1 sborrill if (error != 0) {
237 1.1 sborrill perror("HDAUDIO_FGRP_SETCONFIG failed");
238 1.1 sborrill return error;
239 1.1 sborrill }
240 1.1 sborrill
241 1.1 sborrill prop_object_release(response);
242 1.1 sborrill prop_object_release(request);
243 1.1 sborrill
244 1.1 sborrill return 0;
245 1.1 sborrill }
246 1.1 sborrill
247 1.3 sborrill /* Based on page 178 onwards:
248 1.3 sborrill * https://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf
249 1.3 sborrill * 31:30 = Port connectivity
250 1.3 sborrill * 29:24 = Location
251 1.3 sborrill * 23:20 = Default device
252 1.3 sborrill * 19:16 = Connection type
253 1.3 sborrill * 15:12 = Color
254 1.3 sborrill * 11:8 = Misc
255 1.3 sborrill * 7:4 = Default association
256 1.3 sborrill * 3:0 = Sequence
257 1.3 sborrill */
258 1.3 sborrill
259 1.3 sborrill static int
260 1.3 sborrill hdaudioctl_show(int fd, int argc, char *argv[])
261 1.3 sborrill {
262 1.3 sborrill prop_dictionary_t request, response, dict;
263 1.3 sborrill prop_array_t array;
264 1.3 sborrill prop_object_iterator_t iter;
265 1.3 sborrill prop_object_t obj;
266 1.3 sborrill uint16_t nid, codecid;
267 1.3 sborrill uint32_t config;
268 1.3 sborrill int error;
269 1.3 sborrill const char *device, *conn, *jack, *loc, *color;
270 1.3 sborrill if (argc != 2)
271 1.3 sborrill usage();
272 1.3 sborrill
273 1.3 sborrill codecid = strtol(argv[0], NULL, 0);
274 1.3 sborrill nid = strtol(argv[1], NULL, 0);
275 1.3 sborrill
276 1.3 sborrill request = prop_dictionary_create();
277 1.3 sborrill if (request == NULL) {
278 1.3 sborrill fprintf(stderr, "out of memory\n");
279 1.3 sborrill return ENOMEM;
280 1.3 sborrill }
281 1.3 sborrill
282 1.3 sborrill prop_dictionary_set_uint16(request, "codecid", codecid);
283 1.3 sborrill prop_dictionary_set_uint16(request, "nid", nid);
284 1.3 sborrill
285 1.3 sborrill error = prop_dictionary_sendrecv_ioctl(request, fd,
286 1.3 sborrill HDAUDIO_FGRP_GETCONFIG, &response);
287 1.3 sborrill if (error != 0) {
288 1.3 sborrill perror("HDAUDIO_FGRP_GETCONFIG failed");
289 1.3 sborrill return error;
290 1.3 sborrill }
291 1.3 sborrill
292 1.3 sborrill array = prop_dictionary_get(response, "pin-config");
293 1.3 sborrill iter = prop_array_iterator(array);
294 1.3 sborrill prop_object_iterator_reset(iter);
295 1.3 sborrill printf("nid Data As Seq Device Conn Jack "
296 1.3 sborrill "Location Color Misc\n");
297 1.3 sborrill printf("================================================="
298 1.3 sborrill "=======================\n");
299 1.3 sborrill while ((obj = prop_object_iterator_next(iter)) != NULL) {
300 1.3 sborrill dict = (prop_dictionary_t)obj;
301 1.3 sborrill prop_dictionary_get_uint32(dict, "config", &config);
302 1.3 sborrill prop_dictionary_get_uint16(dict, "nid", &nid);
303 1.3 sborrill device = pin_devices[(config >> 20U) & 0xf];
304 1.3 sborrill conn = pin_connections[(config >> 30U) & 0x3];
305 1.3 sborrill jack = pin_jacks[(config >> 16) & 0xf];
306 1.3 sborrill loc = pin_locations[(config >> 24) & 0x3f];
307 1.3 sborrill color = pin_colors[(config >> 12) & 0xf];
308 1.3 sborrill printf("%3d %08X %2d %3d %-14s %-5s %-7s %-10s %-7s %4X\n",
309 1.3 sborrill nid, config, ((config >> 4U) & 0xf), (config & 0xf),
310 1.3 sborrill device, conn, jack, loc, color, ((config >> 8U) & 0xf));
311 1.3 sborrill
312 1.3 sborrill }
313 1.3 sborrill prop_object_release(array);
314 1.3 sborrill prop_object_release(response);
315 1.3 sborrill prop_object_release(request);
316 1.3 sborrill
317 1.3 sborrill return 0;
318 1.3 sborrill }
319 1.3 sborrill
320 1.1 sborrill
321 1.1 sborrill int
322 1.1 sborrill main(int argc, char *argv[])
323 1.1 sborrill {
324 1.1 sborrill int fd, error;
325 1.1 sborrill int ch;
326 1.1 sborrill const char *devpath = DEVPATH_HDAUDIO;
327 1.1 sborrill
328 1.1 sborrill while ((ch = getopt(argc, argv, "f:h")) != -1) {
329 1.1 sborrill switch (ch) {
330 1.1 sborrill case 'f':
331 1.1 sborrill devpath = strdup(optarg);
332 1.1 sborrill break;
333 1.1 sborrill case 'h':
334 1.1 sborrill default:
335 1.1 sborrill usage();
336 1.1 sborrill /* NOTREACHED */
337 1.1 sborrill }
338 1.1 sborrill }
339 1.1 sborrill argc -= optind;
340 1.1 sborrill argv += optind;
341 1.1 sborrill
342 1.1 sborrill if (argc < 1)
343 1.1 sborrill usage();
344 1.1 sborrill
345 1.1 sborrill fd = open(devpath, O_RDWR);
346 1.1 sborrill if (fd < 0) {
347 1.1 sborrill fprintf(stderr, "Error opening %s: %s\n", devpath,
348 1.1 sborrill strerror(errno));
349 1.1 sborrill return EXIT_FAILURE;
350 1.1 sborrill }
351 1.1 sborrill
352 1.1 sborrill error = 0;
353 1.1 sborrill if (strcmp(argv[0], "list") == 0)
354 1.1 sborrill error = hdaudioctl_list(fd);
355 1.1 sborrill else if (strcmp(argv[0], "get") == 0)
356 1.1 sborrill error = hdaudioctl_get(fd, argc - 1, argv + 1);
357 1.1 sborrill else if (strcmp(argv[0], "set") == 0)
358 1.1 sborrill error = hdaudioctl_set(fd, argc - 1, argv + 1);
359 1.1 sborrill else if (strcmp(argv[0], "graph") == 0)
360 1.1 sborrill error = hdaudioctl_graph(fd, argc - 1, argv + 1);
361 1.3 sborrill else if (strcmp(argv[0], "show") == 0)
362 1.3 sborrill error = hdaudioctl_show(fd, argc - 1, argv + 1);
363 1.1 sborrill else
364 1.1 sborrill usage();
365 1.1 sborrill
366 1.1 sborrill close(fd);
367 1.1 sborrill
368 1.1 sborrill if (error)
369 1.1 sborrill return EXIT_FAILURE;
370 1.1 sborrill return EXIT_SUCCESS;
371 1.1 sborrill }
372