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. Java开源框架知识整理

    1.Spring的了解     Spring是一个轻量级的IOC/DI和AOP容器的开源框架.可以实现Java模块化开发,贯穿表现层,业务层,逻辑层,实现各层之间的解耦合关系.     IOC,控制反 ...

  2. 【C/C++】数组 & 指针

    int main() { ]; ]; ][]; ]; ]; ]; ][]; cout << sizeof(a) << endl; cout << sizeof(pa ...

  3. mlp_clf_mnist_test

    import os os.environ['CUDA_VISIBLE_DEVICES'] = "0" from mlp_clf import MLPClassifier impor ...

  4. The innodb_system data file 'ibdata1' must be writable

    在安装MySQL的时候报的错,我理解的这个错是因为有个文件是Innodb需要在安装MySQL(或者创建数据库的时候)的时候需要写入这个文件,但是他现在没有写的权限. 日志中的错误是: 5.7版本以前是 ...

  5. 【Monkey】Monkey基础概念

    1.什么是Monkey? 发送伪随机用户事件的命令 2.Monkey在哪? 在手机系统里 3.什么是ADB? 4.MonkeyScript 一组可以被Monkey识别的命令集合,可以完成重复固定的操作 ...

  6. python 对象存储OSS 阿里云

    SDK参考 ->python->上传文件->简单上传 #  -*- coding: utf-8 -*- import oss2 auth=oss2.Auth('<yourAcc ...

  7. transform,transtion属性

    transform:变化类型,transtion变化方式

  8. es6 - 一共有 6 种声明变量的方法(var, function, let, const, class, import)

    var命令和function命令声明的全局变量,依旧是顶层对象的属性:let命令.const命令.class命令声明的全局变量,不属于顶层对象的属性.也就是说,从 ES6 开始,全局变量将逐步与顶层对 ...

  9. h5或者微信端吊起app

    [https://www.cnblogs.com/shadajin/p/5724117.html]! 魔窗sdk http://www.magicwindow.cn/doc/universal-lin ...

  10. linux使用npm成功安装命令后,执行时却报找不到命令的问题

    # 使用npm安装serve命令 ~$ npm install serve --global 安装成功 # 可是执行命令会报错 ~$ serve -v bash: serve: command not ...