2008年9月10日星期三

在procfs里添加可读写文件做调试

procfs可以查看内核信息,不过我刚开始做的时候还不知道procfs里的文件可以写。一旦可以写了,就有方便我们的调试接口,嗯,那么留在这里,忘了的时候看看。sysfs其实更好一些,以后再写一个sysfs的好了
做的是pcf50606寄存器读写接口文件

1>
在procfs的根目录下注册pcf目录/proc/pcf
static struct proc_dir_entry *pcfdir;
#define PCF_DIRNAME "pcf"
pcfdir = proc_mkdir( PCF_DIRNAME, &proc_root);
if ( pcfdir == NULL )
{
PMIC_PRINT(KERN_ERR "can't create /proc/" PCF_DIRNAME "\n");
return ;
}

2>
在/proc/pcf下建立pcf50606所有寄存器读写文件,比如/proc/pcf/ID
typedef struct pcf50606_reg_entry
{
u8 addr;
char *name;
unsigned short low_ino;
} pcf50606_reg_entry_t;

static pcf50606_reg_entry_t pcf50606_regs[] = {
{ 0x00 , "ID" },
{ 0x01 , "OOCS" },
{ 0x02 , "INT1" },
{ 0x03 , "INT2" },
{ 0x04 , "INT3" },
...
};

//读写处理函数
static struct file_operations proc_reg_operations = {
read: proc_read_reg,
write: proc_write_reg
};

//建立文件时把读写处理函数挂上
#define NUM_OF_PCF50606_REG_ENTRY ( sizeof(pcf50606_regs) / sizeof(pcf50606_reg_entry_t))
for ( i = 0 ; i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
entry = create_proc_entry( pcf50606_regs[i].name,
S_IWUSR S_IRUSR S_IRGRP S_IROTH, pcfdir );
if (entry) {
pcf50606_regs[i].low_ino = entry->low_ino; //把文件inode赋值给pcf变量,读写时根据inode判断是哪个
entry->proc_fops = &proc_reg_operations;
} else {
#define PMIC_PRINT(fmt, args...) printk("%s%s(): "fmt"", "[PCF50606] ",__FUNCTION__, ##args)
PMIC_PRINT( KERN_ERR "can't create /proc/" PCF_DIRNAME );
return ;
}
}

3>
创建读写处理函数
static ssize_t proc_read_reg( struct file *file, char *buf, size_t nbytes, loff_t *ppos )
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
int i, count;
char outputbuf[15];
u8 addr = 0;

if (*ppos > 0 )
return 0;

//根据注册文件时对应的inode来确定到底那个文件名对应哪个寄存器,读写都这样
for ( i =0 ;i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
if ( pcf50606_regs[i].low_ino == i_ino ) {
addr = pcf50606_regs[i].addr;
break;
}
}

if ( i == NUM_OF_PCF50606_REG_ENTRY )
return -EINVAL;

//ul转字符串
count = sprintf(outputbuf, "0x%02x\n", readPCFregister(addr));
*ppos += count;
if (count > nbytes )
return -EINVAL;
if (copy_to_user(buf, outputbuf, count))
return -EFAULT;
return count;
}

static ssize_t proc_write_reg( struct file *file, const char *buf, size_t count, loff_t *ppos )
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
int i;
char *endp;
u8 addr = 0;

for ( i = 0 ; i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
if ( pcf50606_regs[i].low_ino == i_ino ) {
addr = pcf50606_regs[i].addr;
break;
}
}
if ( i == NUM_OF_PCF50606_REG_ENTRY )
return -EINVAL;

//字符串转ul
writePCFregister( addr, simple_strtoul( buf, &endp, 0));
return ( count+endp-buf );
}

4>
在procfs中读写文件
cd /proc/pcf/ 到pcf目录
ll 列出所有寄存器名
cat * 列出所有寄存器值
或者单独的cat ID,显示ID寄存器值
echo 1 > ID 写ID寄存器,>左右有空格,1作为字符串传进去

除了这种多个文件公用一个读写函数的读写寄存器的接口,单独建立读写文件当然会更简单,比如常用的打印变量。在procfs里动态改变这个全局变量,而达到屏蔽/放开不同模块的信息,而不需要重新编译来开关打印宏。

没有评论: