SayoriOS  0.3.3
hda.c
1 //
2 // Created by ndraey on 21.01.24.
3 //
4 
5 #include "drv/pci.h"
6 #include "drv/audio/hda.h"
7 #include "io/ports.h"
8 #include "io/tty.h"
9 #include "mem/pmm.h"
10 #include "mem/vmm.h"
11 #include "sys/isr.h"
12 #include "../../lib/libvector/include/vector.h"
13 
14 uint8_t hda_bus = 0,
15  hda_slot = 0,
16  hda_func = 0;
17 
18 uint16_t hda_vendor = 0,
19  hda_device = 0;
20 
21 uint32_t hda_addr = 0;
22 
23 volatile uint32_t* hda_corb = 0;
24 size_t hda_corb_phys = 0;
25 volatile uint32_t* hda_rirb = 0;
26 size_t hda_rirb_phys = 0;
27 
28 size_t hda_corb_entry_count = 0;
29 size_t hda_rirb_entry_count = 0;
30 
31 size_t hda_corb_current = 0;
32 size_t hda_rirb_current = 0;
33 
34 size_t hda_irq = 0;
35 
36 volatile bool hda_fired = false;
37 volatile size_t hda_response = 0;
38 
39 #define WRITE32(reg, value) *(volatile uint32_t*)(hda_addr + (reg)) = (value)
40 #define READ32(reg) (*(volatile uint32_t*)(hda_addr + (reg)))
41 #define WRITE16(reg, value) *(volatile uint16_t*)(hda_addr + (reg)) = (value)
42 #define READ16(reg) (*(volatile uint16_t*)(hda_addr + (reg)))
43 #define WRITE8(reg, value) *(volatile uint8_t*)(hda_addr + (reg)) = (value)
44 #define READ8(reg) (*(volatile uint8_t*)(hda_addr + (reg)))
45 
46 #define VERB(codec, node, verb, command) ((codec << 28) | (node << 20) | (verb << 8) | (command))
47 
48 #define REG_GCAP 0x00
49 #define REG_SSYNC 0x34
50 #define REG_DMA_LOW_POSITION_ADDR 0x70
51 #define REG_DMA_HIGH_POSITION_ADDR 0x74
52 
53 size_t hda_afg_codec_id = 0;
54 size_t hda_afg_node_id = 0;
55 
56 vector_t* hda_output_nodes;
57 
58 void hda_init() {
59  // Find devce by its class and subclass numbers.
60  pci_find_device_by_class_and_subclass(4, 3, &hda_vendor, &hda_device, &hda_bus, &hda_slot, &hda_func);
61 
62  if(hda_vendor && hda_device) {
63  qemu_ok("Found Intel HDA! (%x:%x)", hda_vendor, hda_device);
64  } else {
65  return;
66  }
67 
68  // Read memory base address
69  hda_addr = pci_read32(hda_bus, hda_slot, hda_func, 0x10) & ~0b1111;
70 
71  uint32_t word = pci_read_confspc_word(hda_bus, hda_slot, hda_func, 0x3C); // All 0xF PCI register
72  hda_irq = word & 0xff;
73 
74  pci_enable_bus_mastering(hda_bus, hda_slot, hda_func);
75 
76  qemu_ok("HDA address: %x", hda_addr);
77  tty_printf("HDA address: %x\n", hda_addr);
78 
79  // Map the registers into our address space (without caching, because memory-mapped regs should not be cached).
80  map_pages(
81  get_kernel_page_directory(),
82  hda_addr,
83  hda_addr,
84  PAGE_SIZE,
85  PAGE_WRITEABLE | PAGE_CACHE_DISABLE // PAGE_PRESENT is set automatically
86  );
87 
88  // Reset the entire controller!
89  hda_reset();
90 
91  tty_printf("HDA RESET OKAY!\n");
92 
93  // Read capabilities
94  size_t data = READ16(REG_GCAP);
95 
96  size_t input_streams = (data >> 8) & 0b1111;
97  size_t output_streams = (data >> 12) & 0b1111;
98 
99  tty_printf("HDA: I: %d; O: %d;\n", input_streams, output_streams);
100 
101  hda_output_nodes = vector_new();
102 
103  WRITE32(0x20, 0);
104 
105  //turn off dma position transfer
106  WRITE32(REG_DMA_LOW_POSITION_ADDR, 0);
107  WRITE32(REG_DMA_HIGH_POSITION_ADDR, 0);
108 
109  //disable synchronization
110  WRITE32(REG_SSYNC, 0);
111  // WRITE32(0x38, 0);
112 
113  //stop CORB and RIRB
114  WRITE8(0x4C, 0x0);
115  WRITE8(0x5C, 0x0);
116 
117  hda_corb = kmalloc_common(1024, PAGE_SIZE);
118  hda_rirb = kmalloc_common(2048, PAGE_SIZE);
119 // phys_set_flags(get_kernel_page_directory(), (virtual_addr_t)hda_corb, PAGE_PRESENT | PAGE_WRITEABLE | PAGE_CACHE_DISABLE);
120 // phys_set_flags(get_kernel_page_directory(), (virtual_addr_t)hda_rirb, PAGE_PRESENT | PAGE_WRITEABLE | PAGE_CACHE_DISABLE);
121  hda_corb_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) hda_corb);
122  hda_rirb_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) hda_rirb);
123 
124  qemu_note("CORB: V%x => P%x", (size_t)hda_corb, hda_corb_phys);
125  qemu_note("RIRB: V%x => P%x", (size_t)hda_rirb, hda_rirb_phys);
126 
127  memset((uint32_t*)hda_corb, 0, 1024);
128  memset((uint32_t*)hda_rirb, 0, 1024);
129 
130  qemu_ok("Allocated memory for CORB and RIRB!");
131 
132  // Write CORB address
133  WRITE32(0x40, (uint32_t)hda_corb_phys); // First 32 bits
134  WRITE32(0x44, 0); // Last 32 bits (we are 32-bit, so we don't need it)
135 
136  hda_corb_entry_count = hda_calculate_entries(READ8(0x4E));
137 
138  tty_printf("HDA: CORB: %d entries\n", hda_corb_entry_count);
139 
140  // Reset read pointer
141  WRITE16(0x4A, (1 << 15));
142  while((READ16(0x4A) & (1 << 15)) != (1 << 15))
143  ;
144 
145  WRITE16(0x4A, 0);
146  while((READ16(0x4A) & (1 << 15)) != 0)
147  ;
148 
149  WRITE16(0x48, 0);
150 
151  // RIRB
152 
153  WRITE32(0x50, (uint32_t)hda_rirb_phys); // First 32 bits
154  WRITE32(0x54, 0); // Last 32 bits (we are 32-bit, so we don't need it)
155 
156  hda_rirb_entry_count = hda_calculate_entries(READ8(0x5E));
157 
158  tty_printf("HDA: RIRB: %d entries\n", hda_rirb_entry_count);
159 
160  // Reset write pointer
161  WRITE16(0x58, (1 << 15));
162 
163  // Implement loop to check is WP ready
164 
165  sleep_ms(50);
166 
167  // Enable interrupts
168  WRITE16(0x5A, READ16(0x5A) | 1);
169 // WRITE16(0x5A, 0xff);
170 
171  qemu_log("Starting engines");
172  // Start!
173  WRITE8(0x4C, (1 << 1) | 1);
174  WRITE8(0x5C, (1 << 1) | 1);
175 
176  qemu_note("IRQ LINE IS: %d", hda_irq);
177 
178  register_interrupt_handler(32 + hda_irq, hda_interrupt_handler);
179 
180  WRITE32(0x20, (1 << 30) | (1 << 31));
181 
182  qemu_ok("Okay!");
183 
184  size_t codec_bitmap = READ16(0x0E);
185 
186  for(size_t codec = 0; codec < 16; codec++) {
187  if(~codec_bitmap & (1 << codec)) {
188  continue;
189  }
190 
191  qemu_log("Probing codec: %d", codec);
192 
193  size_t id = hda_send_verb_via_corb_rirb(VERB(codec, 0, 0xf00, 0));
194 
195  if(id != 0) {
196  tty_printf("FOUND CODEC: %x\n", id);
197 
198  hda_find_afg(id, codec);
199  }
200  }
201 
202  tty_printf("Found %d suitable output nodes.\n", hda_output_nodes->size);
203 }
204 
205 void hda_find_afg(size_t codec_response, size_t codec_id) {
206  hda_afg_codec_id = codec_id; // Save codec id
207 
208  // Read vendor id
209  size_t vendor_id = (codec_response >> 16) & 0xffff;
210  size_t dev_id = codec_response & 0xffff;
211 
212  tty_printf("|- Vendor: %x; Device: %x\n", vendor_id, dev_id);
213 
214  size_t child_nodes_info = hda_send_verb_via_corb_rirb(VERB(codec_id, 0, 0xf00, 0x04));
215  size_t first_gnode = (child_nodes_info >> 16) & 0xff;
216  size_t node_count = child_nodes_info & 0xff;
217  size_t last_node = first_gnode + node_count;
218 
219  tty_printf("|- First group node: %d; Node count: %d\n", first_gnode, node_count);
220 
221  for(size_t node = first_gnode; node < last_node; node++) {
222  size_t function_group_type = hda_send_verb_via_corb_rirb(VERB(codec_id, node, 0xf00, 0x05));
223 
224  if((function_group_type & 0x7f) == 0x01) {
225  tty_printf("|- AFG at node: %d\n", node);
226  tty_printf("|- FP: %d -> %d\n", codec_id, node);
227 
228  hda_afg_node_id = node; // Save node
229  qemu_ok("UNBELIEVABLE! FOUND AFG!");
230  tty_printf("UNBELIEVABLE! FOUND AFG!\n");
231 
232  hda_initialize_afg();
233  break;
234  }
235  }
236 }
237 
238 void hda_initialize_afg() {
239  hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0x7ff, 0));
240  hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0x705, 0));
241  hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0x708, 0));
242 
243  size_t hda_afg_node_sample_capabilities = hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0xF00, 0x0A));
244  size_t hda_afg_node_stream_format_capabilities = hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0xF00, 0x0B));
245  size_t hda_afg_node_input_amp_capabilities = hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0xF00, 0x0D));
246  size_t hda_afg_node_output_amp_capabilities = hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0xF00, 0x12));
247 
248  qemu_note("hda_afg_node_sample_capabilities: %x", hda_afg_node_sample_capabilities);
249  qemu_note("hda_afg_node_stream_format_capabilities: %x", hda_afg_node_stream_format_capabilities);
250  qemu_note("hda_afg_node_input_amp_capabilities: %x", hda_afg_node_input_amp_capabilities);
251  qemu_note("hda_afg_node_output_amp_capabilities: %x", hda_afg_node_output_amp_capabilities);
252 
253 
254  size_t node_data = hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, hda_afg_node_id, 0xf00, 0x04));
255  size_t first_gnode = (node_data >> 16) & 0xff; // First group node
256  size_t node_count = node_data & 0xff; // Node count
257  size_t last_node = first_gnode + node_count;
258 
259  char* node_types[] = {
260  "Output",
261  "Input",
262  "Mixer",
263  "Selector",
264  "Complex"
265  };
266 
267  for(size_t node = first_gnode; node < last_node; node++) {
268  qemu_note("node: %d", node);
269  size_t type = (hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, node, 0xF00, 0x09)) >> 20) & 0xF;
270 
271  if(type >= 5) {
272  continue;
273  }
274 
275  // qemu_note("type: %d = %s", type, node_types[type]);
276  // tty_printf("|- %s at node: %d\n", node_types[type], node);
277 
278  if(type == 0x4) {
279  size_t type_of_node = ((hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, node, 0xF1C, 0x00)) >> 20) & 0xF);
280 
281  // qemu_note("COMPLEX PIN HAS TYPE: %d", type_of_node);
282  // tty_printf("|- COMPLEX PIN HAS TYPE: %d\n", type_of_node);
283 
284  if(type_of_node == 0) {
285  tty_printf("Node %d is LINE OUT\n", node);
286  vector_push_back(hda_output_nodes, node);
287  } else if(type_of_node == 1) {
288  tty_printf("Node %d is SPEAKER\n", node);
289  vector_push_back(hda_output_nodes, node);
290  }
291  }
292  }
293 }
294 
295 void hda_interrupt_handler(__attribute__((unused)) registers_t regs) {
296 // qemu_warn("HDA Interrupt!");
297 
298  size_t interrupt_status = READ32(0x24);
299 
300  if(~interrupt_status & (1 << 31)) {
301  return;
302  }
303 
304  if(interrupt_status & (1 << 30)) {
305  size_t rirb_status = READ8(0x5D);
306 
307  WRITE8(0x5D, rirb_status);
308 
309  if(rirb_status & (1 << 0)) {
310  size_t rirb_wp = READ16(0x58);
311 
312 // qemu_ok("RESPONSE!");
313 
314  while(hda_rirb_current != rirb_wp) {
315  hda_rirb_current = (hda_rirb_current + 1) % hda_rirb_entry_count;
316 
317  hda_fired = true;
318  hda_response = hda_rirb[hda_rirb_current * 2];
319 
320 // qemu_ok("RIRB: %x", hda_rirb[hda_rirb_current * 2]);
321  }
322  }
323  }
324 }
325 
326 uint32_t hda_send_verb_via_corb_rirb(uint32_t verb) {
327 // qemu_warn("CWP: %d; CRP: %d; RWP: %d", READ16(0x48), READ16(0x4A), READ16(0x58));
328 
329  hda_corb_current = (hda_corb_current + 1) % hda_corb_entry_count;
330 
331 // qemu_warn("CORB CUR: %d; RIRB CUR: %d", hda_corb_current, hda_rirb_current);
332  // SEND VERB
333  hda_corb[hda_corb_current] = verb;
334 
335  WRITE16(0x48, hda_corb_current & 0xff);
336 
337  while(!hda_fired)
338  ;
339 
340  hda_fired = false;
341  qemu_log("VERB %x got response %x", verb, hda_response);
342 
343  return hda_response;
344 }
345 
346 void hda_reset() {
347  if(!hda_vendor)
348  return;
349 
350  WRITE32(0x8, READ32(0x8) & ~1);
351 
352  while((READ32(0x08) & 1) != 0);
353 
354  WRITE32(0x8, READ32(0x8) | 1);
355 
356  while ((READ32(0x08) & 1) != 1);
357 
358  qemu_ok("Reset ok!");
359 }
360 
361 size_t hda_calculate_entries(size_t word) {
362  if((word & 0x40) == 0x40) {
363  return 256;
364  } else if((word & 0x20) == 0x20) {
365  return 16;
366  } else if((word & 0x10) == 0x10) {
367  return 2;
368  } else {
369  return 0;
370  }
371 }
struct registers __attribute__((packed))
Структура данных пакета от мыши
Definition: psf.h:19
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
Definition: string.c:203
uint16_t pci_read_confspc_word(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
[PCI] Чтение 16-битных полей из пространства механизма конфигураций 1
Definition: pci.c:32
uint32_t pci_read32(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
Чтение данных из шины PCI.
Definition: pci.c:54
Definition: vector.h:7
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам
Definition: timer.c:68