460 Notes
LAB ASSIGNMENT #8 SERIAL PORT DRIVER
DUE : April 11, 2006
1. Objective:
To design and implement a serial driver for the MTX system.
2. Pre-work:
Download the files in samples/LAB8/:
ts.s : assembly file for LAB8, and
serial.c: serial driver for LAB8
Incoporate them into YOUR MTX based on LAB5, i.e.
Use ts.s for the assembly code and
In YOUR main.c, install vector 12 (for COM1 serial port) and
include serial.c
Also, add the 'o' commands in Kmode and Umode to output a line
to the serial port.
3. REQUIREMENTS:
Modify serial.c to implement the input part of the serial driver.
// serial.c file for SERIAL LAB ASSIGNEMNT
struct semaphore{
int value;
PROC *queue;
};
int P(s) struct semaphore *s;
{
lock();
s->value--;
if (s->value < 0){
running->status=BLOCK;
enqueue(&s->queue, running);
tswitch();
}
restore();
}
int V(s) struct semaphore *s;
{
PROC *p;
lock();
s->value++;
if (s->value <= 0){
p = dequeue(&s->queue);
p->status = READY;
enqueue(&readyQueue, p);
}
restore();
}
/**************** CONSTANTS ***********************/
#define BUFLEN 80
#define EBUFLEN 10
#define NR_STTY 1 /* number of serial ports */
/* offset from serial ports base */
#define DATA 0 /* Data reg for Rx, Tx */
#define DIVL 0 /* When used as divisor */
#define DIVH 1 /* to generate baud rate */
#define IER 1 /* Interrupt Enable reg */
#define IIR 2 /* Interrupt ID rer */
#define LCR 3 /* Line Control reg */
#define MCR 4 /* Modem Control reg */
#define LSR 5 /* Line Status reg */
#define MSR 6 /* Modem Status reg */
/**** The serial terminal data structure ****/
struct stty {
/* input buffer */
/* echo buffer */
/* output buffer */
char outbuf[BUFLEN];
int outhead, outtail;
struct semaphore outroom;
int tx_on;
/* I/O port base address */
int port;
} stty[NR_STTY];
/******** bgetc()/bputc() by polling *********/
int bputc(port, c) int port, c;
{
while ((in_byte(port+LSR) & 0x20) == 0);
out_byte(port+DATA, c);
}
int enable_irq(irq_nr) unsigned irq_nr;
{
out_byte(0x21, in_byte(0x21) & ~(1 << irq_nr));
}
/************ serial ports initialization ***************/
char *p = "\n\rSerial Port Ready\n\r\007";
int sinit()
{
int i;
struct stty *t;
char *q;
/* initialize stty[] and serial ports */
for (i = 0; i < NR_STTY; i++){
q = p;
t = &stty[i];
/* initialize data structures and pointers */
if (i==0)
t->port = 0x3F8; /* COM1 base address */
else
t->port = 0x2F8; /* COM2 base address */
printf("sinit : port %x\n", t->port);
t->outroom.value = BUFLEN;
t->outhead = t->outtail = 0;
t->tx_on = 0;
lock(); // CLI; no interrupts
out_byte(t->port+IER, 0x00); /* disable serial port interrupts */
out_byte(t->port+LCR, 0x80); /* ready to use 3f9,3f8 as divisor */
out_byte(t->port+DIVH, 0x00);
out_byte(t->port+DIVL, 12); /* divisor = 12 ===> 9600 bauds */
/******** term 9600 /dev/ttyS0: 8 bits/char, no parity *************/
out_byte(t->port+LCR, 0x03);
/*******************************************************************
Writing to 3fc ModemControl tells modem : DTR, then RTS ==>
let modem respond as a DCE. Here we must let the (crossed)
cable tell the TVI terminal that the "DCE" has DSR and CTS.
So we turn the port's DTR and RTS on.
********************************************************************/
out_byte(t->port+MCR, 0x0B); /* 1011 ==> IRQ4, RTS, DTR on */
out_byte(t->port+IER, 0x01); /* Enable Rx interrupt, Tx off */
unlock();
enable_irq(4-i); // COM1: IRQ4; COM2: IRQ3
/* show greeting message */
printf(q);
while (*q){
bputc(t->port, *q);
q++;
}
}
}
/* enable/disable Tx interrupts */
enable_tx(t) struct stty *t;
{
out_byte(t->port+IER, 0x03); /* 0011 ==> both tx and rx on */
}
disable_tx(t) struct stty *t;
{
out_byte(t->port+IER, 0x01); /* 0001 ==> tx off, rx on */
}
//======================== LOWER HALF ROUTINES ===============================
int s0handler()
{
shandler(0);
}
int shandler(port) int port;
{
struct stty *t;
int IntID, LineStatus, ModemStatus, intType, c;
t = &stty[port]; /* IRQ 4 interrupt : COM1 = stty[0] */
IntID = in_byte(t->port+IIR); /* read InterruptID Reg */
LineStatus= in_byte(t->port+LSR); /* read LineStatus Reg */
ModemStatus=in_byte(t->port+MSR); /* read ModemStatus Reg */
intType = IntID & 7; /* mask out all except the lowest 3 bits */
switch(intType){
case 6 : do_errors(t); break; /* 110 = errors */
case 4 : do_rx(t); break; /* 100 = rx interrupt */
case 2 : do_tx(t); break; /* 010 = tx interrupt */
case 0 : do_modem(t); break; /* 000 = modem interrupt */
}
out_byte(0x20, 0x20); /* reenable the 8259 controller */
}
int do_tx(tty) struct stty *tty;
{
int c;
if (tty->outroom.value == BUFLEN){ /* nothing to do */
out_byte(tty->port, 0); /* send NULL char to clear interrupt */
disable_tx(tty); /* turn off tx interrupt */
return;
}
/* has something to output */
c = tty->outbuf[tty->outtail++];
tty->outtail %= BUFLEN;
out_byte(tty->port, c);
V(&tty->outroom); // wakeup any BLOCKED process
}
int sputc(c) int c;
{
struct stty *tty = &stty[0];
P(&tty->outroom); /* wait for room in outbuf[] */
lock(); /* disalble interrupts */
tty->outbuf[tty->outhead++] = c;
tty->outhead %= BUFLEN;
enable_tx(tty);
unlock();
}
int sputline(line) char *line;
{
while (*line){
sputc(*line);
line++;
}
}
// input interrupt handler
int do_rx(tty) struct stty *tty; /* interrupts already disabled */
{
int c = in_byte(tty->port) & 0x7F; /* read the char ASCII from port */
printf("\nport %x interrupt : c=%c", tty->port, c);
}
int sgetc()
{
}
int sgetline(line) char *line;
{
}
int usgets(y) char *y;
{
}
// error and modem interrupt handler
int do_errors()
{ }
int do_modem()
{ }