PROC介绍,和PROC在线调试LCM以及dmesg && EXPORT_SYMBOL的用法

来源:互联网 发布:apache tomcat 闪退 编辑:程序博客网 时间:2024/06/11 12:07

      proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。它的目录结构包括普通常用目录和数字命名目录:

(1) 用户如果要查看系统信息,可以用cat命令。例如:# cat /proc/interrupts 。

cmdline :内核命令行

Cpuinfo :关于Cpu信息

Devices :可以用到的设备(块设备/字符设备),可通过cat /proc/devices得到主设备号和设备名 

Filesystems :支持的文件系统

Interrupts :中断的使用

Ioports I/O:端口的使用

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

原创粉丝点击