zoukankan      html  css  js  c++  java
  • kobox: key_proc.c -v1 怎样使用proc文件系统调试驱动

    使用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]
    ",
    					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:
    "
    			"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!
    "
    			);
    	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
    ", key_num);
    
    		switch(key_num)
    		{
    			case 'a':
    				for(i=0; i<ARRAY_SIZE(pressCnt); i++)
    				{
    					printk("pressCnt[i]:%d
    ", i, pressCnt[i]);	
    				}
    				break;
    
    			case '0':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[0].irqName,pressCnt[0]);
    				break;
    
    			case '1':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[1].irqName,pressCnt[1]);
    				break;
    				
    			case '2':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[2].irqName,pressCnt[2]);
    				break;
    
    			case '3':
    				printk("key:[%s], pressCnt:%d
    ", 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]
    ", __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
    ", irq);
    
    	if(dev_id)
    		printk("dev_id:%s
    ", 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
    ", 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
    ", __FUNCTION__,__LINE__, pin);	
    
    	uiVal = readl(S3C2410_GPFDAT);
    	ret = (0x1 << pin) & uiVal;
    
    	printk("I AM @ [%s][%d], ret:%d
    ", __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
    ", __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
    ", 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!
    ", __FUNCTION__,__LINE__,ret);
    		else
    			printk("[func:%s][line:%d] request_irq ok, irq:%d!
    ", __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]
    ",
    					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:
    "
    			"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!
    "
    			);
    	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
    ", key_num);
    
    		switch(key_num)
    		{
    			case 'a':
    				for(i=0; i<ARRAY_SIZE(pressCnt); i++)
    				{
    					printk("pressCnt[i]:%d
    ", i, pressCnt[i]);	
    				}
    				break;
    
    			case '0':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[0].irqName,pressCnt[0]);
    				break;
    
    			case '1':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[1].irqName,pressCnt[1]);
    				break;
    				
    			case '2':
    				printk("key:[%s], pressCnt:%d
    ", key_gpio_res[2].irqName,pressCnt[2]);
    				break;
    
    			case '3':
    				printk("key:[%s], pressCnt:%d
    ", 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!
    ");
    
    	major = register_chrdev(0, GPIO_KEY_NAME, &kobox_key_operations);
    	if (major < 0)
    	{
    		printk(" can't register major number
    ");
    		return major;
    	}
    
    	/* create class */
    	kobox_key_class = class_create(THIS_MODULE, GPIO_KEY_NAME);
    	if(IS_ERR(kobox_key_class))
    	{
    		printk("class_create failed!
    ");
    		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!
    ");
    		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!
    ");
    	
    	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!
    ");	
    
    	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");
    




  • 相关阅读:
    正则去掉 html标签
    app内嵌 h5页面 再滑动的时候 触发击穿底下的一些touchstart事件
    设置按钮不能连续点击并触发点击事件
    使用NPOI导入导出标准Excel
    ASP.NET导出word实例
    常用SQL语句大全总结
    判断以及防止SQL注入
    javascript 正则表达式总结
    前端页面优化技巧
    自我介绍
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5215713.html
Copyright © 2011-2022 走看看