Sun 12 Jan 19:29:58 CET 2025
This commit is contained in:
parent
bab1b053bf
commit
528fc9432e
|
@ -16,6 +16,8 @@ See the file LICENSE for details.
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "event_queue.h"
|
||||||
|
|
||||||
#define COM1 0x3f8
|
#define COM1 0x3f8
|
||||||
#define COM2 0x2F8
|
#define COM2 0x2F8
|
||||||
|
@ -24,7 +26,8 @@ See the file LICENSE for details.
|
||||||
|
|
||||||
#define SERIAL_DATA 0 // If DLAB disabled in LCR
|
#define SERIAL_DATA 0 // If DLAB disabled in LCR
|
||||||
|
|
||||||
#define SERIAL_IRQ_ENABLE 1 // If DLAB disabled in LCR
|
#define SERIAL_IER 1
|
||||||
|
|
||||||
#define SERIAL_IRQ_DATA_AVAILABILE (0x01 << 0)
|
#define SERIAL_IRQ_DATA_AVAILABILE (0x01 << 0)
|
||||||
#define SERIAL_IRQ_TRASMITTER_EMPTY (0x01 << 1)
|
#define SERIAL_IRQ_TRASMITTER_EMPTY (0x01 << 1)
|
||||||
#define SERIAL_IRQ_ERROR (0x01 << 2)
|
#define SERIAL_IRQ_ERROR (0x01 << 2)
|
||||||
|
@ -64,21 +67,32 @@ See the file LICENSE for details.
|
||||||
#define SERIAL_SCRATCH 7
|
#define SERIAL_SCRATCH 7
|
||||||
|
|
||||||
// units 0,1,2,3
|
// units 0,1,2,3
|
||||||
static const int serial_ports[4] = { COM1, COM2, COM3, COM4 };
|
static const int serial_ports[2] = { COM1, COM2 };
|
||||||
static const int serial_ports_irq[4] = { 4, 3, 4, 3 };
|
static const int serial_ports_irq[2] = { 4, 3 };
|
||||||
|
static struct event_queue *queue[2];
|
||||||
|
|
||||||
static void serial_interrupt(int i, int intr_code)
|
static void serial_interrupt(int intr, int intr_code)
|
||||||
{
|
{
|
||||||
printf("serial_interrupt %d %d\n",i,intr_code);
|
intr=intr-32; // reduce by IRQ table offset; IRQ is not unique! We may only support 2 COMs!
|
||||||
|
int port_no=intr==4?0:1,
|
||||||
|
port = serial_ports[port_no];
|
||||||
|
while(inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE) {
|
||||||
|
char ch=inb(port);
|
||||||
|
struct event e;
|
||||||
|
e.type = EVENT_DATA;
|
||||||
|
e.code = ch;
|
||||||
|
event_queue_post(queue[port_no],&e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int serial_init_port(int unit)
|
||||||
|
|
||||||
static void serial_init_port(int unit)
|
|
||||||
{
|
{
|
||||||
int port = serial_ports[unit];
|
int port = serial_ports[unit];
|
||||||
|
|
||||||
|
// probe for hardware
|
||||||
|
if(inb(port+SERIAL_LSR)==0xff) return 0;
|
||||||
//Disable interrupts
|
//Disable interrupts
|
||||||
outb(0x00, port + SERIAL_IRQ_ENABLE);
|
outb(0x00, port + SERIAL_IER);
|
||||||
//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);
|
||||||
//Set divisor to 3(lo byte) 38400 baud
|
//Set divisor to 3(lo byte) 38400 baud
|
||||||
|
@ -87,18 +101,24 @@ static void serial_init_port(int unit)
|
||||||
outb(0x00, port + SERIAL_DIVISOR_HI);
|
outb(0x00, port + SERIAL_DIVISOR_HI);
|
||||||
//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);
|
||||||
|
#ifdef SERIALFIFO
|
||||||
//Enable FIFO, clear them, with 14 - byte threshold
|
//Enable FIFO, clear them, with 14 - byte threshold
|
||||||
outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR);
|
outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR);
|
||||||
|
#else
|
||||||
|
outb(0 , port + SERIAL_FCR);
|
||||||
|
#endif
|
||||||
//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
|
// setup interrupt support (need to add 32 to IRQ number!!!!)
|
||||||
interrupt_register(serial_ports_irq[unit], serial_interrupt);
|
interrupt_register(32+serial_ports_irq[unit], serial_interrupt);
|
||||||
interrupt_enable(serial_ports_irq[unit]);
|
interrupt_enable(32+serial_ports_irq[unit]);
|
||||||
// + received data available
|
// + received data available
|
||||||
outb(0x01, port + SERIAL_IRQ_ENABLE);
|
outb(SERIAL_IRQ_DATA_AVAILABILE, port + SERIAL_IER);
|
||||||
|
|
||||||
printf("[COM%d] serial_init_port %x: ready.\n",unit,port);
|
queue[unit]=event_queue_create();
|
||||||
|
printf("[COM%d] serial_init_port %x: ready [IRQ=%d QUE=%x].\n",unit,port,serial_ports_irq[unit],queue[unit]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,6 +137,9 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Polling read
|
||||||
|
*/
|
||||||
int 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))
|
||||||
|
@ -124,7 +147,21 @@ int serial_read(uint8_t port_no)
|
||||||
|
|
||||||
while(serial_received(serial_ports[port_no]) == 0);
|
while(serial_received(serial_ports[port_no]) == 0);
|
||||||
printf("[COM%d]\n",port_no);
|
printf("[COM%d]\n",port_no);
|
||||||
return inb(serial_ports[port_no]);
|
return inb(serial_ports[port_no]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Interrupt driven event queue (blocks process if no dat ais available)
|
||||||
|
*/
|
||||||
|
int serial_getchar(uint8_t port_no) {
|
||||||
|
struct event e;
|
||||||
|
if(!is_valid_port(port_no))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
event_queue_read(queue[port_no],&e,sizeof(e));
|
||||||
|
|
||||||
|
if(e.type==EVENT_DATA) return (int)e.code;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_read_nonblock(uint8_t port_no)
|
int serial_read_nonblock(uint8_t port_no)
|
||||||
|
@ -152,7 +189,8 @@ 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;
|
||||||
// TODO probing for real hardware
|
// TODO probing for real hardware
|
||||||
// reinit, second time (first time in serial_init, but needed to register the device)
|
// reinit, second time (first time in serial_init, but needed to register the device)
|
||||||
serial_init_port(unit);
|
int status=serial_init_port(unit);
|
||||||
|
if (!status) return -1;
|
||||||
*blocksize = 1;
|
*blocksize = 1;
|
||||||
*nblocks = 0;
|
*nblocks = 0;
|
||||||
strcpy(info,"serial");
|
strcpy(info,"serial");
|
||||||
|
@ -206,7 +244,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(i);
|
int status = serial_init_port(i);
|
||||||
}
|
}
|
||||||
device_driver_register(&serial_driver);
|
device_driver_register(&serial_driver);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user