Voxia OS
v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
intel_hda.c
Go to the documentation of this file.
1
// #include "./intel_hda.h"
2
3
// #include <firmw/pci/pci.h>
4
// #include <libk/debug/debug.h>
5
// #include <libk/serial.h>
6
// #include <str.h>
7
// #include <libk/timer.h>
8
// #include <type.h>
9
// #include <memory/memory_utils.h>
10
// #include <memory/phys_base_allocator.h>
11
// #include <vfs/vfs.h>
12
13
// /* Variabel global HDA */
14
// pci_device_t hda_device;
15
16
// static volatile uint32_t *hda_corr = 0; // CORB: Command Output Ring Buffer
17
// static volatile uint32_t *hda_rirrb = 0; // RIRB: Response Input Ring Buffer
18
// static uint8_t hda_corb_pointer = 1;
19
// static uint8_t hda_rirb_pointer = 1;
20
// static int ticks = 0;
21
// static uint8_t pin_speaker_node = 0, pin_alt_speaker_node = 0;
22
23
// /* Fungsi-fungsi MMIO dasar */
24
// uint8_t
25
// mmio_readb(uint16_t offset)
26
// {
27
// return *((volatile uint8_t *)(hda_device.bar[0] + offset));
28
// }
29
30
// void
31
// mmio_writeb(uint16_t offset, uint8_t data)
32
// {
33
// *((volatile uint8_t *)(hda_device.bar[0] + offset)) = data;
34
// }
35
36
// uint16_t
37
// mmio_readw(uint16_t offset)
38
// {
39
// return *((volatile uint16_t *)(hda_device.bar[0] + offset));
40
// }
41
42
// void
43
// mmio_writew(uint16_t offset, uint16_t data)
44
// {
45
// *((volatile uint16_t *)(hda_device.bar[0] + offset)) = data;
46
// }
47
48
// uint32_t
49
// mmio_readl(uint16_t offset)
50
// {
51
// return *((volatile uint32_t *)(hda_device.bar[0] + offset));
52
// }
53
54
// void
55
// mmio_writel(uint16_t offset, uint32_t data)
56
// {
57
// *((volatile uint32_t *)(hda_device.bar[0] + offset)) = data;
58
// }
59
60
// /* Prototipe fungsi */
61
// void parse_codec(int codec);
62
// void audio_function_group_process(int codec, int node);
63
64
// /*
65
// * Kirim perintah (verb) melalui PIO.
66
// * Metode ini mengirim perintah secara langsung dan menunggu respons.
67
// */
68
// uint32_t
69
// send_verb_pio(uint32_t codec, uint32_t node, uint32_t verb, uint32_t cmd)
70
// {
71
// uint32_t data = ((codec << 28) | (node << 20) | (verb << 8) | cmd);
72
// // Mulai PIO: set bit (misal: offset 0x68) sebelum menulis data
73
// mmio_writew(0x68, 0x2);
74
// mmio_writel(0x60, data);
75
// mmio_writew(0x68, 0x1);
76
77
// ticks = 0;
78
// while (ticks < 4)
79
// {
80
// ticks++;
81
// usleep(100);
82
// // Cek status PIO (offset 0x68)
83
// if ((mmio_readw(0x68) & 0x3) == 0x2)
84
// {
85
// mmio_writew(0x68, 0x2);
86
// return mmio_readl(0x64);
87
// }
88
// }
89
// return 0;
90
// }
91
92
// /*
93
// * Kirim perintah melalui mekanisme CORB/RIRB.
94
// * Perhatikan bahwa implementasi ini harus disesuaikan dengan
95
// * spesifikasi dan pengaturan sinkronisasi hardware.
96
// */
97
// uint32_t
98
// send_verb(uint32_t codec, uint32_t node, uint32_t command, uint32_t verb)
99
// {
100
// serial_trace("HDA CORB base: 0x%x\n", (uintptr_t)hda_corr);
101
// uint32_t data = ((codec << 28) | (node << 20) | (command << 8) | verb);
102
// serial_trace("Sending verb: 0x%x\n", data);
103
// hda_corr[hda_corb_pointer] = data;
104
// serial_trace("CORB pointer: %d -> 0x%x\n", hda_corb_pointer, hda_corr[hda_corb_pointer]);
105
106
// mmio_writew(0x48, hda_corb_pointer);
107
// int c = 0;
108
// while (c < 3)
109
// {
110
// usleep(500);
111
// uint8_t a = mmio_readb(0x58);
112
// if (a == hda_corb_pointer)
113
// {
114
// break;
115
// }
116
// c++;
117
// }
118
119
// data = hda_rirrb[hda_rirb_pointer * 2];
120
// hda_rirb_pointer = (hda_rirb_pointer + 1) % 256;
121
// hda_corb_pointer = (hda_corb_pointer + 1) % 256;
122
123
// serial_trace("Verb response: 0x%x\n", data);
124
// return data;
125
// }
126
127
// /*
128
// * Inisialisasi Intel HDA:
129
// * - Mencari perangkat PCI dengan class 0x04 (audio) dan subclass 0x03 (HDA)
130
// * - Reset dan konfigurasi awal register
131
// * - Alokasi dan inisialisasi buffer CORB dan RIRB
132
// */
133
// void
134
// intel_hda_init(void)
135
// {
136
// /* Cari perangkat HDA pada daftar PCI */
137
// for (int i = 0; i < 32; i++)
138
// {
139
// if (pci_devices[i].class == 0x4 && pci_devices[i].subclass == 0x3)
140
// {
141
// serial_trace("\nFound Intel HDA device BAR at: 0x%x\n", pci_devices[i].bar[0]);
142
// hda_device = pci_devices[i];
143
// enable_bus_mastering(hda_device);
144
// break;
145
// }
146
// }
147
148
// /* Reset HDA controller */
149
// mmio_writel(INTEL_HDA_GCTL_OFFSET, 0);
150
// usleep(100);
151
// if ((mmio_readb(INTEL_HDA_GCTL_OFFSET) & 0x1) == 0)
152
// serial_trace("Intel HDA reset success\n");
153
154
// mmio_writel(INTEL_HDA_GCTL_OFFSET, 1);
155
// usleep(100);
156
// if ((mmio_readb(INTEL_HDA_GCTL_OFFSET) & 0x1) == 1)
157
// serial_trace("Intel HDA exited reset state successfully\n");
158
159
// /* Baca versi spesifikasi */
160
// uint8_t major_version = mmio_readb(INTEL_HDA_VMAJ_OFFSET);
161
// uint8_t minor_version = mmio_readb(INTEL_HDA_VMIN_OFFSET);
162
// serial_trace("Intel HDA version: %d.%d\n", major_version, minor_version);
163
164
// /* Nonaktifkan interrupt */
165
// mmio_writel(INTEL_HDA_INT_OFFSET, 0);
166
167
// /* Konfigurasi DMA Position Buffer */
168
// mmio_writel(0x70, 0);
169
// mmio_writel(0x74, 0);
170
171
// /* Nonaktifkan stream synchronisation dan CORB/RIRB */
172
// mmio_writel(0x38, 0);
173
// mmio_writeb(0x4C, 0);
174
// mmio_writeb(0x5C, 0);
175
176
// /* Alokasikan dan inisialisasi CORB */
177
// uint8_t corb_size_reg = mmio_readb(0x4E);
178
// serial_trace("CORB size register: 0x%x\n", corb_size_reg);
179
180
// /* Alokasikan setidaknya satu halaman dan pastikan alignment 128-byte */
181
// hda_corr = (volatile uint32_t *)VIRT2PHYS(phys_base_alloc(1));
182
// hda_corr = (volatile uint32_t *)((((uint32_t)hda_corr + 0x80 - 1) / 0x80) * 0x80);
183
// serial_trace("CORB allocated at: 0x%x\n", (uint32_t)hda_corr);
184
// memset((void *)hda_corr, 0xFF, 256 * 8);
185
// mmio_writel(0x40, (uint32_t)hda_corr);
186
// mmio_writel(0x44, 0);
187
// /* Set CORB ring size ke 256 entri (0b10) */
188
// mmio_writeb(0x4E, 0x2);
189
190
// /* Reset pointer CORB */
191
// mmio_writew(0x4A, 0x8000);
192
// while ((mmio_readw(0x4A) & 0x8000) != 0x8000)
193
// usleep(100);
194
// mmio_writew(0x4A, 0);
195
// while ((mmio_readw(0x4A) & 0x8000) != 0)
196
// usleep(100);
197
// if ((mmio_readw(0x4A) & 0x8000) == 0x8000)
198
// serial_trace("CORB reset failed\n");
199
200
// mmio_writel(0x48, 0);
201
202
// /* Alokasikan dan inisialisasi RIRB */
203
// uint8_t rirb_size_reg = mmio_readb(0x5E);
204
// serial_trace("RIRB size register: 0x%x\n", rirb_size_reg);
205
// hda_rirrb = (volatile uint32_t *)VIRT2PHYS(phys_base_alloc(1));
206
// memset((void *)hda_rirrb, 0, 256 * 8);
207
// mmio_writel(0x50, (uint32_t)hda_rirrb);
208
// mmio_writel(0x54, 0);
209
// /* Set RIRB ring size ke 256 entri */
210
// mmio_writeb(0x5E, 0x2);
211
212
// /* Reset pointer RIRB */
213
// mmio_writew(0x58, 0x8000);
214
// while ((mmio_readw(0x58) & 0x8000) != 0)
215
// ;
216
// usleep(500);
217
// mmio_writew(0x5A, 0xFF); // Set response interrupt count
218
219
// /* Konfigurasi DMA Position Buffer */
220
// mmio_writel(0x70, 1);
221
// mmio_writel(0x74, 0x0);
222
223
// /* Nyalakan CORB dan RIRB (DMA mode), namun jika ada masalah pada QEMU,
224
// * gunakan PIO */
225
// mmio_writeb(0x4C, 0x2);
226
// mmio_writeb(0x5C, 0x2);
227
// // Jika DMA bermasalah, nonaktifkan DMA:
228
// mmio_writeb(0x4C, 0);
229
// mmio_writeb(0x5C, 0);
230
231
// /* Pindai CODEC menggunakan mode PIO */
232
// for (int i = 0; i < 16; i++)
233
// {
234
// uint32_t codecid = send_verb_pio(i, 0, 0xF00, 0);
235
// if (codecid != 0)
236
// {
237
// serial_trace("\nFound CODEC (PIO) id: 0x%x\n", codecid);
238
// parse_codec(i);
239
// }
240
// }
241
// serial_trace("Intel HDA init done\n\n");
242
// }
243
244
// /*
245
// * Fungsi parse_codec mengambil informasi CODEC, seperti vendor/device,
246
// * revision, dan data subordinate untuk menentukan function group.
247
// */
248
// void
249
// parse_codec(int codec)
250
// {
251
// uint32_t info = send_verb_pio(codec, 0, 0xF00, 0);
252
// uint16_t device_id = info & 0xFFFF;
253
// uint16_t vendor_id = (info >> 16) & 0xFFFF;
254
255
// info = send_verb_pio(codec, 0, 0xF00, 0x2);
256
// uint16_t revision_id = info >> 16;
257
// serial_trace("Codec %d: Vendor 0x%x, Device 0x%x, Revision 0x%x\n", codec, vendor_id,
258
// device_id,
259
// revision_id);
260
261
// uint32_t subordinate_info = send_verb_pio(codec, 0, 0xF00, 0x4);
262
// serial_trace("Subordinate info: 0x%x\n", subordinate_info);
263
// uint8_t total_nodes = subordinate_info & 0xFF;
264
// uint8_t start_node = (subordinate_info >> 16) & 0xFF;
265
// serial_trace("Total nodes: %d, Start node: %d\n", total_nodes, start_node);
266
267
// for (uint8_t i = start_node; i < start_node + total_nodes; i++)
268
// {
269
// uint32_t node_info = send_verb_pio(codec, i, 0xF00, 0x5);
270
// if ((node_info & 0x7F) == 0x1)
271
// {
272
// serial_trace("Node 0x%x is an Audio Function Group\n", i);
273
// audio_function_group_process(codec, i);
274
// return;
275
// }
276
// }
277
// }
278
279
// /*
280
// * Fungsi get_connection_list mengambil entri daftar koneksi dari suatu node.
281
// * Memilih format pendek atau panjang sesuai bit paling atas dari response.
282
// */
283
// uint16_t
284
// get_connection_list(int codec, int node, uint32_t connection_number)
285
// {
286
// uint32_t connection_lst_cap = send_verb_pio(codec, node, 0xF00, 0x0E);
287
// if (connection_number >= (connection_lst_cap & 0x7F))
288
// return 0;
289
290
// if ((connection_lst_cap & 0x80) == 0x00)
291
// { // short form
292
// return (send_verb_pio(codec, node, 0xF02, ((connection_number / 4) * 4)) >>
293
// ((connection_number % 4) * 8)) &
294
// 0xFF;
295
// }
296
// else
297
// { // long form
298
// return (send_verb_pio(codec, node, 0xF02, ((connection_number / 2) * 2)) >>
299
// ((connection_number % 2) * 16)) &
300
// 0xFFFF;
301
// }
302
// }
303
304
// /*
305
// * Fungsi set_gain_node mengatur gain (volume) untuk sebuah node.
306
// */
307
// void
308
// set_gain_node(int codec, int node, int type, uint16_t cap, uint16_t gain)
309
// {
310
// uint16_t payload = 0x3000;
311
// if (type == 0x1)
312
// payload |= 0x8000;
313
// if (gain == 0 && (cap & 0x80000000))
314
// payload |= 0x80; // mute
315
// else
316
// payload |= (((cap >> 8) & 0x7F) * gain / 100); // konversi 0-100 ke range node
317
// send_verb_pio(codec, node, 0x3, payload);
318
// }
319
320
// /*
321
// * Fungsi audio_function_group_process melakukan inisialisasi untuk Audio
322
// * Function Group:
323
// * - Reset, power on, aktifkan unsolicited response,
324
// * - Baca capability widget, cari widget output,
325
// * - Jika ditemukan, konfigurasi node output speaker.
326
// */
327
// void
328
// audio_function_group_process(int codec, int node)
329
// {
330
// uint32_t node_info = send_verb_pio(codec, node, 0xF00, 0x5);
331
// uint8_t node_type = node_info & 0xFF;
332
// uint8_t unsol = (node_info >> 8) & 0xFF;
333
// serial_trace("Node 0x%x type: %d, unsol: %d\n", node, node_type, unsol);
334
335
// /* Inisialisasi AFG */
336
// send_verb_pio(codec, node, 0x7FF, 0); // Reset function group
337
// send_verb_pio(codec, node, 0x705, 0); // Power on
338
// send_verb_pio(codec, node, 0x708, 0); // Enable unsolicited response
339
340
// uint32_t sample_capability = send_verb_pio(codec, node, 0xF00, 0x0A);
341
// uint32_t supported_format = send_verb_pio(codec, node, 0xF00, 0x0B);
342
// uint32_t pin_capability = send_verb_pio(codec, node, 0xF00, 0x0C);
343
// uint32_t input_amp_capability = send_verb_pio(codec, node, 0xF00, 0x0D);
344
// uint32_t output_amp_capability = send_verb_pio(codec, node, 0xF00, 0x0E);
345
346
// serial_trace("Sample capability: 0x%x\n", sample_capability);
347
// serial_trace("Supported format: AC3: %d, Float32: %d, PCM: %d\n",
348
// (supported_format & 0b100) != 0, (supported_format & 0b010) != 0,
349
// (supported_format & 0b001) != 0);
350
// serial_trace("Pin capability: 0x%x\n", pin_capability);
351
352
// uint32_t subordinate_info = send_verb_pio(codec, node, 0xF00, 0x4);
353
// uint8_t total_nodes = subordinate_info & 0xFF;
354
// uint8_t start_node = (subordinate_info >> 16) & 0xFF;
355
// serial_trace("Total nodes: %d, Start node: %d\n", total_nodes, start_node);
356
357
// for (uint8_t i = start_node; i < start_node + total_nodes; i++)
358
// {
359
// uint32_t widget_cap = send_verb_pio(codec, i, 0xF00, 0x9);
360
// uint8_t widget_type = (widget_cap >> 20) & 0xF;
361
// if (widget_type == 0)
362
// {
363
// serial_trace("Widget 0x%x is an audio output\n", i);
364
// send_verb_pio(codec, i, 0x706, 0x0);
365
// // pin_speaker_node = i;
366
// }
367
// else if (widget_type == 1)
368
// serial_trace("Widget 0x%x is an audio input\n", i);
369
// else if (widget_type == 0x4)
370
// {
371
// serial_trace("Widget 0x%x is a complex widget\n", i);
372
// widget_type = (send_verb_pio(codec, i, 0xF1C, 0x00) >> 20) & 0xF;
373
// if (widget_type == 0x0)
374
// {
375
// serial_trace("Widget 0x%x is a Line Out widget\n", i);
376
// pin_alt_speaker_node = i;
377
// }
378
// else if (widget_type == 0x1)
379
// serial_trace("Widget 0x%x is a Speaker widget\n", i);
380
// else if (widget_type == 0x2)
381
// serial_trace("Widget 0x%x is a HP Out widget\n", i);
382
// else if (widget_type == 0x3)
383
// serial_trace("Widget 0x%x is a CD widget\n", i);
384
// else if (widget_type == 0x4)
385
// serial_trace("Widget 0x%x is a SPDIF Out widget\n", i);
386
// else if (widget_type == 0x5)
387
// serial_trace("Widget 0x%x is a Digital Other Out widget\n", i);
388
// else if (widget_type == 0x6)
389
// serial_trace("Widget 0x%x is a Modem Line Side widget\n", i);
390
// else if (widget_type == 0x7)
391
// serial_trace("Widget 0x%x is a Modem Handset Side widget\n", i);
392
// else if (widget_type == 0x8)
393
// serial_trace("Widget 0x%x is a Line In widget\n", i);
394
// else if (widget_type == 0x9)
395
// serial_trace("Widget 0x%x is a Aux widget\n", i);
396
// else if (widget_type == 0xA)
397
// serial_trace("Widget 0x%x is a Mic In widget\n", i);
398
// else if (widget_type == 0xB)
399
// serial_trace("Widget 0x%x is a Telephony widget\n", i);
400
// else if (widget_type == 0xC)
401
// serial_trace("Widget 0x%x is a SPDIF In widget\n", i);
402
// else if (widget_type == 0xD)
403
// serial_trace("Widget 0x%x is a Digital Other In widget\n", i);
404
// else if (widget_type == 0xE)
405
// serial_trace("Widget 0x%x is a Analog Other widget\n", i);
406
// else if (widget_type == 0xF)
407
// serial_trace("Widget 0x%x is a Reserved widget\n", i);
408
// }
409
// else if (widget_type == 0x6)
410
// serial_trace("Widget 0x%x is a volume knob\n", i);
411
// else if (widget_type == 0x7)
412
// serial_trace("Widget 0x%x is a beep generator\n", i);
413
// else if (widget_type == 0x8)
414
// serial_trace("Widget 0x%x is a vendor defined\n", i);
415
// else
416
// serial_trace("Widget 0x%x is a reserved\n", i);
417
418
// /* Coba cari output node yang terhubung */
419
// uint8_t out_amp_present = widget_cap & 0x4;
420
// if (out_amp_present)
421
// {
422
// serial_trace("Output amp present on widget 0x%x\n", i);
423
// if ((send_verb_pio(codec, i, 0xF1C, 0) >> 30) != 0x1)
424
// {
425
// if ((send_verb_pio(codec, i, 0xF00, 0x0C) & 0x10) == 0x10)
426
// {
427
// serial_trace("Codec %d, Node 0x%x connected to "
428
// "output device\n",
429
// codec, i);
430
// pin_speaker_node = i;
431
// }
432
// else
433
// {
434
// serial_trace("no output device\n");
435
// }
436
// }
437
// }
438
439
// /* Tampilkan daftar koneksi (jika ada) */
440
// uint8_t con_entry_number = 0;
441
// uint16_t con_list = get_connection_list(codec, i, con_entry_number);
442
// while (con_list != 0)
443
// {
444
// serial_trace("Node 0x%x Connection list entry: %d\n", i, con_list);
445
// con_entry_number++;
446
// con_list = get_connection_list(codec, i, con_entry_number);
447
// }
448
// }
449
450
// /* Jika ditemukan output node untuk speaker, lakukan inisialisasi lebih
451
// * lanjut */
452
// if (pin_speaker_node != 0)
453
// {
454
// serial_trace("Found speaker node: 0x%x\n", pin_speaker_node);
455
// send_verb_pio(codec, pin_speaker_node, 0x705,
456
// 0); // Power on speaker node
457
// send_verb_pio(codec, pin_speaker_node, 0x708,
458
// 0); // Enable unsolicited response
459
// send_verb_pio(codec, pin_speaker_node, 0x703,
460
// 0); // Stop processing (jika diperlukan)
461
// send_verb_pio(codec, pin_speaker_node, 0x706,
462
// 0x10); // Set stream/channel
463
// uint16_t pin_out_cap = send_verb_pio(codec, pin_speaker_node, 0xF00, 0x012);
464
// set_gain_node(codec, pin_speaker_node, 1, pin_out_cap, 100);
465
// serial_trace("Audio output node initialized\n");
466
// }
467
// else if (pin_alt_speaker_node != 0)
468
// {
469
// serial_trace("Found alternate speaker node: 0x%x\n", pin_alt_speaker_node);
470
// send_verb_pio(codec, pin_alt_speaker_node, 0x705,
471
// 0); // Power on speaker node
472
// send_verb_pio(codec, pin_alt_speaker_node, 0x708,
473
// 0); // Enable unsolicited response
474
// send_verb_pio(codec, pin_alt_speaker_node, 0x703,
475
// 0); // Stop processing (jika diperlukan)
476
// send_verb_pio(codec, pin_alt_speaker_node, 0x706,
477
// 0x10); // Set stream/channel
478
// uint16_t pin_out_cap = send_verb_pio(codec, pin_alt_speaker_node, 0xF00, 0x012);
479
// set_gain_node(codec, pin_alt_speaker_node, 1, pin_out_cap, 100);
480
// serial_trace("Alternate audio output node initialized\n");
481
// pin_speaker_node = pin_alt_speaker_node;
482
// }
483
// else
484
// {
485
// serial_trace("No speaker node found\n");
486
// }
487
// }
488
489
// /*
490
// * Fungsi intel_hda_play:
491
// * - Membaca file audio dari sistem file
492
// * - Mengatur stream descriptor untuk output stream
493
// * - Memulai pemutaran
494
// */
495
// struct stream_buffer
496
// {
497
// uint64_t buffer;
498
// uint32_t length;
499
// uint32_t ioc;
500
// } __attribute__((packed));
501
502
// uint16_t
503
// hda_return_sound_data_format(uint32_t sample_rate, uint32_t channels, uint32_t bits_per_sample)
504
// {
505
// uint16_t data_format = 0;
506
507
// // channels
508
// data_format = (channels - 1);
509
510
// // bits per sample
511
// if (bits_per_sample == 16)
512
// {
513
// data_format |= ((0b001) << 4);
514
// }
515
// else if (bits_per_sample == 20)
516
// {
517
// data_format |= ((0b010) << 4);
518
// }
519
// else if (bits_per_sample == 24)
520
// {
521
// data_format |= ((0b011) << 4);
522
// }
523
// else if (bits_per_sample == 32)
524
// {
525
// data_format |= ((0b100) << 4);
526
// }
527
528
// // sample rate
529
// if (sample_rate == 48000)
530
// {
531
// data_format |= ((0b0000000) << 8);
532
// }
533
// else if (sample_rate == 44100)
534
// {
535
// data_format |= ((0b1000000) << 8);
536
// }
537
// else if (sample_rate == 32000)
538
// {
539
// data_format |= ((0b0001010) << 8);
540
// }
541
// else if (sample_rate == 22050)
542
// {
543
// data_format |= ((0b1000001) << 8);
544
// }
545
// else if (sample_rate == 16000)
546
// {
547
// data_format |= ((0b0000010) << 8);
548
// }
549
// else if (sample_rate == 11025)
550
// {
551
// data_format |= ((0b1000011) << 8);
552
// }
553
// else if (sample_rate == 8000)
554
// {
555
// data_format |= ((0b0000101) << 8);
556
// }
557
// else if (sample_rate == 88200)
558
// {
559
// data_format |= ((0b1001000) << 8);
560
// }
561
// else if (sample_rate == 96000)
562
// {
563
// data_format |= ((0b0001000) << 8);
564
// }
565
// else if (sample_rate == 176400)
566
// {
567
// data_format |= ((0b1011000) << 8);
568
// }
569
// else if (sample_rate == 192000)
570
// {
571
// data_format |= ((0b0011000) << 8);
572
// }
573
574
// return data_format;
575
// }
576
577
// void
578
// test_beep(void)
579
// {
580
// int beep_node = -1;
581
// // Asumsikan codec 0; iterasi node 0 sampai 15 (sesuaikan dengan rentang
582
// // node yang valid)
583
// for (int node = 0; node < 16; node++)
584
// {
585
// uint32_t widget_cap = send_verb_pio(0, node, 0xF00, 0x9);
586
// uint8_t widget_type = (widget_cap >> 20) & 0xF;
587
// if (widget_type == 0x7)
588
// {
589
// beep_node = node;
590
// serial_trace("Found beep generator at node 0x%x\n", node);
591
// break;
592
// }
593
// }
594
// if (beep_node == -1)
595
// {
596
// serial_trace("No beep generator found\n");
597
// return;
598
// }
599
600
// /* Memicu beep:
601
// Contoh: mengirimkan verb 0x70 dengan payload 0x1 untuk memulai beep,
602
// kemudian 0x70 dengan payload 0x0 untuk menghentikannya.
603
// (Nilai-nilai ini hanya contoh; sesuaikan dengan dokumentasi codec Anda)
604
// */
605
// serial_trace("Triggering beep...\n");
606
// send_verb_pio(0, beep_node, 0x70, 0x1);
607
// usleep(500000); // Beep selama 0.5 detik
608
// send_verb_pio(0, beep_node, 0x70, 0x0);
609
// serial_trace("Beep finished.\n");
610
// }
611
612
// void
613
// intel_hda_play(const char *file_path)
614
// {
615
// int fd = vfs_open(file_path, 0);
616
// struct vfs_file_stats stats;
617
// int fs_resp = vfs_fstat(fd, &stats);
618
// serial_trace("File size: %d bytes\n", stats.size);
619
620
// /* Alokasikan buffer untuk file audio dan pastikan alamat fisiknya benar */
621
// uint8_t *file = (uint8_t *)VIRT2PHYS(phys_base_alloc((stats.size / 4096) + 1));
622
// file = (uint8_t *)(((uint32_t)file + 0x7F) & ~0x7F);
623
// serial_trace("File buffer: 0x%x\n", (uint32_t)file);
624
// int o = vfs_read(fd, file, stats.size);
625
// if (o != 0)
626
// {
627
// serial_trace("Error reading file\n");
628
// return;
629
// }
630
631
// uint32_t pos = ((mmio_readw(0x00) >> 8) & 0xF);
632
// serial_trace("HDA stream input stream number %d\n", pos);
633
634
// uint32_t output_pos = ((mmio_readw(0x00) >> 12) & 0xF);
635
// serial_trace("HDA stream output stream number %d\n", output_pos);
636
637
// /* Atur alamat stream output dari register stream descriptor.
638
// Perhitungan offset disesuaikan dengan jumlah stream input/output yang
639
// tersedia. */
640
// volatile uint32_t *hda_stream_output_base =
641
// (volatile uint32_t *)(hda_device.bar[0] + 0x80 + (0x20 * ((mmio_readw(0x00) >> 8) &
642
// 0xF)));
643
// serial_trace("HDA stream output base: 0x%x\n", (uint32_t)hda_stream_output_base);
644
645
// /* Reset stream: update control register untuk memulai stream */
646
// uint32_t stream_desc = *((volatile uint32_t *)hda_stream_output_base);
647
// stream_desc &= ~0x2; // Clear flag tertentu (sesuaikan dengan spesifikasi)
648
// stream_desc |= 0x1; // Set stream run flag
649
// *((volatile uint32_t *)hda_stream_output_base) = stream_desc;
650
651
// int counter = 0;
652
// *((volatile uint32_t *)(hda_stream_output_base)) = 0;
653
654
// while ((*((volatile uint32_t *)(hda_stream_output_base + 0)) & 0x1) != 0)
655
// {
656
// usleep(100);
657
// counter++;
658
// if (counter > 100)
659
// {
660
// serial_trace("\nHDA: can not reset stream");
661
// break;
662
// }
663
// }
664
665
// *((volatile uint32_t *)(hda_stream_output_base + 0x03)) = 0x1C;
666
667
// /* Buat stream buffer descriptor */
668
// struct stream_buffer *stream_list = (struct stream_buffer *)((uint64_t)VIRT2PHYS(
669
// phys_base_alloc(1 + (sizeof(struct stream_buffer) * 2))));
670
// stream_list = (struct stream_buffer *)(((uint32_t)stream_list + 0x7F) & ~0x7F);
671
// memset(stream_list, 0, sizeof(struct stream_buffer) * 2);
672
// asm("wbinvd");
673
674
// for (int i = 0; i < 1; i++)
675
// {
676
// stream_list[i].buffer = (uint64_t)(file);
677
// stream_list[i].length = stats.size;
678
// stream_list[i].ioc = 1;
679
// }
680
681
// serial_trace("Stream buffer descriptor: 0x%x\n", (uint32_t)stream_list);
682
// // asm("wbinvd"); // Flush cache (jika diperlukan)
683
684
// asm("wbinvd");
685
// mmio_writel(0x80 + pos * 0x20 + 0x18, (uint32_t)(uintptr_t)stream_list);
686
// mmio_writel(0x80 + pos * 0x20 + 0x1C, (uint32_t)((uintptr_t)stream_list >> 32));
687
688
// mmio_writel(0x80 + pos * 0x20 + 0x08, stats.size);
689
// serial_trace("Stream size: %d\n", sizeof(struct stream_buffer));
690
// mmio_writel(0x80 + pos * 0x20 + 0x0C, 1);
691
692
// /* Kirim perintah untuk memulai pemutaran */
693
694
// uint32_t payload = hda_return_sound_data_format(44100, 2, 16);
695
// mmio_writel(0x80 + pos * 0x20 + 0x12, payload);
696
697
// send_verb_pio(0, pin_speaker_node, 0x200, payload);
698
// usleep(100);
699
700
// // mmio_writel (0x20, 0xFFFF);
701
702
// mmio_writel(0x80 + pos * 0x20 + 0x02, 0x14);
703
// mmio_writel(0x80 + pos * 0x20 + 0x0, mmio_readl(0x80 + pos * 0x20 + 0x0) | 0x2);
704
// KDEBUG(1, "HDA: playing %s with size %d\n", file_path, stats.size);
705
// }
kernel
hal
sound
intel_hda.c
Generated on Sat May 30 2026 11:09:57 for Voxia OS by
1.13.2