Mon 9 Dec 20:40:44 CET 2024

This commit is contained in:
sbosse 2024-12-09 20:42:06 +01:00
parent 6460cc87d0
commit 64731d077e

View File

@ -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);
} }