铅笔

在你的害怕中坚持的越多,你就会越自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

按键驱动

Posted on 2017-01-04 09:14  黑色の铅笔  阅读(181)  评论(0编辑  收藏  举报

 

一、static int button_init(void)  入口函数作用: 

1、major = register_chrdev(0, DEVICE_NAME, &button_ops);注册字符设备

2、button_class = class_create(THIS_MODULE, "button");创建类

3、button_dev_class = class_device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button"); /* /dev/my_button */ 创建设备文件

4、  gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);ioremap函数虚拟add映射

button_exit出口函数 作用与入口函数类似;

二、static int button_open (struct inode *inode, struct file *filep)  配置输入引脚

 

三、ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)读取引脚电平并由copy_to_user(buf, key_vals, sizeof(key_vals))函数上传至用户层读函数

my_button.c

#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#define DEVICE_NAME "mybutton"   /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
static struct class *button_class;
static struct class_device *button_dev_class;
int major;

volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;

volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;

/* 应用程序对设备文件/dev/xxx 执行open(...)时,
 * 就会调用button_open函数
 */
static int button_open (struct inode *inode, struct file *filep)  
{  
    /* 配置GPF0,2为输入引脚 */
    //1、对应位置为0  2 、相应位配置
    *gpfcon &= ~((0x3<<(0*2)) | (0x3<<(2*2)));
    /* 配置GPG3,11为输入引脚 */
    *gpgcon &= ~((0x3<<(3*2)) | (0x3<<(11*2)));
    return 0;  
}  
ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    /* 返回4个引脚的电平 */
    unsigned char key_vals[4];
    int regval;
    if (size != sizeof(key_vals))
        return -EINVAL;
    regval=*gpfdat;
    key_vals[0] =(regval&(1<<0))?1:0;
    key_vals[1] =(regval&(1<<2))?1:0;
    /* 读GPG3,11 */
    regval = *gpgdat;
    key_vals[2] = (regval & (1<<3)) ? 1 : 0;
    key_vals[3] = (regval & (1<<11)) ? 1 : 0;
    
    copy_to_user(buf, key_vals, sizeof(key_vals));
    return sizeof(key_vals);
}
/* 这个结构是字符设备驱动程序的核心
 * 当应用程序操作设备文件时所调用的open、read、write等函数,
 * 最终会调用这个结构中指定的对应函数
 */
static struct file_operations button_ops=  
{    
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   = button_open,  
    .read    =    button_read,       
    
}; 
 
/*
 * 执行insmod命令时就会调用这个函数 
 */
  
static int button_init(void)  
{  
    int ret;
    /* 注册字符设备
     * 参数为主设备号、设备名字、file_operations结构;
     * 这样,主设备号就和具体的file_operations结构联系起来了,
     * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数
     * LED_MAJOR可以设为0,表示由内核自动分配主设备号
     */
     major = register_chrdev(0, DEVICE_NAME, &button_ops);
      if (major < 0) 
      {
      printk(DEVICE_NAME  " can't register major number number::%d\n",major);
      return ret;
      }
    printk(DEVICE_NAME " initialized1\n");
    button_class = class_create(THIS_MODULE, "button");
    if (IS_ERR(button_class))
        return PTR_ERR(button_class);
    button_dev_class = class_device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button"); /* /dev/my_button */ 
    
    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;
   
       gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;
    return 0;

}

/*
 * 执行rmmod命令时就会调用这个函数 
 */
static void button_exit(void)
{
    class_device_unregister(button_dev_class);
    class_destroy(button_class);       
     /* 卸载驱动程序 */
    unregister_chrdev(major, DEVICE_NAME);
      iounmap(gpfcon);
    iounmap(gpgcon);
}

/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(button_init);  
module_exit(button_exit);  

/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("http://www.100ask.net");// 驱动程序的作者
MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");// 一些描述信息
MODULE_LICENSE("GPL");   // 遵循的协议

test.c

#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <stdio.h>  
int main(int argc,char**argv)  
{  
    int fd;  
    unsigned char key_vals[4];
    int cnt = 0;
    
  //1、打开设备
    fd = open("/dev/my_button",O_RDWR);  
    if(fd<0)  
    {  
        perror("open fail \n");  
        return -1;  
    } 
    while(1)//一直再次循环执行,很占用cpu资源  将其后台运行 ./a.out & 然后再执行top 可以看到其占用资源达到99%所以必须将其该井为中断
    {
        read(fd,key_vals, sizeof(key_vals));
       if (!key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3])
        {
            printf("%04d key pressed: %d %d %d %d\n", cnt++, key_vals[0], key_vals[1], key_vals[2], key_vals[3]);
        }
    }
    close(fd);
    return 0;
}  

 

#ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个
#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build    

        
# 开发板的linux内核的源码树目录
#KERN_DIR =/lib/modules/2.6.31-14-generic/build
KERN_DIR = /home/book/per/kernel/linux-2.6.22.6
#/root/driver/kernel

obj-m    += my_button.o

all:
    make -C $(KERN_DIR) M=`pwd` modules 

#cp:
#    cp *.ko /root/porting_x210/rootfs/rootfs/driver_test

.PHONY: clean    
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
cp:
    cp /mnt/hgfs/publicshare/drivers_and_test/my_button/ /home/book/dri/ -rf