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

      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

你可能感兴趣的:(struct,File,cmd,buffer,filesystems)