linux 0.11 内核学习 -- char_dev.c
/*
* linux/fs/char_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <sys/types.h> // 定义了基本的系统数据类型
#include <linux/sched.h>
#include <linux/kernel.h> // 含有一些内核常用函数的原形定义
#include <asm/segment.h>
#include <asm/io.h>
/* 中断读 */
extern int tty_read(unsigned minor,char * buf,int count);
/* 中断写 */
extern int tty_write(unsigned minor,char * buf,int count);
/* 定义字符设备读写函数指针类型 */
typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos);
/* 串口终端读写操作函数。参数 : rw读写命令,minor中断子设备号,buf缓冲区 */
/* count读写的字节数,pos读写操作当前指针,返回实际读写的字节数 */
static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos)
{
return ((rw==READ)?tty_read(minor,buf,count):
tty_write(minor,buf,count));
}
/* 终端读写操作函数,只是增加了对进程是否有控制终端的检测 */
static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)
{
// 若进程没有对应的控制终端,则返回出错号
if (current->tty<0)
return -EPERM;
return rw_ttyx(rw,current->tty,buf,count,pos);
}
/* 内存数据读写函数,还没实现 */
static int rw_ram(int rw,char * buf, int count, off_t *pos)
{
return -EIO;
}
/* 内存数据读写操作函数。未实现 */
static int rw_mem(int rw,char * buf, int count, off_t * pos)
{
return -EIO;
}
/* 内核数据区读写函数。未实现 */
static int rw_kmem(int rw,char * buf, int count, off_t * pos)
{
return -EIO;
}
/* 端口读写操作函数,参数 : rw读写命令,buf缓冲区,count读写字节数,pos */
/* 端口地址,返回的是实际读写的字节数 */
static int rw_port(int rw,char * buf, int count, off_t * pos)
{
int i=*pos; // 端口地址
// 对于所要求读写的字节数,并且端口地址小于64k
while (count-->0 && i<65536)
{
// 若是读命令,则从端口i 中读取一字节内容并放到用户缓冲区中
if (rw==READ)
put_fs_byte(inb(i),buf++);
// 若是写命令,则从用户数据缓冲区中取一字节输出到端口i
else
outb(get_fs_byte(buf++),i);
i++; // 前移一个端口
}
// 计算读/写的字节数,并相应调整读写指针
i -= *pos;
*pos += i;
// 返回读/写的字节数
return i;
}
/* 内存读写操作函数 */
static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
{
// 根据内存设备子设备号,分别调用不同的内存读写函数
switch(minor)
{
case 0:
return rw_ram(rw,buf,count,pos);
case 1:
return rw_mem(rw,buf,count,pos);
case 2:
return rw_kmem(rw,buf,count,pos);
case 3:
return (rw==READ)?0:count; /* rw_null */
case 4:
return rw_port(rw,buf,count,pos);
default:
return -EIO;
}
}
/* 定义系统中设备种数 */
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
/* // 字符设备读写函数指针表,定义函数指针 */
static crw_ptr crw_table[]={
NULL, /* nodev */ /* 无设备(空设备) */
rw_memory, /* /dev/mem etc */ /* /dev/mem 等 */
NULL, /* /dev/fd */ /* /dev/fd 软驱 */
NULL, /* /dev/hd */ /* /dev/hd 硬盘 */
rw_ttyx, /* /dev/ttyx */ /* /dev/ttyx 串口终端 */
rw_tty, /* /dev/tty */ /* /dev/tty 终端 */
NULL, /* /dev/lp */ /* /dev/lp 打印机 */
NULL /* unnamed pipes */ /* 未命名管道 */
};
/* 字符设备读写操作函数,参数 : rw读写命令,dev设备号,buf缓冲区,count */
/* 读写字节数,pos读写指针,函数返回的是读写的字节数 */
int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
{
crw_ptr call_addr;
// 如果设备号超出系统设备数,则返回出错码
if (MAJOR(dev)>=NRDEVS)
return -ENODEV;
// 若该设备没有对应的读/写函数,则返回出错码
if (!(call_addr=crw_table[MAJOR(dev)]))
return -ENODEV;
// 调用对应设备的读写操作函数,并返回实际读/写的字节数
return call_addr(rw,MINOR(dev),buf,count,pos);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?