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();