johnc@rtmvax.UUCP (John Connin) (07/19/88)
I am posting the following code fragments with the idea that
concepts expressed may be helpful in establishing a definitive
serial port driver for Minix. The salient features which are
not currently in the present driver are: (1) determining the port
address base from the bios data area, and (2) enabling the
corresponding PIC irq line.
#define CRITICAL int crit_save
#define C_ENTER crit_save = lock()
#define C_LEAVE restore(crit_save)
rs_open(line)
{
CRITICAL;
int irq;
uchar mcr, ocw1;
struct rs_struct *rs;
rs = &rs_struct[line - NR_CONS];
.....
/* if device exits, set its address into rs232 struct */
if (set_port(rs) != OK)
return( ERR_NO_PORT );
/* set interrupt request level */
switch (rs->rs_base) {
case COM1_ADDR: irq = 4; break;
case COM2_ADDR: irq = 3; break;
default: return( -EINVAL );
}
rs->irq_level = (irq | 0x08);
rs->irq_disable = (1 << irq); /* disable mask */
rs->irq_enable = ~rs->irq_disable; /* enable mask */
C_ENTER;
/* Turn on DTR, RTS, and OUT2 signals. */
port_in(rs->rs_base + MCR,&mcr);
port_out(rs->rs_base + MCR,(mcr|MCR_DTR|MCR_RTS|MCR_OUT2));
/* Tell 8259 PIC to allow interrupts */
port_in(PIC_MASTER,&ocw1);
port_out(PIC_MASTER,(ocw1 & rs->irq_enable)); /* enable desired irq level */
/* Enable interrupts on the com port. */
port_out(rs->rs_base + IER,(IER_READ|IER_ERROR|IER_STATUS|IER_WRITE));
/* Reset the 8259 */
port_out(PIC_MSTAT,EOI);
C_LEAVE;
.....
}
aux_close(line)
{
CRITICAL;
uchar lcr, mcr, owc1;
struct rs_struct *rs;
rs = &rs_struct[line - NR_CONS];
.....
C_ENTER;
/* turn off all interrupts */
lcr = inp(rs->dev_addr + LCR);
port_out(rs->dev_addr + LCR, (lcr & 0x7F));
port_out(rs->dev_addr + IER,0x00);
/* Turn off DTR, RTS, and OUT2. */
mcr = inp(rs->dev_addr + MCR);
port_out(rs->dev_addr + MCR,(mcr & ~(MCR_DTR|MCR_RTS|MCR_OUT2)));
/* Tell 8259 PIC to mask interrupts */
owc1 = inp(PIC_MASTER);
port_out(PIC_MASTER,(owc1 | rs->irq_disable));
C_LEAVE;
.....
return ( OK );
}
/*-------------------------------------------------------------------
Function: set_port() --
Description: Given the logical communications port number,
set the device I/O port address into the
control structure.
The port address is determined by consulting the
printer table contained in the bios data area
beginning at 0x0040:0x0000
-------------------------------------------------------------------*/
set_port(rs)
struct rs232 *rs;
{
int far *fp;
int offset;
switch (rs->port_nmbr) /* sort out the base address */
{
case 1 : offset = 0x0000; break; /* only ports one & two allowed */
case 2 : offset = 0x0002; break;
default : return( -1 );
}
/* find out the port address */
fp = (int far *) MK_FP(PC_SEGMENT,offset);
if ( (rs->rs_base = *fp) == 0)
return( -1 );
return( OK );
}
"Interrupt" Interference:
-------------------------
One more item. Microsoft C, Turbo C, and perhaps other compilers reserve
the word "interrupt". Consequently I would like to recommend that the
Minix function interrupt() contained in kernel/proc.c be renamed. Lack
imagination, I have simply renamed it as hw_interrupt();