Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ image: $(img)
qemu-opts = -name "MOROS $$MOROS_VERSION" \
-m $(memory) -smp $(smp) -drive file=$(img),format=raw \
-audiodev $(audio),id=a0 -machine pcspk-audiodev=a0 \
-audio driver=$(audio),model=sb16 \
-netdev user,id=e0,hostfwd=tcp::8080-:80 -device $(nic),netdev=e0
ifeq ($(kvm),true)
qemu-opts += -cpu host -accel kvm
Expand Down
1 change: 1 addition & 0 deletions src/api/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ fn device_type(name: &str) -> Result<DeviceType, ()> {
"net-ip" => Ok(DeviceType::NetIp),
"net-mac" => Ok(DeviceType::NetMac),
"net-usage" => Ok(DeviceType::NetUsage),
"snd-buffer" => Ok(DeviceType::SndBuffer),
"vga-buffer" => Ok(DeviceType::VgaBuffer),
"vga-font" => Ok(DeviceType::VgaFont),
"vga-mode" => Ok(DeviceType::VgaMode),
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub fn init(boot_info: &'static BootInfo) {
sys::acpi::init(); // Require MEM
sys::rng::init();
sys::pci::init(); // Require MEM
sys::snd::init();
sys::net::init(); // Require PCI
sys::ata::init();
sys::fs::init(); // Require ATA
Expand Down
12 changes: 11 additions & 1 deletion src/sys/fs/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::sys::net::socket::udp::UdpSocket;
use crate::sys::rng::Random;
use crate::sys::speaker::Speaker;
use crate::sys::vga::{VgaFont, VgaMode, VgaPalette, VgaBuffer};
use crate::sys::snd::SndBuffer;

use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -43,6 +44,7 @@ pub enum DeviceType {
NetIp = 16,
NetMac = 17,
NetUsage = 18,
SndBuffer = 19,
}

impl TryFrom<&[u8]> for DeviceType {
Expand All @@ -69,6 +71,7 @@ impl TryFrom<&[u8]> for DeviceType {
16 => Ok(DeviceType::NetIp),
17 => Ok(DeviceType::NetMac),
18 => Ok(DeviceType::NetUsage),
19 => Ok(DeviceType::SndBuffer),
_ => Err(()),
}
}
Expand All @@ -94,6 +97,7 @@ impl DeviceType {
DeviceType::NetIp => NetIp::size(),
DeviceType::NetMac => NetMac::size(),
DeviceType::NetUsage => NetUsage::size(),
DeviceType::SndBuffer => SndBuffer::size(),
_ => 1,
};
let mut res = vec![0; len];
Expand Down Expand Up @@ -123,6 +127,7 @@ pub enum Device {
NetIp(NetIp),
NetMac(NetMac),
NetUsage(NetUsage),
SndBuffer(SndBuffer),
}

impl TryFrom<&[u8]> for Device {
Expand All @@ -148,6 +153,7 @@ impl TryFrom<&[u8]> for Device {
DeviceType::NetIp => Ok(Device::NetIp(NetIp::new())),
DeviceType::NetMac => Ok(Device::NetMac(NetMac::new())),
DeviceType::NetUsage => Ok(Device::NetUsage(NetUsage::new())),
DeviceType::SndBuffer => Ok(Device::SndBuffer(SndBuffer::new())),
DeviceType::Drive if buf.len() > 2 => {
let bus = buf[1];
let dsk = buf[2];
Expand Down Expand Up @@ -197,7 +203,7 @@ impl Device {
impl FileIO for Device {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
match self {
Device::Null => Err(()),
Device::Null => Ok(0),
Device::File(io) => io.read(buf),
Device::Console(io) => io.read(buf),
Device::Random(io) => io.read(buf),
Expand All @@ -216,6 +222,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.read(buf),
Device::NetMac(io) => io.read(buf),
Device::NetUsage(io) => io.read(buf),
Device::SndBuffer(io) => io.read(buf),
}
}

Expand All @@ -240,6 +247,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.write(buf),
Device::NetMac(io) => io.write(buf),
Device::NetUsage(io) => io.write(buf),
Device::SndBuffer(io) => io.write(buf),
}
}

Expand All @@ -264,6 +272,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.close(),
Device::NetMac(io) => io.close(),
Device::NetUsage(io) => io.close(),
Device::SndBuffer(io) => io.close(),
}
}

Expand All @@ -288,6 +297,7 @@ impl FileIO for Device {
Device::NetIp(io) => io.poll(event),
Device::NetMac(io) => io.poll(event),
Device::NetUsage(io) => io.poll(event),
Device::SndBuffer(io) => io.poll(event),
}
}
}
4 changes: 4 additions & 0 deletions src/sys/mem/phys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ impl PhysBuf {
pub fn addr(&self) -> u64 {
phys_addr(&self.buf.lock()[0])
}

pub fn size(&self) -> usize {
self.buf.lock().len()
}
}

impl<I: SliceIndex<[u8]>> Index<I> for PhysBuf {
Expand Down
1 change: 1 addition & 0 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub mod pic;
pub mod process;
pub mod rng;
pub mod serial;
pub mod snd;
pub mod speaker;
pub mod syscall;
pub mod vga;
44 changes: 44 additions & 0 deletions src/sys/snd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
mod sb16;

use crate::api::fs::{FileIO, IO};

#[derive(Debug, Clone)]
pub struct SndBuffer;

impl SndBuffer {
pub fn new() -> Self {
Self {}
}

pub fn size() -> usize {
sb16::BUF_LEN
}
}

impl FileIO for SndBuffer {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize, ()> {
Err(())
}

fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
if buf.is_empty() {
sb16::stop();
} else {
sb16::play(buf);
}
Ok(buf.len())
}

fn close(&mut self) {}

fn poll(&mut self, event: IO) -> bool {
match event {
IO::Read => false,
IO::Write => true,
}
}
}

pub fn init() {
sb16::init();
}
158 changes: 158 additions & 0 deletions src/sys/snd/sb16.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use crate::sys;
use crate::sys::mem::PhysBuf;

use alloc::vec::Vec;
use spin::Mutex;
use x86_64::instructions::port::Port;

// Sources:
// https://wiki.osdev.org/Sound_Blaster_16
// https://pdos.csail.mit.edu/6.828/2006/readings/hardware/SoundBlaster.pdf

const MIXER_ADDR: u16 = 0x224;
const MIXER_DATA: u16 = 0x225;
const DSP_RESET: u16 = 0x226;
const DSP_READ: u16 = 0x22A;
const DSP_WRITE: u16 = 0x22C;
const DSP_ACK: u16 = 0x22E;

const IRQ: u8 = 5;

pub const BUF_LEN: usize = 32 << 10;

pub static SND: Mutex<Option<(PhysBuf, Vec<Vec<u8>>)>> = Mutex::new(None);

fn irq(num: u8) -> u8 {
match num {
2 => 0x01,
5 => 0x02,
7 => 0x04,
10 => 0x08,
_ => panic!(),
}
}

fn outb(addr: u16, value: u8) {
let mut port: Port<u8> = Port::new(addr);
unsafe {
port.write(value);
}
}

fn inb(addr: u16) -> u8 {
let mut port: Port<u8> = Port::new(addr);
unsafe {
port.read()
}
}

fn reset() {
outb(DSP_RESET, 1);
sys::clk::wait(3000);
outb(DSP_RESET, 0);
loop {
let res = inb(DSP_READ);
if res == 0xAA {
break;
}
}
}

fn version() -> u8 {
outb(DSP_WRITE, 0xE1);
inb(DSP_WRITE)
}

fn dma(addr: u64, size: usize) {
let addr = addr.to_le_bytes();
let size = size.to_le_bytes();
let chan = 1;
outb(0x0A, 0x04 + chan); // Disable channel
outb(0x0C, 0x01); // Flip flop
outb(0x0B, 0x58 + chan); // Send transfer mode
outb(0x83, addr[2]); // Send page number
outb(0x02, addr[0]); // Send low bits of addr
outb(0x02, addr[1]); // Send high bits of addr
outb(0x03, size[0]); // Send low bits of size
outb(0x03, size[1]); // Send high bits of size
outb(0x0A, chan); // Enable channel
}

pub fn stop() {
if let Some((ref mut buf, ref mut queue)) = *SND.lock() {
outb(MIXER_ADDR, 0xD0);
let chan = 1;
outb(0x0A, 0x04 + chan); // Disable channel
buf.fill(0x80);
queue.clear();
}
}

pub fn play(pcm: &[u8]) {
if let Some((ref mut buf, ref mut queue)) = *SND.lock() {
queue.clear();
for chunk in pcm.chunks(buf.len()) {
queue.push(chunk.to_vec());
}
let pcm = queue.remove(0);
let len = core::cmp::min(buf.len(), pcm.len());
buf[0..len].copy_from_slice(&pcm[0..len]);
buf[len..].fill(0x80);

// Set sample rate
let rate: u16 = 22050;
let rate = rate.to_le_bytes();
outb(DSP_WRITE, 0x41); // Sample rate
outb(DSP_WRITE, rate[1]);
outb(DSP_WRITE, rate[0]);

outb(DSP_WRITE, 0xC6); // 8 bit sound played continuously
outb(DSP_WRITE, 0x00); // Mono and unsigned sound data

// Set DMA
dma(buf.addr(), buf.size() - 1);
let bytes = (buf.size() - 1).to_le_bytes();
outb(DSP_WRITE, bytes[0]);
outb(DSP_WRITE, bytes[1]);
}
}

pub fn init() {
if version() != 0xFF {
reset();

// Set IRQ
sys::idt::set_irq_handler(IRQ, interrupt_handler);
outb(MIXER_ADDR, 0x80);
outb(MIXER_DATA, irq(IRQ));

let buf = PhysBuf::new(BUF_LEN);
let queue = Vec::new();
*SND.lock() = Some((buf, queue));
log!("SND DRV SB16");

/*
// Play a square wave
let mut pcm = [0; BUF_LEN];
for i in 0..pcm.len() {
pcm[i] = if (i / 64) % 2 == 0 { 0x00 } else { 0xFF };
}
play(&pcm);
*/
}
}

fn interrupt_handler() {
if let Some((ref mut buf, ref mut queue)) = *SND.lock() {
if queue.is_empty() {
let chan = 1;
outb(0x0A, 0x04 + chan); // Disable channel
} else {
let pcm = queue.remove(0);
let len = core::cmp::min(buf.len(), pcm.len());
buf[0..len].copy_from_slice(&pcm[0..len]);
buf[len..].fill(0x80);
}
}
let _ = inb(DSP_ACK);
}
2 changes: 2 additions & 0 deletions src/usr/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub fn copy_files(verbose: bool) {
create_dir("/dev/ata/1", verbose);
create_dir("/dev/clk", verbose); // Clock
create_dir("/dev/net", verbose); // Network
create_dir("/dev/snd", verbose); // Sound
create_dir("/dev/vga", verbose);

create_dev("/dev/ata/0/0", "ata-0-0", verbose);
Expand All @@ -67,6 +68,7 @@ pub fn copy_files(verbose: bool) {
create_dev("/dev/net/usage", "net-usage", verbose);
create_dev("/dev/null", "null", verbose);
create_dev("/dev/random", "random", verbose);
create_dev("/dev/snd/buf", "snd-buffer", verbose);
create_dev("/dev/speaker", "speaker", verbose);
create_dev("/dev/vga/buffer", "vga-buffer", verbose);
create_dev("/dev/vga/font", "vga-font", verbose);
Expand Down
4 changes: 4 additions & 0 deletions src/usr/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
return Ok(());
}
if let Ok(bytes) = fs::read_to_bytes(path) {
if bytes.is_empty() {
print!("");
return Ok(());
}
if is_char_device && bytes.len() == 1 {
match bytes[0] as char {
api::console::ETX_KEY => {
Expand Down
Loading