hdaudioctl.c revision 1.1.28.1 1 1.1.28.1 martin /* $NetBSD: hdaudioctl.c,v 1.1.28.1 2020/06/20 16:15:45 martin 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.1 sborrill #include <dev/pci/hdaudio/hdaudioio.h>
46 1.1 sborrill #include <dev/pci/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.1.28.1 martin const char *pin_devices[16] = {
53 1.1.28.1 martin "Line out", "Speaker", "Headphones", "CD",
54 1.1.28.1 martin "SPDIF Out", "Digital Out", "Modem Line", "Modem Handset",
55 1.1.28.1 martin "Line In", "AUX", "Mic In", "Telephony",
56 1.1.28.1 martin "SPDIF In", "Digital In", "Reserved", "Other"
57 1.1.28.1 martin };
58 1.1.28.1 martin static const char *pin_jacks[16] = {
59 1.1.28.1 martin "Unknown", "1/8\"", "1/4\"", "ATAPI",
60 1.1.28.1 martin "RCA", "Optic", "Digital", "Analog",
61 1.1.28.1 martin "DIN", "XLR", "RJ-11", "Combo",
62 1.1.28.1 martin "0xC", "0xD", "0xE", "Other"
63 1.1.28.1 martin };
64 1.1.28.1 martin static const char *pin_connections[4] = {
65 1.1.28.1 martin "Jack", "None", "Fixed", "Both"
66 1.1.28.1 martin };
67 1.1.28.1 martin static const char *pin_colors[16] = {
68 1.1.28.1 martin "Unknown", "Black", "Grey", "Blue",
69 1.1.28.1 martin "Green", "Red", "Orange", "Yellow",
70 1.1.28.1 martin "Purple", "Pink", "Res. A", "Res. B",
71 1.1.28.1 martin "Res. C", "Res. D", "White", "Other"
72 1.1.28.1 martin };
73 1.1.28.1 martin static const char *pin_locations[64] = {
74 1.1.28.1 martin "0x00", "Rear", "Front", "Left",
75 1.1.28.1 martin "Right", "Top", "Bottom", "Rear-panel",
76 1.1.28.1 martin "Drive-bay", "0x09", "0x0a", "0x0b",
77 1.1.28.1 martin "0x0c", "0x0d", "0x0e", "0x0f",
78 1.1.28.1 martin "Internal", "0x11", "0x12", "0x13",
79 1.1.28.1 martin "0x14", "0x15", "0x16", "Riser",
80 1.1.28.1 martin "0x18", "Onboard", "0x1a", "0x1b",
81 1.1.28.1 martin "0x1c", "0x1d", "0x1e", "0x1f",
82 1.1.28.1 martin "External", "Ext-Rear", "Ext-Front", "Ext-Left",
83 1.1.28.1 martin "Ext-Right", "Ext-Top", "Ext-Bottom", "0x07",
84 1.1.28.1 martin "0x28", "0x29", "0x2a", "0x2b",
85 1.1.28.1 martin "0x2c", "0x2d", "0x2e", "0x2f",
86 1.1.28.1 martin "Other", "0x31", "0x32", "0x33",
87 1.1.28.1 martin "0x34", "0x35", "Other-Bott", "Lid-In",
88 1.1.28.1 martin "Lid-Out", "0x39", "0x3a", "0x3b",
89 1.1.28.1 martin "0x3c", "0x3d", "0x3e", "0x3f"
90 1.1.28.1 martin };
91 1.1.28.1 martin
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.28.1 martin
98 1.1 sborrill fprintf(stderr, "usage: %s [-f dev] list\n", prog);
99 1.1.28.1 martin 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.1.28.1 martin /* Based on page 178 onwards:
248 1.1.28.1 martin * https://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf
249 1.1.28.1 martin * 31:30 = Port connectivity
250 1.1.28.1 martin * 29:24 = Location
251 1.1.28.1 martin * 23:20 = Default device
252 1.1.28.1 martin * 19:16 = Connection type
253 1.1.28.1 martin * 15:12 = Color
254 1.1.28.1 martin * 11:8 = Misc
255 1.1.28.1 martin * 7:4 = Default association
256 1.1.28.1 martin * 3:0 = Sequence
257 1.1.28.1 martin */
258 1.1.28.1 martin
259 1.1.28.1 martin static int
260 1.1.28.1 martin hdaudioctl_show(int fd, int argc, char *argv[])
261 1.1.28.1 martin {
262 1.1.28.1 martin prop_dictionary_t request, response, dict;
263 1.1.28.1 martin prop_array_t array;
264 1.1.28.1 martin prop_object_iterator_t iter;
265 1.1.28.1 martin prop_object_t obj;
266 1.1.28.1 martin uint16_t nid, codecid;
267 1.1.28.1 martin uint32_t config;
268 1.1.28.1 martin int error;
269 1.1.28.1 martin const char *device, *conn, *jack, *loc, *color;
270 1.1.28.1 martin if (argc != 2)
271 1.1.28.1 martin usage();
272 1.1.28.1 martin
273 1.1.28.1 martin codecid = strtol(argv[0], NULL, 0);
274 1.1.28.1 martin nid = strtol(argv[1], NULL, 0);
275 1.1.28.1 martin
276 1.1.28.1 martin request = prop_dictionary_create();
277 1.1.28.1 martin if (request == NULL) {
278 1.1.28.1 martin fprintf(stderr, "out of memory\n");
279 1.1.28.1 martin return ENOMEM;
280 1.1.28.1 martin }
281 1.1.28.1 martin
282 1.1.28.1 martin prop_dictionary_set_uint16(request, "codecid", codecid);
283 1.1.28.1 martin prop_dictionary_set_uint16(request, "nid", nid);
284 1.1.28.1 martin
285 1.1.28.1 martin error = prop_dictionary_sendrecv_ioctl(request, fd,
286 1.1.28.1 martin HDAUDIO_FGRP_GETCONFIG, &response);
287 1.1.28.1 martin if (error != 0) {
288 1.1.28.1 martin perror("HDAUDIO_FGRP_GETCONFIG failed");
289 1.1.28.1 martin return error;
290 1.1.28.1 martin }
291 1.1.28.1 martin
292 1.1.28.1 martin array = prop_dictionary_get(response, "pin-config");
293 1.1.28.1 martin iter = prop_array_iterator(array);
294 1.1.28.1 martin prop_object_iterator_reset(iter);
295 1.1.28.1 martin printf("nid Data As Seq Device Conn Jack "
296 1.1.28.1 martin "Location Color Misc\n");
297 1.1.28.1 martin printf("================================================="
298 1.1.28.1 martin "=======================\n");
299 1.1.28.1 martin while ((obj = prop_object_iterator_next(iter)) != NULL) {
300 1.1.28.1 martin dict = (prop_dictionary_t)obj;
301 1.1.28.1 martin prop_dictionary_get_uint32(dict, "config", &config);
302 1.1.28.1 martin prop_dictionary_get_uint16(dict, "nid", &nid);
303 1.1.28.1 martin device = pin_devices[(config >> 20U) & 0xf];
304 1.1.28.1 martin conn = pin_connections[(config >> 30U) & 0x3];
305 1.1.28.1 martin jack = pin_jacks[(config >> 16) & 0xf];
306 1.1.28.1 martin loc = pin_locations[(config >> 24) & 0x3f];
307 1.1.28.1 martin color = pin_colors[(config >> 12) & 0xf];
308 1.1.28.1 martin printf("%3d %08X %2d %3d %-14s %-5s %-7s %-10s %-7s %4X\n",
309 1.1.28.1 martin nid, config, ((config >> 4U) & 0xf), (config & 0xf),
310 1.1.28.1 martin device, conn, jack, loc, color, ((config >> 8U) & 0xf));
311 1.1.28.1 martin }
312 1.1.28.1 martin prop_object_release(array);
313 1.1.28.1 martin prop_object_release(response);
314 1.1.28.1 martin prop_object_release(request);
315 1.1.28.1 martin
316 1.1.28.1 martin return 0;
317 1.1.28.1 martin }
318 1.1.28.1 martin
319 1.1 sborrill
320 1.1 sborrill int
321 1.1 sborrill main(int argc, char *argv[])
322 1.1 sborrill {
323 1.1 sborrill int fd, error;
324 1.1 sborrill int ch;
325 1.1 sborrill const char *devpath = DEVPATH_HDAUDIO;
326 1.1.28.1 martin
327 1.1 sborrill while ((ch = getopt(argc, argv, "f:h")) != -1) {
328 1.1 sborrill switch (ch) {
329 1.1 sborrill case 'f':
330 1.1 sborrill devpath = strdup(optarg);
331 1.1 sborrill break;
332 1.1 sborrill case 'h':
333 1.1 sborrill default:
334 1.1 sborrill usage();
335 1.1 sborrill /* NOTREACHED */
336 1.1 sborrill }
337 1.1 sborrill }
338 1.1 sborrill argc -= optind;
339 1.1 sborrill argv += optind;
340 1.1 sborrill
341 1.1 sborrill if (argc < 1)
342 1.1 sborrill usage();
343 1.1 sborrill
344 1.1 sborrill fd = open(devpath, O_RDWR);
345 1.1 sborrill if (fd < 0) {
346 1.1 sborrill fprintf(stderr, "Error opening %s: %s\n", devpath,
347 1.1 sborrill strerror(errno));
348 1.1 sborrill return EXIT_FAILURE;
349 1.1 sborrill }
350 1.1.28.1 martin
351 1.1 sborrill error = 0;
352 1.1 sborrill if (strcmp(argv[0], "list") == 0)
353 1.1 sborrill error = hdaudioctl_list(fd);
354 1.1 sborrill else if (strcmp(argv[0], "get") == 0)
355 1.1 sborrill error = hdaudioctl_get(fd, argc - 1, argv + 1);
356 1.1 sborrill else if (strcmp(argv[0], "set") == 0)
357 1.1 sborrill error = hdaudioctl_set(fd, argc - 1, argv + 1);
358 1.1 sborrill else if (strcmp(argv[0], "graph") == 0)
359 1.1 sborrill error = hdaudioctl_graph(fd, argc - 1, argv + 1);
360 1.1.28.1 martin else if (strcmp(argv[0], "show") == 0)
361 1.1.28.1 martin error = hdaudioctl_show(fd, argc - 1, argv + 1);
362 1.1 sborrill else
363 1.1 sborrill usage();
364 1.1 sborrill
365 1.1 sborrill close(fd);
366 1.1 sborrill
367 1.1 sborrill if (error)
368 1.1 sborrill return EXIT_FAILURE;
369 1.1 sborrill return EXIT_SUCCESS;
370 1.1 sborrill }
371