summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Audio/DevHDACommon.h
blob: c667d57a81452383abf2c824264685a7ed3f9ff2 (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
/* $Id: DevHDACommon.h $ */
/** @file
 * DevHDACommon.h - Shared HDA device defines / functions.
 */

/*
 * Copyright (C) 2016-2019 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef VBOX_INCLUDED_SRC_Audio_DevHDACommon_h
#define VBOX_INCLUDED_SRC_Audio_DevHDACommon_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include "AudioMixer.h"
#include <VBox/log.h> /* LOG_ENABLED */

/** See 302349 p 6.2. */
typedef struct HDAREGDESC
{
    /** Register offset in the register space. */
    uint32_t    offset;
    /** Size in bytes. Registers of size > 4 are in fact tables. */
    uint32_t    size;
    /** Readable bits. */
    uint32_t    readable;
    /** Writable bits. */
    uint32_t    writable;
    /** Register descriptor (RD) flags of type HDA_RD_FLAG_.
     *  These are used to specify the handling (read/write)
     *  policy of the register. */
    uint32_t    fFlags;
    /** Read callback. */
    int       (*pfnRead)(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
    /** Write callback. */
    int       (*pfnWrite)(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
    /** Index into the register storage array. */
    uint32_t    mem_idx;
    /** Abbreviated name. */
    const char *abbrev;
    /** Descripton. */
    const char *desc;
} HDAREGDESC, *PHDAREGDESC;

/**
 * HDA register aliases (HDA spec 3.3.45).
 * @remarks Sorted by offReg.
 */
typedef struct HDAREGALIAS
{
    /** The alias register offset. */
    uint32_t    offReg;
    /** The register index. */
    int         idxAlias;
} HDAREGALIAS, *PHDAREGALIAS;

/**
 * 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);

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

/**
 * ICH6 datasheet defines limits for FIFOS registers (18.2.39).
 * Formula: size - 1
 * Other values not listed are not supported.
 */
/** Maximum FIFO size (in bytes). */
#define HDA_FIFO_MAX                256

/** Default timer frequency (in Hz).
 *
 * Lowering this value can ask for trouble, as backends then can run
 * into data underruns.
 *
 * Note: For handling surround setups (e.g. 5.1 speaker setups) we need
 *       a higher Hz rate, as the device emulation otherwise will come into
 *       timing trouble, making the output (DMA reads) crackling. */
#define HDA_TIMER_HZ_DEFAULT        100

/** Default position adjustment (in audio samples).
 *
 * For snd_hda_intel (Linux guests), the first BDL entry always is being used as
 * so-called BDL adjustment, which can vary, and is being used for chipsets which
 * misbehave and/or are incorrectly implemented.
 *
 * The BDL adjustment entry *always* has the IOC (Interrupt on Completion) bit set.
 *
 * For Intel Baytrail / Braswell implementations the BDL default adjustment is 32 frames, whereas
 * for ICH / PCH it's only one (1) frame.
 *
 * See default_bdl_pos_adj() and snd_hdac_stream_setup_periods() for more information.
 *
 * By default we apply some simple heuristics in hdaStreamInit().
 */
#define HDA_POS_ADJUST_DEFAULT      0

/** HDA's (fixed) audio frame size in bytes.
 *  We only support 16-bit stereo frames at the moment. */
#define HDA_FRAME_SIZE_DEFAULT      4

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

/** Turn a short global register name into an memory index and a stringized name. */
#define HDA_REG_IDX(abbrev)         HDA_MEM_IND_NAME(abbrev), #abbrev

/** Turns a short stream register name into an memory index and a stringized name. */
#define HDA_REG_IDX_STRM(reg, suff) HDA_MEM_IND_NAME(reg ## suff), #reg #suff

/** Same as above for a register *not* stored in memory. */
#define HDA_REG_IDX_NOMEM(abbrev)   0, #abbrev

extern const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS];

/**
 * NB: Register values stored in memory (au32Regs[]) are indexed through
 * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
 * register descriptors in g_aHdaRegMap[] are indexed through the
 * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
 *
 * The au32Regs[] layout is kept unchanged for saved state
 * compatibility.
 */

/* Registers */
#define HDA_REG_IND_NAME(x)         HDA_REG_##x
#define HDA_MEM_IND_NAME(x)         HDA_RMX_##x
#define HDA_REG_IND(pThis, x)       ((pThis)->au32Regs[g_aHdaRegMap[x].mem_idx])
#define HDA_REG(pThis, x)           (HDA_REG_IND((pThis), HDA_REG_IND_NAME(x)))


#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_OUTSTRMPAY          9           /* 0x18 */
#define HDA_RMX_OUTSTRMPAY          112

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

#define HDA_REG_INTCTL              11          /* 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              12          /* 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              13          /* 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.
 */
#define HDA_REG_SSYNC               14          /* 0x34 */
#define HDA_RMX_SSYNC               12

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

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

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

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

#define HDA_REG_CORBCTL             19          /* 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             20          /* 0x4D */
#define HDA_RMX_CORBSTS             18

#define HDA_REG_CORBSIZE            21          /* 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           22          /* 0x50 */
#define HDA_RMX_RIRBLBASE           20

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

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

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

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

#define HDA_REG_RIRBCTL             26          /* 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             27          /* 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            28          /* 0x5E */
#define HDA_RMX_RIRBSIZE            26

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

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

#define HDA_REG_IRS                 31          /* 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             32          /* 0x70 */
#define HDA_RMX_DPLBASE             30

#define HDA_REG_DPUBASE             33          /* 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]. */
#define HDA_STREAM_REG(pThis, name, sdnum)      (HDA_REG_IND((pThis), HDA_REG_SD0##name + (sdnum) * 10))

#define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 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              35          /* 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             36          /* 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              37          /* 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              38          /* 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            39          /* 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            40          /* 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)

#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              41          /* 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             42          /* 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             43          /* 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))

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



/** The HDA controller. */
typedef struct HDASTATE *PHDASTATE;
/** The HDA stream. */
typedef struct HDASTREAM *PHDASTREAM;

typedef struct HDAMIXERSINK *PHDAMIXERSINK;


/**
 * Internal state of a Buffer Descriptor List Entry (BDLE),
 * needed to keep track of the data needed for the actual device
 * emulation.
 */
typedef struct HDABDLESTATE
{
    /** Own index within the BDL (Buffer Descriptor List). */
    uint32_t     u32BDLIndex;
    /** Number of bytes below the stream's FIFO watermark (SDFIFOW).
     *  Used to check if we need fill up the FIFO again. */
    uint32_t     cbBelowFIFOW;
    /** Current offset in DMA buffer (in bytes).*/
    uint32_t     u32BufOff;
    uint32_t     Padding;
} HDABDLESTATE, *PHDABDLESTATE;

/**
 * BDL description structure.
 * Do not touch this, as this must match to the HDA specs.
 */
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;
    /** Bit 0: Interrupt on completion; the controller will generate
     *  an interrupt when the last byte of the buffer has been
     *  fetched by the DMA engine.
     *
     *  Rest is 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. */

/**
 * Buffer Descriptor List Entry (BDLE) (3.6.3).
 */
typedef struct HDABDLE
{
    /** The actual BDL description. */
    HDABDLEDESC  Desc;
    /** Internal state of this BDLE.
     *  Not part of the actual BDLE registers. */
    HDABDLESTATE State;
} HDABDLE;
AssertCompileSizeAlignment(HDABDLE, 8);
/** Pointer to a buffer descriptor list entry (BDLE). */
typedef HDABDLE *PHDABDLE;

/** @name Object lookup functions.
 * @{
 */
#ifdef IN_RING3
PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATE pThis, uint8_t uSD);
#endif
PDMAUDIODIR   hdaGetDirFromSD(uint8_t uSD);
PHDASTREAM    hdaGetStreamFromSD(PHDASTATE pThis, uint8_t uSD);
#ifdef IN_RING3
PHDASTREAM    hdaR3GetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink);
#endif
/** @} */

/** @name Interrupt functions.
 * @{
 */
#ifdef LOG_ENABLED
int           hdaProcessInterrupt(PHDASTATE pThis, const char *pszSource);
#else
int           hdaProcessInterrupt(PHDASTATE pThis);
#endif
/** @} */

/** @name Wall clock (WALCLK) functions.
 * @{
 */
uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
#ifdef IN_RING3
bool          hdaR3WalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce);
#endif
/** @} */

/** @name DMA utility functions.
 * @{
 */
#ifdef IN_RING3
int           hdaR3DMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
int           hdaR3DMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
#endif
/** @} */

/** @name Register functions.
 * @{
 */
uint32_t      hdaGetINTSTS(PHDASTATE pThis);
#ifdef IN_RING3
int           hdaR3SDFMTToPCMProps(uint16_t u16SDFMT, PPDMAUDIOPCMPROPS pProps);
#endif /* IN_RING3 */
/** @} */

/** @name BDLE (Buffer Descriptor List Entry) functions.
 * @{
 */
#ifdef IN_RING3
# ifdef LOG_ENABLED
void          hdaR3BDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE);
# endif
int           hdaR3BDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
bool          hdaR3BDLEIsComplete(PHDABDLE pBDLE);
bool          hdaR3BDLENeedsInterrupt(PHDABDLE pBDLE);
#endif /* IN_RING3 */
/** @} */

/** @name Device timer functions.
 * @{
 */
#ifdef IN_RING3
bool          hdaR3TimerSet(PHDASTATE pThis, PHDASTREAM pStream, uint64_t u64Expire, bool fForce);
#endif /* IN_RING3 */
/** @} */

#endif /* !VBOX_INCLUDED_SRC_Audio_DevHDACommon_h */