button_drv.c驱动文件:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h>                  //包含iomap函数iounmap函数
#include <asm/uaccess.h>                      //包含copy_from_user函数
#include <linux/device.h>                     //包含类相关的处理函数
#include <asm/arch/regs-gpio.h>            //包含S3C2410_GPF0等相关的
#include <linux/irq.h>                       //包含IRQ_HANDLED、IRQ_TYPE_EDGE_RISING
#include <asm-arm/irq.h>                          //包含IRQT_BOTHEDGE触发类型
#include <linux/interrupt.h>request_irq、free_irq函数
#include <linux/delay.h>
#include <asm/hardware.h>

#define DRIVER_NAME "button_drv"
#define DEVICE_NAME "button_dev"

int major;

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

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

struct class *buttondrv_class;
struct class_device *buttondrv_class_device;

unsigned int key_val;
unsigned int ev_press = 0;
DECLARE_WAIT_QUEUE_HEAD(button_waitq);                //注册等待队列button_waitq

struct pin_desc{
  unsigned int pin;
  unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
  {S3C2410_GPF0, 0x01},
  {S3C2410_GPF2, 0x02},
  {S3C2410_GPG3, 0x03},
  {S3C2410_GPG11, 0x04},
};

irqreturn_t buttons_irq(int irq, void *dev_id)      //按键中断服务函数
{
  unsigned int pin_val;
  struct pin_desc *pin_desc = (struct pin_desc *)dev_id;

  pin_val = s3c2410_gpio_getpin(pin_desc->pin);

  if(pin_val)
  {
    key_val = 0x80 | pin_desc->key_val;
  }
  else
  {
    key_val = pin_desc->key_val;
  }
  wake_up_interruptible(&button_waitq);                              //唤醒休眠的进程, 即调用read函数的进程
  ev_press = 1;
  return IRQ_HANDLED;
}

int button_drv_open(struct inode *inode, struct file *file)
{
  int ret;
  ret = request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S1", (void*)&pins_desc[0]);  //注册一个外部中断S1, 双边沿触发

                                                      //dev_id为&pins_desc[0]

  if(ret)
  {
    printk("open failed 1 \n");
    return -1;
  }
  ret = request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S2", (void*)&pins_desc[1]);
  if(ret)
  {
    printk("open failed 2 \n");
    return -1;
  }
  ret = request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S3", (void*)&pins_desc[2]);
  if(ret)
  {
    printk("open fail 3 \n");
    return -1;
  }
  ret = request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S4", (void*)&pins_desc[3]);
  if(ret)
  {
    printk("open fail 4 \n");
    return -1;
  }
  return 0;
}

ssize_t button_drv_read(struct file *file, char __user *userbuf, size_t count, loff_t *off)
{
  int ret;

  wait_event_interruptible(button_waitq, ev_press); //上层应用调用read函数时, ev_press为0, 就将button_waitq加入等待队列, 并释放cpu进入睡眠状态

                                     //当有按键按下时, 中断处理函数唤醒休眠进程, 将ev_press置为1,当上层应用再次调用read函数时

                                //就会不进入睡眠状态而直接读取按键值
  ret = copy_to_user(userbuf, &key_val, 1);      //将取得的键值传递给上层应用
  if(ret)
  {
    printk("copy eror \n");
    return -1;
  }
  ev_press = 0;                                             //按键值读取后再次将ev_press置0, 这样上层再次调用时就又会进入睡眠,直到中断再次唤醒
  return 1;
}

int button_drv_close(struct inode *inode, struct file *file)
{
  free_irq(IRQ_EINT0, (void*)&pins_desc[0]);      //释放中断, 根据IRQEINT0找到irq_desc结构, 根据pins_desc[0]找到irq_desc->action结构
  free_irq(IRQ_EINT2, (void*)&pins_desc[1]);
  free_irq(IRQ_EINT11, (void*)&pins_desc[2]);
  free_irq(IRQ_EINT19, (void*)&pins_desc[3]);
  return 0;
}

struct file_operations button_drv_fops = {
  .owner = THIS_MODULE,
  .open = button_drv_open,
  .read = button_drv_read,
  .release = button_drv_close,
};

int __init button_drv_init(void)
{
  major = register_chrdev(0, DRIVER_NAME, &button_drv_fops);
  if(major<0)
  {
    printk("fail 1 button_drv \n");
  }

  buttondrv_class = class_create(THIS_MODULE, DEVICE_NAME);
  if(buttondrv_class<0)
  {
    printk("fail 2 button_dev \n");
  }
  buttondrv_class_device = class_device_create(buttondrv_class, NULL, MKDEV(major,0), NULL, DEVICE_NAME);
  if(buttondrv_class_device<0)
  {
    printk("fail 3 button_dev \n");
  }

  gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
  gpfdat = gpfcon + 1;
  gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
  gpgdat = gpgcon + 1;
  return 0;
}

void __exit button_drv_exit(void)
{
  unregister_chrdev(major, DEVICE_NAME);
  class_device_unregister(buttondrv_class_device);
  class_destroy(buttondrv_class);
  iounmap(gpfcon);
  iounmap(gpgcon);
}

module_init(button_drv_init);
module_exit(button_drv_exit);

MODULE_LICENSE("GPL");

Makefile文件:

obj-m += button_drv.o

KERN_DIR = /work/system/linux-2.6.22.6

all:
make -C $(KERN_DIR) M=`pwd` modules 
clean:
rm -rf *.o *.ko *.order *.symvers *.mod.c

button_app.c文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  int fd;
  char *filename;
  unsigned char keyVal;

  filename = argv[1];

  fd = open(filename, O_RDWR);
  if(fd<0)
  {
    printf("can not open \n");
  }

  while(1)
  {
    read(fd, &keyVal, 1);
    printf("keyVal: %x \n",keyVal);
  }

  return 0;
}

编译生成button_drv.ko文件和button_app文件,运行:./button_app /dev/button_dev

Linux 驱动——Button驱动2的更多相关文章

  1. Linux 驱动——Button驱动7(Timer)消抖

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...

  2. Linux 驱动——Button驱动6(mutex、NBLOCK、O_NONBLOCK)互斥信号量、阻塞、非阻塞

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...

  3. Linux 驱动——Button驱动5(atomic)原子量

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...

  4. Linux 驱动——Button驱动4(fasync)异步通知

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...

  5. Linux 驱动——Button驱动3(poll机制)

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...

  6. Linux 驱动——Button驱动1

    button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/i ...

  7. Linux GPIO键盘驱动开发记录_OMAPL138

    Linux GPIO键盘驱动开发记录_OMAPL138 Linux基本配置完毕了,这几天开始着手Linux驱动的开发,从一个最简单的键盘驱动开始,逐步的了解开发驱动的过程有哪些.看了一下Linux3. ...

  8. linux块设备驱动之实例

    1.注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动 sbull_major  =  register_blkdev(sbull_major, "sbull&quo ...

  9. Linux 视频设备驱动V4L2最常用的控制命令

    http://blog.csdn.net/shaolyh/article/details/6583226 Linux 视频设备驱动V4L2最常用的控制命令使用说明(1.02) 命令 功能 VIDIOC ...

随机推荐

  1. 《CoderXiaoban团队》第一次作业:团队亮相

    实验五 这个作业属于哪个课程 软件工程任教教师 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/10687492.html 团队名称 CoderXiao ...

  2. SWUST OJ(1044)

    顺序栈基本操作的实现 #include <iostream> #include <cstdlib> using namespace std; typedef struct st ...

  3. 有趣的if循环

    今天,在论坛看到一个有趣的if 循环,我感觉有不错,就分享出来 问题,列表只有6个数,为什么打印8个数?原理? q = ['a', 'b', 'c', 'd', 'e', 'f'] for i in ...

  4. BootStrap 学习笔记一

    1.bootstrap列偏移 列偏移是指在网格系统中,可以使用偏移列来达到让某列右移的效果,只需要在class的“col-*-*”后追加“col-*-offset-*” <div class=& ...

  5. 人生苦短,我用python(目录)

    一.python基础篇 python中闭包及延时绑定问题 python中的装饰器.生成器 二.前端 bootstrap框架 BOM&DOM JavaScript中的词法分析 三.数据库 mys ...

  6. 思科模拟器PacketTracer7-----2台PC通过交叉线互连

    实验二—3 实验工具:思科模拟器PacketTracer7(可在思科官网下载,免费) 实验设备: PC两台,交叉线 实验步骤: 一.配置网络拓扑图 二.配置PC0和PC1的IP地址,掩码和网关 四.通 ...

  7. C语言博客作业04——数组

    1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量 1.2.1学习体会 这几周学习了数组,数组分为三大块:一维数组.二维数组和字符数组.数组相对于之前普通变量的好处就是可以储存数值,方便数据 ...

  8. CloudStack 云计算平台框架

    前言 CloudStack 和OpenStack 一样都是IaaS层 开源框架,可以管理XenServer.ESXI.KVM.OVM等主流虚拟机,相对OpenStack比较简单.稳定: 二.Cloud ...

  9. CentOS7系统上的GPSTK示例代码调试 & 运行结果 & 心得

    下载的源码程序包中,共有16个例子,这里记录它们的调试及运行结果,尤其是哪些可用,哪些不可用,今后使用时用作参考. 总结: (1)在 18 个示例程序中,example16 和 example17 编 ...

  10. bind与继承 待研究

    class a { f() { console.log('a') } get f2() { console.log('f2') return (this['f'] = this.f.bind(this ...