gioser

tawasuyu/brahman

Rust 483TOML 191Markdown 50JSON 176777 Sutichaykuna

⎇ 8fc1d99ddff618eaa0c2c29f4a51eaaed73443dd renaser/kernel/src/drivers/altavoz.rs Rust · 73 siq'ikuna · 3.2 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat(renaser): Fase 12 — la bocina del PC como capacidad de host 922ad1f86 · sergio ·

1// =============================================================================
2//  renaser :: kernel/src/drivers/altavoz.rs — Fase 12 :: la bocina del PC
3// -----------------------------------------------------------------------------
4//  La bocina del PC es el instrumento mas humilde del hardware: un solo bit que,
5//  conmutado a la frecuencia justa, hace vibrar una membrana. No hay PCM, ni
6//  DMA, ni mezclador — solo el canal 2 del PIT generando una onda cuadrada y
7//  una compuerta en el puerto 0x61 que la deja pasar al altavoz, o no.
8//
9//  El canal 0 del PIT es el latido del kernel (ver `pic`); el canal 2 es de la
10//  bocina y de nadie mas — programarlo aqui no perturba el temporizador—. Esta
11//  es la unica via del kernel hacia el sonido; la capacidad `sys_tono` la
12//  ofrece al userspace, gobernada por el foco del compositor.
13// =============================================================================
14
15use x86_64::instructions::port::Port;
16
17/// Frecuencia del cristal del PIT, en Hz — el divisor se calcula contra ella.
18const PIT_BASE_HZ: u32 = 1_193_182;
19
20/// Puerto de comando del PIT.
21const PIT_COMANDO: u16 = 0x43;
22/// Puerto de datos del canal 2 del PIT — el de la bocina.
23const PIT_CANAL2: u16 = 0x42;
24/// Puerto de control de la bocina (bits 0 y 1: compuerta del PIT y dato).
25const CONTROL_BOCINA: u16 = 0x61;
26
27/// Pone la bocina a sonar a `frecuencia_hz`. Un `0` —o una frecuencia que un
28/// divisor de 16 bits no pueda representar (por debajo de ~19 Hz)— la SILENCIA.
29/// Es la unica via del kernel hacia el sonido.
30pub fn tono(frecuencia_hz: u32) {
31    if frecuencia_hz == 0 || PIT_BASE_HZ / frecuencia_hz > 0xFFFF {
32        silenciar();
33        return;
34    }
35    // El divisor cabe en 16 bits; un `.max(1)` lo protege de una frecuencia
36    // disparatadamente alta que lo dejara en cero.
37    let divisor = (PIT_BASE_HZ / frecuencia_hz).max(1) as u16;
38
39    // SEGURIDAD: 0x43 y 0x42 son los puertos del PIT en la arquitectura PC;
40    // 0xB6 selecciona el canal 2, acceso lobyte+hibyte, modo 3 (onda cuadrada).
41    // El canal 2 es exclusivo de la bocina: no perturba el latido del kernel.
42    unsafe {
43        let mut comando = Port::<u8>::new(PIT_COMANDO);
44        let mut canal2 = Port::<u8>::new(PIT_CANAL2);
45        comando.write(0xB6u8);
46        canal2.write((divisor & 0xFF) as u8);
47        canal2.write((divisor >> 8) as u8);
48    }
49    abrir_compuerta();
50}
51
52/// Abre la compuerta del puerto 0x61: deja pasar la onda del canal 2 al altavoz.
53fn abrir_compuerta() {
54    // SEGURIDAD: 0x61 es el puerto de control de la bocina; sus bits 0 y 1
55    // —compuerta del PIT y dato del altavoz— se tocan con leer-modificar-
56    // escribir para no perturbar los demas bits del chipset.
57    unsafe {
58        let mut control = Port::<u8>::new(CONTROL_BOCINA);
59        let estado = control.read();
60        control.write(estado | 0b11);
61    }
62}
63
64/// Silencia la bocina: cierra la compuerta del puerto 0x61. La onda del canal 2
65/// sigue generandose, pero ya no alcanza la membrana.
66fn silenciar() {
67    // SEGURIDAD: ver `abrir_compuerta`. Limpiar los bits 0 y 1 corta el sonido.
68    unsafe {
69        let mut control = Port::<u8>::new(CONTROL_BOCINA);
70        let estado = control.read();
71        control.write(estado & !0b11);
72    }
73}