| 1 | /* |
| 2 | * Common code to disable/enable mixer emulation at run time |
| 3 | * |
| 4 | * Copyright (C) 2013 Red Hat, Inc. |
| 5 | * |
| 6 | * Written by Bandan Das <bsd@redhat.com> |
| 7 | * with important bits picked up from hda-codec.c |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License as |
| 11 | * published by the Free Software Foundation; either version 2 or |
| 12 | * (at your option) version 3 of the License. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 21 | */ |
| 22 | |
| 23 | /* |
| 24 | * HDA codec descriptions |
| 25 | */ |
| 26 | |
| 27 | #ifdef HDA_MIXER |
| 28 | #define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12) |
| 29 | #define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22) |
| 30 | #define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32) |
| 31 | #define QEMU_HDA_AMP_CAPS \ |
| 32 | (AC_AMPCAP_MUTE | \ |
| 33 | (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \ |
| 34 | (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \ |
| 35 | (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) |
| 36 | #else |
| 37 | #define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11) |
| 38 | #define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21) |
| 39 | #define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31) |
| 40 | #define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE |
| 41 | #endif |
| 42 | |
| 43 | |
| 44 | /* common: audio output widget */ |
| 45 | static const desc_param glue(common_params_audio_dac_, PARAM)[] = { |
| 46 | { |
| 47 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
| 48 | .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) | |
| 49 | AC_WCAP_FORMAT_OVRD | |
| 50 | AC_WCAP_AMP_OVRD | |
| 51 | AC_WCAP_OUT_AMP | |
| 52 | AC_WCAP_STEREO), |
| 53 | },{ |
| 54 | .id = AC_PAR_PCM, |
| 55 | .val = QEMU_HDA_PCM_FORMATS, |
| 56 | },{ |
| 57 | .id = AC_PAR_STREAM, |
| 58 | .val = AC_SUPFMT_PCM, |
| 59 | },{ |
| 60 | .id = AC_PAR_AMP_IN_CAP, |
| 61 | .val = QEMU_HDA_AMP_NONE, |
| 62 | },{ |
| 63 | .id = AC_PAR_AMP_OUT_CAP, |
| 64 | .val = QEMU_HDA_AMP_CAPS, |
| 65 | }, |
| 66 | }; |
| 67 | |
| 68 | /* common: audio input widget */ |
| 69 | static const desc_param glue(common_params_audio_adc_, PARAM)[] = { |
| 70 | { |
| 71 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
| 72 | .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) | |
| 73 | AC_WCAP_CONN_LIST | |
| 74 | AC_WCAP_FORMAT_OVRD | |
| 75 | AC_WCAP_AMP_OVRD | |
| 76 | AC_WCAP_IN_AMP | |
| 77 | AC_WCAP_STEREO), |
| 78 | },{ |
| 79 | .id = AC_PAR_CONNLIST_LEN, |
| 80 | .val = 1, |
| 81 | },{ |
| 82 | .id = AC_PAR_PCM, |
| 83 | .val = QEMU_HDA_PCM_FORMATS, |
| 84 | },{ |
| 85 | .id = AC_PAR_STREAM, |
| 86 | .val = AC_SUPFMT_PCM, |
| 87 | },{ |
| 88 | .id = AC_PAR_AMP_IN_CAP, |
| 89 | .val = QEMU_HDA_AMP_CAPS, |
| 90 | },{ |
| 91 | .id = AC_PAR_AMP_OUT_CAP, |
| 92 | .val = QEMU_HDA_AMP_NONE, |
| 93 | }, |
| 94 | }; |
| 95 | |
| 96 | /* common: pin widget (line-out) */ |
| 97 | static const desc_param glue(common_params_audio_lineout_, PARAM)[] = { |
| 98 | { |
| 99 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
| 100 | .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | |
| 101 | AC_WCAP_CONN_LIST | |
| 102 | AC_WCAP_STEREO), |
| 103 | },{ |
| 104 | .id = AC_PAR_PIN_CAP, |
| 105 | .val = AC_PINCAP_OUT, |
| 106 | },{ |
| 107 | .id = AC_PAR_CONNLIST_LEN, |
| 108 | .val = 1, |
| 109 | },{ |
| 110 | .id = AC_PAR_AMP_IN_CAP, |
| 111 | .val = QEMU_HDA_AMP_NONE, |
| 112 | },{ |
| 113 | .id = AC_PAR_AMP_OUT_CAP, |
| 114 | .val = QEMU_HDA_AMP_NONE, |
| 115 | }, |
| 116 | }; |
| 117 | |
| 118 | /* common: pin widget (line-in) */ |
| 119 | static const desc_param glue(common_params_audio_linein_, PARAM)[] = { |
| 120 | { |
| 121 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
| 122 | .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | |
| 123 | AC_WCAP_STEREO), |
| 124 | },{ |
| 125 | .id = AC_PAR_PIN_CAP, |
| 126 | .val = AC_PINCAP_IN, |
| 127 | },{ |
| 128 | .id = AC_PAR_AMP_IN_CAP, |
| 129 | .val = QEMU_HDA_AMP_NONE, |
| 130 | },{ |
| 131 | .id = AC_PAR_AMP_OUT_CAP, |
| 132 | .val = QEMU_HDA_AMP_NONE, |
| 133 | }, |
| 134 | }; |
| 135 | |
| 136 | /* output: root node */ |
| 137 | static const desc_param glue(output_params_root_, PARAM)[] = { |
| 138 | { |
| 139 | .id = AC_PAR_VENDOR_ID, |
| 140 | .val = QEMU_HDA_ID_OUTPUT, |
| 141 | },{ |
| 142 | .id = AC_PAR_SUBSYSTEM_ID, |
| 143 | .val = QEMU_HDA_ID_OUTPUT, |
| 144 | },{ |
| 145 | .id = AC_PAR_REV_ID, |
| 146 | .val = 0x00100101, |
| 147 | },{ |
| 148 | .id = AC_PAR_NODE_COUNT, |
| 149 | .val = 0x00010001, |
| 150 | }, |
| 151 | }; |
| 152 | |
| 153 | /* output: audio function */ |
| 154 | static const desc_param glue(output_params_audio_func_, PARAM)[] = { |
| 155 | { |
| 156 | .id = AC_PAR_FUNCTION_TYPE, |
| 157 | .val = AC_GRP_AUDIO_FUNCTION, |
| 158 | },{ |
| 159 | .id = AC_PAR_SUBSYSTEM_ID, |
| 160 | .val = QEMU_HDA_ID_OUTPUT, |
| 161 | },{ |
| 162 | .id = AC_PAR_NODE_COUNT, |
| 163 | .val = 0x00020002, |
| 164 | },{ |
| 165 | .id = AC_PAR_PCM, |
| 166 | .val = QEMU_HDA_PCM_FORMATS, |
| 167 | },{ |
| 168 | .id = AC_PAR_STREAM, |
| 169 | .val = AC_SUPFMT_PCM, |
| 170 | },{ |
| 171 | .id = AC_PAR_AMP_IN_CAP, |
| 172 | .val = QEMU_HDA_AMP_NONE, |
| 173 | },{ |
| 174 | .id = AC_PAR_AMP_OUT_CAP, |
| 175 | .val = QEMU_HDA_AMP_NONE, |
| 176 | },{ |
| 177 | .id = AC_PAR_GPIO_CAP, |
| 178 | .val = 0, |
| 179 | },{ |
| 180 | .id = AC_PAR_AUDIO_FG_CAP, |
| 181 | .val = 0x00000808, |
| 182 | },{ |
| 183 | .id = AC_PAR_POWER_STATE, |
| 184 | .val = 0, |
| 185 | }, |
| 186 | }; |
| 187 | |
| 188 | /* output: nodes */ |
| 189 | static const desc_node glue(output_nodes_, PARAM)[] = { |
| 190 | { |
| 191 | .nid = AC_NODE_ROOT, |
| 192 | .name = "root", |
| 193 | .params = glue(output_params_root_, PARAM), |
| 194 | .nparams = ARRAY_SIZE(glue(output_params_root_, PARAM)), |
| 195 | },{ |
| 196 | .nid = 1, |
| 197 | .name = "func", |
| 198 | .params = glue(output_params_audio_func_, PARAM), |
| 199 | .nparams = ARRAY_SIZE(glue(output_params_audio_func_, PARAM)), |
| 200 | },{ |
| 201 | .nid = 2, |
| 202 | .name = "dac", |
| 203 | .params = glue(common_params_audio_dac_, PARAM), |
| 204 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
| 205 | .stindex = 0, |
| 206 | },{ |
| 207 | .nid = 3, |
| 208 | .name = "out", |
| 209 | .params = glue(common_params_audio_lineout_, PARAM), |
| 210 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
| 211 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
| 212 | (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | |
| 213 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
| 214 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
| 215 | 0x10), |
| 216 | .pinctl = AC_PINCTL_OUT_EN, |
| 217 | .conn = (uint32_t[]) { 2 }, |
| 218 | } |
| 219 | }; |
| 220 | |
| 221 | /* output: codec */ |
| 222 | static const desc_codec glue(output_, PARAM) = { |
| 223 | .name = "output", |
| 224 | .iid = QEMU_HDA_ID_OUTPUT, |
| 225 | .nodes = glue(output_nodes_, PARAM), |
| 226 | .nnodes = ARRAY_SIZE(glue(output_nodes_, PARAM)), |
| 227 | }; |
| 228 | |
| 229 | /* duplex: root node */ |
| 230 | static const desc_param glue(duplex_params_root_, PARAM)[] = { |
| 231 | { |
| 232 | .id = AC_PAR_VENDOR_ID, |
| 233 | .val = QEMU_HDA_ID_DUPLEX, |
| 234 | },{ |
| 235 | .id = AC_PAR_SUBSYSTEM_ID, |
| 236 | .val = QEMU_HDA_ID_DUPLEX, |
| 237 | },{ |
| 238 | .id = AC_PAR_REV_ID, |
| 239 | .val = 0x00100101, |
| 240 | },{ |
| 241 | .id = AC_PAR_NODE_COUNT, |
| 242 | .val = 0x00010001, |
| 243 | }, |
| 244 | }; |
| 245 | |
| 246 | /* duplex: audio function */ |
| 247 | static const desc_param glue(duplex_params_audio_func_, PARAM)[] = { |
| 248 | { |
| 249 | .id = AC_PAR_FUNCTION_TYPE, |
| 250 | .val = AC_GRP_AUDIO_FUNCTION, |
| 251 | },{ |
| 252 | .id = AC_PAR_SUBSYSTEM_ID, |
| 253 | .val = QEMU_HDA_ID_DUPLEX, |
| 254 | },{ |
| 255 | .id = AC_PAR_NODE_COUNT, |
| 256 | .val = 0x00020004, |
| 257 | },{ |
| 258 | .id = AC_PAR_PCM, |
| 259 | .val = QEMU_HDA_PCM_FORMATS, |
| 260 | },{ |
| 261 | .id = AC_PAR_STREAM, |
| 262 | .val = AC_SUPFMT_PCM, |
| 263 | },{ |
| 264 | .id = AC_PAR_AMP_IN_CAP, |
| 265 | .val = QEMU_HDA_AMP_NONE, |
| 266 | },{ |
| 267 | .id = AC_PAR_AMP_OUT_CAP, |
| 268 | .val = QEMU_HDA_AMP_NONE, |
| 269 | },{ |
| 270 | .id = AC_PAR_GPIO_CAP, |
| 271 | .val = 0, |
| 272 | },{ |
| 273 | .id = AC_PAR_AUDIO_FG_CAP, |
| 274 | .val = 0x00000808, |
| 275 | },{ |
| 276 | .id = AC_PAR_POWER_STATE, |
| 277 | .val = 0, |
| 278 | }, |
| 279 | }; |
| 280 | |
| 281 | /* duplex: nodes */ |
| 282 | static const desc_node glue(duplex_nodes_, PARAM)[] = { |
| 283 | { |
| 284 | .nid = AC_NODE_ROOT, |
| 285 | .name = "root", |
| 286 | .params = glue(duplex_params_root_, PARAM), |
| 287 | .nparams = ARRAY_SIZE(glue(duplex_params_root_, PARAM)), |
| 288 | },{ |
| 289 | .nid = 1, |
| 290 | .name = "func", |
| 291 | .params = glue(duplex_params_audio_func_, PARAM), |
| 292 | .nparams = ARRAY_SIZE(glue(duplex_params_audio_func_, PARAM)), |
| 293 | },{ |
| 294 | .nid = 2, |
| 295 | .name = "dac", |
| 296 | .params = glue(common_params_audio_dac_, PARAM), |
| 297 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
| 298 | .stindex = 0, |
| 299 | },{ |
| 300 | .nid = 3, |
| 301 | .name = "out", |
| 302 | .params = glue(common_params_audio_lineout_, PARAM), |
| 303 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
| 304 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
| 305 | (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | |
| 306 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
| 307 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
| 308 | 0x10), |
| 309 | .pinctl = AC_PINCTL_OUT_EN, |
| 310 | .conn = (uint32_t[]) { 2 }, |
| 311 | },{ |
| 312 | .nid = 4, |
| 313 | .name = "adc", |
| 314 | .params = glue(common_params_audio_adc_, PARAM), |
| 315 | .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), |
| 316 | .stindex = 1, |
| 317 | .conn = (uint32_t[]) { 5 }, |
| 318 | },{ |
| 319 | .nid = 5, |
| 320 | .name = "in", |
| 321 | .params = glue(common_params_audio_linein_, PARAM), |
| 322 | .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), |
| 323 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
| 324 | (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) | |
| 325 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
| 326 | (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | |
| 327 | 0x20), |
| 328 | .pinctl = AC_PINCTL_IN_EN, |
| 329 | } |
| 330 | }; |
| 331 | |
| 332 | /* duplex: codec */ |
| 333 | static const desc_codec glue(duplex_, PARAM) = { |
| 334 | .name = "duplex", |
| 335 | .iid = QEMU_HDA_ID_DUPLEX, |
| 336 | .nodes = glue(duplex_nodes_, PARAM), |
| 337 | .nnodes = ARRAY_SIZE(glue(duplex_nodes_, PARAM)), |
| 338 | }; |
| 339 | |
| 340 | /* micro: root node */ |
| 341 | static const desc_param glue(micro_params_root_, PARAM)[] = { |
| 342 | { |
| 343 | .id = AC_PAR_VENDOR_ID, |
| 344 | .val = QEMU_HDA_ID_MICRO, |
| 345 | },{ |
| 346 | .id = AC_PAR_SUBSYSTEM_ID, |
| 347 | .val = QEMU_HDA_ID_MICRO, |
| 348 | },{ |
| 349 | .id = AC_PAR_REV_ID, |
| 350 | .val = 0x00100101, |
| 351 | },{ |
| 352 | .id = AC_PAR_NODE_COUNT, |
| 353 | .val = 0x00010001, |
| 354 | }, |
| 355 | }; |
| 356 | |
| 357 | /* micro: audio function */ |
| 358 | static const desc_param glue(micro_params_audio_func_, PARAM)[] = { |
| 359 | { |
| 360 | .id = AC_PAR_FUNCTION_TYPE, |
| 361 | .val = AC_GRP_AUDIO_FUNCTION, |
| 362 | },{ |
| 363 | .id = AC_PAR_SUBSYSTEM_ID, |
| 364 | .val = QEMU_HDA_ID_MICRO, |
| 365 | },{ |
| 366 | .id = AC_PAR_NODE_COUNT, |
| 367 | .val = 0x00020004, |
| 368 | },{ |
| 369 | .id = AC_PAR_PCM, |
| 370 | .val = QEMU_HDA_PCM_FORMATS, |
| 371 | },{ |
| 372 | .id = AC_PAR_STREAM, |
| 373 | .val = AC_SUPFMT_PCM, |
| 374 | },{ |
| 375 | .id = AC_PAR_AMP_IN_CAP, |
| 376 | .val = QEMU_HDA_AMP_NONE, |
| 377 | },{ |
| 378 | .id = AC_PAR_AMP_OUT_CAP, |
| 379 | .val = QEMU_HDA_AMP_NONE, |
| 380 | },{ |
| 381 | .id = AC_PAR_GPIO_CAP, |
| 382 | .val = 0, |
| 383 | },{ |
| 384 | .id = AC_PAR_AUDIO_FG_CAP, |
| 385 | .val = 0x00000808, |
| 386 | },{ |
| 387 | .id = AC_PAR_POWER_STATE, |
| 388 | .val = 0, |
| 389 | }, |
| 390 | }; |
| 391 | |
| 392 | /* micro: nodes */ |
| 393 | static const desc_node glue(micro_nodes_, PARAM)[] = { |
| 394 | { |
| 395 | .nid = AC_NODE_ROOT, |
| 396 | .name = "root", |
| 397 | .params = glue(micro_params_root_, PARAM), |
| 398 | .nparams = ARRAY_SIZE(glue(micro_params_root_, PARAM)), |
| 399 | },{ |
| 400 | .nid = 1, |
| 401 | .name = "func", |
| 402 | .params = glue(micro_params_audio_func_, PARAM), |
| 403 | .nparams = ARRAY_SIZE(glue(micro_params_audio_func_, PARAM)), |
| 404 | },{ |
| 405 | .nid = 2, |
| 406 | .name = "dac", |
| 407 | .params = glue(common_params_audio_dac_, PARAM), |
| 408 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
| 409 | .stindex = 0, |
| 410 | },{ |
| 411 | .nid = 3, |
| 412 | .name = "out", |
| 413 | .params = glue(common_params_audio_lineout_, PARAM), |
| 414 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
| 415 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
| 416 | (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) | |
| 417 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
| 418 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
| 419 | 0x10), |
| 420 | .pinctl = AC_PINCTL_OUT_EN, |
| 421 | .conn = (uint32_t[]) { 2 }, |
| 422 | },{ |
| 423 | .nid = 4, |
| 424 | .name = "adc", |
| 425 | .params = glue(common_params_audio_adc_, PARAM), |
| 426 | .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), |
| 427 | .stindex = 1, |
| 428 | .conn = (uint32_t[]) { 5 }, |
| 429 | },{ |
| 430 | .nid = 5, |
| 431 | .name = "in", |
| 432 | .params = glue(common_params_audio_linein_, PARAM), |
| 433 | .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), |
| 434 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
| 435 | (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) | |
| 436 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
| 437 | (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | |
| 438 | 0x20), |
| 439 | .pinctl = AC_PINCTL_IN_EN, |
| 440 | } |
| 441 | }; |
| 442 | |
| 443 | /* micro: codec */ |
| 444 | static const desc_codec glue(micro_, PARAM) = { |
| 445 | .name = "micro", |
| 446 | .iid = QEMU_HDA_ID_MICRO, |
| 447 | .nodes = glue(micro_nodes_, PARAM), |
| 448 | .nnodes = ARRAY_SIZE(glue(micro_nodes_, PARAM)), |
| 449 | }; |
| 450 | |
| 451 | #undef PARAM |
| 452 | #undef HDA_MIXER |
| 453 | #undef QEMU_HDA_ID_OUTPUT |
| 454 | #undef QEMU_HDA_ID_DUPLEX |
| 455 | #undef QEMU_HDA_ID_MICRO |
| 456 | #undef QEMU_HDA_AMP_CAPS |