SayoriOS 0.3.3

ac97.c
1 // AC'97 driver by NDRAEY (Drew Pavlenko >_)
2
3 // FIXME: Not working in VirtualBox, only in QEMU
4
5 #include <common.h>
6 #include <lib/math.h>
7 #include <drv/audio/ac97.h>
8 #include "io/ports.h"
9 #include "drv/pci.h"
10 #include "mem/pmm.h"
11 #include "lib/stdio.h"
12 #include "mem/vmm.h"
13
14 uint8_t ac97_busnum, ac97_slot, ac97_func;
15
16 bool ac97_initialized = false;
17 bool ac97_varibale_sample_rate = false;
18
19 uint16_t native_audio_mixer = 0;
20 uint16_t native_audio_bus_master = 0;
21
22 uint8_t ac97_bar0_type = 0;
23 uint8_t ac97_bar1_type = 0;
24
25 size_t currently_pages_count = 0;
26
27 uint32_t current_sample_rate = 44100;
28
29 __attribute__((aligned(PAGE_SIZE))) AC97_BDL_t ac97_buffer[32];
30
31 char* ac97_audio_buffer = 0;
32 size_t ac97_audio_buffer_phys;
33
34 size_t ac97_lvi = 0;
35
36 #define AUDIO_BUFFER_SIZE (128 * KB)
37
38 // Volume in dB, not % (max 64)
39 void ac97_set_master_volume(uint8_t left, uint8_t right, bool mute) {
40 const uint16_t value = (right & 63) << 0
41 | (left & 63) << 8
42 | (uint8_t)mute << 15;
43 outw(native_audio_mixer + NAM_SET_MASTER_VOLUME, value);
44 }
45
46 // Volume in dB, not % (max 32)
47 void ac97_set_pcm_volume(uint8_t right, uint8_t left, bool mute) {
48 uint16_t value = (right & 31) << 0
49 | (left & 31) << 8
50 | (mute?1:0) << 15;
51 outw(native_audio_mixer + NAM_SET_PCM_VOLUME, value);
52 }
53
54 void ac97_set_pcm_sample_rate(uint16_t sample_rate) {
55 if(!ac97_varibale_sample_rate
56 || sample_rate > AC97_MAX_RATE
57 || sample_rate < AC97_MIN_RATE)
58 return;
59
60 outw(native_audio_mixer + NAM_SAMPLE_RATE, sample_rate);
61 // outs(native_audio_mixer + 0x2E, sample_rate);
62 // outs(native_audio_mixer + 0x30, sample_rate);
63 }
64
65 //void ac97_load_data(char* data, uint32_t length) {
66 // size_t samples = 0xfffe;
67 // size_t i;
68 // size_t times = MIN(31, length/samples);
69 //
70 // for (i = 0; i < times; i++) {
71 // ac97_buffer[i].memory_pos = data + (i * samples);
72 // ac97_buffer[i].sample_count = samples;
73 // }
74 // ac97_buffer[i-1].flags = 1 << 14; // 14 bit - last entry of buffer, stop playing
75 //}
76
77 void ac97_reset_channel() {
78 outb(native_audio_bus_master + 0x1b, inb(native_audio_bus_master + 0x1B) | 0x02);
79 }
80
81 void ac97_clear_status_register() {
82 outb(native_audio_bus_master + 0x16, 0x1C);
83 }
84
85 void _ac97_update_bdl(uint32_t address) {
86 outl(native_audio_bus_master + NABM_PCM_OUT, address); // BDL Address register
87 }
88
89 void ac97_update_bdl() {
90 _ac97_update_bdl((uint32_t) ac97_buffer);
91 }
92
93 void ac97_update_lvi(uint8_t index) {
94 outb(native_audio_bus_master + NABM_PCM_OUT + 0x05, index);
95 }
96
97 void ac97_set_play_sound(bool play) {
98 // outb(native_audio_bus_master + 0x1b, inb(native_audio_bus_master + 0x1B) | (uint8_t)play);
99 outb(native_audio_bus_master + 0x1b, (uint8_t)play);
100 }
101
102 void ac97_init() {
103 // Find device
104 pci_find_device(AC97_VENDOR, AC97_DEVICE, &ac97_busnum, &ac97_slot, &ac97_func);
105
106 const uint16_t devnum = pci_get_device(ac97_busnum, ac97_slot, ac97_func);
107
108 qemu_log("AC'97 ID: %d (%x)", devnum, devnum);
109
110 if(devnum == PCI_VENDOR_NO_DEVICE) {
111 qemu_log("AC'97 not connected!");
112 return;
113 }else{
114 qemu_log("Detected AC'97");
115 }
116
117 // Enable IO Busmastering
118
119 uint16_t command_register = pci_read_confspc_word(ac97_busnum, ac97_slot, ac97_func, 4);
120 qemu_log("Command register is: %x", command_register);
121
122 command_register |= 0x05;
123
124 qemu_log("Command register now is: %x", command_register);
125 pci_write(ac97_busnum, ac97_slot, ac97_func, 4, command_register);
126
127 // Get NAM and NABM adresses for port i/o.
128
129 native_audio_mixer = pci_read_confspc_word(ac97_busnum, ac97_slot, ac97_func, 0x10); // BAR0
130 native_audio_bus_master = pci_read_confspc_word(ac97_busnum, ac97_slot, ac97_func, 0x14); // BAR1
131
132 // That's QEMU BUG?
133 native_audio_mixer--;
134 native_audio_bus_master--;
135
136 // uint8_t hdrtype = pci_get_hdr_type(ac97_busnum, ac97_slot, ac97_func);
137 // native_audio_mixer = pci_get_bar(hdrtype, ac97_busnum, ac97_slot, ac97_func, 0, ac97_bar0_type); // BAR0
138 // native_audio_bus_master = pci_get_bar(hdrtype, ac97_busnum, ac97_slot, ac97_func, 1, ac97_bar1_type); // BAR1
139
140 qemu_log("NAM: %x; NABM: %x", native_audio_mixer, native_audio_bus_master);
141
142 const uint16_t extended_id = inw(native_audio_mixer + NAM_EXTENDED_ID);
143
144 const size_t rev = (extended_id >> 10) & 0b11;
145 const char* rev_strs[] = {"r < 21", "r22", "r23"};
146 qemu_log("Codec revision: (%d) %s", rev, rev_strs[rev]);
147
148 uint32_t gc = inl(native_audio_bus_master + NABM_GLOBAL_CONTROL);
149 qemu_log("Received global control: (%d) %x", gc, gc);
150 gc |= 1 << 1; // Cold reset
151 outl(native_audio_bus_master + NABM_GLOBAL_CONTROL, gc);
152 outw(native_audio_mixer + NAM_RESET, 1);
153 qemu_log("Cold reset");
154
155 // /*
156 // ac97_global_status_t status;
157 // ac97_global_status_t* statusptr = &status;
158
159 const uint32_t status = inl(native_audio_bus_master + NABM_GLOBAL_STATUS);
160
161 qemu_log("Status: %d (%x)\n", status, status);
162 // qemu_log("Status Reserved: %d\n", status.reserved);
163 // qemu_log("Status Channels: %d\n", (status.channel==0?2:(status.channel==1?4:(status.channel==2?6:0))));
164 // qemu_log("Status Samples: %s\n", status.sample==1?"16 and 20 bits":"only 16 bits");
165
166 // */
167
168 uint16_t extended_audio = inw(native_audio_mixer + NAM_EXTENDED_AUDIO);
169 qemu_log("Status: %d", extended_audio);
170
171 if((extended_id & 1) != 0) { // Check for variable sample rate
172 qemu_log("AC'97 supports variable sample rate!!!\n");
173 extended_audio |= 1;
174 ac97_varibale_sample_rate = true;
175 }
176
177 outw(native_audio_mixer + NAM_EXTENDED_AUDIO, extended_audio);
178
179 ac97_set_pcm_sample_rate(ac97_varibale_sample_rate ? 44100 : 48000);
180
181 ac97_set_master_volume(0, 0, false);
182 ac97_set_pcm_volume(0, 0, false);
183
184 ac97_audio_buffer = kmalloc_common(AUDIO_BUFFER_SIZE, PAGE_SIZE);
185 ac97_audio_buffer_phys = virt2phys(get_kernel_page_directory(),
186 (virtual_addr_t)ac97_audio_buffer);
187
188 qemu_log("Updated capabilities\n");
189
190 ac97_FillBDLs();
191
192 ac97_initialized = true;
193
194 qemu_log("AC'97 initialized successfully!");
195 }
196
197 bool ac97_is_initialized() {
198 return ac97_initialized;
199 }
200
201 void ac97_FillBDLs() {
202 size_t sample_divisor = 2;
203 // We need to fill ALL BDL entries.
204 // If we don't do that, we can encounter lags and freezes, because DMA doesn't stop
205 // even when its read pointer reached the end marker. (It will scroll to the end)
206 // So we need to spread buffer on BDL array
207
208 size_t bdl_span = AUDIO_BUFFER_SIZE / 32; // It's the size of each transfer (32 is the count of BDLs)
209
210 size_t filled = 0;
211 for (size_t j = 0; j < AUDIO_BUFFER_SIZE; j += bdl_span) {
212 ac97_buffer[filled].memory_pos = (void*)(ac97_audio_buffer_phys + j);
213 ac97_buffer[filled].sample_count = (bdl_span / sample_divisor) + 2;
214
215 // LOG("[%d] %x; %x", filled, ac97_data_buffer.second[filled].memory_pos, ac97_data_buffer.second[filled].sample_count);
216 filled++;
217 }
218
219 qemu_log("Fills: %d", filled);
220
221 filled--;
222
223 ac97_buffer[filled].flags = (1 << 14) | (1 << 15);
224
225 ac97_update_bdl();
226 ac97_update_lvi(filled);
227
228 ac97_lvi = filled;
229 }
230
231 void ac97_WriteAll(void* buffer, size_t size) {
232 qemu_log("Start");
233
234 size_t loaded = 0;
235
236 for(; loaded < size; loaded += AUDIO_BUFFER_SIZE) {
237 size_t block_size = MIN(size - loaded, AUDIO_BUFFER_SIZE);
238
239 memcpy(ac97_audio_buffer,
240 (char*)buffer + loaded,
241 block_size);
242
243 if (block_size < AUDIO_BUFFER_SIZE) {
244 memset((char *) ac97_audio_buffer + block_size,
245 0,
246 AUDIO_BUFFER_SIZE - block_size);
247 }
248
249 ac97_update_lvi(ac97_lvi);
250
251 ac97_set_play_sound(true);
252 ac97_clear_status_register();
253
254 while ((inb(native_audio_bus_master + 0x16) & (1 << 1)) == 0) {
255 __asm__ volatile("nop");
256 }
257 }
258
259 qemu_log("Finish");
260 }
261
262
263 void ac97_test() {
264 FILE* file = fopen("R:\\Sayori\\a.wav", "rb");
265 fseek(file, 0, SEEK_END);
266
267 const uint32_t filesize = ftell(file);
268
269 fseek(file, 0xae, SEEK_SET);
270
271 char* data = kmalloc(filesize);
272 fread(file, filesize, 1, data);
273
274 // size_t page_count = ac97_copy_user_memory_to_dma(data, filesize);
275
276 // qemu_log("Allocated %d pages for user memory in DMA", page_count);
277
278 ac97_set_master_volume(2, 2, false);
279 ac97_set_pcm_volume(2, 2, false);
280
281 ac97_WriteAll(data, filesize);
282
283 qemu_log("Exiting");
284 ac97_reset_channel();
285
286 kfree(data);
287 fclose(file);
288
289 // ac97_destroy_user_buffer();
290 }
common.h
Основные определения ядра
__attribute__
struct registers __attribute__((packed))
Структура данных пакета от мыши
Definition: psf.h:19
filesize
size_t filesize(const char *Path)
[FileIO] Возвращает размер указанного файла
Definition: fileio.c:67
memset
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
Definition: string.c:203
memcpy
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
pci_read_confspc_word
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
pci_find_device
void pci_find_device(uint16_t vendor, uint16_t device, uint8_t *bus_ret, uint8_t *slot_ret, uint8_t *func_ret)
[PCI] Поиск устройства по ID-поставшика и устройства
Definition: pci.c:362
pci_get_device
uint16_t pci_get_device(uint8_t bus, uint8_t slot, uint8_t function)
[PCI] Получение ID-Устройства
Definition: pci.c:269
fseek
ssize_t fseek(FILE *stream, ssize_t offset, uint8_t whence)
Установка позиции в потоке данных относительно текущей позиции
Definition: stdio.c:315
fclose
void fclose(FILE *stream)
Закончить работу с файлом
Definition: stdio.c:213
fopen
FILE * fopen(const char *filename, const char *_mode)
Открывает файл
Definition: stdio.c:166
ftell
int ftell(FILE *stream)
Текущая позиция считывания в файле
Definition: stdio.c:287
fread
int fread(FILE *stream, size_t count, size_t size, void *buffer)
Чтение файла
Definition: stdio.c:250
__attribute__
Структура файла
Definition: ahci.h:15
AC97_BDL_t
Definition: ac97.h:33
FILE
Структура файла. Требуется для работы с VFS.
Definition: stdio.h:21