summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Audio/DevHda.h
blob: 5c3bad5843692f0d37e2279fdcbe670be214ada5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
/* $Id: DevHda.h $ */
/** @file
 * Intel HD Audio Controller Emulation - Structures.
 */

/*
 * Copyright (C) 2016-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#ifndef VBOX_INCLUDED_SRC_Audio_DevHda_h
#define VBOX_INCLUDED_SRC_Audio_DevHda_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/path.h>
#include <VBox/vmm/pdmdev.h>
#include "AudioMixer.h"

/*
 * Compile time feature configuration.
 */

/** @def VBOX_HDA_WITH_ON_REG_ACCESS_DMA
 * Enables doing DMA work on certain register accesses (LPIB, WALCLK) in
 * addition to the DMA timer.   All but the last frame can be done during
 * register accesses (as we don't wish to leave the DMA timer w/o work to
 * do in case that upsets it). */
#if defined(DOXYGEN_RUNNING) || 0
# define VBOX_HDA_WITH_ON_REG_ACCESS_DMA
#endif

#ifdef DEBUG_andy
/** Enables strict mode, which checks for stuff which isn't supposed to happen.
 *  Be prepared for assertions coming in! */
//# define HDA_STRICT
#endif

/** @def HDA_AS_PCI_EXPRESS
 * Enables PCI express hardware.  */
#if defined(DOXYGEN_RUNNING) || 0
# define HDA_AS_PCI_EXPRESS
#endif

/** @def HDA_DEBUG_SILENCE
 * To debug silence coming from the guest in form of audio gaps.
 * Very crude implementation for now.
 * @todo probably borked atm */
#if defined(DOXYGEN_RUNNING) || 0
# define HDA_DEBUG_SILENCE
#endif


/*
 * Common pointer types.
 */
/** Pointer to an HDA stream (SDI / SDO).  */
typedef struct HDASTREAMR3 *PHDASTREAMR3;
/** Pointer to a shared HDA device state.  */
typedef struct HDASTATE    *PHDASTATE;
/** Pointer to a ring-3 HDA device state.  */
typedef struct HDASTATER3  *PHDASTATER3;
/** Pointer to an HDA mixer sink definition (ring-3). */
typedef struct HDAMIXERSINK *PHDAMIXERSINK;


/*
 * The rest of the headers.
 */
#include "DevHdaStream.h"
#include "DevHdaCodec.h"



/** @name Stream counts.
 *
 * At the moment we support 4 input + 4 output streams max, which is 8 in total.
 * Bidirectional streams are currently *not* supported.
 *
 * @note When changing any of those values, be prepared for some saved state
 *       fixups / trouble!
 * @{
 */
#define HDA_MAX_SDI                 4
#define HDA_MAX_SDO                 4
#define HDA_MAX_STREAMS             (HDA_MAX_SDI + HDA_MAX_SDO)
/** @} */
AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);


/** @defgroup grp_hda_regs  HDA Register Definitions
 *
 * There are two variants for most register defines:
 *      - HDA_REG_XXX: Index into g_aHdaRegMap
 *      - HDA_RMX_XXX: Index into HDASTATE::au32Regs
 *
 * Use the HDA_REG and HDA_STREAM_REG macros to access registers where possible.
 *
 * @note The au32Regs[] layout is kept unchanged for saved state compatibility,
 *       thus the HDA_RMX_XXX assignments are for all purposes set in stone.
 *
 * @{ */

/** Number of general registers. */
#define HDA_NUM_GENERAL_REGS        36
/** Number of stream registers (10 registers per stream). */
#define HDA_NUM_STREAM_REGS         (HDA_MAX_STREAMS * 10 /* Each stream descriptor has 10 registers */)
/** Number of register after the stream registers. */
#define HDA_NUM_POST_STREAM_REGS    (2 + HDA_MAX_STREAMS * 2)
/** Number of total registers in the HDA's register map. */
#define HDA_NUM_REGS                (HDA_NUM_GENERAL_REGS + HDA_NUM_STREAM_REGS + HDA_NUM_POST_STREAM_REGS)
/** Total number of stream tags (channels). Index 0 is reserved / invalid. */
#define HDA_MAX_TAGS                16


/** Offset of the SD0 register map. */
#define HDA_REG_DESC_SD0_BASE       0x80

/* Registers */
#define HDA_REG_IND_NAME(x)         HDA_REG_##x
#define HDA_MEM_IND_NAME(x)         HDA_RMX_##x

/** Direct register access by HDASTATE::au32Reg index. */
#define HDA_REG_BY_IDX(a_pThis, a_idxReg)   ((a_pThis)->au32Regs[(a_idxReg)])

/** Accesses register @a ShortRegNm. */
#if defined(VBOX_STRICT) && defined(VBOX_HDA_CAN_ACCESS_REG_MAP)
# define HDA_REG(a_pThis, a_ShortRegNm)     (*hdaStrictRegAccessor(a_pThis, HDA_REG_IND_NAME(a_ShortRegNm), HDA_MEM_IND_NAME(a_ShortRegNm)))
#else
# define HDA_REG(a_pThis, a_ShortRegNm)     HDA_REG_BY_IDX(a_pThis, HDA_MEM_IND_NAME(a_ShortRegNm))
#endif

/** Indirect register access via g_aHdaRegMap[].idxReg. */
#define HDA_REG_IND(a_pThis, a_idxMap)      HDA_REG_BY_IDX(a_pThis, g_aHdaRegMap[(a_idxMap)].idxReg)


#define HDA_REG_GCAP                0           /* Range 0x00 - 0x01 */
#define HDA_RMX_GCAP                0
/**
 * GCAP HDASpec 3.3.2 This macro encodes the following information about HDA in a compact manner:
 *
 * oss (15:12) - Number of output streams supported.
 * iss (11:8)  - Number of input streams supported.
 * bss (7:3)   - Number of bidirectional streams supported.
 * bds (2:1)   - Number of serial data out (SDO) signals supported.
 * b64sup (0)  - 64 bit addressing supported.
 */
#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
    (  (((oss)   & 0xF)  << 12) \
     | (((iss)   & 0xF)  << 8)  \
     | (((bss)   & 0x1F) << 3)  \
     | (((bds)   & 0x3)  << 2)  \
     | ((b64sup) & 1))

#define HDA_REG_VMIN                1           /* 0x02 */
#define HDA_RMX_VMIN                1

#define HDA_REG_VMAJ                2           /* 0x03 */
#define HDA_RMX_VMAJ                2

#define HDA_REG_OUTPAY              3           /* 0x04-0x05 */
#define HDA_RMX_OUTPAY              3

#define HDA_REG_INPAY               4           /* 0x06-0x07 */
#define HDA_RMX_INPAY               4

#define HDA_REG_GCTL                5           /* 0x08-0x0B */
#define HDA_RMX_GCTL                5
#define HDA_GCTL_UNSOL              RT_BIT(8)   /* Accept Unsolicited Response Enable */
#define HDA_GCTL_FCNTRL             RT_BIT(1)   /* Flush Control */
#define HDA_GCTL_CRST               RT_BIT(0)   /* Controller Reset */

#define HDA_REG_WAKEEN              6           /* 0x0C */
#define HDA_RMX_WAKEEN              6

#define HDA_REG_STATESTS            7           /* 0x0E */
#define HDA_RMX_STATESTS            7
#define HDA_STATESTS_SCSF_MASK      0x7         /* State Change Status Flags (6.2.8). */

#define HDA_REG_GSTS                8           /* 0x10-0x11*/
#define HDA_RMX_GSTS                8
#define HDA_GSTS_FSTS               RT_BIT(1)   /* Flush Status */

#define HDA_REG_LLCH                9           /* 0x14 */
#define HDA_RMX_LLCH                114

#define HDA_REG_OUTSTRMPAY          10           /* 0x18 */
#define HDA_RMX_OUTSTRMPAY          112

#define HDA_REG_INSTRMPAY           11          /* 0x1a */
#define HDA_RMX_INSTRMPAY           113

#define HDA_REG_INTCTL              12          /* 0x20 */
#define HDA_RMX_INTCTL              9
#define HDA_INTCTL_GIE              RT_BIT(31)  /* Global Interrupt Enable */
#define HDA_INTCTL_CIE              RT_BIT(30)  /* Controller Interrupt Enable */
/** Bits 0-29 correspond to streams 0-29. */
#define HDA_STRMINT_MASK            0xFF        /* Streams 0-7 implemented. Applies to INTCTL and INTSTS. */

#define HDA_REG_INTSTS              13          /* 0x24 */
#define HDA_RMX_INTSTS              10
#define HDA_INTSTS_GIS              RT_BIT(31)  /* Global Interrupt Status */
#define HDA_INTSTS_CIS              RT_BIT(30)  /* Controller Interrupt Status */

#define HDA_REG_WALCLK              14          /* 0x30 */
/* NB: HDA_RMX_WALCLK is not defined because the register is not stored in memory. */

/**
 * @note The HDA specification defines a SSYNC register at offset 0x38.  The ICH6/ICH9
 *       datahseet defines SSYNC at offset 0x34.  The Linux HDA driver matches the datasheet.
 *       See also https://mailman.alsa-project.org/pipermail/alsa-devel/2011-March/037819.html
 */
#define HDA_REG_SSYNC               15          /* 0x34 */
#define HDA_RMX_SSYNC               12

#define HDA_REG_NEW_SSYNC           16          /* 0x38 */
#define HDA_RMX_NEW_SSYNC           HDA_RMX_SSYNC

#define HDA_REG_CORBLBASE           17          /* 0x40 */
#define HDA_RMX_CORBLBASE           13

#define HDA_REG_CORBUBASE           18          /* 0x44 */
#define HDA_RMX_CORBUBASE           14

#define HDA_REG_CORBWP              19          /* 0x48 */
#define HDA_RMX_CORBWP              15

#define HDA_REG_CORBRP              20          /* 0x4A */
#define HDA_RMX_CORBRP              16
#define HDA_CORBRP_RST              RT_BIT(15)  /* CORB Read Pointer Reset */

#define HDA_REG_CORBCTL             21          /* 0x4C */
#define HDA_RMX_CORBCTL             17
#define HDA_CORBCTL_DMA             RT_BIT(1)   /* Enable CORB DMA Engine */
#define HDA_CORBCTL_CMEIE           RT_BIT(0)   /* CORB Memory Error Interrupt Enable */

#define HDA_REG_CORBSTS             22          /* 0x4D */
#define HDA_RMX_CORBSTS             18

#define HDA_REG_CORBSIZE            23          /* 0x4E */
#define HDA_RMX_CORBSIZE            19
#define HDA_CORBSIZE_SZ_CAP         0xF0
#define HDA_CORBSIZE_SZ             0x3

/** Number of CORB buffer entries. */
#define HDA_CORB_SIZE               256
/** CORB element size (in bytes). */
#define HDA_CORB_ELEMENT_SIZE       4
/** Number of RIRB buffer entries. */
#define HDA_RIRB_SIZE               256
/** RIRB element size (in bytes). */
#define HDA_RIRB_ELEMENT_SIZE       8

#define HDA_REG_RIRBLBASE           24          /* 0x50 */
#define HDA_RMX_RIRBLBASE           20

#define HDA_REG_RIRBUBASE           25          /* 0x54 */
#define HDA_RMX_RIRBUBASE           21

#define HDA_REG_RIRBWP              26          /* 0x58 */
#define HDA_RMX_RIRBWP              22
#define HDA_RIRBWP_RST              RT_BIT(15)  /* RIRB Write Pointer Reset */

#define HDA_REG_RINTCNT             27          /* 0x5A */
#define HDA_RMX_RINTCNT             23

/** Maximum number of Response Interrupts. */
#define HDA_MAX_RINTCNT             256

#define HDA_REG_RIRBCTL             28          /* 0x5C */
#define HDA_RMX_RIRBCTL             24
#define HDA_RIRBCTL_ROIC            RT_BIT(2)   /* Response Overrun Interrupt Control */
#define HDA_RIRBCTL_RDMAEN          RT_BIT(1)   /* RIRB DMA Enable */
#define HDA_RIRBCTL_RINTCTL         RT_BIT(0)   /* Response Interrupt Control */

#define HDA_REG_RIRBSTS             29          /* 0x5D */
#define HDA_RMX_RIRBSTS             25
#define HDA_RIRBSTS_RIRBOIS         RT_BIT(2)   /* Response Overrun Interrupt Status */
#define HDA_RIRBSTS_RINTFL          RT_BIT(0)   /* Response Interrupt Flag */

#define HDA_REG_RIRBSIZE            30          /* 0x5E */
#define HDA_RMX_RIRBSIZE            26

#define HDA_REG_IC                  31          /* 0x60 */
#define HDA_RMX_IC                  27

#define HDA_REG_IR                  32          /* 0x64 */
#define HDA_RMX_IR                  28

#define HDA_REG_IRS                 33          /* 0x68 */
#define HDA_RMX_IRS                 29
#define HDA_IRS_IRV                 RT_BIT(1)   /* Immediate Result Valid */
#define HDA_IRS_ICB                 RT_BIT(0)   /* Immediate Command Busy */

#define HDA_REG_DPLBASE             34          /* 0x70 */
#define HDA_RMX_DPLBASE             30

#define HDA_REG_DPUBASE             35          /* 0x74 */
#define HDA_RMX_DPUBASE             31

#define DPBASE_ADDR_MASK            (~(uint64_t)0x7f)

#define HDA_STREAM_REG_DEF(name, num)           (HDA_REG_SD##num##name)
#define HDA_STREAM_RMX_DEF(name, num)           (HDA_RMX_SD##num##name)
/** @note sdnum here _MUST_ be stream reg number [0,7]. */
#if defined(VBOX_STRICT) && defined(VBOX_HDA_CAN_ACCESS_REG_MAP)
# define HDA_STREAM_REG(pThis, name, sdnum)      (*hdaStrictStreamRegAccessor((pThis), HDA_REG_SD0##name, HDA_RMX_SD0##name, (sdnum)))
#else
# define HDA_STREAM_REG(pThis, name, sdnum)      (HDA_REG_BY_IDX((pThis), HDA_RMX_SD0##name + (sdnum) * 10))
#endif

#define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
#define HDA_SD_TO_REG(a_Name, uSD)              (HDA_STREAM_REG_DEF(a_Name, 0) + (uSD) * 10)

/** @todo Condense marcos! */

#define HDA_REG_SD0CTL              HDA_NUM_GENERAL_REGS /* 0x80; other streams offset by 0x20 */
#define HDA_RMX_SD0CTL              32
#define HDA_RMX_SD1CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
#define HDA_RMX_SD2CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
#define HDA_RMX_SD3CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 30)
#define HDA_RMX_SD4CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 40)
#define HDA_RMX_SD5CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 50)
#define HDA_RMX_SD6CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 60)
#define HDA_RMX_SD7CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 70)

#define HDA_SDCTL_NUM_MASK          0xF
#define HDA_SDCTL_NUM_SHIFT         20
#define HDA_SDCTL_DIR               RT_BIT(19)  /* Direction (Bidirectional streams only!) */
#define HDA_SDCTL_TP                RT_BIT(18)  /* Traffic Priority (PCI Express) */
#define HDA_SDCTL_STRIPE_MASK       0x3
#define HDA_SDCTL_STRIPE_SHIFT      16
#define HDA_SDCTL_DEIE              RT_BIT(4)   /* Descriptor Error Interrupt Enable */
#define HDA_SDCTL_FEIE              RT_BIT(3)   /* FIFO Error Interrupt Enable */
#define HDA_SDCTL_IOCE              RT_BIT(2)   /* Interrupt On Completion Enable */
#define HDA_SDCTL_RUN               RT_BIT(1)   /* Stream Run */
#define HDA_SDCTL_SRST              RT_BIT(0)   /* Stream Reset */

#define HDA_REG_SD0STS              (HDA_NUM_GENERAL_REGS + 1) /* 0x83; other streams offset by 0x20 */
#define HDA_RMX_SD0STS              33
#define HDA_RMX_SD1STS              (HDA_STREAM_RMX_DEF(STS, 0) + 10)
#define HDA_RMX_SD2STS              (HDA_STREAM_RMX_DEF(STS, 0) + 20)
#define HDA_RMX_SD3STS              (HDA_STREAM_RMX_DEF(STS, 0) + 30)
#define HDA_RMX_SD4STS              (HDA_STREAM_RMX_DEF(STS, 0) + 40)
#define HDA_RMX_SD5STS              (HDA_STREAM_RMX_DEF(STS, 0) + 50)
#define HDA_RMX_SD6STS              (HDA_STREAM_RMX_DEF(STS, 0) + 60)
#define HDA_RMX_SD7STS              (HDA_STREAM_RMX_DEF(STS, 0) + 70)

#define HDA_SDSTS_FIFORDY           RT_BIT(5)   /* FIFO Ready */
#define HDA_SDSTS_DESE              RT_BIT(4)   /* Descriptor Error */
#define HDA_SDSTS_FIFOE             RT_BIT(3)   /* FIFO Error */
#define HDA_SDSTS_BCIS              RT_BIT(2)   /* Buffer Completion Interrupt Status */

#define HDA_REG_SD0LPIB             (HDA_NUM_GENERAL_REGS + 2) /* 0x84; other streams offset by 0x20 */
#define HDA_REG_SD1LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */
#define HDA_REG_SD2LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */
#define HDA_REG_SD3LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */
#define HDA_REG_SD4LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */
#define HDA_REG_SD5LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */
#define HDA_REG_SD6LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */
#define HDA_REG_SD7LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */
#define HDA_RMX_SD0LPIB             34
#define HDA_RMX_SD1LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 10)
#define HDA_RMX_SD2LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 20)
#define HDA_RMX_SD3LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 30)
#define HDA_RMX_SD4LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 40)
#define HDA_RMX_SD5LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 50)
#define HDA_RMX_SD6LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 60)
#define HDA_RMX_SD7LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 70)

#define HDA_REG_SD0CBL              (HDA_NUM_GENERAL_REGS + 3) /* 0x88; other streams offset by 0x20 */
#define HDA_RMX_SD0CBL              35
#define HDA_RMX_SD1CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 10)
#define HDA_RMX_SD2CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 20)
#define HDA_RMX_SD3CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 30)
#define HDA_RMX_SD4CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 40)
#define HDA_RMX_SD5CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 50)
#define HDA_RMX_SD6CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 60)
#define HDA_RMX_SD7CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 70)

#define HDA_REG_SD0LVI              (HDA_NUM_GENERAL_REGS + 4) /* 0x8C; other streams offset by 0x20 */
#define HDA_RMX_SD0LVI              36
#define HDA_RMX_SD1LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 10)
#define HDA_RMX_SD2LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 20)
#define HDA_RMX_SD3LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 30)
#define HDA_RMX_SD4LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 40)
#define HDA_RMX_SD5LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 50)
#define HDA_RMX_SD6LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 60)
#define HDA_RMX_SD7LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 70)

#define HDA_REG_SD0FIFOW            (HDA_NUM_GENERAL_REGS + 5) /* 0x8E; other streams offset by 0x20 */
#define HDA_RMX_SD0FIFOW            37
#define HDA_RMX_SD1FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 10)
#define HDA_RMX_SD2FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 20)
#define HDA_RMX_SD3FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 30)
#define HDA_RMX_SD4FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 40)
#define HDA_RMX_SD5FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 50)
#define HDA_RMX_SD6FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 60)
#define HDA_RMX_SD7FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 70)

/*
 * ICH6 datasheet defined limits for FIFOW values (18.2.38).
 */
#define HDA_SDFIFOW_8B              0x2
#define HDA_SDFIFOW_16B             0x3
#define HDA_SDFIFOW_32B             0x4

#define HDA_REG_SD0FIFOS            (HDA_NUM_GENERAL_REGS + 6) /* 0x90; other streams offset by 0x20 */
#define HDA_RMX_SD0FIFOS            38
#define HDA_RMX_SD1FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 10)
#define HDA_RMX_SD2FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 20)
#define HDA_RMX_SD3FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 30)
#define HDA_RMX_SD4FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 40)
#define HDA_RMX_SD5FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 50)
#define HDA_RMX_SD6FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 60)
#define HDA_RMX_SD7FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 70)

/* The ICH6 datasheet defines limits for FIFOS registers (18.2.39).
   Formula: size - 1
   Other values not listed are not supported. */

#define HDA_SDIFIFO_120B            0x77        /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
#define HDA_SDIFIFO_160B            0x9F        /* 20-, 24-bit Input Streams Streams */

#define HDA_SDOFIFO_16B             0x0F        /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
#define HDA_SDOFIFO_32B             0x1F        /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
#define HDA_SDOFIFO_64B             0x3F        /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
#define HDA_SDOFIFO_128B            0x7F        /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
#define HDA_SDOFIFO_192B            0xBF        /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
#define HDA_SDOFIFO_256B            0xFF        /* 20-, 24-bit Output Streams */

#define HDA_REG_SD0FMT              (HDA_NUM_GENERAL_REGS + 7) /* 0x92; other streams offset by 0x20 */
#define HDA_RMX_SD0FMT              39
#define HDA_RMX_SD1FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 10)
#define HDA_RMX_SD2FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 20)
#define HDA_RMX_SD3FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 30)
#define HDA_RMX_SD4FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 40)
#define HDA_RMX_SD5FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 50)
#define HDA_RMX_SD6FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
#define HDA_RMX_SD7FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 70)

#define HDA_REG_SD0BDPL             (HDA_NUM_GENERAL_REGS + 8) /* 0x98; other streams offset by 0x20 */
#define HDA_RMX_SD0BDPL             40
#define HDA_RMX_SD1BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 10)
#define HDA_RMX_SD2BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 20)
#define HDA_RMX_SD3BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 30)
#define HDA_RMX_SD4BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 40)
#define HDA_RMX_SD5BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 50)
#define HDA_RMX_SD6BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 60)
#define HDA_RMX_SD7BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 70)

#define HDA_REG_SD0BDPU             (HDA_NUM_GENERAL_REGS + 9) /* 0x9C; other streams offset by 0x20 */
#define HDA_RMX_SD0BDPU             41
#define HDA_RMX_SD1BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 10)
#define HDA_RMX_SD2BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 20)
#define HDA_RMX_SD3BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 30)
#define HDA_RMX_SD4BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 40)
#define HDA_RMX_SD5BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 50)
#define HDA_RMX_SD6BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 60)
#define HDA_RMX_SD7BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 70)

#define HDA_CODEC_CAD_SHIFT         28
/** Encodes the (required) LUN into a codec command. */
#define HDA_CODEC_CMD(cmd, lun)     ((cmd) | (lun << HDA_CODEC_CAD_SHIFT))

#define HDA_SDFMT_NON_PCM_SHIFT     15
#define HDA_SDFMT_NON_PCM_MASK      0x1
#define HDA_SDFMT_BASE_RATE_SHIFT   14
#define HDA_SDFMT_BASE_RATE_MASK    0x1
#define HDA_SDFMT_MULT_SHIFT        11
#define HDA_SDFMT_MULT_MASK         0x7
#define HDA_SDFMT_DIV_SHIFT         8
#define HDA_SDFMT_DIV_MASK          0x7
#define HDA_SDFMT_BITS_SHIFT        4
#define HDA_SDFMT_BITS_MASK         0x7
#define HDA_SDFMT_CHANNELS_MASK     0xF

#define HDA_SDFMT_TYPE              RT_BIT(15)
#define HDA_SDFMT_TYPE_PCM          (0)
#define HDA_SDFMT_TYPE_NON_PCM      (1)

#define HDA_SDFMT_BASE              RT_BIT(14)
#define HDA_SDFMT_BASE_48KHZ        (0)
#define HDA_SDFMT_BASE_44KHZ        (1)

#define HDA_SDFMT_MULT_1X           (0)
#define HDA_SDFMT_MULT_2X           (1)
#define HDA_SDFMT_MULT_3X           (2)
#define HDA_SDFMT_MULT_4X           (3)

#define HDA_SDFMT_DIV_1X            (0)
#define HDA_SDFMT_DIV_2X            (1)
#define HDA_SDFMT_DIV_3X            (2)
#define HDA_SDFMT_DIV_4X            (3)
#define HDA_SDFMT_DIV_5X            (4)
#define HDA_SDFMT_DIV_6X            (5)
#define HDA_SDFMT_DIV_7X            (6)
#define HDA_SDFMT_DIV_8X            (7)

#define HDA_SDFMT_8_BIT             (0)
#define HDA_SDFMT_16_BIT            (1)
#define HDA_SDFMT_20_BIT            (2)
#define HDA_SDFMT_24_BIT            (3)
#define HDA_SDFMT_32_BIT            (4)

#define HDA_SDFMT_CHAN_MONO         (0)
#define HDA_SDFMT_CHAN_STEREO       (1)

/** Emits a SDnFMT register format.
 * Also being used in the codec's converter format. */
#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))


/* Post stream registers: */
#define HDA_REG_MLCH                (HDA_NUM_GENERAL_REGS + HDA_NUM_STREAM_REGS) /* 0xc00 */
#define HDA_RMX_MLCH                115
#define HDA_REG_MLCD                (HDA_REG_MLCH + 1)      /* 0xc04 */
#define HDA_RMX_MLCD                116

/* Registers added/specific-to skylake/broxton: */
#define HDA_SD_NUM_FROM_SKYLAKE_REG(a_Name, a_iMap)   (((a_iMap) - HDA_STREAM_REG_DEF(a_Name, 0)) / 2)

#define HDA_REG_SD0DPIB             (HDA_REG_MLCD + 1)      /* 0x1084 */
#define HDA_REG_SD1DPIB             (HDA_REG_SD0DPIB + 1*2)
#define HDA_REG_SD2DPIB             (HDA_REG_SD0DPIB + 2*2)
#define HDA_REG_SD3DPIB             (HDA_REG_SD0DPIB + 3*2)
#define HDA_REG_SD4DPIB             (HDA_REG_SD0DPIB + 4*2)
#define HDA_REG_SD5DPIB             (HDA_REG_SD0DPIB + 5*2)
#define HDA_REG_SD6DPIB             (HDA_REG_SD0DPIB + 6*2)
#define HDA_REG_SD7DPIB             (HDA_REG_SD0DPIB + 7*2)

#define HDA_RMX_SD0DPIB             HDA_RMX_SD0LPIB
#define HDA_RMX_SD1DPIB             HDA_RMX_SD1LPIB
#define HDA_RMX_SD2DPIB             HDA_RMX_SD2LPIB
#define HDA_RMX_SD3DPIB             HDA_RMX_SD3LPIB
#define HDA_RMX_SD4DPIB             HDA_RMX_SD4LPIB
#define HDA_RMX_SD5DPIB             HDA_RMX_SD5LPIB
#define HDA_RMX_SD6DPIB             HDA_RMX_SD6LPIB
#define HDA_RMX_SD7DPIB             HDA_RMX_SD7LPIB

#define HDA_REG_SD0EFIFOS           (HDA_REG_SD0DPIB + 1)   /* 0x1094 */
#define HDA_REG_SD1EFIFOS           (HDA_REG_SD0EFIFOS + 1*2)
#define HDA_REG_SD2EFIFOS           (HDA_REG_SD0EFIFOS + 2*2)
#define HDA_REG_SD3EFIFOS           (HDA_REG_SD0EFIFOS + 3*2)
#define HDA_REG_SD4EFIFOS           (HDA_REG_SD0EFIFOS + 4*2)
#define HDA_REG_SD5EFIFOS           (HDA_REG_SD0EFIFOS + 5*2)
#define HDA_REG_SD6EFIFOS           (HDA_REG_SD0EFIFOS + 6*2)
#define HDA_REG_SD7EFIFOS           (HDA_REG_SD0EFIFOS + 7*2)

#define HDA_RMX_SD0EFIFOS           117
#define HDA_RMX_SD1EFIFOS           (HDA_RMX_SD0EFIFOS + 1)
#define HDA_RMX_SD2EFIFOS           (HDA_RMX_SD0EFIFOS + 2)
#define HDA_RMX_SD3EFIFOS           (HDA_RMX_SD0EFIFOS + 3)
#define HDA_RMX_SD4EFIFOS           (HDA_RMX_SD0EFIFOS + 4)
#define HDA_RMX_SD5EFIFOS           (HDA_RMX_SD0EFIFOS + 5)
#define HDA_RMX_SD6EFIFOS           (HDA_RMX_SD0EFIFOS + 6)
#define HDA_RMX_SD7EFIFOS           (HDA_RMX_SD0EFIFOS + 7)

/** @} */ /* grp_hda_regs */


/**
 * Buffer descriptor list entry (BDLE).
 *
 * See 3.6.3 in HDA specs rev 1.0a (2010-06-17).
 */
typedef struct HDABDLEDESC
{
    /** Starting address of the actual buffer. Must be 128-bit aligned. */
    uint64_t     u64BufAddr;
    /** Size of the actual buffer (in bytes). */
    uint32_t     u32BufSize;
    /** HDA_BDLE_F_XXX.
     *
     * Bit 0: IOC - Interrupt on completion / HDA_BDLE_F_IOC.
     * The controller will generate an interrupt when the last byte of the buffer
     * has been fetched by the DMA engine.
     *
     * Bits 31:1 are reserved for further use and must be 0. */
    uint32_t     fFlags;
} HDABDLEDESC, *PHDABDLEDESC;
AssertCompileSize(HDABDLEDESC, 16); /* Always 16 byte. Also must be aligned on 128-byte boundary. */

/** Interrupt on completion (IOC) flag. */
#define HDA_BDLE_F_IOC              RT_BIT(0)


/**
 * HDA mixer sink definition (ring-3).
 *
 * Its purpose is to know which audio mixer sink is bound to which SDn
 * (SDI/SDO) device stream.
 *
 * This is needed in order to handle interleaved streams (that is, multiple
 * channels in one stream) or non-interleaved streams (each channel has a
 * dedicated stream).
 *
 * This is only known to the actual device emulation level.
 */
typedef struct HDAMIXERSINK
{
    R3PTRTYPE(PHDASTREAM)   pStreamShared;
    R3PTRTYPE(PHDASTREAMR3) pStreamR3;
    /** Pointer to the actual audio mixer sink. */
    R3PTRTYPE(PAUDMIXSINK)  pMixSink;
} HDAMIXERSINK;

/**
 * Mapping a stream tag to an HDA stream (ring-3).
 */
typedef struct HDATAG
{
    /** Own stream tag. */
    uint8_t                 uTag;
    uint8_t                 Padding[7];
    /** Pointer to associated stream. */
    R3PTRTYPE(PHDASTREAMR3) pStreamR3;
} HDATAG;
/** Pointer to a HDA stream tag mapping. */
typedef HDATAG *PHDATAG;

/**
 * Shared ICH Intel HD audio controller state.
 */
typedef struct HDASTATE
{
    /** Critical section protecting the HDA state. */
    PDMCRITSECT             CritSect;
    /** Internal stream states (aligned on 64 byte boundrary). */
    HDASTREAM               aStreams[HDA_MAX_STREAMS];
    /** The HDA's register set. */
    uint32_t                au32Regs[HDA_NUM_REGS];
    /** CORB buffer base address. */
    uint64_t                u64CORBBase;
    /** RIRB buffer base address. */
    uint64_t                u64RIRBBase;
    /** DMA base address.
     *  Made out of DPLBASE + DPUBASE (3.3.32 + 3.3.33). */
    uint64_t                u64DPBase;
    /** Size in bytes of CORB buffer (#au32CorbBuf). */
    uint32_t                cbCorbBuf;
    /** Size in bytes of RIRB buffer (#au64RirbBuf). */
    uint32_t                cbRirbBuf;
    /** Response Interrupt Count (RINTCNT). */
    uint16_t                u16RespIntCnt;
    /** DMA position buffer enable bit. */
    bool                    fDMAPosition;
    /** Current IRQ level. */
    uint8_t                 u8IRQL;
    /** Config: Internal input DMA buffer size override, specified in milliseconds.
     * Zero means default size according to buffer and stream config.
     * @sa BufSizeInMs config value.  */
    uint16_t                cMsCircBufIn;
    /** Config: Internal output DMA buffer size override, specified in milliseconds.
     * Zero means default size according to buffer and stream config.
     * @sa BufSizeOutMs config value.  */
    uint16_t                cMsCircBufOut;
    /** The start time of the wall clock (WALCLK), measured on the virtual sync clock. */
    uint64_t                tsWalClkStart;
    /** CORB DMA task handle.
     * We use this when there is stuff we cannot handle in ring-0.  */
    PDMTASKHANDLE           hCorbDmaTask;
    /** The CORB buffer. */
    uint32_t                au32CorbBuf[HDA_CORB_SIZE];
    /** Pointer to RIRB buffer. */
    uint64_t                au64RirbBuf[HDA_RIRB_SIZE];

    /** PCI Region \#0: 16KB of MMIO stuff. */
    IOMMMIOHANDLE           hMmio;

#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
    STAMCOUNTER             StatAccessDmaOutput;
    STAMCOUNTER             StatAccessDmaOutputToR3;
#endif
#ifdef VBOX_WITH_STATISTICS
    STAMPROFILE             StatIn;
    STAMPROFILE             StatOut;
    STAMCOUNTER             StatBytesRead;
    STAMCOUNTER             StatBytesWritten;

    /** @name Register statistics.
     * The array members run parallel to g_aHdaRegMap.
     * @{ */
    STAMCOUNTER             aStatRegReads[HDA_NUM_REGS];
    STAMCOUNTER             aStatRegReadsToR3[HDA_NUM_REGS];
    STAMCOUNTER             aStatRegWrites[HDA_NUM_REGS];
    STAMCOUNTER             aStatRegWritesToR3[HDA_NUM_REGS];
    STAMCOUNTER             StatRegMultiReadsRZ;
    STAMCOUNTER             StatRegMultiReadsR3;
    STAMCOUNTER             StatRegMultiWritesRZ;
    STAMCOUNTER             StatRegMultiWritesR3;
    STAMCOUNTER             StatRegSubWriteRZ;
    STAMCOUNTER             StatRegSubWriteR3;
    STAMCOUNTER             StatRegUnknownReads;
    STAMCOUNTER             StatRegUnknownWrites;
    STAMCOUNTER             StatRegWritesBlockedByReset;
    STAMCOUNTER             StatRegWritesBlockedByRun;
    /** @} */
#endif

#ifdef DEBUG
    /** Debug stuff.
     * @todo Make STAM values out some of this? */
    struct
    {
# if 0 /* unused */
        /** Timestamp (in ns) of the last timer callback (hdaTimer).
         * Used to calculate the time actually elapsed between two timer callbacks. */
        uint64_t                tsTimerLastCalledNs;
# endif
        /** IRQ debugging information. */
        struct
        {
            /** Timestamp (in ns) of last processed (asserted / deasserted) IRQ. */
            uint64_t            tsProcessedLastNs;
            /** Timestamp (in ns) of last asserted IRQ. */
            uint64_t            tsAssertedNs;
# if 0 /* unused */
            /** How many IRQs have been asserted already. */
            uint64_t            cAsserted;
            /** Accumulated elapsed time (in ns) of all IRQ being asserted. */
            uint64_t            tsAssertedTotalNs;
            /** Timestamp (in ns) of last deasserted IRQ. */
            uint64_t            tsDeassertedNs;
            /** How many IRQs have been deasserted already. */
            uint64_t            cDeasserted;
            /** Accumulated elapsed time (in ns) of all IRQ being deasserted. */
            uint64_t            tsDeassertedTotalNs;
# endif
        } IRQ;
    } Dbg;
#endif
    /** This is for checking that the build was correctly configured in all contexts.
     *  This is set to HDASTATE_ALIGNMENT_CHECK_MAGIC. */
    uint64_t                uAlignmentCheckMagic;
} HDASTATE;
AssertCompileMemberAlignment(HDASTATE, aStreams, 64);
/** Pointer to a shared HDA device state.  */
typedef HDASTATE *PHDASTATE;

/** Value for HDASTATE:uAlignmentCheckMagic. */
#define HDASTATE_ALIGNMENT_CHECK_MAGIC  UINT64_C(0x1298afb75893e059)

/**
 * Ring-0 ICH Intel HD audio controller state.
 */
typedef struct HDASTATER0
{
# if 0 /* Codec is not yet kosher enough for ring-0.  @bugref{9890c64} */
    /** Pointer to HDA codec to use. */
    HDACODECR0              Codec;
# else
    uint32_t                u32Dummy;
# endif
} HDASTATER0;
/** Pointer to a ring-0 HDA device state.  */
typedef HDASTATER0 *PHDASTATER0;

/**
 * Ring-3 ICH Intel HD audio controller state.
 */
typedef struct HDASTATER3
{
    /** Internal stream states. */
    HDASTREAMR3             aStreams[HDA_MAX_STREAMS];
    /** Mapping table between stream tags and stream states. */
    HDATAG                  aTags[HDA_MAX_TAGS];
    /** R3 Pointer to the device instance. */
    PPDMDEVINSR3            pDevIns;
    /** The base interface for LUN\#0. */
    PDMIBASE                IBase;
    /** List of associated LUN drivers (HDADRIVER). */
    RTLISTANCHORR3          lstDrv;
    /** The device' software mixer. */
    R3PTRTYPE(PAUDIOMIXER)  pMixer;
    /** HDA sink for (front) output. */
    HDAMIXERSINK            SinkFront;
#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    /** HDA sink for center / LFE output. */
    HDAMIXERSINK            SinkCenterLFE;
    /** HDA sink for rear output. */
    HDAMIXERSINK            SinkRear;
#endif
    /** HDA mixer sink for line input. */
    HDAMIXERSINK            SinkLineIn;
#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
    /** Audio mixer sink for microphone input. */
    HDAMIXERSINK            SinkMicIn;
#endif
    /** Debug stuff. */
    struct
    {
        /** Whether debugging is enabled or not. */
        bool                    fEnabled;
        /** Path where to dump the debug output to.
         *  Can be NULL, in which the system's temporary directory will be used then. */
        R3PTRTYPE(char *)       pszOutPath;
    } Dbg;
    /** Align the codec state on a cache line. */
    uint64_t                au64Padding[3];
    /** The HDA codec state. */
    HDACODECR3              Codec;
} HDASTATER3;
AssertCompileMemberAlignment(HDASTATER3, Codec, 64);


/** Pointer to the context specific HDA state (HDASTATER3 or HDASTATER0). */
typedef CTX_SUFF(PHDASTATE) PHDASTATECC;


/** @def HDA_PROCESS_INTERRUPT
 * Wrapper around hdaProcessInterrupt that supplies the source function name
 * string in logging builds. */
#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING)
void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource);
# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis)  hdaProcessInterrupt((a_pDevIns), (a_pThis), __FUNCTION__)
#else
void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis);
# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis)  hdaProcessInterrupt((a_pDevIns), (a_pThis))
#endif

/**
 * Returns the audio direction of a specified stream descriptor.
 *
 * The register layout specifies that input streams (SDI) come first,
 * followed by the output streams (SDO). So every stream ID below HDA_MAX_SDI
 * is an input stream, whereas everything >= HDA_MAX_SDI is an output stream.
 *
 * @note SDnFMT register does not provide that information, so we have to judge
 *       for ourselves.
 *
 * @return  Audio direction.
 * @param   uSD     The stream number.
 */
DECLINLINE(PDMAUDIODIR) hdaGetDirFromSD(uint8_t uSD)
{
    if (uSD < HDA_MAX_SDI)
        return PDMAUDIODIR_IN;
    AssertReturn(uSD < HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN);
    return PDMAUDIODIR_OUT;
}

/* Used by hdaR3StreamSetUp: */
uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW);

#if defined(VBOX_STRICT) && defined(VBOX_HDA_CAN_ACCESS_REG_MAP)
/* Only in DevHda.cpp: */
DECLINLINE(uint32_t *) hdaStrictRegAccessor(PHDASTATE pThis, uint32_t idxMap, uint32_t idxReg);
DECLINLINE(uint32_t *) hdaStrictStreamRegAccessor(PHDASTATE pThis, uint32_t idxMap0, uint32_t idxReg0, size_t idxStream);
#endif /* VBOX_STRICT && VBOX_HDA_CAN_ACCESS_REG_MAP */


/** @name HDA device functions used by the codec.
 * @{ */
DECLHIDDEN(int)     hdaR3MixerAddStream(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, PCPDMAUDIOSTREAMCFG pCfg);
DECLHIDDEN(int)     hdaR3MixerRemoveStream(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, bool fImmediate);
DECLHIDDEN(int)     hdaR3MixerControl(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel);
DECLHIDDEN(int)     hdaR3MixerSetVolume(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol);
/** @} */


/** @name Saved state versions for the HDA device
 * @{ */
/** The current staved state version.
 * @note Only for the registration call.  Never used for tests. */
#define HDA_SAVED_STATE_VERSION         HDA_SAVED_STATE_WITHOUT_PERIOD

/** Removed period and redefined wall clock. */
#define HDA_SAVED_STATE_WITHOUT_PERIOD  8
/** Added (Controller):              Current wall clock value (this independent from WALCLK register value).
  * Added (Controller):              Current IRQ level.
  * Added (Per stream):              Ring buffer. This is optional and can be skipped if (not) needed.
  * Added (Per stream):              Struct g_aSSMStreamStateFields7.
  * Added (Per stream):              Struct g_aSSMStreamPeriodFields7.
  * Added (Current BDLE per stream): Struct g_aSSMBDLEDescFields7.
  * Added (Current BDLE per stream): Struct g_aSSMBDLEStateFields7. */
#define HDA_SAVED_STATE_VERSION_7       7
/** Saves the current BDLE state.
 * @since 5.0.14 (r104839) */
#define HDA_SAVED_STATE_VERSION_6       6
/** Introduced dynamic number of streams + stream identifiers for serialization.
 *  Bug: Did not save the BDLE states correctly.
 *  Those will be skipped on load then.
 * @since 5.0.12 (r104520)  */
#define HDA_SAVED_STATE_VERSION_5       5
/** Since this version the number of MMIO registers can be flexible. */
#define HDA_SAVED_STATE_VERSION_4       4
#define HDA_SAVED_STATE_VERSION_3       3
#define HDA_SAVED_STATE_VERSION_2       2
#define HDA_SAVED_STATE_VERSION_1       1
/** @} */

#endif /* !VBOX_INCLUDED_SRC_Audio_DevHda_h */