Home | History | Annotate | Line # | Download | only in hdaudioctl
      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