Metropoli BBS
VIEWER: 386bsd.392 MODE: TEXT (ASCII)
_PORTING UNIX TO THE 386: DEVICE DRIVERS_
by William Jolitz and Lynne Jolitz


[LISTING ONE]

/* [Excerpted from /sys/i386/isa/icu.h] */
 ...
/* Interrupt enable bits -- in order of priority */
#define IRQ0        0x0001      /* highest priority - timer */
#define IRQ1        0x0002
#define IRQ_SLAVE   0x0004
#define IRQ8        0x0100
#define IRQ9        0x0200
#define IRQ2        IRQ9
#define IRQ10       0x0400
#define IRQ11       0x0800
#define IRQ12       0x1000
#define IRQ13       0x2000
#define IRQ14       0x4000
#define IRQ15       0x8000
#define IRQ3        0x0008
#define IRQ4        0x0010
#define IRQ5        0x0020
#define IRQ6        0x0040
#define IRQ7        0x0080      /* lowest - parallel printer */
 ...




[LISTING TWO]

/* [Excerpted from /sys/i386/isa/icu.h] */
  ...
/* Interrupt "level" mechanism variables, masks, and macros */

#define INTREN(s)   __nonemask__ &= ~(s)
#define INTRDIS(s)  __nonemask__ |= (s)
#define INTRMASK(msk,s) msk |= (s)
  ...
/* [Excerpted from /sys/i386/isa/isa.c] */
  ...
/* Configure all ISA devices */
isa_configure() {
    struct isa_device *dvp;
    struct isa_driver *dp;
    splhigh();
    INTREN(IRQ_SLAVE);
    /* configure devices, constructing group masks as we go */
    for (dvp = isa_devtab_bio; config_isadev(dvp,&__biomask__); dvp++);
    for (dvp = isa_devtab_tty; config_isadev(dvp,&__ttymask__); dvp++);
    for (dvp = isa_devtab_net; config_isadev(dvp,&__netmask__); dvp++);
    for (dvp = isa_devtab_null; config_isadev(dvp,0); dvp++);
/* if we support slip, then any tty interrupt is a potential net intr */
#include "sl.h"
#if NSL > 0
    __netmask__ |= __ttymask__;
    __ttymask__ |= __netmask__;
#endif

    /* if not enabled, don't allow in ANY mask to become enabled */
    __biomask__ |= __nonemask__;
    __ttymask__ |= __nonemask__;
    __netmask__ |= __nonemask__;
    __protomask__ |= __nonemask__;
    splnone();
}
/* Configure an ISA device. */
config_isadev(isdp, mp)
    struct isa_device *isdp;
    int *mp;
{
    struct isa_driver *dp;
    if (dp = isdp->id_driver) {
        /* does this device have any I/O shared memory? */
        if (isdp->id_maddr) {
            extern int atdevbase[];
            /* convert from PC absolute physical to virtual */
            isdp->id_maddr -= IOM_BEGIN;
            isdp->id_maddr += (int)&atdevbase;
        }
        /* "Is there anyone on board?" -- Star Trek */
        isdp->id_alive = (*dp->probe)(isdp);
        if (isdp->id_alive) {
            printf("%s%d", dp->name, isdp->id_unit);
            (*dp->attach)(isdp);
            printf(" at 0x%x ", isdp->id_iobase);
            /* have we got an interrupt to wire down? */
            if(isdp->id_irq) {
                int intrno;
                intrno = ffs(isdp->id_irq)-1;
                printf("irq %d ", intrno);
                INTREN(isdp->id_irq);
                /* add to a group mask?? */
                if(mp)INTRMASK(*mp,isdp->id_irq);
                /* wire interrupt */
                setidt(ICU_OFFSET+intrno, isdp->id_intr,
                     SDT_SYS386IGT, SEL_KPL);
            }
            /* perhaps a DMA channel request as well? */
                       if (isdp->id_drq != -1) printf("drq %d ", isdp->id_drq);

            printf("on isa\n");
        }
        return (1);
    } else  return(0);
}
...




[LISTING THREE

/* [Excerpted from /sys/i386/include/param.h] */

  ...
#ifndef __ORPL__
/* Interrupt Group Masks  */
extern  u_short __highmask__;   /* interrupts masked with splhigh() */
extern  u_short __ttymask__;    /* interrupts masked with spltty() */
extern  u_short __biomask__;    /* interrupts masked with splbio() */
extern  u_short __netmask__;    /* interrupts masked with splimp() */
extern  u_short __protomask__;  /* interrupts masked with splnet() */
extern  u_short __nonemask__;   /* interrupts masked with splnone() */

asm("   .set IO_ICU1, 0x20 ; .set IO_ICU2, 0xa0 "); 

/* adjust priority level to disable a group of interrupts */
#define __ORPL__(m) ({ u_short oldpl, msk; \
    msk = (msk); \
    asm volatile (" \
    cli ;               /* modify interrupts atomically */ \
    movw    %1, %%dx ;      /* get mask to OR in */ \
    inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
    xchgb   %%dl, %%al ;        /* switch the old with the new */ \
    orb %%dl, %%al ;        /* finally, OR both it in! */ \
    outb    %%al, $ IO_ICU1+1 ;     /* and stuff it back where it came */ \
    inb $ 0x84, %%al ;      /* post it & handle write recovery */ \
    inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
    xchgb   %%dh, %%al ;        /* switch the old with the new */ \
    orb %%dh, %%al ;        /* finally, or it in! */ \
    outb    %%al, $ IO_ICU2+1 ;     /* and stuff it back where it came */ \
    inb $ 0x84, %%al ;      /* post it & handle write recovery */ \
    movw    %%dx, %0 ;      /* return old mask */ \
    sti             /* allow interrupts again */ " \
    : "&=g" (oldpl)         /* return values */ \
    : "g" ((m))         /* arguments */ \
    : "ax", "dx"            /* registers used */ \
    ); \
    oldpl;              /* return the "old" value */ \
})
/* force priority mask to a set value */
#define __SETPL__(m)    ({ u_short oldpl, msk; \
    msk = (msk); \
    asm volatile (" \
    cli ;               /* modify interrupts atomically */ \
    movw    %1, %%dx ;      /* get mask to OR in */ \
    inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
    xchgb   %%dl, %%al ;        /* switch the old with the new */ \
    outb    %%al, $ IO_ICU1+1 ;     /* and stuff it back where it came */ \
    inb $ 0x84, %%al ;      /* post it & handle write recovery */ \
    inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
    xchgb   %%dh, %%al ;        /* switch the old with the new */ \
    outb    %%al, $ IO_ICU2+1 ;     /* and stuff it back where it came */ \
    inb $ 0x84, %%al ;      /* post it & handle write recovery */ \
    movw    %%dx, %0 ;      /* return old mask */ \
    sti             /* allow interrupts again */ " \
    : "&=g" (oldpl)         /* return values */ \
    : "g" ((m))         /* arguments */ \
    : "ax", "dx"            /* registers used */ \
    ); \
    oldpl;              /* return the "old" value */ \
})
#define splhigh()   __ORPL__(__highmask__)
#define spltty()    __ORPL__(__ttymask__)
#define splbio()    __ORPL__(__biomask__)
#define splimp()    __ORPL__(__netmask__)
#define splnet()    __ORPL__(__protomask__)
#define splsoftclock()  __ORPL__(__protomask__)
#define splx(v) ({ u_short val; \
    val = (v); \
    if (val == __nonemask__) (void) spl0(); /* zero is special */ \
    else (void) __SETPL__(val); \
})
#endif __ORPL__
 ...




[LISTING FOUR]

/* [Excerpted from /sys/i386/i386/machdep.c] */

  ...
/* Fill out a gate descriptor uses as an interrupt vector. */
setidt(idx, func, typ, dpl) char *func; {
    struct gate_descriptor *ip = idt + idx;
    ip->gd_looffset = (int)func;
    ip->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
    ip->gd_stkcpy = 0;
    ip->gd_xx = 0;
    ip->gd_type = typ;
    ip->gd_dpl = dpl;   /* can we allow INT's to this IDT index? */
    ip->gd_p = 1;       /* yup, we're here, don't segment fault me */
    ip->gd_hioffset = ((int)func)>>16 ;
}
  ...




[LISTING FIVE]

/* [Excerpted from /sys/i386/include/segments.h] */

  ...
/* Gate descriptors (e.g. indirect descriptors)
 * [The IDT is made up of these as well.] */
struct  gate_descriptor {
    unsigned gd_looffset:16 ;   /* gate offset (lsb) */
    unsigned gd_selector:16 ;   /* gate segment selector */
    unsigned gd_stkcpy:5 ;      /* number of stack wds to cpy */
    unsigned gd_xx:3 ;      /* unused */
    unsigned gd_type:5 ;        /* segment type */
    unsigned gd_dpl:2 ;     /* segment descriptor priority level */
    unsigned gd_p:1 ;       /* segment descriptor present */
    unsigned gd_hioffset:16 ;   /* gate offset (msb) */
} ;
 ...





[ RETURN TO DIRECTORY ]