diff --git a/Makefile b/Makefile index 52b96c4..302db5f 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ OBJ = boot/boot.o \ kernel/string.o \ drivers/serial.o \ drivers/vga.o \ + drivers/speaker.o \ drivers/timer.o \ drivers/keyboard.o @@ -67,7 +68,7 @@ iso: $(TARGET) # Честный запуск через ISO в QEMU run: iso @echo "[+] Запускаем peredOS в QEMU через CD-ROM..." - qemu-system-i386 -cdrom $(ISO_IMAGE) -serial stdio + qemu-system-i386 -cdrom $(ISO_IMAGE) -serial stdio -audiodev sdl,id=snd0 -machine pcspk-audiodev=snd0 # Очистка мусора clean: diff --git a/README.md b/README.md index 5bd6210..a9c8ff1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - [x] Драйвер клавиатуры - [x] Нормальный драйвер VGA (скролл итд) - [x] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд) -- [ ] Драйвер PC Speaker +- [x] Драйвер PC Speaker - [ ] Screen buffers (как tty в Linux) - [ ] ANSI Escape в screen buffers - [ ] Драйвер мыши diff --git a/drivers/speaker.c b/drivers/speaker.c new file mode 100644 index 0000000..be128f0 --- /dev/null +++ b/drivers/speaker.c @@ -0,0 +1,48 @@ +#include "speaker.h" +#include "timer.h" // Теперь здесь виден extern uint32_t system_ticks +#include "../kernel/io.h" + +void sleep_ms(uint32_t ms) { + // 1 тик = 10 мс на частоте 100 Гц + uint32_t ticks_to_wait = ms / 10; + if (ticks_to_wait == 0) ticks_to_wait = 1; // Защита от слишком маленького интервала + + uint32_t start_ticks = system_ticks; + + // Ждем, пока разница тиков не достигнет нужного значения + while ((system_ticks - start_ticks) < ticks_to_wait) { + // Аппаратно засыпаем до следующего прерывания PIT + __asm__ __volatile__("hlt"); + } +} + +void speaker_play(uint32_t frequency) { + if (frequency == 0) return; + + uint32_t divisor = 1193182 / frequency; + + // Настраиваем Канал 2 PIT (порт 0x43, режим 0xB6) + outb(0x43, 0xB6); + + // Передаем делитель в порт данных Канала 2 (0x42) + outb(0x42, (uint8_t)(divisor & 0xFF)); + outb(0x42, (uint8_t)((divisor >> 8) & 0xFF)); + + // Подключаем PIT к динамику через порт управления системными функциями + uint8_t speaker_state = inb(0x61); + if ((speaker_state & 3) != 3) { + outb(0x61, speaker_state | 3); + } +} + +void speaker_stop(void) { + // Отключаем динамик, сбрасывая 0 и 1 биты + uint8_t speaker_state = inb(0x61) & 0xFC; + outb(0x61, speaker_state); +} + +void speaker_beep(uint32_t frequency, uint32_t duration_ms) { + speaker_play(frequency); + sleep_ms(duration_ms); // Наш халяльный sleep по прерываниям + speaker_stop(); +} diff --git a/drivers/speaker.h b/drivers/speaker.h new file mode 100644 index 0000000..f42f0e3 --- /dev/null +++ b/drivers/speaker.h @@ -0,0 +1,15 @@ +#ifndef SPEAKER_H +#define SPEAKER_H + +#include + +// Включить звук заданной частоты (в Герцах) +void speaker_play(uint32_t frequency); + +// Выключить звук +void speaker_stop(void); + +// Издать короткий писк (бип) заданной частоты и длительности +void speaker_beep(uint32_t frequency, uint32_t duration); + +#endif diff --git a/drivers/timer.c b/drivers/timer.c index 85edf33..0b2680a 100644 --- a/drivers/timer.c +++ b/drivers/timer.c @@ -23,9 +23,4 @@ void timer_init(uint32_t frequency) { void timer_handler(void) { system_ticks++; - log_info(LOG_DETAIL, "Timer: tick!"); - // Каждые 100 тиков (1 раз в секунду) шлем инфу в логгер - if (system_ticks % 100 == 0) { - log_info(LOG_DETAIL, "Timer: one second passed"); - } } diff --git a/drivers/timer.h b/drivers/timer.h index 7300f53..ee61398 100644 --- a/drivers/timer.h +++ b/drivers/timer.h @@ -3,10 +3,10 @@ #include -// Инициализация таймера нужной частотой (например, 100 Гц) -void timer_init(uint32_t frequency); +// Делаем счетчик видимым для всего ядра +extern uint32_t system_ticks; -// Эта функция будет вызываться из нашего ассемблерного обработчика irq0 +void timer_init(uint32_t frequency); void timer_handler(void); #endif diff --git a/kernel/kmain.c b/kernel/kmain.c index 00b6725..2aebcfb 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,6 +1,7 @@ #include "../drivers/vga.h" #include "../drivers/serial.h" #include "../drivers/timer.h" +#include "../drivers/speaker.h" #include "gdt.h" #include "idt.h" #include "pic.h" @@ -27,5 +28,30 @@ void kernel_main(void) { timer_init(100); log_info(LOG_NORMAL, "Enabling IRQ..."); __asm__ __volatile__("sti"); + vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK); + vga_print("h"); + speaker_beep(100, 10); + vga_print("a"); + speaker_beep(125, 10); + vga_print("i"); + speaker_beep(150, 10); + vga_print("!"); + speaker_beep(175, 10); + vga_print("!"); + speaker_beep(200, 10); + vga_print("!"); + speaker_beep(225, 10); + vga_print("!"); + speaker_beep(250, 10); + vga_print("!"); + speaker_beep(275, 10); + vga_print("!"); + speaker_beep(300, 10); + vga_print("!"); + speaker_beep(325, 10); + vga_print("\n # ### #### \n #### ### # ## ### #### # # # \n # # ##### ## ##### # # # # ### \n # # # # # # # # # # \n #### ### # ### #### ### #### \n # \n"); + speaker_beep(350, 400); + vga_init(); + vga_set_color(VGA_COLOR_LIGHT_GRAY, VGA_COLOR_BLACK); while (1); }