以前老大老是教我说proc文件其实就是内存中的文件。其实是linux提供的一个内核借口,可以方便的让用户和linux内核进行通讯的一种方式。 很多内核程序也都使用了这个功能,想你运行 cat /proc/cpuinfo查看cpu信息或者cat /proc/version查看系统版本的时候,都是用到了这个功能。
widebright@widebright-desktop:~$ cat /proc/cpuinfo
widebright@widebright-desktop:~$ cat /proc/version
Linux version 2.6.24-18-generic (buildd@terranova) (gcc version 4.2.3 (Ubuntu 4.2.3-2ubuntu7)) #1 SMP Wed May 28 20:27:26 UTC 2008
我刚好看到篇相关的文章,就试了一下,你也很想知道这种功能是怎么实现的吧。
在我上次的那个hello world 的简单驱动 的例子上修改一下
--------- hello.c文件内容-------------
#include <linux/module.h> /* module */
#include <linux/kernel.h> /* 内核 */
#include <linux/proc_fs.h> /* proc 文件系统必须的*/
#define procfs_name "widebright" /*这样定义之后,最后的文件就是 /proc/widebright */
/**
* 这个结构是用来定义 /proc 文件的
*
*/
struct proc_dir_entry *Our_Proc_File;
/* 如果用户想读我们定义的proc文件,这个函数将得到调用.
*
* 参数说明
* =========
* 1. 要写东西进去的缓存区
* 2. 字符串的指针的指针. 如果你不想使用内核分配的缓存,这个也许是有用的
*
* 3. 现在的文件偏移位置,就是文件指针位置
* 4. 第一个参数指定的缓存区的大小
* 5. 向这里写入 "1" 表示 EOF.
* 6. 指想一块数据的指针 (如果一个read操作同时读写多个 /proc 文件的
* 时候有用
*
* 函数的返回值
* ======================
* 返回 0 表示文件已经读到末尾 (end of file)
* 返回 负数 表示错误发生
*
* 更多信息
* ====================
* 在内核源代码的以下位置有个使用的例子
<kernel source
* directory>/fs/proc/array.c.
*
* 在linux 环境下可以方便是使用grep来直接查看源代码,如果我们不确定某些
* 东西如何使用的华,开源就是方便
*/
int
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called/n", procfs_name);
/*
* 这里我们把所有的数据,一次性的写入缓存空间了。
* 所以用户读操作的时候最多只能读一次了。
* 注意:一定要在某个时候返回0,不然系统的读操作,会一直读
* 下去,无限的循环下去就会出错。
*/
if (offset > 0) {
/* 完成搜索数据的写入了, 返回 0 */
ret = 0;
} else {
/* 填充缓冲区,返回写入的内容长度 */
ret = sprintf(buffer, "widebright is here ,haha!/n");
}
return ret;
}
/*
int procfile_write(struct file *file, const char *buffer, unsigned long count,
void *data)
{
获取缓存大小
procfs_buffer_size = count;
if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
procfs_buffer_size = PROCFS_MAX_SIZE;
}
复制数据
if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
return -EFAULT;
}
return procfs_buffer_size;
}
*/
int init_module()
{
Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, &proc_root);
printk(KERN_ALERT "Error: Could not initialize /proc/%s/n",
procfs_name);
return -ENOMEM;
}
/*如果你想出来用户写入的数据,还可以设置Our_Proc_File->write_proc 项*/
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "/proc/%s created/n", procfs_name);
return 0; /* everything is ok */
}
void cleanup_module()
{
remove_proc_entry(procfs_name, &proc_root);
printk(KERN_INFO "/proc/%s removed/n", procfs_name);
}
-----Makefile 文件内容-----------------
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
------------------------------
编译和测试:
root@widebright-desktop:/home/widebright/桌面/驱动学习# make
make -C /lib/modules/2.6.24-18-generic/build M=/home/widebright/桌面/驱动学习 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.24-18-generic'
CC [M] /home/widebright/桌面/驱动学习/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/widebright/桌面/驱动学习/hello.mod.o
LD [M] /home/widebright/桌面/驱动学习/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.24-18-generic'
widebright@widebright-desktop:~/桌面/驱动学习$ su root
口令:
root@widebright-desktop:/home/widebright/桌面/驱动学习# insmod hello.ko
root@widebright-desktop:/home/widebright/桌面/驱动学习# ls /proc
1 4092 4558 4974 5044 7351 fs self
118 41 4560 4978 5048 7383 interrupts slabinfo
119 4137 4567 4983 5049 7653 iomem stat
120 4205 4606 4988 5053 7654 ioports swaps
1364 4253 4615 4991 5054 7876 irq sys
1368 4255 4616 4997 5061 84 kallsyms sysrq-trigger
1375 4277 4627 4998 5064 acpi kcore sysvipc
1378 4293 4630 5 5067 buddyinfo key-users timer_list
161 4307 4633 5000 5072 bus kmsg timer_stats
2 4320 4675 5006 5074 cgroups loadavg tty
2298 4340 4676 5009 5102 cmdline locks uptime
2502 4341 4679 5012 5111 cpuinfo meminfo version
2706 4380 4685 5018 5114 crypto misc version_signature
3 44 4740 5020 5124 devices modules vmcore
3916 4454 4754 5023 6 diskstats mounts vmstat
3917 4473 4835 5026 7 dma net widebright
3922 4476 4914 5030 7058 driver pagetypeinfo zoneinfo
3925 4477 4916 5034 7328 execdomains partitions
3927 45 4917 5038 7330 fb sched_debug
4 4549 4966 5039 7331 filesystems scsi
可以看到/proc目录下已经有 widebright 这个文件了,
root@widebright-desktop:/home/widebright/桌面/驱动学习# cat /proc/widebright
widebright is here ,haha!
root@widebright-desktop:/home/widebright/桌面/驱动学习# rmmod hello.ko
初始代码是从
The Linux Kernel Module Programming Guide http://linux.die.net/lkmpg/
复制过来的。
关于proc文件系统的更多信息,你也可以参考那里。
那是个linux 内核学习的文档,还讲到了其他内容,初学linux内核的人可以看一下,写的蛮好的!