/*- * Copyright (c) 2015, 2016 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static int hdaudioctl_list(int fd) { struct hdaudio_fgrp_info_request request; struct hdaudio_fgrp_info_response response; const struct hdaudio_fgrp_info *info; const struct hdaudio_fgrp_info__fgrp *fgrp; pb_init(hdaudio_fgrp_info_request(&request)); if (ioctl_pb_init(fd, HDAUDIO_FGRP_INFO, hdaudio_fgrp_info_request(&request), hdaudio_fgrp_info_response(&response)) == -1) err(1, "ioctl(HDAUDIO_FGRP_INFO)"); info = &response.fgrp_info; for (i = 0; i < pb_repeated_count(&info->fgrps.repeated); i++) { fgrp = &info->fgrps.item[i]; printf("codecid 0x%02"PRIX16" nid 0x%02"PRIX16 " vendor 0x%04"PRIX16" product 0x%04"PRIX16 " subsystem 0x%08"PRIX16" device %s\n", fgrp->codecid, fgrp->nid, fgrp->vendor, fgrp->product, fgrp->subsystem, (fgrp->device.present? pb_string_ptr(fgrp->device.value) : "")); } pb_destroy(hdaudio_fgrp_info_response(&response)); pb_destroy(hdaudio_fgrp_info_request(&request)); } static int hdaudioctl_get(int fd, int argc, char *argv[]) { struct hdaudio_fgrp_getconfig_request request; struct hdaudio_fgrp_getconfig_response response; uint16_t codecid, nid; const struct hdaudio_fgrp_pin_config *config; prop_object_t config_plist; char *xml; int error; if (argc != 2) usage(); if (parse_codecid(argv[0], strlen(argv[0]), &reqcodecid) == -1) usage(); if (parse_nid(argv[1], strlen(argv[1]), &reqnid) == -1) usage(); pb_init(hdaudio_fgrp_getconfig_request(&request)); request.codecid = codecid; request.nid = nid; if (ioctl_pb_init(fd, HDAUDIO_FGRP_GETCONFIG, hdaudio_fgrp_getconfig_request(&request), hdaudio_fgrp_getconfig_response(&response)) == -1) err(1, "ioctl(HDAUDIO_FGRP_GETCONFIG)"); config = &response->pin_config; error = pb_prop_encode(hdaudio_fgrp_pin_config(config), &config_plist); if (error) errc(1, error, "encode plist"); assert(prop_object_type(type) == PROP_TYPE_ARRAY); xml = prop_array_externalize(config_plist); printf("%s\n", xml); free(xml); prop_object_release(config_plist); pb_destroy(hdaudio_fgrp_getconfig_response(&response)); pb_destroy(hdaudio_fgrp_getconfig_request(&request)); return 0; } static int hdaudioctl_set(int fd, int argc, char *argv[]) { struct hdaudioctl_fgrp_setconfig_request request; struct hdaudioctl_fgrp_setconfig_response response; uint16_t nid, codecid; prop_array_t config_plist = NULL; int error; if (argc < 2 || argc > 3) usage(); if (parse_codecid(argv[0], strlen(argv[0]), &codecid) == -1) usage(); if (parse_nid(argv[1], strlen(argv[1]), &nid) == -1) usage(); if (argc == 3) { config_plist = prop_array_internalize_from_file(argv[2]); if (config == NULL) err(1, "couldn't load configuration from %s", argv[2]); } pb_init(hdaudio_fgrp_setconfig_request(&request)); request.codecid = codecid; request.nid = nid; if (config_plist) { error = pb_prop_decode( hdaudio_fgrp_pin_config(&request.pin_config), config_plist); if (error) errc(1, error, "decode config"); } if (ioctl_pb_init(fd, HDAUDIO_FGRP_SETCONFIG, hdaudio_fgrp_setconfig_request(&request), hdaudio_fgrp_setconfig_response(&response)) == -1) err(1, "ioctl(HDAUDIO_FGRP_SETCONFIG)"); pb_destroy(hdaudio_fgrp_setconfig_request(&request)); pb_destroy(hdaudio_fgrp_setconfig_response(&response)); if (config_plist) prop_object_release(config_plist); return 0; } int hdaudioctl_graph(int fd, int argc, char *argv[]) { struct hdaudio_fgrp_codec_info_request codec_req; struct hdaudio_fgrp_codec_info_response codec_resp; struct hdaudio_fgrp_widget_info_request widget_req; struct hdaudio_fgrp_widget_info_response widget_resp; uint16_t reqnid, reqcodecid; size_t index, i, n; char buf[10] = "??h"; /* ??? */ if (argc != 2) usage(); if (parse_codecid(argv[0], strlen(argv[0]), &reqcodecid) == -1) usage(); if (parse_nid(argv[1], strlen(argv[1]), &reqnid) == -1) usage(); pb_init(hdaudio_fgrp_codec_info_request(&codec_req)); codec_req.codecid = codecid; codec_req.nid = nid; if (ioctl_pb_init(fd, HDAUDIO_FGRP_CODEC_INFO, hdaudio_fgrp_codec_info_request(&codec_req), hdaudio_fgrp_codec_info_response(&codec_resp)) == -1) err(1, "ioctl(HDAUDIO_FGRP_CODEC_INFO)"); printf("digraph \"HD Audio %04"PRIX16":%04"PRIX16"\" {\n", codec_resp.vendor_id, codec_resp.product_id); pb_destroy(hdaudio_fgrp_codec_info_response(&codec_resp)); pb_destroy(hdaudio_fgrp_codec_info_request(&codec_req)); pb_init(hdaudio_fgrp_widget_info_request(&widget_req)); widget_req.codecid = codecid; widget_req.nid = nid; for (index = 0;; index++) { const struct hdaudio_widget_info *widget; widget_req.index = index; if (ioctl_pb_init(fd, HDAUDIO_FGRP_WIDGET_INFO, hdaudio_fgrp_widget_info_request(&widget_req), hdaudio_fgrp_widget_info_response(&widget_resp)) == -1) { if (errno == EINVAL) /* XXX not very precise */ break; else err(1, "ioctl(HDAUDIO_FGRP_WIDGET_INFO)"); } widget = &widget_resp.info; snprintf(buf, sizeof buf, "widget%02Xh", widget->nid); switch (widget->type) { case COP_AWCAP_TYPE_AUDIO_OUTPUT: printf(" %s [label=\"%s\\naudio output\"," "shape=box,style=filled," "fillcolor=#88ff88\"];\n", buf, buf); break; case COP_AWCAP_TYPE_AUDIO_INPUT: printf(" %s [label=\"%s\\naudio input\"," "shape=box,style=filled," "fillcolor=#ff8888\"];\n", buf, buf); break; case COP_AWCAP_TYPE_AUDIO_MIXER: printf(" %s [label=\"%s\\naudio mixer\"," "shape=invhouse];\n", buf, buf); break; case COP_AWCAP_TYPE_AUDIO_SELECTOR: printf(" %s [label=\"%s\\naudio mixer\"," "shape=invhouse];\n", buf, buf); break; case COP_AWCAP_TYPE_PIN_COMPLEX: printf(" %s [label=\"%s\\ndevice=%s\",style=filled", buf, buf, pin_devices[COP_CFG_DEFAULT_DEVICE(config)]); if (widget->cap & COP_PINCAP_OUTPUT_CAPABLE && widget->cap & COP_PINCAP_INPUT_CAPABLE) puts(",shape=doublecircle," "fillcolor=\"#ffff88\""); else if (widget->cap & COP_PINCAP_OUTPUT_CAPABLE) puts(",shape=circle,fillcolor=\"#88ff88\""); else if (widget->cap & COP_PINCAP_INPUT_CAPABLE) puts(",shape=circle,fillcolor=\"#ff8888\""); else puts(",shape=circle,fillcolor=\"#888888\""); puts("];\n"); break; case COP_AWCAP_TYPE_POWER_WIDGET: printf(" %s [label=\"%s\\npower widget\"," "shape=box];\n", buf, buf); break; case COP_AWCAP_TYPE_VOLUME_KNOB: printf(" %s [label=\"%s\\nvolume knob\"," "shape=box];\n", buf, buf); break; case COP_AWCAP_TYPE_BEEP_GENERATOR: printf(" %s [label=\"%s\\nbeep generator\"," "shape=box];\n", buf, buf); break; case COP_AWCAP_TYPE_VENDOR_DEFINED: printf(" %s [label=\"%s\\nvendor defined\"," "shape=box];\n", buf, buf); break; } n = pb_repeated_count(&widget->connlist.repeated); for (i = 0; i < n; i++) printf(" widget%02Xh -> %s [sametail=widget%02Xh];\n", widget->connlist.item[i]); pb_destroy(hdaudio_fgrp_widget_info_response(&widget_resp)); } /* XXX HDAUDIO_AFG_CODEC_INFO, HDAUDIO_AFG_WIDGET_INFO? */ printf("}\n"); pb_destroy(hdaudio_fgrp_widget_info_request(&widget_req)); return 0; }