diff --git a/Makefile b/Makefile index 320af626c..c917f3a27 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ image: $(img) cargo bootimage --no-default-features --features $(output),$(nic) --release dd conv=notrunc if=$(bin) of=$(img) -opts = -m 32 -cpu max -nic model=$(nic) -hda $(img) +opts = -m 32 -cpu max -nic model=$(nic) -hda $(img) -soundhw pcspk ifeq ($(output),serial) opts += -display none -serial stdio endif diff --git a/dsk/tmp/beep/mario.sh b/dsk/tmp/beep/mario.sh new file mode 100644 index 000000000..186542659 --- /dev/null +++ b/dsk/tmp/beep/mario.sh @@ -0,0 +1,28 @@ +# Source: http://blog.dhampir.no/content/fun-with-beep +beep -f 130 -l 100 +beep -f 262 -l 100 +beep -f 330 -l 100 +beep -f 392 -l 100 +beep -f 523 -l 100 +beep -f 660 -l 100 +beep -f 784 -l 300 +beep -f 660 -l 300 +beep -f 146 -l 100 +beep -f 262 -l 100 +beep -f 311 -l 100 +beep -f 415 -l 100 +beep -f 523 -l 100 +beep -f 622 -l 100 +beep -f 831 -l 300 +beep -f 622 -l 300 +beep -f 155 -l 100 +beep -f 294 -l 100 +beep -f 349 -l 100 +beep -f 466 -l 100 +beep -f 588 -l 100 +beep -f 699 -l 100 +beep -f 933 -l 300 +beep -f 933 -l 100 +beep -f 933 -l 100 +beep -f 933 -l 100 +beep -f 1047 -l 400 diff --git a/dsk/tmp/beep/starwars.sh b/dsk/tmp/beep/starwars.sh new file mode 100644 index 000000000..019653e99 --- /dev/null +++ b/dsk/tmp/beep/starwars.sh @@ -0,0 +1,132 @@ +# Source: http://kirrus.co.uk/2010/09/linux-beep-music +beep -l 350 -f 392 +sleep 0.100 +beep -l 350 -f 392 +sleep 0.100 +beep -l 350 -f 392 +sleep 0.100 +beep -l 250 -f 311.1 +sleep 0.100 +beep -l 25 -f 466.2 +sleep 0.100 +beep -l 350 -f 392 +sleep 0.100 +beep -l 250 -f 311.1 +sleep 0.100 +beep -l 25 -f 466.2 +sleep 0.100 +beep -l 700 -f 392 +sleep 0.100 +beep -l 350 -f 587.32 +sleep 0.100 +beep -l 350 -f 587.32 +sleep 0.100 +beep -l 350 -f 587.32 +sleep 0.100 +beep -l 250 -f 622.26 +sleep 0.100 +beep -l 25 -f 466.2 +sleep 0.100 +beep -l 350 -f 369.99 +sleep 0.100 +beep -l 250 -f 311.1 +sleep 0.100 +beep -l 25 -f 466.2 +sleep 0.100 +beep -l 700 -f 392 +sleep 0.100 +beep -l 350 -f 784 +sleep 0.100 +beep -l 250 -f 392 +sleep 0.100 +beep -l 25 -f 392 +sleep 0.100 +beep -l 350 -f 784 +sleep 0.100 +beep -l 250 -f 739.98 +sleep 0.100 +beep -l 25 -f 698.46 +sleep 0.100 +beep -l 25 -f 659.26 +sleep 0.100 +beep -l 25 -f 622.26 +sleep 0.100 +beep -l 50 -f 659.26 +sleep 0.400 +beep -l 25 -f 415.3 +sleep 0.200 +beep -l 350 -f 554.36 +sleep 0.100 +beep -l 250 -f 523.25 +sleep 0.100 +beep -l 25 -f 493.88 +sleep 0.100 +beep -l 25 -f 466.16 +sleep 0.100 +beep -l 25 -f 440 +sleep 0.100 +beep -l 50 -f 466.16 +sleep 0.400 +beep -l 25 -f 311.13 +sleep 0.200 +beep -l 350 -f 369.99 +sleep 0.100 +beep -l 250 -f 311.13 +sleep 0.100 +beep -l 25 -f 392 +sleep 0.100 +beep -l 350 -f 466.16 +sleep 0.100 +beep -l 250 -f 392 +sleep 0.100 +beep -l 25 -f 466.16 +sleep 0.100 +beep -l 700 -f 587.32 +sleep 0.100 +beep -l 350 -f 784 +sleep 0.100 +beep -l 250 -f 392 +sleep 0.100 +beep -l 25 -f 392 +sleep 0.100 +beep -l 350 -f 784 +sleep 0.100 +beep -l 250 -f 739.98 +sleep 0.100 +beep -l 25 -f 698.46 +sleep 0.100 +beep -l 25 -f 659.26 +sleep 0.100 +beep -l 25 -f 622.26 +sleep 0.100 +beep -l 50 -f 659.26 +sleep 0.400 +beep -l 25 -f 415.3 +sleep 0.200 +beep -l 350 -f 554.36 +sleep 0.100 +beep -l 250 -f 523.25 +sleep 0.100 +beep -l 25 -f 493.88 +sleep 0.100 +beep -l 25 -f 466.16 +sleep 0.100 +beep -l 25 -f 440 +sleep 0.100 +beep -l 50 -f 466.16 +sleep 0.400 +beep -l 25 -f 311.13 +sleep 0.200 +beep -l 350 -f 392 +sleep 0.100 +beep -l 250 -f 311.13 +sleep 0.100 +beep -l 25 -f 466.16 +sleep 0.100 +beep -l 300 -f 392.00 +sleep 0.150 +beep -l 250 -f 311.13 +sleep 0.100 +beep -l 25 -f 466.16 +sleep 0.100 +beep -l 700 -f 392 diff --git a/dsk/tmp/beep/tetris.sh b/dsk/tmp/beep/tetris.sh new file mode 100644 index 000000000..924451912 --- /dev/null +++ b/dsk/tmp/beep/tetris.sh @@ -0,0 +1,91 @@ +# Source: http://kirrus.co.uk/2010/09/linux-beep-music +beep -f 330 -l 150 +beep -f 1 -l 40 +beep -f 494 -l 159 +beep -f 1 -l 40 +beep -f 660 -l 150 +beep -f 1 -l 40 +beep -f 590 -l 150 +beep -f 660 -l 150 +beep -f 494 -l 100 +beep -f 494 -l 100 +beep -f 523 -l 150 +beep -f 1 -l 40 +beep -f 440 -l 150 +beep -f 1 -l 40 +beep -f 494 -l 150 +beep -f 1 -l 40 +beep -f 392 -l 100 +beep -f 392 -l 100 +beep -f 440 -l 150 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 392 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 100 +beep -f 330 -l 100 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 294 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 247 -l 100 +beep -f 247 -l 100 +beep -f 261 -l 150 +beep -f 1 -l 40 +beep -f 311 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 1 -l 40 +beep -f 247 -l 100 +beep -f 247 -l 100 +beep -f 262 -l 150 +beep -f 1 -l 40 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 1 -l 40 +beep -f 494 -l 159 +beep -f 1 -l 40 +beep -f 660 -l 150 +beep -f 1 -l 40 +beep -f 590 -l 150 +beep -f 660 -l 150 +beep -f 494 -l 100 +beep -f 494 -l 100 +beep -f 523 -l 150 +beep -f 1 -l 40 +beep -f 440 -l 150 +beep -f 1 -l 40 +beep -f 494 -l 150 +beep -f 1 -l 40 +beep -f 392 -l 100 +beep -f 392 -l 100 +beep -f 440 -l 150 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 392 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 100 +beep -f 330 -l 100 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 294 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 247 -l 100 +beep -f 247 -l 100 +beep -f 261 -l 150 +beep -f 1 -l 40 +beep -f 311 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 1 -l 40 +beep -f 247 -l 100 +beep -f 247 -l 100 +beep -f 262 -l 150 +beep -f 1 -l 40 +beep -f 370 -l 150 +beep -f 1 -l 40 +beep -f 330 -l 150 +beep -f 1 -l 40 diff --git a/run/bochs.rc b/run/bochs.rc index c4105df28..34ae004f5 100644 --- a/run/bochs.rc +++ b/run/bochs.rc @@ -1,4 +1,4 @@ -megs: 16 +megs: 32 ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="../disk.img", mode=flat, cylinders=0, heads=0, spt=0 boot: disk diff --git a/src/sys/time.rs b/src/sys/time.rs index 5b14ed22c..66b6df194 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -9,7 +9,7 @@ use x86_64::instructions::port::Port; // which will result in about 54.926 ms between ticks. // During init we will change the divider to 1193 to have about 1.000 ms // between ticks to improve time measurements accuracy. -const PIT_FREQUENCY: f64 = 3_579_545.0 / 3.0; // 1_193_181.666 Hz +pub const PIT_FREQUENCY: f64 = 3_579_545.0 / 3.0; // 1_193_181.666 Hz const PIT_DIVIDER: usize = 1193; const PIT_INTERVAL: f64 = (PIT_DIVIDER as f64) / PIT_FREQUENCY; @@ -56,13 +56,15 @@ pub fn nanowait(nanoseconds: u64) { } /// The frequency divider must be between 0 and 65535, with 0 acting as 65536 -fn set_pit_frequency_divider(divider: u16) { +pub fn set_pit_frequency_divider(divider: u16, channel: u8) { interrupts::without_interrupts(|| { let bytes = divider.to_le_bytes(); let mut cmd: Port = Port::new(0x43); - let mut data: Port = Port::new(0x40); + let mut data: Port = Port::new(0x40 + channel as u16); + let operating_mode = 6; // Square wave generator + let access_mode = 3; // Lobyte + Hibyte unsafe { - cmd.write(0x36); + cmd.write((channel << 6) | (access_mode << 4) | operating_mode); data.write(bytes[0]); data.write(bytes[1]); } @@ -81,7 +83,8 @@ pub fn rtc_interrupt_handler() { pub fn init() { // PIT timmer let divider = if PIT_DIVIDER < 65536 { PIT_DIVIDER } else { 0 }; - set_pit_frequency_divider(divider as u16); + let channel = 0; + set_pit_frequency_divider(divider as u16, channel); sys::idt::set_irq_handler(0, pit_interrupt_handler); // RTC timmer diff --git a/src/usr/beep.rs b/src/usr/beep.rs new file mode 100644 index 000000000..65a3e1a7e --- /dev/null +++ b/src/usr/beep.rs @@ -0,0 +1,75 @@ +use crate::{api, sys, usr}; + +use x86_64::instructions::port::Port; + +// See: https://wiki.osdev.org/PC_Speaker + +const SPEAKER_PORT: u16 = 0x61; + +fn start_sound(freq: f64) { + let divider = (sys::time::PIT_FREQUENCY / freq) as u16; + let channel = 2; + sys::time::set_pit_frequency_divider(divider, channel); + + let mut speaker: Port = Port::new(SPEAKER_PORT); + let tmp = unsafe { speaker.read() }; + if tmp != (tmp | 3) { + unsafe { speaker.write(tmp | 3) }; + } +} + +fn stop_sound() { + let mut speaker: Port = Port::new(SPEAKER_PORT); + let tmp = unsafe { speaker.read() } & 0xFC; + unsafe { speaker.write(tmp) }; +} + +fn beep(freq: f64, len: f64) { + start_sound(freq); + api::syscall::sleep(len); + stop_sound(); +} + +pub fn main(args: &[&str]) -> usr::shell::ExitCode { + let mut freq = 440.0; + let mut len = 200.0; + let mut i = 1; + let n = args.len(); + while i < n { + match args[i] { + "--freq" | "-f" => { + if i + 1 < n { + if let Ok(value) = args[i + 1].parse() { + freq = value; + } else { + println!("Could not parse freq"); + return usr::shell::ExitCode::CommandError; + } + i += 1; + } else { + println!("Missing freq"); + return usr::shell::ExitCode::CommandError; + } + }, + "--len" | "-l" => { + if i + 1 < n { + if let Ok(value) = args[i + 1].parse() { + len = value; + } else { + println!("Could not parse len"); + return usr::shell::ExitCode::CommandError; + } + i += 1; + } else { + println!("Missing len"); + return usr::shell::ExitCode::CommandError; + } + }, + _ => {}, + } + i += 1; + } + + beep(freq, len / 1000.0); + usr::shell::ExitCode::CommandSuccessful +} diff --git a/src/usr/install.rs b/src/usr/install.rs index a67fc4f32..9a6ef8580 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -42,14 +42,20 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt")); copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt")); copy_file("/ini/palette.csv", include_bytes!("../../dsk/ini/palette.csv")); - copy_file("/tmp/alice.txt", include_bytes!("../../dsk/tmp/alice.txt")); - copy_file("/tmp/fibonacci.lisp", include_bytes!("../../dsk/tmp/fibonacci.lisp")); create_dir("/ini/fonts"); copy_file("/ini/fonts/lat15-terminus-8x16.psf", include_bytes!("../../dsk/ini/fonts/lat15-terminus-8x16.psf")); copy_file("/ini/fonts/zap-light-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-light-8x16.psf")); copy_file("/ini/fonts/zap-vga-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-vga-8x16.psf")); + copy_file("/tmp/alice.txt", include_bytes!("../../dsk/tmp/alice.txt")); + copy_file("/tmp/fibonacci.lisp", include_bytes!("../../dsk/tmp/fibonacci.lisp")); + + create_dir("/tmp/beep"); + copy_file("/tmp/beep/tetris.sh", include_bytes!("../../dsk/tmp/beep/tetris.sh")); + copy_file("/tmp/beep/starwars.sh", include_bytes!("../../dsk/tmp/beep/starwars.sh")); + copy_file("/tmp/beep/mario.sh", include_bytes!("../../dsk/tmp/beep/mario.sh")); + if sys::process::user().is_none() { println!(); println!("{}Creating user...{}", csi_color, csi_reset); diff --git a/src/usr/mod.rs b/src/usr/mod.rs index d8dfc74a5..f80fd5e3c 100644 --- a/src/usr/mod.rs +++ b/src/usr/mod.rs @@ -1,4 +1,5 @@ pub mod base64; +pub mod beep; pub mod clear; pub mod colors; pub mod copy; diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 4bdeb46e5..bab867866 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -154,7 +154,7 @@ pub fn exec(cmd: &str) -> ExitCode { "y" => ExitCode::CommandUnknown, "z" => ExitCode::CommandUnknown, "vga" => usr::vga::main(&args), - "shell" => usr::shell::main(&args), + "sh" | "shell" => usr::shell::main(&args), "sleep" => usr::sleep::main(&args), "clear" => usr::clear::main(&args), "base64" => usr::base64::main(&args), @@ -179,6 +179,7 @@ pub fn exec(cmd: &str) -> ExitCode { "kb" | "keyboard" => usr::keyboard::main(&args), "lisp" => usr::lisp::main(&args), "chess" => usr::chess::main(&args), + "beep" => usr::beep::main(&args), _ => ExitCode::CommandUnknown, } }