使用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. Centos7网络配置+图形界面设置

    一. 查看网络地址: centos7取消了ifconfig命令,使用ip addr命令查看IP地址 二.配置网络 用VirtualBox安装的CentOS7,安装完成后,发现无法上网,于是到网上查了一 ...

  2. Asp.Net MVC3 简单入门第一季(三)详解Controller之Filter

    前言 前面两篇写的比较简单,刚开始写这个系列的时候我面向的对象是刚开始接触Asp.Net MVC的朋友,所以写的尽量简单.所以写的没多少技术含量.把这些技术总结出来,然后一简单的方式让更多的人很好的接 ...

  3. 【具体数学 读书笔记】1.2 Lines in the Plane

    本节介绍平面划分问题,即n条直线最多把一个平面划分为几个区域(region). 问题描述: "What is the maximum number Ln of regions defined ...

  4. [IOS]UIWebView 请求网络页面或者加载本地资源页面

    UIWebView是一个能够显示网页的IOS视图控件,我们可以用它来访问一个网站.下面是具体的实例: 操作步骤: 1.首先在xib文件中拖放一个UIWebView控件到view中 2.将下载的页面以及 ...

  5. iOS开展UI一片—简单的浏览器观看节目

    iOS开发UI篇-简单的浏览器查看程序 一.程序实现要求 1.要求 2. 界面分析 (1) 须要读取或改动属性的控件须要设置属性 序号标签 图片 图片描写叙述 左边button 右边button (2 ...

  6. 3.数据库操作相关术语,Oracle认证,insert into,批量插入,update tablename set,delete和truncate的差别,sql文件导入

     1相关术语 语句 含义 操作 DML语句 (Data Manipulation Language) 数据库操作语言 insert update delete select DDL语言 (Date ...

  7. 关于Oracle数据库字符集的选择

    如果数据库只在中国地区使用,数据库字符集选择ZHS16GBK或者常用中文字符集,如果不确定,就推荐使用AL32UTF8 国家字符集就选择: AL16UTF16 字符集一旦设定,不允许修改,修改可能出现 ...

  8. 【泛化物品】【HDU1712】【ACboy needs your help】

    ACboy needs your help Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  9. 【位运算DFS/DLX】【HDU1426】【数独】

    题意:标准的一道数独题 DFS做法: 将横纵九宫格里的数字用位运算状态压缩,且可以通过逻辑或来确定总共有哪些数字被选择了,很方便也很快,代码如下 #include <cstdio> #in ...

  10. Spring事务传播机制详解

    1 事务的传播属性(Propagation) 1) REQUIRED ,这个是默认的属性 Support a current transaction, create a new one if none ...