在这一节中,我们来一起学习和完成文件树中最后一个关键性内容——一切皆文件的设计理念。
所谓一切皆文件就是指计算机操作系统将一切计算机的可用资源都映射成文件形式向使用者提供统一的操作方式。我们在第一节时已经有了明确的讲述,在这一节中我们来看一下具体的设计理念和实现方法。我们在操作系统中为用户构建的虚拟系统中,树的每一个节点都是一个文件,而这些文件虽然有着不同的类型和功能,如普通文件、键盘、鼠标、打印机、显示器、内存页、操作系统调度状态等等,但却有着相同的文件操作接口。对于用户而言普通文件的操作通常只有“打开”、“关闭”、“读取”、“写入”这几个操作,而对于较为特殊的文件,通常还需要加入“输入输出控制”、“尝试获取数据”这两个操作,因此对于虚拟文件系统中的文件我们可以为其定义这样6个通用的操作:
open()close()read()write()ioctl()poll()
`
这6个函数是目前操作系统中对文件操作的函数,当然有的操作系统还实现了一些其它的操作函数,我们不一一列举,只是针对这6个最具有代表性的函数进行说明。用户对文件树中的文件进程上面6个操作,也就是说每一个文件节点中应该有这6个函数的实现方法。具体来说,我们在虚拟文件树中注册一个设备节点时,这个设备节点就是虚拟文件树中的一个文件,我们可以为此设备节点的结构体加入上述6个函数指针:typedef struct file_operations_s{ int (*open)(void); int (*close)(void); size_t (*read)(void *, size_t); size_t (*write)(const void *, size_t); int (*ioctl)(unsigned int, unsigned long); int (*poll)(unsigned int);} file_operations_s;typedef struct vfs_node_s{ struct vfs_node_s *sibling; struct vfs_node_s *child; char name[node_name_size]; struct file_operations_s ops;} vfs_node_s;在这里我们定义了一个结构体struct file_operations_s,这个结构体中定义了6个函数指针,用于表示这个文件的通用的6个操作。而具体的实现由注册这个设备节点的具体驱动程序来实现。接下来我们来实现当用户对某一个文件进行这6个操作时,虚拟文件系统的具体实现方法:
//打开文件int open(char *path, int oflag, int mode){ vfs_node_s *node = fs_get_node(path); pcb_s *pcb = sche_curr_pcb(); node- >ops.open(); uint32_t ind = fcntl_first_empty(pcb); //申请节点 fcntl_alloc(pcb, ind); pcb- >fnodes[ind] = node; return ind;}//关闭文件int close(int fd){ pcb_s *pcb = sche_curr_pcb(); vfs_node_s *node = pcb- >fnodes[fd]; int ret = node- >ops.close(); pcb- >fnodes[fd] = null; fcntl_free(pcb, fd); return ret;}//读取文件内容size_t read(int fd, void *buf, size_t count){ pcb_s *pcb = sche_curr_pcb(); vfs_node_s *node = pcb- >fnodes[fd]; return node- >ops.read(null, buf, count);}//写入文件内容size_t write(int fd, void *buf, size_t count){ pcb_s *pcb = sche_curr_pcb(); vfs_node_s *node = pcb- >fnodes[fd]; return node- >ops.write(null, buf, count);}//输入输出控制int ioctl(int fd, unsigned int cmd, unsigned long arg){ pcb_s *pcb = sche_curr_pcb(); vfs_node_s *node = pcb- >fnodes[fd]; return node- >ops.ioctl(null, cmd, arg);}//尝试获取资源int poll(int fd, unsigned int ms){ pcb_s *pcb = sche_curr_pcb(); vfs_node_s *node = pcb- >fnodes[fd]; return node- >ops.poll(ms);}最后,我们来具体看一下如何编写一个驱动程序,并将这个驱动程序注册为虚拟文件系统中的一个设备节点,即文件。用户又如何通过通用的操作来实现对此设备的控制。
最简单的,我们可以通过对一个gpio引脚的拉高拉低来实现一个led灯的亮和灭,使用cortex-m3处理下的实现方式有两步,第一步:初始化gpio引脚;第二步:对gpio进行拉高或拉低,从而达到led亮和灭的操作。具体实现程序如下:
rcc_apb2periphclockcmd(rcc_apb2periph_gpioc, enable);gpio_initstructure.gpio_pin = gpio_pin_4;gpio_initstructure.gpio_mode = gpio_mode_out_pp;gpio_initstructure.gpio_speed = gpio_speed_50mhz;gpio_init(gpioc, &gpio_initstructure);接下来,当我们需要点亮led灯时,对pc4引脚拉低;当需要熄灭时,对pc4引脚拉高,于是程序如下:
//点亮,拉低gpio_writebit(gpioc, gpio_pin_4, 0);//熄灭,拉高gpio_writebit(gpioc, gpio_pin_4, 1);对于驱动程序而言,我们不希望用户在使用led时编写较为复杂的、直接操作硬件的代码,而是希望操作系统为用户提供一个通用的操作接口函数,于是我们就可以编写一个驱动程序,并向操作系统注册一个/dev/led设备节点,而/dev/led这个文件就是一个设备文件,它的内部由驱动开发人员完成与硬件交互的功能,对使用人员则只提供open()、close()、read()、write()、ioctl()、poll()等操作函数。对于led灯来说,驱动程序比较简单我们只实现其open()、close()、ioctl()这3个函数。有兴趣的读者可以自行实现read()、write()、poll()等函数:
#define led_ioctl_on (0)#define led_ioctl_off (0)void led_drv_init(void){ file_operations_s ops = {0}; ops.open = led_open; ops.close = led_close; ops.read = null; ops.write = null; ops.ioctl = led_ioctl; ops.poll = null; fs_register_dev(/dev/led, ops);}int led_open(void){ rcc_apb2periphclockcmd(rcc_apb2periph_gpioc, enable); gpio_initstructure.gpio_pin = gpio_pin_4; gpio_initstructure.gpio_mode = gpio_mode_out_pp; gpio_initstructure.gpio_speed = gpio_speed_50mhz; gpio_init(gpioc, &gpio_initstructure); return 0;}int led_close(void){ return 0;}int led_ioctl(void, unsigned int cmd, unsigned long arg){ switch (cmd) { case led_ioctl_on: gpio_writebit(gpioc, gpio_pin_4, 0); break; case led_ioctl_off: gpio_writebit(gpioc, gpio_pin_4, 1); break; default: break; } return 0;}这样我们就编写了一个led灯的驱动程序,并在操作系统中注册为/dev/led设备节点,即文件。用户可以通过以下方式来操作这个led设备:
int fd = open(/dev/led);//点亮ioctl(fd, led_ioctl_on);//熄灭ioctl(fd, led_ioctl_off);close(fd);对于用户而言,操作这个硬件led灯就与操作普通文件一样,通过open()函数打开这个文件,通过ioctl这个函数对这个文件进行相关的控制,使用完毕之后再通过close()函数关闭此文件,于是,硬件与用户之间就减少了很多特定的功能操作,用户也不必关心硬件设备的具体实现细节,只需要对这个设备文件进行通用操作即可。而对于编写驱动程序的人员来说,只需要将硬件相关的程序和操作封装到驱动程序内部即可,无需暴露给用户。这样就实现了“一切皆文件”的设计理念。
谱瑞科技4月营收欠佳 股价创9个月新低
OPPOA59m拆解教程
3DSVSP骨科虚拟手术规划平台已获得FDA许可
NEC电子中国将携全新解决方案亮相AMRChina 2008
应急灯电路图工作原理
文件系统-一切皆文件的设计理念
如何将SAP数据集成到任意云平台
汽车电路的基本接线规律
苹果新获两项汽车专利,涉及增强型车辆态势感知警报系统
凌阳16位MCU一改台湾芯片抗干扰性差软肋,EMC测试达国标
Cellink收购双光子聚合3D打印机厂商Nanoscribe
为汽车行业赋能 科达嘉携车规级电感亮相慕尼黑上海电子展
人脸识别市场竞争激烈 探讨新的商业模式十分重要
CPLD逻辑电路
中国半导体技术新突破,成功研发3纳米晶体管
厂家直销8路电话录音卡 8路电话录音板卡 PCI插槽 录音系
开发本该如此高效!动手实操指南奉上
AMD新显卡曝光 性能可达到RTX 2080 Ti级别
TE Connectivity联手贸泽电子推出全新电子书 深入探讨车队远程信息处理的设计注意事项
艾迈斯得通过取消中止协议发起针对欧司朗的收购要约 并宣布拟每股38.50欧元的价格收购欧司朗