proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。它的目录结构包括普通常用目录和数字命名目录:
(1) 用户如果要查看系统信息,可以用cat命令。例如:# cat /proc/interrupts 。
apm :高级电源管理信息
cmdline :内核命令行
Cpuinfo :关于Cpu信息
Devices :可以用到的设备(块设备/字符设备),可通过cat /proc/devices得到主设备号和设备名
Dma :使用的DMA通道
Filesystems :支持的文件系统
Interrupts :中断的使用
Ioports I/O:端口的使用
Kcore :内核核心印象
Kmsg :内核消息
Ksyms :内核符号表
Loadavg :负载均衡
Locks :内核锁
Meminfo :内存信息
Misc :杂项
Modules :加载模块列表
Mounts :加载的文件系统
Partitions :系统识别的分区表
Rtc :实时时钟
Slabinfo Slab:池信息
Stat :全面统计状态表
Swaps :对换空间的利用情况
Version :内核版本
Uptime :系统正常运行时间
并不是所有这些目录在你的系统中都有,这取决于你的内核配置和装载的模块。另外,在/proc下还有三个很重要的目录:net,scsi和sys。 Sys目录是可写的,可以通过它来访问或修改内核的参数来优化你的系统。但是你必须很小心,因为可能会造成系统崩溃。而net和scsi则依赖于内核配置。例如,如果系统不支持scsi,则scsi 目录不存在。
(2)除了以上介绍的这些,还有的是一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的 PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。Proc文件系统的名字就是由之而起。每个进程目录的结构如下:
目录名称 目录内容
Cmdline 命令行参数
Environ 环境变量值
Fd 一个包含所有文件描述符的目录
Mem 进程的内存被利用情况
Stat 进程状态
Status 进程当前状态,以可读的方式显示出来
Cwd 当前工作目录的链接
Exe 指向该进程的执行命令文件
Maps 内存映象
Statm 进程内存状态信息
Root 链接此进程的root目录
(3)正因为采用PROC可以访问linux的内核设备信息,可以采用此种方式在线调试LCM。
A,首先在帧缓冲驱动中创建proc文件系统。头文件申明:
#define LCM_ONLINE_TUNNING #if defined (LCM_ONLINE_TUNNING) #include <linux/proc_fs.h> //proc file use #endif
B,外部申明Proc的读写函数
#if defined (LCM_ONLINE_TUNNING) extern int LCM_HW_DumpReg_To_Proc(char *page, char **start, off_t off,int count, int *eof, void *data); extern int LCM_HW_Reg_Debug( struct file *file, const char *buffer, unsigned long count,void *data); #endif
C,在帧缓冲的PROBE函数中,创建PROC。
#if defined (LCM_ONLINE_TUNNING) struct proc_dir_entry *prEntry; prEntry = create_proc_entry("driver/lcm", 0, NULL); //在/proc创建路径 if (prEntry) { prEntry->read_proc = LCM_HW_DumpReg_To_Proc; prEntry->write_proc = LCM_HW_Reg_Debug; } else { printk("add /proc/driver/lcm entry fail \n"); } #endif
D,在AP显示驱动中添加读写函数原型
#define LCM_ONLINE_TUNNING #if defined (LCM_ONLINE_TUNNING) #include <linux/uaccess.h> #endif
E,proc写函数原型
#if defined (LCM_ONLINE_TUNNING) int LCM_HW_DumpReg_To_Proc(char *page, char **start, off_t off,int count, int *eof, void *data) { return count; } int LCM_HW_Reg_Debug( struct file *file, const char *buffer, unsigned long count,void *data) { char regBuf[512] = {'\0'} ; char temp[256]={0}; u32 u4CopyBufSize = (count < (sizeof(regBuf) - 1)) ? (count) : (sizeof(regBuf) - 1); unsigned int RegAddr; unsigned int RegData[256]; char *p = regBuf; int i = 0,param_count = 0; if (copy_from_user(regBuf, buffer, u4CopyBufSize)) //读入echo的字符串 return -EFAULT; printk("param : %s\n",regBuf); //打印echo的字符串 sscanf(regBuf, "%2s", temp) ; //取regBuf的头两个字符存于temp中 sscanf(temp, "%0x", &RegAddr); //格式化字符串的头两个字符,转成寄存器地址 printk("cmd index : %0x",RegAddr); while((p = strchr(p,' ')) !=NULL) { //依次导入该地址要写入的数据 p++; sscanf(p, "%2s", temp); sscanf(temp, "%0x", &RegData[i]); printk("Cmd data : %0x",RegData[i]); i++; param_count++; } i = 0; printk("param count : %d\n",param_count); lcm_utils.send_cmd(RegAddr) ; //调用地址写入函数 while(i < param_count) { lcm_utils.send_data(RegData[i]) ; //调用数据写入函数 i++; } return count; } #endif
F,调试语句:
如下,连上ADB后,可以单行调试,也可以一次写入多行。第一个是寄存器地址,后面的则是参数。
echo "f1 36 04 00 3c 0f 8f" > /proc/driver/lcm
echo "f2 18 A3 12 02 72 32 FF 12 00" > /proc/driver/lcm
echo "f8 21 04" > /proc/driver/lcm
echo "f9 00 08" > /proc/driver/lcm
echo "36 48" > /proc/driver/lcm
echo "b4 02" > /proc/driver/lcm
G,DSI的写语句:
以上是DBI的在线调试方法,如果是DSI接口的,则用下面的语句把最后的发送指令及while循环替换掉即可。
lcm_utils.dsi_set_cmdq_V2(RegAddr,param_count,RegData,1);
(4)dmesg也可用来查看内核信息,一般用来显示开机信息,kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。另一个用途是查看insmod的打印消息。
=================================================================================================
EXPORT_SYMBOL的一个用法,仅针对module。在MTK的编译系统中,不同驱动之间互相引用变量,直接跟普通C一样采用extern申明就可以访问。但是如果某个模块编译采用的是make中的oby+m,而不是默认的obj-y,这种引用变量的方式编译会出错。
EXPORT_SYMBOL既可以用来导出模块函数,也可以导出模块变量。举一个简单的模块变量的用法:
hello.c:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); int symbol_lxp = 123; EXPORT_SYMBOL(symbol_lxp); static int hello_init(void) { printk(KERN_ALERT "Hello, World!\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world!\n"); } module_init(hello_init); module_exit(hello_exit);
hello2.c:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); extern int symbol_lxp; static int hello2_init(void) { printk(KERN_ALERT "Hello2, World!\n"); printk("symbol_lxp defined in hello.ko: symbol_lxp = %d\n", symbol_lxp); return 0; } static void hello2_exit(void) { printk(KERN_ALERT "Goodbye2, cruel world!\n"); } module_init(hello2_init); module_exit(hello2_exit);
运行结果:在hello2.ko中可以使用hello.ko中导出的变量
[root@(none)/mnt]#insmod hello.ko
Hello, World!
[root@(none)/mnt]#insmod hello2.ko
Hello2, World!
symbol_lxp defined in hello.ko: symbol_lxp = 123
参考原文:http://blog.csdn.net/xiangpingli/article/details/7917931