⎇ 922ad1f86bbef5d4f8c5f59827e5fd6a9b17c1af
renaser/kernel/src/drivers/altavoz.rs
History
Who touched what
raw
feat(renaser): Fase 12 — la bocina del PC como capacidad de host
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}