Kernel: Make serial devices to their own class
This commit is contained in:
		
							parent
							
								
									2e2a913412
								
							
						
					
					
						commit
						9b47603a1d
					
				|  | @ -1,11 +1,28 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace Serial | ||||
| #include <BAN/Errors.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	void initialize(); | ||||
| 	bool is_initialized(); | ||||
| 	class Serial | ||||
| 	{ | ||||
| 	public: | ||||
| 		static void initialize(); | ||||
| 		static bool has_devices(); | ||||
| 		static void putchar_any(char); | ||||
| 
 | ||||
| 	void putchar(char); | ||||
| 		void putchar(char); | ||||
| 
 | ||||
| 	private: | ||||
| 		static bool port_has_device(uint16_t); | ||||
| 
 | ||||
| 		bool is_transmit_empty() const; | ||||
| 
 | ||||
| 		bool is_valid() const { return m_port != 0; } | ||||
| 
 | ||||
| 	private: | ||||
| 		uint16_t m_port { 0 }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -60,8 +60,8 @@ namespace Debug | |||
| 
 | ||||
| 	void putchar(char ch) | ||||
| 	{ | ||||
| 		if (Serial::is_initialized()) | ||||
| 			return Serial::putchar(ch); | ||||
| 		if (Kernel::Serial::has_devices()) | ||||
| 			return Kernel::Serial::putchar_any(ch); | ||||
| 		if (Kernel::TTY::is_initialized()) | ||||
| 			return Kernel::TTY::putchar_current(ch); | ||||
| 	} | ||||
|  |  | |||
|  | @ -1,49 +1,76 @@ | |||
| #include <BAN/Errors.h> | ||||
| #include <BAN/Array.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/Serial.h> | ||||
| 
 | ||||
| #define COM1_PORT 0x3f8 | ||||
| 
 | ||||
| namespace Serial | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	static bool s_initialized = false; | ||||
| 	static constexpr uint16_t s_serial_ports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8 }; | ||||
| 	static BAN::Array<Serial, sizeof(s_serial_ports) / sizeof(*s_serial_ports)> s_serial_devices; | ||||
| 	static bool s_has_devices { false }; | ||||
| 
 | ||||
| 	void initialize() | ||||
| 	void Serial::initialize() | ||||
| 	{ | ||||
| 		IO::outb(COM1_PORT + 1, 0x00);    // Disable all interrupts
 | ||||
| 		IO::outb(COM1_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
 | ||||
| 		IO::outb(COM1_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
 | ||||
| 		IO::outb(COM1_PORT + 1, 0x00);    //                  (hi byte)
 | ||||
| 		IO::outb(COM1_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
 | ||||
| 		IO::outb(COM1_PORT + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
 | ||||
| 		IO::outb(COM1_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
 | ||||
| 		IO::outb(COM1_PORT + 4, 0x1E);    // Set in loopback mode, test the serial chip
 | ||||
| 		IO::outb(COM1_PORT + 0, 0xAE);    // Test serial chip (send byte 0xAE and check if serial returns same byte)
 | ||||
| 		int count = 0; | ||||
| 		for (size_t i = 0; i < s_serial_devices.size(); i++) | ||||
| 		{ | ||||
| 			if (port_has_device(s_serial_ports[i])) | ||||
| 			{ | ||||
| 				s_serial_devices[i].m_port = s_serial_ports[i]; | ||||
| 				count++; | ||||
| 			} | ||||
| 		} | ||||
| 		s_has_devices = !!count; | ||||
| 		dprintln("Initialized {} serial devices", count); | ||||
| 	} | ||||
| 
 | ||||
| 	bool Serial::port_has_device(uint16_t port) | ||||
| 	{ | ||||
| 		IO::outb(port + 1, 0x00);	// Disable all interrupts
 | ||||
| 		IO::outb(port + 3, 0x80);	// Enable DLAB (set baud rate divisor)
 | ||||
| 		IO::outb(port + 0, 0x03);	// Set divisor to 3 (lo byte) 38400 baud
 | ||||
| 		IO::outb(port + 1, 0x00);	//                  (hi byte)
 | ||||
| 		IO::outb(port + 3, 0x03);	// 8 bits, no parity, one stop bit
 | ||||
| 		IO::outb(port + 2, 0xC7);	// Enable FIFO, clear them, with 14-byte threshold
 | ||||
| 		IO::outb(port + 4, 0x0B);	// IRQs enabled, RTS/DSR set
 | ||||
| 		IO::outb(port + 4, 0x1E);	// Set in loopback mode, test the serial chip
 | ||||
| 		IO::outb(port + 0, 0xAE);	// Test serial chip (send byte 0xAE and check if serial returns same byte)
 | ||||
| 
 | ||||
| 		// Check if serial is faulty (i.e: not same byte as sent)
 | ||||
| 		if(IO::inb(COM1_PORT + 0) != 0xAE) | ||||
| 			return; | ||||
| 			return false; | ||||
| 
 | ||||
| 		// If serial is not faulty set it in normal operation mode
 | ||||
| 		// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
 | ||||
| 		IO::outb(COM1_PORT + 4, 0x0F); | ||||
| 		s_initialized = true; | ||||
| 		IO::outb(port + 4, 0x0F); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	bool is_initialized() | ||||
| 	bool Serial::has_devices() | ||||
| 	{ | ||||
| 		return s_initialized; | ||||
| 		return s_has_devices; | ||||
| 	} | ||||
| 
 | ||||
| 	static int is_transmit_empty() { | ||||
| 		return IO::inb(COM1_PORT + 5) & 0x20; | ||||
| 	bool Serial::is_transmit_empty() const | ||||
| 	{ | ||||
| 		return !(IO::inb(m_port + 5) & 0x20); | ||||
| 	} | ||||
|   | ||||
| 	void putchar(char c) | ||||
| 	void Serial::putchar(char c) | ||||
| 	{ | ||||
| 		ASSERT(s_initialized); | ||||
| 		while (is_transmit_empty() == 0); | ||||
| 		IO::outb(COM1_PORT, c); | ||||
| 		while (is_transmit_empty()) | ||||
| 			continue; | ||||
| 		IO::outb(m_port, c); | ||||
| 	} | ||||
| 
 | ||||
| 	void Serial::putchar_any(char c) | ||||
| 	{ | ||||
| 		for (auto& device : s_serial_devices) | ||||
| 			if (device.is_valid()) | ||||
| 				device.putchar(c); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue