1 1.6 christos /* $NetBSD: hdaudioctl.c,v 1.6 2021/06/21 03:09:52 christos 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.4 riastrad 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.6 christos prop_dictionary_get_string(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.5 sborrill printf("nid Data As Seq Device Conn Jack " 296 1.3 sborrill "Location Color Misc\n"); 297 1.5 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.5 sborrill printf("0x%2X %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 prop_object_release(array); 313 1.3 sborrill prop_object_release(response); 314 1.3 sborrill prop_object_release(request); 315 1.3 sborrill 316 1.3 sborrill return 0; 317 1.3 sborrill } 318 1.3 sborrill 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.4 riastrad 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.4 riastrad 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.3 sborrill else if (strcmp(argv[0], "show") == 0) 361 1.3 sborrill 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