Mon 9 Dec 20:40:44 CET 2024
This commit is contained in:
		
							parent
							
								
									6460cc87d0
								
							
						
					
					
						commit
						64731d077e
					
				|  | @ -4,13 +4,16 @@ This software is distributed under the GNU General Public License. | ||||||
| See the file LICENSE for details. | See the file LICENSE for details. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| // Derived from: https://wiki.osdev.org/Serial_Ports#Example_Code
 | /* Derived from: https://wiki.osdev.org/Serial_Ports#Example_Code
 | ||||||
| // For more info:
 |   For more info: | ||||||
| //     https://wiki.osdev.org/Serial_Ports
 |      https://wiki.osdev.org/Serial_Ports
 | ||||||
| //     http://www.webcitation.org/5ugQv5JOw
 |      http://www.webcitation.org/5ugQv5JOw
 | ||||||
|  |   TODO: Interrupt support; polling IO is not a good idea for carbon free air | ||||||
|  | */ | ||||||
| 
 | 
 | ||||||
| #include "kernel/types.h" | #include "kernel/types.h" | ||||||
| #include "ioports.h" | #include "ioports.h" | ||||||
|  | #include "interrupt.h" | ||||||
| #include "string.h" | #include "string.h" | ||||||
| #include "device.h" | #include "device.h" | ||||||
| 
 | 
 | ||||||
|  | @ -33,11 +36,13 @@ See the file LICENSE for details. | ||||||
| 
 | 
 | ||||||
| #define SERIAL_FCR 2 | #define SERIAL_FCR 2 | ||||||
| #define SERIAL_FIFO_ENABLE (0x01 << 0) | #define SERIAL_FIFO_ENABLE (0x01 << 0) | ||||||
| #define SERIAL_FIFO_CLEAR_RECIEVER (0x01 << 1) | #define SERIAL_FIFO_CLEAR_RECEIVER (0x01 << 1) | ||||||
| #define SERIAL_FIFO_CLEAR_TRANSMITTER (0x01 << 2) | #define SERIAL_FIFO_CLEAR_TRANSMITTER (0x01 << 2) | ||||||
| #define SERIAL_FIFO_DMA_MODE (0x01 << 3) | #define SERIAL_FIFO_DMA_MODE (0x01 << 3) | ||||||
| #define SERIAL_TRIGGER_LEVEL0 (0x01 << 6) | #define SERIAL_TRIGGER_LEVEL0 (0x00 << 6)  // 1 byte in FIFO
 | ||||||
| #define SERIAL_TRIGGER_LEVEL1 (0x01 << 7) | #define SERIAL_TRIGGER_LEVEL1 (0x01 << 6)  // 4 bytes
 | ||||||
|  | #define SERIAL_TRIGGER_LEVEL2 (0x10 << 6)  // 8 bytes
 | ||||||
|  | #define SERIAL_TRIGGER_LEVEL3 (0x11 << 6)  // 14 bytes
 | ||||||
| 
 | 
 | ||||||
| #define SERIAL_LCR 3 | #define SERIAL_LCR 3 | ||||||
| #define SERIAL_CHARLEN_START (0x01 << 0) | #define SERIAL_CHARLEN_START (0x01 << 0) | ||||||
|  | @ -58,11 +63,21 @@ See the file LICENSE for details. | ||||||
| 
 | 
 | ||||||
| #define SERIAL_SCRATCH 7 | #define SERIAL_SCRATCH 7 | ||||||
| 
 | 
 | ||||||
|  | // units 0,1,2,3
 | ||||||
| static const int serial_ports[4] = { COM1, COM2, COM3, COM4 }; | static const int serial_ports[4] = { COM1, COM2, COM3, COM4 }; | ||||||
|  | static const int serial_ports_irq[4] = { 4, 3, 4, 3 }; | ||||||
| 
 | 
 | ||||||
| static void serial_init_port(int port) | static void serial_interrupt(int i, int intr_code) | ||||||
| { | { | ||||||
| 	//Disable iterrupts
 |   printf("serial_interrupt %d %d\n",i,intr_code); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void serial_init_port(int unit) | ||||||
|  | { | ||||||
|  |   int port = serial_ports[unit]; | ||||||
|  | 	//Disable interrupts
 | ||||||
| 	outb(0x00, port + SERIAL_IRQ_ENABLE); | 	outb(0x00, port + SERIAL_IRQ_ENABLE); | ||||||
| 	//Enable DLAB(set baud rate divisor)
 | 	//Enable DLAB(set baud rate divisor)
 | ||||||
| 	outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); | 	outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); | ||||||
|  | @ -73,11 +88,20 @@ static void serial_init_port(int port) | ||||||
| 	//8 bits, no parity, one stop bit
 | 	//8 bits, no parity, one stop bit
 | ||||||
| 	outb(SERIAL_CHARLEN_START * 3, port + SERIAL_LCR); | 	outb(SERIAL_CHARLEN_START * 3, port + SERIAL_LCR); | ||||||
| 	//Enable FIFO, clear them, with 14 - byte threshold
 | 	//Enable FIFO, clear them, with 14 - byte threshold
 | ||||||
| 	outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECIEVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 | SERIAL_TRIGGER_LEVEL1, port + SERIAL_FCR); | 	outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR); | ||||||
| 	//IRQs enabled, RTS / DSR set
 | 	//IRQs enabled, RTS / DSR set
 | ||||||
| 	outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); | 	outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); | ||||||
|  | 
 | ||||||
|  | 	// setup interrupt support
 | ||||||
|  |   interrupt_register(serial_ports_irq[unit], serial_interrupt); | ||||||
|  |   interrupt_enable(serial_ports_irq[unit]); | ||||||
|  |   // + received data available
 | ||||||
|  | 	outb(0x01, port + SERIAL_IRQ_ENABLE);  | ||||||
|  |    | ||||||
|  | 	printf("[COM%d] serial_init_port %x: ready.\n",unit,port); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| static int serial_received(int port) | static int serial_received(int port) | ||||||
| { | { | ||||||
| 	return inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE; | 	return inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE; | ||||||
|  | @ -93,12 +117,23 @@ static int is_valid_port(uint8_t port_no) | ||||||
| 	return port_no < sizeof(serial_ports) / sizeof(int); | 	return port_no < sizeof(serial_ports) / sizeof(int); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| char serial_read(uint8_t port_no) | int serial_read(uint8_t port_no) | ||||||
| { | { | ||||||
| 	if(!is_valid_port(port_no)) | 	if(!is_valid_port(port_no)) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	while(serial_received(serial_ports[port_no]) == 0); | 	while(serial_received(serial_ports[port_no]) == 0); | ||||||
|  | 	printf("[COM%d]\n",port_no); | ||||||
|  | 	return inb(serial_ports[port_no]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int serial_read_nonblock(uint8_t port_no) | ||||||
|  | { | ||||||
|  | 	if(!is_valid_port(port_no)) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	if (serial_received(serial_ports[port_no]) == 0) return -1; | ||||||
|  | 	printf("[COM%d]\n",port_no); | ||||||
| 	return inb(serial_ports[port_no]); | 	return inb(serial_ports[port_no]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -115,7 +150,9 @@ int serial_write(uint8_t port_no, char a) | ||||||
| int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) | int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) | ||||||
| { | { | ||||||
| 	if(unit<0 || unit>3) return 0; | 	if(unit<0 || unit>3) return 0; | ||||||
| 	serial_init_port(serial_ports[unit]); | 	// TODO probing for real hardware
 | ||||||
|  | 	// reinit, second time (first time in serial_init, but needed to register the device)
 | ||||||
|  | 	serial_init_port(unit); | ||||||
| 	*blocksize = 1; | 	*blocksize = 1; | ||||||
| 	*nblocks = 0; | 	*nblocks = 0; | ||||||
| 	strcpy(info,"serial"); | 	strcpy(info,"serial"); | ||||||
|  | @ -124,10 +161,24 @@ int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) | ||||||
| 
 | 
 | ||||||
| int serial_device_read( int unit, void *data, int length, int offset ) | int serial_device_read( int unit, void *data, int length, int offset ) | ||||||
| { | { | ||||||
| 	int i; | 	int i,byte; | ||||||
| 	char *cdata = data; | 	char *cdata = data; | ||||||
| 	for(i=0;i<length;i++) { | 	for(i=0;i<length;i++) { | ||||||
| 		cdata[i] = serial_read(unit); | 		byte = serial_read(unit); | ||||||
|  | 		if (byte==-1) break; | ||||||
|  | 		cdata[i] = (char)byte;  | ||||||
|  | 	} | ||||||
|  | 	return length; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int serial_device_read_nonblock( int unit, void *data, int length, int offset ) | ||||||
|  | { | ||||||
|  | 	int i,byte; | ||||||
|  | 	char *cdata = data; | ||||||
|  | 	for(i=0;i<length;i++) { | ||||||
|  | 		byte = serial_read_nonblock(unit); | ||||||
|  | 		if (byte==-1) break; | ||||||
|  | 		cdata[i] = (char)byte; | ||||||
| 	} | 	} | ||||||
| 	return length; | 	return length; | ||||||
| } | } | ||||||
|  | @ -142,11 +193,12 @@ int serial_device_write( int unit, const void *data, int length, int offset ) | ||||||
| 	return length; | 	return length; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| static struct device_driver serial_driver = { | static struct device_driver serial_driver = { | ||||||
|        .name           = "serial", |        .name           = "serial", | ||||||
|        .probe          = serial_device_probe, |        .probe          = serial_device_probe, | ||||||
|        .read           = serial_device_read, |        .read           = serial_device_read, | ||||||
|        .read_nonblock  = serial_device_read, |        .read_nonblock  = serial_device_read_nonblock, | ||||||
|        .write          = serial_device_write |        .write          = serial_device_write | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -154,7 +206,7 @@ void serial_init() | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	for(i = 0; i < sizeof(serial_ports) / sizeof(int); i++) { | 	for(i = 0; i < sizeof(serial_ports) / sizeof(int); i++) { | ||||||
| 		serial_init_port(serial_ports[i]); | 		serial_init_port(i); | ||||||
| 	} | 	} | ||||||
| 	device_driver_register(&serial_driver); | 	device_driver_register(&serial_driver); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user