-
Notifications
You must be signed in to change notification settings - Fork 2
Device management
The main functions of device management include buffer management, device allocation, device processing, virtual devices, and device independence. Because I/O devices are not only diverse, but also their characteristics and operation methods are often very different, making device management called The most complicated part of the operating system and the most closely related to the hardware, start the formal learning 1 below.
The main function of the device management module is to manage the driver of each device, so that the device can read and write I/O operations, and other operations; in the design of the system, the difference between character devices and block devices is not considered, and All devices are divided into 2 buffers.
//队列
//head出队
//tail入队
struct Buffer{
char * buf;
unsigned long bufferLength;
unsigned long head;
unsigned long tail;
};The Buffer structure is a queue (implemented using an array), and head and tail are the head and tail of the queue.
Device corresponds to a specific 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);//该设备的卸载函数
};When registering the device, the driver function code of the device will be copied to the kernel space and assigned to the structure; each device has 2 Buffers.
struct DeviceTable{
//管理系统的所有设备DeviceClass==255
struct Device * devices[DeviceClass];
//当前已经分配的设备数量
unsigned long count;
};You can use the function registerDevice(void * deviceLoad, unsigned long bufferSize) to register a device to the kernel. The detailed description of the function is given later.
To write a driver program in user mode and register it to the kernel for use, you can use the following steps (using the keyboard device as an example):
unsigned long keyboardInit(unsigned long devID){
while(!is8042InBufReady());
io_out8(CMDPort,0x60);
while(!is8042InBufReady());
io_out8(DataPort,initMode);
return True;
}This method can enter a device number. The main function is to initialize the device's registers and return whether the initialization is successful.
unsigned long keyboardOpen(unsigned long devID){
return True;
}
unsigned long kerboardClose(unsigned long devID){
return True;
}This function accepts a device number input and returns whether the execution is successful.
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;
}These two functions are mainly to read and write the inBuffer or outBuffer of the device. If the parameter InOrOutbuffer==0, then read and write inBuffer, otherwise read and write outBuffer.
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 is used to register a device. The function can directly use the above template, and use the above (init, open, close, read, write) function to assign the function pointer variable of the parameter device . The parameter bufferSize indicates the size of the inBuffer or outBuffer to be initialized.
exit is used to uninstall a device, currently you can return to Ture directly.
After writing the above code in user mode, you can use a system call (not yet implemented), which enters the kernel or eventually calls the registerDevice(void * deviceLoad, unsigned long bufferSize) function, which is implemented as follows:
//向系统注册驱动程序,返回驱动程序的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;
}After the function is executed, the driver will be registered in the deviceTable of the kernel.