[comp.os.minix] rs232 code fragments

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