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
#![allow(dead_code)]
pub const MIXER_REGS_SIZE: u64 = 0x100;
pub const MASTER_REGS_SIZE: u64 = 0x400;
pub const MIXER_RESET_00: u64 = 0x00;
pub const MIXER_MASTER_VOL_MUTE_02: u64 = 0x02;
pub const MIXER_MIC_VOL_MUTE_0E: u64 = 0x0e;
pub const MIXER_PCM_OUT_VOL_MUTE_18: u64 = 0x18;
pub const MIXER_REC_VOL_MUTE_1C: u64 = 0x1c;
pub const MIXER_POWER_DOWN_CONTROL_26: u64 = 0x26;
pub const MIXER_EXTENDED_AUDIO_ID_28: u64 = 0x28;
pub const MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28: u64 = 0x2a;
pub const MIXER_PCM_FRONT_DAC_RATE_2C: u64 = 0x2c;
pub const MIXER_PCM_SURR_DAC_RATE_2E: u64 = 0x2e;
pub const MIXER_PCM_LFE_DAC_RATE_30: u64 = 0x30;
pub const MIXER_VENDOR_ID1_7C: u64 = 0x7c;
pub const MIXER_VENDOR_ID2_7E: u64 = 0x7e;
pub const MIXER_EI_VRA: u16 = 0x0001; pub const MIXER_EI_CDAC: u16 = 0x0040; pub const MIXER_EI_SDAC: u16 = 0x0080; pub const MIXER_EI_LDAC: u16 = 0x0100; pub const BC_DEDICATED_MIC: u16 = 0x0001; pub const GLOB_CNT_2C: u64 = 0x2C;
pub const GLOB_CNT_COLD_RESET: u32 = 0x0000_0002;
pub const GLOB_CNT_WARM_RESET: u32 = 0x0000_0004;
pub const GLOB_CNT_STABLE_BITS: u32 = 0x0000_007f; pub const GLOB_CNT_PCM_2: u32 = 0x0000_0000; pub const GLOB_CNT_PCM_4: u32 = 0x0010_0000; pub const GLOB_CNT_PCM_6: u32 = 0x0020_0000; pub const GLOB_CNT_PCM_246_MASK: u32 = GLOB_CNT_PCM_4 | GLOB_CNT_PCM_6; pub const GLOB_STA_30: u64 = 0x30;
pub const GLOB_STA_RESET_VAL: u32 = 0x0030_0100;
pub const GS_MD3: u32 = 1 << 17;
pub const GS_AD3: u32 = 1 << 16;
pub const GS_RCS: u32 = 1 << 15;
pub const GS_B3S12: u32 = 1 << 14;
pub const GS_B2S12: u32 = 1 << 13;
pub const GS_B1S12: u32 = 1 << 12;
pub const GS_S1R1: u32 = 1 << 11;
pub const GS_S0R1: u32 = 1 << 10;
pub const GS_S1CR: u32 = 1 << 9;
pub const GS_S0CR: u32 = 1 << 8;
pub const GS_MINT: u32 = 1 << 7;
pub const GS_POINT: u32 = 1 << 6;
pub const GS_PIINT: u32 = 1 << 5;
pub const GS_RSRVD: u32 = 1 << 4 | 1 << 3;
pub const GS_MOINT: u32 = 1 << 2;
pub const GS_MIINT: u32 = 1 << 1;
pub const GS_GSCI: u32 = 1;
pub const GS_RO_MASK: u32 = GS_B3S12
| GS_B2S12
| GS_B1S12
| GS_S1CR
| GS_S0CR
| GS_MINT
| GS_POINT
| GS_PIINT
| GS_RSRVD
| GS_MOINT
| GS_MIINT;
pub const GS_VALID_MASK: u32 = 0x0003_ffff;
pub const GS_WCLEAR_MASK: u32 = GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI;
pub const ACC_SEMA_34: u64 = 0x34;
pub const CIV_OFFSET: u64 = 0x04;
pub const LVI_OFFSET: u64 = 0x05;
pub const SR_OFFSET: u64 = 0x06;
pub const PICB_OFFSET: u64 = 0x08;
pub const PIV_OFFSET: u64 = 0x0a;
pub const CR_OFFSET: u64 = 0x0b;
pub const PI_BASE_00: u64 = 0x00;
pub const PI_BDBAR_00: u64 = PI_BASE_00;
pub const PI_CIV_04: u64 = PI_BASE_00 + CIV_OFFSET;
pub const PI_LVI_05: u64 = PI_BASE_00 + LVI_OFFSET;
pub const PI_SR_06: u64 = PI_BASE_00 + SR_OFFSET;
pub const PI_PICB_08: u64 = PI_BASE_00 + PICB_OFFSET;
pub const PI_PIV_0A: u64 = PI_BASE_00 + PIV_OFFSET;
pub const PI_CR_0B: u64 = PI_BASE_00 + CR_OFFSET;
pub const PO_BASE_10: u64 = 0x10;
pub const PO_BDBAR_10: u64 = PO_BASE_10;
pub const PO_CIV_14: u64 = PO_BASE_10 + CIV_OFFSET;
pub const PO_LVI_15: u64 = PO_BASE_10 + LVI_OFFSET;
pub const PO_SR_16: u64 = PO_BASE_10 + SR_OFFSET;
pub const PO_PICB_18: u64 = PO_BASE_10 + PICB_OFFSET;
pub const PO_PIV_1A: u64 = PO_BASE_10 + PIV_OFFSET;
pub const PO_CR_1B: u64 = PO_BASE_10 + CR_OFFSET;
pub const MC_BASE_20: u64 = 0x20;
pub const MC_BDBAR_20: u64 = MC_BASE_20;
pub const MC_CIV_24: u64 = MC_BASE_20 + CIV_OFFSET;
pub const MC_LVI_25: u64 = MC_BASE_20 + LVI_OFFSET;
pub const MC_SR_26: u64 = MC_BASE_20 + SR_OFFSET;
pub const MC_PICB_28: u64 = MC_BASE_20 + PICB_OFFSET;
pub const MC_PIV_2A: u64 = MC_BASE_20 + PIV_OFFSET;
pub const MC_CR_2B: u64 = MC_BASE_20 + CR_OFFSET;
pub const SR_DCH: u16 = 0x01;
pub const SR_CELV: u16 = 0x02;
pub const SR_LVBCI: u16 = 0x04;
pub const SR_BCIS: u16 = 0x08;
pub const SR_FIFOE: u16 = 0x10;
pub const SR_VALID_MASK: u16 = 0x1f;
pub const SR_WCLEAR_MASK: u16 = SR_FIFOE | SR_BCIS | SR_LVBCI;
pub const SR_RO_MASK: u16 = SR_DCH | SR_CELV;
pub const SR_INT_MASK: u16 = SR_BCIS | SR_LVBCI;
pub const CR_RPBM: u8 = 0x01;
pub const CR_RR: u8 = 0x02;
pub const CR_LVBIE: u8 = 0x04;
pub const CR_FEIE: u8 = 0x08;
pub const CR_IOCE: u8 = 0x10;
pub const CR_VALID_MASK: u8 = 0x1f;
pub const CR_DONT_CLEAR_MASK: u8 = CR_IOCE | CR_FEIE | CR_LVBIE;
pub const MUTE_REG_BIT: u16 = 0x8000;
pub const VOL_REG_MASK: u16 = 0x003f;
pub const MIXER_VOL_MASK: u16 = 0x001f;
pub const MIXER_VOL_LEFT_SHIFT: usize = 8;
pub const MIXER_MIC_20DB: u16 = 0x0040;
pub const PD_REG_STATUS_MASK: u16 = 0x000f;
pub const PD_REG_OUTPUT_MUTE_MASK: u16 = 0xb200;
pub const PD_REG_INPUT_MUTE_MASK: u16 = 0x0d00;
pub const DESCRIPTOR_LENGTH: usize = 8;
pub const BD_IOC: u32 = 1 << 31;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Ac97Function {
Input,
Output,
Microphone,
}
#[derive(Clone, Default)]
pub struct Ac97FunctionRegs {
pub bdbar: u32,
pub civ: u8,
pub lvi: u8,
pub sr: u16,
pub picb: u16,
pub piv: u8,
pub cr: u8,
}
impl Ac97FunctionRegs {
pub fn new() -> Self {
let mut regs = Ac97FunctionRegs {
sr: SR_DCH,
..Default::default()
};
regs.do_reset();
regs
}
pub fn do_reset(&mut self) {
self.bdbar = 0;
self.civ = 0;
self.lvi = 0;
self.picb = 0;
self.piv = 0;
self.cr &= CR_DONT_CLEAR_MASK;
}
pub fn atomic_status_regs(&self) -> u32 {
u32::from(self.civ) | u32::from(self.lvi) << 8 | u32::from(self.sr) << 16
}
pub fn int_mask(&self) -> u16 {
let mut int_mask = 0;
if self.cr & CR_LVBIE != 0 {
int_mask |= SR_LVBCI;
}
if self.cr & CR_IOCE != 0 {
int_mask |= SR_BCIS;
}
int_mask
}
pub fn move_to_next_buffer(&mut self) {
self.civ = self.piv;
self.piv = (self.piv + 1) % 32; }
pub fn has_irq(&self) -> bool {
self.sr & self.int_mask() != 0
}
}