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 }
Основные определения ядра
struct registers __attribute__((packed))
Структура данных пакета от мыши
Definition: psf.h:19
size_t filesize(const char *Path)
[FileIO] Возвращает размер указанного файла
Definition: fileio.c:67
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
Definition: string.c:203
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
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
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
uint16_t pci_get_device(uint8_t bus, uint8_t slot, uint8_t function)
[PCI] Получение ID-Устройства
Definition: pci.c:269
ssize_t fseek(FILE *stream, ssize_t offset, uint8_t whence)
Установка позиции в потоке данных относительно текущей позиции
Definition: stdio.c:315
void fclose(FILE *stream)
Закончить работу с файлом
Definition: stdio.c:213
FILE * fopen(const char *filename, const char *_mode)
Открывает файл
Definition: stdio.c:166
int ftell(FILE *stream)
Текущая позиция считывания в файле
Definition: stdio.c:287
int fread(FILE *stream, size_t count, size_t size, void *buffer)
Чтение файла
Definition: stdio.c:250
Структура файла
Definition: ahci.h:15
Структура файла. Требуется для работы с VFS.
Definition: stdio.h:21