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