1 /* $NetBSD: graph.c,v 1.2 2010/08/10 13:52:13 joerg Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk> 5 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Precedence Technologies Ltd 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/ioctl.h> 34 35 #include <prop/proplib.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 43 #include <dev/pci/hdaudio/hdaudioio.h> 44 #include <dev/pci/hdaudio/hdaudioreg.h> 45 46 #include "hdaudioctl.h" 47 48 static const char *pin_devices[16] = { 49 "Line Out", "Speaker", "HP Out", "CD", 50 "SPDIF Out", "Digital Out", "Modem Line", "Modem Handset", 51 "Line In", "AUX", "Mic In", "Telephony", 52 "SPDIF In", "Digital In", "Reserved", "Other" 53 }; 54 55 int 56 hdaudioctl_graph(int fd, int argc, char *argv[]) 57 { 58 prop_dictionary_t request, response; 59 prop_object_iterator_t iter; 60 prop_number_t nnid; 61 prop_array_t connlist; 62 const char *name; 63 int error, index; 64 uint32_t cap, config; 65 uint16_t reqnid, reqcodecid; 66 uint16_t vendor, product; 67 uint8_t type, nid; 68 char buf[10] = "??h"; 69 70 if (argc != 2) 71 usage(); 72 73 reqcodecid = strtol(argv[0], NULL, 0); 74 reqnid = strtol(argv[1], NULL, 0); 75 76 request = prop_dictionary_create(); 77 if (request == NULL) { 78 fprintf(stderr, "out of memory\n"); 79 return ENOMEM; 80 } 81 82 prop_dictionary_set_uint16(request, "codecid", reqcodecid); 83 prop_dictionary_set_uint16(request, "nid", reqnid); 84 85 error = prop_dictionary_sendrecv_ioctl(request, fd, 86 HDAUDIO_FGRP_CODEC_INFO, &response); 87 if (error != 0) { 88 perror("HDAUDIO_FGRP_CODEC_INFO failed"); 89 prop_object_release(request); 90 return error; 91 } 92 93 prop_dictionary_get_uint16(response, "vendor-id", &vendor); 94 prop_dictionary_get_uint16(response, "product-id", &product); 95 96 printf("digraph \"HD Audio %04X:%04X\" {\n", 97 vendor, product); 98 99 for (index = 0;; index++) { 100 prop_dictionary_set_uint16(request, "index", index); 101 error = prop_dictionary_sendrecv_ioctl(request, fd, 102 HDAUDIO_FGRP_WIDGET_INFO, &response); 103 if (error != 0) 104 break; 105 prop_dictionary_get_cstring_nocopy(response, "name", &name); 106 prop_dictionary_get_uint32(response, "cap", &cap); 107 prop_dictionary_get_uint32(response, "config", &config); 108 prop_dictionary_get_uint8(response, "type", &type); 109 prop_dictionary_get_uint8(response, "nid", &nid); 110 111 sprintf(buf, "widget%02Xh", nid); 112 113 switch (type) { 114 case COP_AWCAP_TYPE_AUDIO_OUTPUT: 115 printf(" %s [label=\"%s\\naudio output\",shape=box,style=filled,fillcolor=\"" 116 "#88ff88\"];\n", buf, buf); 117 break; 118 case COP_AWCAP_TYPE_AUDIO_INPUT: 119 printf(" %s [label=\"%s\\naudio input\",shape=box,style=filled,fillcolor=\"" 120 "#ff8888\"];\n", buf, buf); 121 break; 122 case COP_AWCAP_TYPE_AUDIO_MIXER: 123 printf(" %s [label=\"%s\\naudio mixer\"," 124 "shape=invhouse];\n", buf, buf); 125 break; 126 case COP_AWCAP_TYPE_AUDIO_SELECTOR: 127 printf(" %s [label=\"%s\\naudio selector\"," 128 "shape=invtrapezium];\n", buf, buf); 129 break; 130 case COP_AWCAP_TYPE_PIN_COMPLEX: 131 printf(" %s [label=\"%s\\ndevice=%s\",style=filled", 132 buf, buf, 133 pin_devices[COP_CFG_DEFAULT_DEVICE(config)]); 134 if (cap & COP_PINCAP_OUTPUT_CAPABLE && 135 cap & COP_PINCAP_INPUT_CAPABLE) 136 puts(",shape=doublecircle,fillcolor=\"" 137 "#ffff88\"];"); 138 else if (cap & COP_PINCAP_OUTPUT_CAPABLE) 139 puts(",shape=circle,fillcolor=\"#88ff88\"];"); 140 else if (cap & COP_PINCAP_INPUT_CAPABLE) 141 puts(",shape=circle,fillcolor=\"#ff8888\"];"); 142 else 143 puts(",shape=circle,fillcolor=\"#888888\"];"); 144 break; 145 case COP_AWCAP_TYPE_POWER_WIDGET: 146 printf(" %s [label=\"%s\\npower widget\"," 147 "shape=box];\n", buf, buf); 148 break; 149 case COP_AWCAP_TYPE_VOLUME_KNOB: 150 printf(" %s [label=\"%s\\nvolume knob\"," 151 "shape=box];\n", buf, buf); 152 break; 153 case COP_AWCAP_TYPE_BEEP_GENERATOR: 154 printf(" %s [label=\"%s\\nbeep generator\"," 155 "shape=box];\n", buf, buf); 156 break; 157 case COP_AWCAP_TYPE_VENDOR_DEFINED: 158 printf(" %s [label=\"%s\\nvendor defined\"," 159 "shape=box];\n", buf, buf); 160 break; 161 } 162 connlist = prop_dictionary_get(response, "connlist"); 163 if (connlist == NULL) 164 goto next; 165 iter = prop_array_iterator(connlist); 166 prop_object_iterator_reset(iter); 167 while ((nnid = prop_object_iterator_next(iter)) != NULL) { 168 nid = prop_number_unsigned_integer_value(nnid); 169 printf(" widget%02Xh -> %s [sametail=widget%02Xh];\n", 170 nid, buf, nid); 171 } 172 prop_object_iterator_release(iter); 173 next: 174 prop_object_release(response); 175 } 176 177 printf(" {rank=min;"); 178 for (index = 0;; index++) { 179 prop_dictionary_set_uint16(request, "index", index); 180 error = prop_dictionary_sendrecv_ioctl(request, fd, 181 HDAUDIO_AFG_WIDGET_INFO, &response); 182 if (error != 0) 183 break; 184 prop_dictionary_get_cstring_nocopy(response, "name", &name); 185 prop_dictionary_get_uint8(response, "type", &type); 186 prop_dictionary_get_uint8(response, "nid", &nid); 187 188 sprintf(buf, "widget%02Xh", nid); 189 190 switch (type) { 191 case COP_AWCAP_TYPE_AUDIO_OUTPUT: 192 case COP_AWCAP_TYPE_AUDIO_INPUT: 193 printf(" %s;", buf); 194 break; 195 } 196 prop_object_release(response); 197 } 198 printf("}\n"); 199 200 printf(" {rank=max;"); 201 for (index = 0;; index++) { 202 prop_dictionary_set_uint16(request, "index", index); 203 error = prop_dictionary_sendrecv_ioctl(request, fd, 204 HDAUDIO_AFG_WIDGET_INFO, &response); 205 if (error != 0) 206 break; 207 prop_dictionary_get_cstring_nocopy(response, "name", &name); 208 prop_dictionary_get_uint8(response, "type", &type); 209 prop_dictionary_get_uint8(response, "nid", &nid); 210 211 sprintf(buf, "widget%02Xh", nid); 212 213 switch (type) { 214 case COP_AWCAP_TYPE_PIN_COMPLEX: 215 printf(" %s;", buf); 216 break; 217 } 218 prop_object_release(response); 219 } 220 printf("}\n"); 221 222 printf("}\n"); 223 224 prop_object_release(request); 225 226 return 0; 227 } 228