The basic idea is each driver is written as a relocatable binary, the file format is yet to be defined but ELF is a standard that might handle the loading/relocation. The entry point in the header is always to initdevice.
In general a pdi driver is written with all its supported functions passed to the OS in a device ops struct. A native OS driver acts as a wrapper to the pdi functions. Any functions not suported by the OS are ignored, any functions that an OS requires are included in a specific version. If the function is not handled by the driver the OS either drops back its function support or unloads the driver. A minimum amount of library support is included in the kernel.
The interface is designed for asm using ecx as a parameter count and edx as a pointer to the parameters. C drivers will need a save these values to use the parameters.
An example driver for vga is shown below.
pdi_vga.c
Code: Select all
struct videoop{
// required for every device
int opversion; // driver operations version
int (*initdevice)(void) // initializes the device
int (*resetdevice)(void) // resets the device
int (*enddevice)(void) // stops the device
int (*deviceinfo)(void) // info about the device
// device specific
int (*setmode)(void) // sets the video mode
int (*getmode)(void) // gets the video mode
int (*gotoxy)(void) // set cursor position
int (*getxy)(void) // get cursor position
int (*putchar)(void) // writes a character
int (*getchar)(void) // reads a character
int (*putpixel)(void) // puts a pixel
int (*getpixel)(void) // gets a pixel
// svga/3d acceleration goes here in an extended version
};
#define VGA_OP_VERSION 1
struct videoop vgaops={
.opversion=VGA_OP_VERSION,
.initdevice=initvga,
.resetdevice=resetvga,
.enddevice=endvga,
.deviceinfo=infovga,
.setmode=setmode,
.getmode=getmode,
.gotoxy=gotoxy,
.getxy=getxy,
.putchar=putchar,
.getchar=getchar,
.putpixel=putpixel,
.getpixel=getpixel
};
int initvga(void)
{
int argc,*argv;
int ver;
asm(
mov [argc],ecx
mov [argv],edx
);
if(!argc){
return -1; // no version number
}
ver=*argv[0]; // required version of videoop for OS
if(ver>VGA_OP_VERSION){
return -1; // unsupported version
}
asm(
mov edx,&vgaops // return vgaops in edx
);
return 0;
}
int setmode(void)
{
int argc,*argv;
int mode;
asm(
mov [argc],ecx
mov [argv],edx
);
if(!argc){
return -1; // no mode number
}
return writeregs(mode);
}
vgadrv.c
Code: Select all
struct videoops *vgaops;
struct videoops *initvga(int ver)
{
struct videoops *ops;
int (*initdevice)(void);
initdevice=pdi_vga_entry; // entry point in driver file
asm(
mov edx,&ver
mov ecx,1
);
initdevice();
asm(
mov [ops],edx
);
return ops;
}
int driver_init(...)
{
load("pdi_vga.drv");
vgaops=initvga(1,1); // initdevice vgaops version 1 required
setmode(T80x25x16); // set display to a known mode
return 0;
}
int setmode(int mode)
{
asm(
mov edx,&mode
mov ecx,1
);
return vgaops->setmode();
}