设备管理
1.概念
设备管理的主要功能有缓冲区管理、设备分配、设备处理、虚拟设备及实现设备独立性等,由于I/O设备不仅种类繁多,而且他们的特性和操作方式往往相差甚大,使得设备管理称为操作系统中最繁杂且与硬件最紧密的部分,下面开始正式的学习1。
2.相关结构体
设备管理模块主要的功能是管理每一个设备的驱动程序,从而可以对设备进行读写I/O操作,和其他操作;在该系统设计时,没有考虑字符设备和块设备的区别,简单的为所有的设备都划分2块缓冲区。
1.Buffer
//队列
//head出队
//tail入队
struct Buffer{
char * buf;
unsigned long bufferLength;
unsigned long head;
unsigned long tail;
};
Buffer结构体是一个队列(使用数组实现),head和tail是队列头和队列尾。
2.Device
Device对应一个具体的设备。
struct Device{
unsigned long devID;
//输入到cpu的buffer ----->CPU
struct Buffer inBuffer;
//输出到设备的buffer ----->设备
struct Buffer outBuffer;
//返回设备号
unsigned long (* load)(struct Device *,unsigned long );//注册一个设备和并复制其驱动程序到内核
unsigned long (* init)(unsigned long);//该设备的初始化函数
unsigned long (* open)(unsigned long);//该设备的打开函数
//2:输入的字符,3:字符长度 4:(0)inbuffer (1)outbuffer
unsigned long (* write)(unsigned long,char * ,unsigned long,unsigned long);//写入该设备
//2:字符长度 3:(0)inbuffer (1)outbuffer
char (* read)(unsigned long,unsigned long,unsigned long);//读取该设备
//返回设备号
unsigned long (* close)(unsigned long);//该设备的关闭函数
unsigned long (* exit)(unsigned long);//该设备的卸载函数
};
在注册设备的时候,会同时将设备的驱动程序复制到内核空间,并赋值给该结构体;每一个设备都有2个Buffer。
3.DeviceTable
struct DeviceTable{
//管理系统的所有设备DeviceClass==255
struct Device * devices[DeviceClass];
//当前已经分配的设备数量
unsigned long count;
};
可以使用函数registerDevice(void * deviceLoad,unsigned long bufferSize)注册一个设备到内核,函数详细说明见后。
3.使用
想要在用户态编写一个驱动程序,并注册到内核使用,可以使用下面的步骤(使用键盘设备为例):
1.编写设备init方法:
unsigned long keyboardInit(unsigned long devID){
while(!is8042InBufReady());
io_out8(CMDPort,0x60);
while(!is8042InBufReady());
io_out8(DataPort,initMode);
return True;
}
该方法可以输入一个设备号,该函数的主要功能是初始化设备的寄存器,返回是否初始化成功。
2.编写设备Open,Close方法:
unsigned long keyboardOpen(unsigned long devID){
return True;
}
unsigned long kerboardClose(unsigned long devID){
return True;
}
该函数接受一个设备号输入,返回执行是否成功。
3.编写Read,Write方法:
unsigned char keyboardRead(unsigned long devID,unsigned long length,unsigned long InOrOutbuffer){
unsigned long i;
struct Buffer * buffer;
if(InOrOutbuffer == 0) buffer = &deviceTable.devices[devID]->inBuffer;
else buffer = &deviceTable.devices[devID]->outBuffer;
return deleteAndreturn(buffer);
}
unsigned long kerboardWrite(unsigned long devID,char * buf,unsigned long length,unsigned long InOrOutbuffer){
unsigned long i;
struct Buffer * buffer;
if(InOrOutbuffer == 0) buffer = &deviceTable.devices[devID]->inBuffer;
else buffer = &deviceTable.devices[devID]->outBuffer;
for(i=0;i<length;i++){
char c = *(buf + i);
insert(buffer,c);
}
return True;
}
这两个函数主要是读写该设备的inBuffer或者outBuffer,如果参数InOrOutbuffer==0则读写inBuffer,否则读写outBuffer。
4.编写load,exit方法:
unsigned long kerboardLoad(struct Device * device,unsigned long bufferSize){
device->init = keyboardInit;
device->open = keyboardOpen;
device->read = keyboardRead;
device->write = kerboardWrite;
device->exit = kerboardExit;
device->close = kerboardClose;
return True;
}
unsigned long kerboardExit(unsigned long devID){
return True;
}
load用来注册一个设备,函数可以直接使用上面的模板,赋值参数device的函数指针变量为上面步骤编写的(init,open,close,read,write)函数,参数bufferSize表示要初始化的inBuffer或者outBuffer的大小。
exit用来卸载一个设备,目前可以直接返回Ture。
5.注册
在用户态编写完上述代码后,可以使用系统调用(还未实现),该系统调用进入内核或最终会调用registerDevice(void * deviceLoad,unsigned long bufferSize)函数,该函数实现如下:
//向系统注册驱动程序,返回驱动程序的id号
unsigned long registerDevice(void * deviceLoad,unsigned long bufferSize){
//向内核申请一块内存
struct Device * device = (struct Device *) getMemoryBlock(sizeof(struct Device));
device->devID = deviceTable.count;
deviceTable.devices[deviceTable.count] = device;
//复制用户态的load函数到内核态
void * loadfun = (void *)getMemoryBlock(4096);
copy((unsigned long) deviceLoad,(unsigned long) loadfun,4096);
device->load = loadfun;
//loadDeviceFunTOKernel函数用来复制其他函数到内核
if(device->load(device,bufferSize)){
if(loadDeviceFunTOKernel(device)){
device->init(device->devID);
}
}
//初始化inBuffer和outBuffer
initBuffer(&device->inBuffer,bufferSize);
initBuffer(&device->outBuffer,bufferSize);
deviceTable.count++;
return device->devID;
}
该函数执行完后会把该驱动程序注册到内核的deviceTable表中。