6 #include "drv/audio/hda.h"
12 #include "../../lib/libvector/include/vector.h"
18 uint16_t hda_vendor = 0,
21 uint32_t hda_addr = 0;
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;
28 size_t hda_corb_entry_count = 0;
29 size_t hda_rirb_entry_count = 0;
31 size_t hda_corb_current = 0;
32 size_t hda_rirb_current = 0;
36 volatile bool hda_fired =
false;
37 volatile size_t hda_response = 0;
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)))
46 #define VERB(codec, node, verb, command) ((codec << 28) | (node << 20) | (verb << 8) | (command))
49 #define REG_SSYNC 0x34
50 #define REG_DMA_LOW_POSITION_ADDR 0x70
51 #define REG_DMA_HIGH_POSITION_ADDR 0x74
53 size_t hda_afg_codec_id = 0;
54 size_t hda_afg_node_id = 0;
60 pci_find_device_by_class_and_subclass(4, 3, &hda_vendor, &hda_device, &hda_bus, &hda_slot, &hda_func);
62 if(hda_vendor && hda_device) {
63 qemu_ok(
"Found Intel HDA! (%x:%x)", hda_vendor, hda_device);
69 hda_addr =
pci_read32(hda_bus, hda_slot, hda_func, 0x10) & ~0b1111;
72 hda_irq = word & 0xff;
74 pci_enable_bus_mastering(hda_bus, hda_slot, hda_func);
76 qemu_ok(
"HDA address: %x", hda_addr);
77 tty_printf(
"HDA address: %x\n", hda_addr);
81 get_kernel_page_directory(),
85 PAGE_WRITEABLE | PAGE_CACHE_DISABLE
91 tty_printf(
"HDA RESET OKAY!\n");
94 size_t data = READ16(REG_GCAP);
96 size_t input_streams = (data >> 8) & 0b1111;
97 size_t output_streams = (data >> 12) & 0b1111;
99 tty_printf(
"HDA: I: %d; O: %d;\n", input_streams, output_streams);
101 hda_output_nodes = vector_new();
106 WRITE32(REG_DMA_LOW_POSITION_ADDR, 0);
107 WRITE32(REG_DMA_HIGH_POSITION_ADDR, 0);
110 WRITE32(REG_SSYNC, 0);
117 hda_corb = kmalloc_common(1024, PAGE_SIZE);
118 hda_rirb = kmalloc_common(2048, PAGE_SIZE);
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);
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);
127 memset((uint32_t*)hda_corb, 0, 1024);
128 memset((uint32_t*)hda_rirb, 0, 1024);
130 qemu_ok(
"Allocated memory for CORB and RIRB!");
133 WRITE32(0x40, (uint32_t)hda_corb_phys);
136 hda_corb_entry_count = hda_calculate_entries(READ8(0x4E));
138 tty_printf(
"HDA: CORB: %d entries\n", hda_corb_entry_count);
141 WRITE16(0x4A, (1 << 15));
142 while((READ16(0x4A) & (1 << 15)) != (1 << 15))
146 while((READ16(0x4A) & (1 << 15)) != 0)
153 WRITE32(0x50, (uint32_t)hda_rirb_phys);
156 hda_rirb_entry_count = hda_calculate_entries(READ8(0x5E));
158 tty_printf(
"HDA: RIRB: %d entries\n", hda_rirb_entry_count);
161 WRITE16(0x58, (1 << 15));
168 WRITE16(0x5A, READ16(0x5A) | 1);
171 qemu_log(
"Starting engines");
173 WRITE8(0x4C, (1 << 1) | 1);
174 WRITE8(0x5C, (1 << 1) | 1);
176 qemu_note(
"IRQ LINE IS: %d", hda_irq);
178 register_interrupt_handler(32 + hda_irq, hda_interrupt_handler);
180 WRITE32(0x20, (1 << 30) | (1 << 31));
184 size_t codec_bitmap = READ16(0x0E);
186 for(
size_t codec = 0; codec < 16; codec++) {
187 if(~codec_bitmap & (1 << codec)) {
191 qemu_log(
"Probing codec: %d", codec);
193 size_t id = hda_send_verb_via_corb_rirb(VERB(codec, 0, 0xf00, 0));
196 tty_printf(
"FOUND CODEC: %x\n",
id);
198 hda_find_afg(
id, codec);
202 tty_printf(
"Found %d suitable output nodes.\n", hda_output_nodes->size);
205 void hda_find_afg(
size_t codec_response,
size_t codec_id) {
206 hda_afg_codec_id = codec_id;
209 size_t vendor_id = (codec_response >> 16) & 0xffff;
210 size_t dev_id = codec_response & 0xffff;
212 tty_printf(
"|- Vendor: %x; Device: %x\n", vendor_id, dev_id);
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;
219 tty_printf(
"|- First group node: %d; Node count: %d\n", first_gnode, node_count);
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));
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);
228 hda_afg_node_id = node;
229 qemu_ok(
"UNBELIEVABLE! FOUND AFG!");
230 tty_printf(
"UNBELIEVABLE! FOUND AFG!\n");
232 hda_initialize_afg();
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));
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));
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);
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;
256 size_t node_count = node_data & 0xff;
257 size_t last_node = first_gnode + node_count;
259 char* node_types[] = {
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;
279 size_t type_of_node = ((hda_send_verb_via_corb_rirb(VERB(hda_afg_codec_id, node, 0xF1C, 0x00)) >> 20) & 0xF);
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);
298 size_t interrupt_status = READ32(0x24);
300 if(~interrupt_status & (1 << 31)) {
304 if(interrupt_status & (1 << 30)) {
305 size_t rirb_status = READ8(0x5D);
307 WRITE8(0x5D, rirb_status);
309 if(rirb_status & (1 << 0)) {
310 size_t rirb_wp = READ16(0x58);
314 while(hda_rirb_current != rirb_wp) {
315 hda_rirb_current = (hda_rirb_current + 1) % hda_rirb_entry_count;
318 hda_response = hda_rirb[hda_rirb_current * 2];
326 uint32_t hda_send_verb_via_corb_rirb(uint32_t verb) {
329 hda_corb_current = (hda_corb_current + 1) % hda_corb_entry_count;
333 hda_corb[hda_corb_current] = verb;
335 WRITE16(0x48, hda_corb_current & 0xff);
341 qemu_log(
"VERB %x got response %x", verb, hda_response);
350 WRITE32(0x8, READ32(0x8) & ~1);
352 while((READ32(0x08) & 1) != 0);
354 WRITE32(0x8, READ32(0x8) | 1);
356 while ((READ32(0x08) & 1) != 1);
358 qemu_ok(
"Reset ok!");
361 size_t hda_calculate_entries(
size_t word) {
362 if((word & 0x40) == 0x40) {
364 }
else if((word & 0x20) == 0x20) {
366 }
else if((word & 0x10) == 0x10) {
struct registers __attribute__((packed))
Структура данных пакета от мыши
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
uint16_t pci_read_confspc_word(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
[PCI] Чтение 16-битных полей из пространства механизма конфигураций 1
uint32_t pci_read32(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
Чтение данных из шины PCI.
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам