使用proc文件系统能够非常方便调试驱动。查看驱动中的一些数据

平台:TQ2440

系统版本号:

root@ubuntu:/mnt/shared/kobox# uname -a

Linux ubuntu 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:12:00 UTC 2013 i686 i686 i686 GNU/Linux

事实上在3.x中创建proc文件系统和在2.x中创建是有所差别的,这里须要注意下。在2.6.x中创建起来更加方便

这里是在3.x的内核中创建proc文件的方法

功能:

/proc/key_drv写操作:

这里使用proc文件系统查看TQ2440各按键被按的次数

echo 'a' > /proc/key_drv -- 查看全部按键状态

echo '0' > /proc/key_drv -- 查看key1按键状态 

...

echo 'h' > /proc/key_drv -- 打印帮助

/proc/key_drv读操作:

cat /proc/key_drv -- 查看TQ2440各按键被按的次数

(一)运行结果:

[\u@\h \W]# echo '0'> /proc/key_drv 

key_num:0

key:[key1], pressCnt:3

[\u@\h \W]# echo '1'> /proc/key_drv 

key_num:1

key:[key2], pressCnt:4

[\u@\h \W]# echo '2'> /proc/key_drv 

key_num:2

key:[key3], pressCnt:6

[\u@\h \W]# echo '3'> /proc/key_drv 

key_num:3

key:[key4], pressCnt:0

[\u@\h \W]# echo 'a'> /proc/key_drv 

key_num:a

pressCnt[i]:0

pressCnt[i]:1

pressCnt[i]:2

pressCnt[i]:3

[\u@\h \W]# echo 'h'> /proc/key_drv 

key_num:h

/proc/key_drv help:

echo a > /proc/key_drv -- get all keys' pressCnt!

echo i(0~3) > /proc/key_drv -- get all key[i+1]'s pressCnt!

echo h > /proc/key_drv -- usage help!

(二) proc文件系统的创建:

static int key_drv_proc_show(struct seq_file *m, void *v)
{
int i; read_lock(&key_drv_proc_lock); for(i=0; i<ARRAY_SIZE(key_gpio_res); i++)
{
seq_printf(m, "name:[%s], count:[%d]\n",
key_gpio_res[i].irqName,
pressCnt[i]);
} read_unlock(&key_drv_proc_lock); return 0;
} static int key_drv_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, key_drv_proc_show, NULL);
} static void key_drv_proc_help(void)
{
printk("/proc/key_drv help:\n"
"echo a > /proc/key_drv -- get all keys' pressCnt!\n"
"echo i(0~3) > /proc/key_drv -- get all key[i+1]'s pressCnt!\n"
"echo h > /proc/key_drv -- usage help!\n"
);
return;
} static ssize_t key_drv_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
char mode;
char key_num;
int i; if (count > 0) {
if (get_user(key_num, buffer))
return -EFAULT; printk("key_num:%c\n", key_num); switch(key_num)
{
case 'a':
for(i=0; i<ARRAY_SIZE(pressCnt); i++)
{
printk("pressCnt[i]:%d\n", i, pressCnt[i]);
}
break; case '0':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[0].irqName,pressCnt[0]);
break; case '1':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[1].irqName,pressCnt[1]);
break; case '2':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[2].irqName,pressCnt[2]);
break; case '3':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[3].irqName,pressCnt[3]);
break; case 'h':
default:
key_drv_proc_help();
return -1;
}
}
return count;
} static const struct file_operations key_drv_fops = {
.open = key_drv_proc_open,
.read =seq_read,
.write = key_drv_proc_write,
.release = single_release,
}; static int key_proc_file_init(void)
{
proc_create("key_drv", 0, NULL, &key_drv_fops);
return 0;
} key_proc_file_init();

(三)key_proc.c所有源代码

#include "key.h"
#include <linux/seq_file.h> #define S3C_ADDR_BASE 0xF6000000
//#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#define S3C2410_PA_UART (0x50000000)
#define S3C2410_PA_GPIO (0x56000000)
#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */
#define S3C24XX_PA_UART S3C2410_PA_UART
#define S3C24XX_VA_UART S3C_VA_UART
#define S3C24XX_PA_GPIO S3C2410_PA_GPIO
#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART) #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) #define S3C2410_GPBCON S3C2410_GPIOREG(0x10)
#define S3C2410_GPBDAT S3C2410_GPIOREG(0x14)
#define S3C2410_GPBUP S3C2410_GPIOREG(0x18) #define S3C2410_GPFCON S3C2410_GPIOREG(0x50)
#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54)
#define S3C2410_GPFUP S3C2410_GPIOREG(0x58) #define S3C2410_EXTINT0 S3C2410_GPIOREG(0x88)
#define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C)
#define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90) #define S3C2410_CPUIRQ_OFFSET (16)
#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
/* main cpu interrupts */
#define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */
#define IRQ_EINT1 S3C2410_IRQ(1) /* 17 */
#define IRQ_EINT2 S3C2410_IRQ(2) /* 18 */
#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */
#define IRQ_EINT4 S3C2410_IRQ(36) /* 52 */ #define IRQF_DISABLED 0x00000020
#define IRQF_SHARED 0x00000080
#define IRQF_PROBE_SHARED 0x00000100
#define __IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
#define IRQF_IRQPOLL 0x00001000
#define IRQF_ONESHOT 0x00002000
#define IRQF_NO_SUSPEND 0x00004000
#define IRQF_FORCE_RESUME 0x00008000
#define IRQF_NO_THREAD 0x00010000
#define IRQF_EARLY_RESUME 0x00020000 typedef struct gpioRes
{
int irqNum; /* 中断号 */
unsigned int ctrlReg; /* 控制寄存器,用于设置复用为GPIO */
unsigned int ctrlBit; /* 控制寄存器的哪一位,用于复用为GPIO */
unsigned int trigReg; /* 中断方式寄存器,设置中断的触发方式 */
unsigned int trigBit; /* 中断方式寄存器哪一位。设置中断的触发方式 */
unsigned int irqFlag; /* 共享还是不共享,注冊中断的flag */
char irqName[32]; /* 中断名称 */
unsigned int gpfPin; /* GPF的第几个pin */
char Reserved[10]; /* 保留 */
}gpioRes; unsigned int pressCnt[4] = {0, 0, 0, 0}; //#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) static int kobox_key_open(struct inode *inode, struct file *file)
{
return 0;
} static int kobox_key_release(struct inode *inode, struct file *file)
{
return 0;
} static long kobox_key_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return 0;
} static int kobox_key_read(struct file *file, char __user *buff, size_t count, loff_t *pos)
{
printk("Enter [%s][%d]\n", __FUNCTION__,__LINE__);
copy_to_user(buff, &pressCnt[0], sizeof(pressCnt)); return 0;
} /*
GPF相关寄存器: GPFCON 0x56000050 R/W Configures the pins of port F 0x0
GPFDAT 0x56000054 R/W The data register for port F Undef.
GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000 K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input 01 = Output 10 = EINT[1] 11 = Reserved
K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input 01 = Output 10 = EINT[4] 11 = Reserved
K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input 01 = Output 10 = EINT2] 11 = Reserved
K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input 01 = Output 10 = EINT[0] 11 = Reserved
*/ gpioRes key_gpio_res[4] =
{
{IRQ_EINT1, S3C2410_GPFCON, 2, S3C2410_EXTINT0, 5, NULL, "key1", 1}, /* key1 */
{IRQ_EINT4, S3C2410_GPFCON, 8, S3C2410_EXTINT0, 17, IRQF_SHARED, "key2", 4}, /* key2 */
{IRQ_EINT2, S3C2410_GPFCON, 4, S3C2410_EXTINT0, 9, NULL, "key3", 2}, /* key3 */
{IRQ_EINT0, S3C2410_GPFCON, 0, S3C2410_EXTINT0, 1, NULL, "key4", 0}, /* key4 */
}; #define KEY_TIMER_DELAY1 (HZ/50) //按键按下去抖延时20毫秒
#define KEY_TIMER_DELAY2 (HZ/10) //按键抬起去抖延时100毫秒
#define KEY_COUNT 4
static struct timer_list key_timers[KEY_COUNT]; //定义4个按键去抖动定时器
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //定义并初始化等待队列 static void set_gpio_as_eint(void)
{
int i;
unsigned uiVal = 0; for(i=0; i< ARRAY_SIZE(key_gpio_res); i++)
{
uiVal = readl(key_gpio_res[i].ctrlReg);
uiVal &= ~(0x01 << key_gpio_res[i].ctrlBit);
uiVal |= (0x01 << (key_gpio_res[i].ctrlBit + 1));
writel(uiVal, key_gpio_res[i].ctrlReg);
} return;
} static void set_gpio_as_gpio(void)
{
int i;
unsigned uiVal = 0; for(i=0; i< ARRAY_SIZE(key_gpio_res); i++)
{
uiVal = readl(key_gpio_res[i].ctrlReg);
uiVal &= ~(0x01 << key_gpio_res[i].ctrlBit);
uiVal &= ~(0x01 << (key_gpio_res[i].ctrlBit + 1));
writel(uiVal, key_gpio_res[i].ctrlReg);
} return;
} static irqreturn_t kobox_gpio_irq_handle(int irq, void *dev_id)
{
int key; disable_irq_nosync(irq); printk("irq = %d\n", irq); if(dev_id)
printk("dev_id:%s\n", dev_id); switch(irq)
{
case IRQ_EINT1:
key = 0;
break;
case IRQ_EINT4:
key = 1;
break;
case IRQ_EINT2:
key = 2;
break;
case IRQ_EINT0:
key = 3;
break;
default:
printk("invalid irq:%d\n", irq);
return IRQ_HANDLED;
} /* 去抖:延时100ms后,在buttons_timer中读取按键状态。假设还是按下的。就说明是被正常按下的
使用timer是一种方式。后面再採用工作队列、tasklet中的方式来处理 */
mod_timer(&key_timers[key], jiffies + KEY_TIMER_DELAY2); enable_irq(irq); return IRQ_RETVAL(IRQ_HANDLED);
} /*
GPF相关寄存器: GPFCON 0x56000050 R/W Configures the pins of port F 0x0
GPFDAT 0x56000054 R/W The data register for port F Undef.
GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000 K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input 01 = Output 10 = EINT[1] 11 = Reserved
K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input 01 = Output 10 = EINT[4] 11 = Reserved
K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input 01 = Output 10 = EINT2] 11 = Reserved
K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input 01 = Output 10 = EINT[0] 11 = Reserved
*/
/* 该函数返回0表示按键被按下。返回非0表示没有再被按下,觉得这是电平毛刺导致的,是噪声信号
所以。该函数返回0,表示有按键被按下,返回非0表示是抖动 */
static int get_gpio_portf_value(unsigned int pin)
{
int ret;
unsigned int uiVal = 0; printk("I AM @ [%s][%d], pin:%d\n", __FUNCTION__,__LINE__, pin); uiVal = readl(S3C2410_GPFDAT);
ret = (0x1 << pin) & uiVal; printk("I AM @ [%s][%d], ret:%d\n", __FUNCTION__,__LINE__, ret); return ret;
} /* 去抖:中断中设置定时器100ms,在buttons_timer中读取按键状态,假设还是按下的,就说明是被正常按下的 */
static void buttons_timer(unsigned long arg)
{
int ret;
unsigned int pin; /* 中断后100ms才会导致。运行该函数 */
printk("i am at [%s][%d], arg:%d\n", __FUNCTION__, __LINE__, arg); pin = key_gpio_res[arg].gpfPin; /* 将引脚由EINTX设置会GPIO */
set_gpio_as_gpio(); /* 读取相应引脚GPIO的值,返回0表示按键真正被按下。返回1表示抖动 */
ret = get_gpio_portf_value(pin);
if(0 == ret)
{
pressCnt[arg]++;
printk("key%d pressed: pressCnt[arg]:%d\n", arg, pressCnt[arg]);
} /* 将引脚设置回EINTX */
set_gpio_as_eint(); return;
} static int request_irq_for_gpio(void)
{
int i;
int ret;
unsigned uiVal;
int nouse; for(i=0; i<ARRAY_SIZE(key_gpio_res);i++)
{
/* 设置中断触发方式:下降沿有效,触发中断,以便依据GPIO的值来推断是否仍在按下 */
uiVal = readl(key_gpio_res[i].trigReg);
uiVal |= (0x1 << (key_gpio_res[i].trigBit));
uiVal &= ~(0x1 << (key_gpio_res[i].trigBit + 1));
writel(uiVal, key_gpio_res[i].trigReg); /* 注冊中断 */
ret = request_irq(key_gpio_res[i].irqNum,
kobox_gpio_irq_handle,
key_gpio_res[i].irqFlag,
key_gpio_res[i].irqName,
(void *)key_gpio_res[i].irqName);
if(ret)
printk("[func:%s][line:%d] request_irq failed, ret:%d!\n", __FUNCTION__,__LINE__,ret);
else
printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __FUNCTION__,__LINE__, key_gpio_res[i].irqNum); /* 初始化定时器,后面用于去抖动 */
setup_timer(&key_timers[i], buttons_timer, i);
key_timers[i].expires = jiffies + KEY_TIMER_DELAY1*i;
add_timer(&key_timers[i]);
} return 0;
} struct file_operations kobox_key_operations = {
.owner = THIS_MODULE,
.open = kobox_key_open,
.read = kobox_key_read,
.release = kobox_key_release,
.unlocked_ioctl = kobox_key_ioctl,
}; static DEFINE_RWLOCK(key_drv_proc_lock);
extern int seq_printf(struct seq_file *m, const char *f, ...); static int key_drv_proc_show(struct seq_file *m, void *v)
{
int i; read_lock(&key_drv_proc_lock); for(i=0; i<ARRAY_SIZE(key_gpio_res); i++)
{
seq_printf(m, "name:[%s], count:[%d]\n",
key_gpio_res[i].irqName,
pressCnt[i]);
} read_unlock(&key_drv_proc_lock); return 0;
} static int key_drv_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, key_drv_proc_show, NULL);
} static void key_drv_proc_help(void)
{
printk("/proc/key_drv help:\n"
"echo a > /proc/key_drv -- get all keys' pressCnt!\n"
"echo i(0~3) > /proc/key_drv -- get all key[i+1]'s pressCnt!\n"
"echo h > /proc/key_drv -- usage help!\n"
);
return;
} static ssize_t key_drv_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
char mode;
char key_num;
int i; if (count > 0) {
if (get_user(key_num, buffer))
return -EFAULT; printk("key_num:%c\n", key_num); switch(key_num)
{
case 'a':
for(i=0; i<ARRAY_SIZE(pressCnt); i++)
{
printk("pressCnt[i]:%d\n", i, pressCnt[i]);
}
break; case '0':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[0].irqName,pressCnt[0]);
break; case '1':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[1].irqName,pressCnt[1]);
break; case '2':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[2].irqName,pressCnt[2]);
break; case '3':
printk("key:[%s], pressCnt:%d\n", key_gpio_res[3].irqName,pressCnt[3]);
break; case 'h':
default:
key_drv_proc_help();
return -1;
}
}
return count;
} static const struct file_operations key_drv_fops = {
.open = key_drv_proc_open,
.read =seq_read,
.write = key_drv_proc_write,
.release = single_release,
}; static int key_proc_file_init(void)
{
proc_create("key_drv", 0, NULL, &key_drv_fops);
return 0;
} //GPB0
int major;
int minor;
struct cdev cdev;
struct class *kobox_key_class;
struct device *pstdev = NULL;
#define GPIO_KEY_NAME "kobox_key" int __init key_drv_init(void)
{
int error;
dev_t dev; printk("#####enter key_drv_init!\n"); major = register_chrdev(0, GPIO_KEY_NAME, &kobox_key_operations);
if (major < 0)
{
printk(" can't register major number\n");
return major;
} /* create class */
kobox_key_class = class_create(THIS_MODULE, GPIO_KEY_NAME);
if(IS_ERR(kobox_key_class))
{
printk("class_create failed!\n");
goto fail;
} /* create /dev/kobox_gpio */
pstdev = device_create(kobox_key_class, NULL, MKDEV(major, 0), NULL, GPIO_KEY_NAME);
if(!pstdev)
{
printk("device_create failed!\n");
goto fail1;
} /* set gpf0/1/2/4 as extern interrupt pins */
set_gpio_as_eint(); request_irq_for_gpio(); /* create proc files */
key_proc_file_init(); printk("#####key_drv_init ok!\n"); return 0;
fail1:
class_destroy(kobox_key_class);
fail:
unregister_chrdev(major, GPIO_KEY_NAME);
return -1;
} void __exit key_drv_exit(void)
{
printk("exit gpio drv!\n"); device_destroy(kobox_key_class, MKDEV(major, 0));
class_destroy(kobox_key_class);
unregister_chrdev(major, GPIO_KEY_NAME); return;
} module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

kobox: key_proc.c -v1 怎样使用proc文件系统调试驱动的更多相关文章

  1. linux 使用/proc文件系统 实现用户空间与内核模块之间通信

    项目中可能会用到用户态和内核模块之间进行通信的功能.想到linux系统本身很多通信都是通过/proc文件系统来的,比如修改网络中连接跟踪表连接数限制/proc/sys/net/netfilter/nf ...

  2. proc文件系统

    在shell终端里不带任何参数,直接运行mount命令可以显示正在挂载的文件系统.其中有这么一行 none on /proc type proc (rw) 这就是/proc文件系统.第一个域显示non ...

  3. proc文件系统在内核中的表现

    当Linux内核启动起来之后,我们可以通过proc虚拟文件系统来查看内的中的一些动态信息. 例如:可以 cat  /proc/misc  来查看系统中装载的所有misc类设备 cat  /proc/d ...

  4. 使用 /proc 文件系统来访问 linux操作系统 内核的内容 && 虚拟文件系统vfs及proc详解

    http://blog.163.com/he_junwei/blog/static/19793764620152743325659/ http://www.01yun.com/other/201304 ...

  5. <解说linux下proc文件系统>

    proc文件系统的作用是访问系统内核信息 proc不是一个真实的文件系统,它不占系统的外存空间,只是以文件的形式为用户访问linux内核数据提供接口,因为系统内核总是动态的变化,所以我们所捕捉到的也只 ...

  6. (转)使用 /proc 文件系统来访问 Linux 内核的内容

    转载网址:http://www.ibm.com/developerworks/cn/linux/l-proc.html 这个虚拟文件系统在内核空间和用户空间之间打开了一个通信窗口/proc 文件系统是 ...

  7. linux中proc文件系统 -- ldd3读书笔记

    1./proc 文件系统概述 /proc 文件系统是由软件创建,被内核用来向外界报告信息的一个文件系统./proc 下面的每一个文件都和一个内核函数相关联,当文件的被读取时,与之对应的内核函数用于产生 ...

  8. 在/proc文件系统中增加一个目录hello,并在这个目录中增加一个文件world,文件的内容为hello world

    一.题目 编写一个内核模块,在/proc文件系统中增加一个目录hello,并在这个目录中增加一个文件world,文件的内容为hello world.内核版本要求2.6.18 二.实验环境 物理主机:w ...

  9. linux kernel (proc文件系统)参数

    http://blog.csdn.net/guowake/article/details/3279796 Linux Proc文件系统,通过对Proc文件系统进行调整,达到性能优化的目的. 二./pr ...

随机推荐

  1. SpringBoot优化内嵌的Tomcat

    SpringBoot测试版本 <parent> <groupId>org.springframework.boot</groupId> <artifactId ...

  2. hdu 4497 GCD and LCM 质因素分解+排列组合or容斥原理

    //昨天把一个i写成1了 然后挂了一下午 首先进行质因数分解g=a1^b1+a2^b2...... l=a1^b1'+a2^b2'.......,然后判断两种不可行情况:1,g的分解式中有l的分解式中 ...

  3. 采用dlopen、dlsym、dlclose加载动态链接库【总结】

    摘自http://www.cnblogs.com/Anker/p/3746802.html 采用dlopen.dlsym.dlclose加载动态链接库[总结]   1.前言 为了使程序方便扩展,具备通 ...

  4. Centos下需安装Pytnon,Pytharm

    1.在www.python.org/PIPY/下载python3.4.2.tar.gz 2.在安装之前最好先安装相关的开发工具 # yum groupinstall develtools # yum ...

  5. .NET委托:一个关于C#的睡前故事 【转】

    紧耦合 从前,在南方一块奇异的土地上,有个工人名叫彼得,他非常勤奋,对他的老板总是百依百顺.但是他的老板是个吝啬的人,从不信任别人,坚决要求随时知道彼得的工作进度,以防止他偷懒.但是彼得又不想让老板呆 ...

  6. C和指针 (pointers on C)——第五章:操作符和表达式

    第五章 操作符和表达式 这一章假设没做过玩过单片机.汇编的话,读起来可能比較吃力,尤其是在移位运算符.位运算符应用上.另外多注意一下左值和右值的理解. 总结: 算术操作符.赋值操作符.关系操作符.条件 ...

  7. Windows 2012 AD配置

    //本文选在快帮网,非原创. Active Directory概述: 使用 Active Directory(R) 域服务 (AD DS) 服务器角色,可以创建用于用户和资源管理的可伸缩.安全及可管理 ...

  8. (二)Activity启动模式

    一.标准模式(standrard) 1.当新建一个Activity时,默认情况下就是标准模式,也可以通过AndroidManifest文件显示指定其launchMode为standard <?x ...

  9. 初学.NET小技巧(不断更新)

    1.快速打出Console.WriteLine : 输入cw,然后按两下tab键. 2.创建一个函数快捷键:bool b = IsPrimeNumber();   把光标放到函数名上,Shift+Al ...

  10. js学习心得(一)(菜鸟)

    js基础已经打了好几次了,慕课跟着学了一遍,视频看了一些,还读了诸如 jsdom艺术,js精粹以及锋利jq(没读完). 这次再次重头读并写一遍代码,工具书是js,查缺补漏高级程序设计第二版,犀牛书有点 ...