Linux设备驱动之button按键驱动学习与小结

button按键驱动,相对于前面的LED驱动来说。增加了中断服务程序以及等待队列等新知识点。

先上学习的驱动代码。

内核:linux3.0

板子:fl2440

/*********************************************************************************
 *      Copyright:  (C) 2011 Guo Wenxue<[email protected]>
 *                  All rights reserved.
 *
 *       Filename:  plat_button.c
 *    Description:  This is the common button driver runs on S3C2440
 *
 *        Version:  1.0.0(10/27/2011~)
 *         Author:  Guo Wenxue <[email protected]>
 *      ChangeLog:  1, Release initial version on "10/27/2011 11:39:10 AM"
 *
 ********************************************************************************/
#include "s3c_driver.h"

#define DRV_AUTHOR                "Guo Wenxue <[email protected]>"
#define DRV_DESC                  "S3C24XX button driver"

/* Driver version*/
#define DRV_MAJOR_VER             1
#define DRV_MINOR_VER             0
#define DRV_REVER_VER             0

#define DEV_NAME                  DEV_BUTTON_NAME

//#define DEV_MAJOR               DEV_BUTTON_MAJOR
#ifndef DEV_MAJOR
#define DEV_MAJOR                 0 /* dynamic major by default */
#endif

#define BUTTON_UP                 0 /* Button status is up */
#define BUTTON_DOWN               1 /* Button status is pushed down */
#define BUTTON_UNCERTAIN          2 /* Button status uncerntain */

#define TIMER_DELAY_DOWN          (HZ/50)   /*Remove button push down dithering timer delay 20ms  */
#define TIMER_DELAY_UP            (HZ/10)   /*Remove button up dithering timer delay 100ms  */

static int debug = DISABLE;
static int dev_major = DEV_MAJOR;
static int dev_minor = 0;

/*============================ Platform Device part ===============================*/
/* Button hardware informtation structure*/
struct s3c_button_info
{
    unsigned char           num;       /*Button nubmer  按键号*/
    char *                  name;      /*Button nubmer  按键名*/
    int                     nIRQ;      /*Button IRQ number 中断号*/
    unsigned int            setting;   /*Button IRQ Pin Setting 中断引脚配置*/
    unsigned int            gpio;      /*Button GPIO port 对应的IO引脚*/
};

/* The button plaotform device private data structure */
struct s3c_button_platform_data //按键数据结构体
{
    struct s3c_button_info *buttons; //用来访问按键硬件信息的指针
    int                     nbuttons;//按键数量
};

/* Button hardware informtation data*/ //具体的相应按键信息
static struct s3c_button_info  s3c_buttons[] = {
    [0] = {
        .num = 1,
        .name = "KEY1",
        .nIRQ = IRQ_EINT0,//中断号
        .gpio = S3C2410_GPF(0),
        .setting = S3C2410_GPF0_EINT0,//datasheet手册上对应的IO中断口
    },
    [1] = {
        .num = 2,
        .name = "KEY2",
        .nIRQ = IRQ_EINT2,
        .gpio = S3C2410_GPF(2),
        .setting = S3C2410_GPF2_EINT2,
    },
    [2] = {
        .num = 3,
        .name = "KEY3",
        .nIRQ = IRQ_EINT3,
        .gpio = S3C2410_GPF(3),
        .setting = S3C2410_GPF3_EINT3,
    },
    [3] = {
        .num = 4,
        .name = "KEY4",
        .nIRQ = IRQ_EINT4,
        .gpio = S3C2410_GPF(4),
        .setting = S3C2410_GPF4_EINT4,
    },
};

/* The button platform device private data */
static struct s3c_button_platform_data s3c_button_data = {
    .buttons = s3c_buttons,
    .nbuttons = ARRAY_SIZE(s3c_buttons),
};

struct button_device
{
    unsigned char                      *status;      /* The buttons Push down or up status */
    struct s3c_button_platform_data    *data;        /* The buttons hardware information data */

    struct timer_list                  *timers;      /* The buttons remove dithering timers */
    wait_queue_head_t                  waitq;           /* Wait queue for poll()  */
    volatile int                       ev_press;     /* Button pressed event */

    struct cdev                        cdev;
    struct class                       *dev_class;
} button_device;

static void platform_button_release(struct device * dev)
{
    return;
}

static struct platform_device s3c_button_device = {
    .name    = "s3c_button",
    .id      = 1,
    .dev     =
    {
        .platform_data = &s3c_button_data,
        .release = platform_button_release,
    },
};

static irqreturn_t s3c_button_intterupt(int irq,void *de_id) //按键中断服务程序
{
    int i;
    int found = 0;
    struct s3c_button_platform_data *pdata = button_device.data;

    for(i=0; i<pdata->nbuttons; i++)
    {
        if(irq == pdata->buttons[i].nIRQ)//找到具体的中断号
        {
            found = 1;
            break;
        }
    }

    if(!found) /* An ERROR interrupt  */
        return IRQ_NONE;

    /* Only when button is up then we will handle this event */
    if(BUTTON_UP  == button_device.status[i])
    {
       button_device.status[i] = BUTTON_UNCERTAIN;//因为要防抖动,且不确定是否为有效按键,所以先设置为不确定状态
       mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);
    }

    return IRQ_HANDLED;
}

static void button_timer_handler(unsigned long data) //定时器中断服务程序
{
    struct s3c_button_platform_data *pdata = button_device.data;
    int num =(int)data;
    int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio );

    if(LOWLEVEL == status)
    {
        if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */
        {
            //dbg_print("Key pressed!\n");
            button_device.status[num] = BUTTON_DOWN;

            printk("%s pressed.\n", pdata->buttons[num].name); //~!@#)¥%……&^.,(

            /* Wake up the wait queue for read()/poll() */
            button_device.ev_press = 1;
            wake_up_interruptible(&(button_device.waitq)); ev_press唤醒等待队列
        }

        /* Cancel the dithering  */
        mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);//重新激活并设置定时器
    }
    else
    {
        //dbg_print("Key Released!\n");
        button_device.status[num] = BUTTON_UP;
     //   enable_irq(pdata->buttons[num].nIRQ);
    }

    return ;
}

/*===================== Button device driver part ===========================*/

static int button_open(struct inode *inode, struct file *file)
{
    struct button_device *pdev ;
    struct s3c_button_platform_data *pdata;
    int i, result;

    pdev = container_of(inode->i_cdev,struct button_device, cdev);
    pdata = pdev->data;
    file->private_data = pdev;

    /* Malloc for all the buttons remove dithering timer */
    pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL);
    if(NULL == pdev->timers)//内核里的内存申请失败
    {
        printk("Alloc %s driver for timers failure.\n", DEV_NAME);
        return -ENOMEM;
    }
    memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list));

    /* Malloc for all the buttons status buffer */
    pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL);
    if(NULL == pdev->status)
    {
        printk("Alloc %s driver for status failure.\n", DEV_NAME);
        result = -ENOMEM;
        goto  ERROR;
    }
    memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char));

    init_waitqueue_head(&(pdev->waitq));//初始化等待队列头

    for(i=0; i<pdata->nbuttons; i++)
    {
        /* Initialize all the buttons status to UP  */
        pdev->status[i] = BUTTON_UP; 

        /* Initialize all the buttons' remove dithering timer */
        setup_timer(&(pdev->timers[i]), button_timer_handler, i); //初始化每个定时器

        /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */
        s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);//按键相应的管脚配置成IRQ中断模式
        irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING);//把相应的中断号设置为下降沿触发方式

        /* Request for button GPIO pin interrupt  */
        result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);//注册给内核,一旦发生中断号的中断就调用s3c_button_intterupt这个中断处理程序
        if( result )
        {
            result = -EBUSY;
            goto ERROR1;
        }
    }

    return 0;

ERROR1:
     kfree((unsigned char *)pdev->status);
     while(--i)
     {
         disable_irq(pdata->buttons[i].nIRQ);
         free_irq(pdata->buttons[i].nIRQ, (void *)i);
     }

ERROR:
     kfree(pdev->timers);

     return result;
}

static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    struct button_device *pdev = file->private_data;
    struct s3c_button_platform_data *pdata;
    int   i, ret;
    unsigned int status = 0;

    pdata = pdev->data;

    dbg_print("ev_press: %d\n", pdev->ev_press);
    if(!pdev->ev_press) //ev_press为按键标识符,即按下时才为1.结合下面等待队列程序
    {
         if(file->f_flags & O_NONBLOCK)
         {
             dbg_print("read() without block mode.\n");// O_NONBLOCK是设置为非阻塞模式
             return -EAGAIN;//若没有按键按下,还采用非阻塞模式则会一直浪费CPU的时间等待。
         }
         else
         {
             /* Read() will be blocked here */
             dbg_print("read() blocked here now.\n");
             wait_event_interruptible(pdev->waitq, pdev->ev_press); //在阻塞模式读取且没按键按下则让等待队列进入睡眠,直到ev_press为1
         }
    }

    pdev->ev_press = 0;清除标识,准备下一次

    for(i=0; i<pdata->nbuttons; i++)
    {
        dbg_print("button[%d] status=%d\n", i, pdev->status[i]);
        status |= (pdev->status[i]<<i);
    }

    ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count));

    return ret ? -EFAULT : min(sizeof(status), count);
}

static unsigned int button_poll(struct file *file, poll_table * wait)//类似于应用层的select轮询监听
{
    struct button_device *pdev = file->private_data;
    unsigned int mask = 0;

    poll_wait(file, &(pdev->waitq), wait);//添加等待队列到等待队列中
    if(pdev->ev_press)
    {
        mask |= POLLIN | POLLRDNORM; /* The data aviable */
    }

    return mask;
}

static int button_release(struct inode *inode, struct file *file)
{
    int i;
    struct button_device *pdev = file->private_data;
    struct s3c_button_platform_data *pdata;
    pdata = pdev->data;

    for(i=0; i<pdata->nbuttons; i++)
    {
        disable_irq(pdata->buttons[i].nIRQ);
        free_irq(pdata->buttons[i].nIRQ, (void *)i);
        del_timer(&(pdev->timers[i]));
    }

    kfree(pdev->timers);
    kfree((unsigned char *)pdev->status);

    return 0;
}

static struct file_operations button_fops = {
    .owner = THIS_MODULE,
    .open = button_open,
    .read = button_read,
    .poll = button_poll,
    .release = button_release,
};

static int s3c_button_probe(struct platform_device *dev)
{
    int result = 0;
    dev_t devno;

    /* Alloc the device for driver  */
    if (0 != dev_major)
    {
        devno = MKDEV(dev_major, dev_minor);
        result = register_chrdev_region(devno, 1, DEV_NAME);
    }
    else
    {
        result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);
        dev_major = MAJOR(devno);
    }

    /* Alloc for device major failure */
    if (result < 0)
    {
        printk("%s driver can't get major %d\n", DEV_NAME, dev_major);
        return result;
    }

    /*  Initialize button_device structure and register cdev*/
     memset(&button_device, 0, sizeof(button_device));
     button_device.data = dev->dev.platform_data;
     cdev_init (&(button_device.cdev), &button_fops);
     button_device.cdev.owner  = THIS_MODULE;

     result = cdev_add (&(button_device.cdev), devno , 1);
     if (result)
     {
         printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);
         goto ERROR;
     }

     button_device.dev_class = class_create(THIS_MODULE, DEV_NAME);
     if(IS_ERR(button_device.dev_class))
     {
         printk("%s driver create class failture\n",DEV_NAME);
         result =  -ENOMEM;
         goto ERROR;
     }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
     device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);
#else
     device_create (button_device.dev_class, NULL, devno, DEV_NAME);
#endif

     printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);

     return 0;

ERROR:
     printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
     cdev_del(&(button_device.cdev));
     unregister_chrdev_region(devno, 1);
     return result;
}

static int s3c_button_remove(struct platform_device *dev)
{
    dev_t devno = MKDEV(dev_major, dev_minor);

    cdev_del(&(button_device.cdev));
    device_destroy(button_device.dev_class, devno);
    class_destroy(button_device.dev_class);

    unregister_chrdev_region(devno, 1);
    printk("S3C %s driver removed\n", DEV_NAME);

    return 0;
}

/*===================== Platform Device and driver regist part ===========================*/

static struct platform_driver s3c_button_driver = {
    .probe      = s3c_button_probe,
    .remove     = s3c_button_remove,
    .driver     = {
        .name       = "s3c_button",
        .owner      = THIS_MODULE,
    },
};

static int __init s3c_button_init(void)
{
   int       ret = 0;

   ret = platform_device_register(&s3c_button_device);
   if(ret)
   {
        printk(KERN_ERR "%s: Can't register platform device %d\n", __FUNCTION__, ret);
        goto fail_reg_plat_dev;
   }
   dbg_print("Regist S3C %s Device successfully.\n", DEV_NAME);

   ret = platform_driver_register(&s3c_button_driver);
   if(ret)
   {
        printk(KERN_ERR "%s: Can't register platform driver %d\n", __FUNCTION__, ret);
        goto fail_reg_plat_drv;
   }
   dbg_print("Regist S3C %s Driver successfully.\n", DEV_NAME);

   return 0;

fail_reg_plat_drv:
   platform_driver_unregister(&s3c_button_driver);
fail_reg_plat_dev:
   return ret;
}

static void s3c_button_exit(void)
{
    platform_driver_unregister(&s3c_button_driver);
    dbg_print("S3C %s platform device removed.\n", DEV_NAME);

    platform_device_unregister(&s3c_button_device);
    dbg_print("S3C %s platform driver removed.\n", DEV_NAME);
}

module_init(s3c_button_init);
module_exit(s3c_button_exit);

module_param(debug, int, S_IRUGO);
module_param(dev_major, int, S_IRUGO);
module_param(dev_minor, int, S_IRUGO);

MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:S3C24XX_button");

学习小结

(一)

request_irq  (中断号,中断处理程序,标志位,设备名,中断处理的参数)

在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

int request_irq(
unsigned int irq,

irq_handler_t handler,

unsigned long irqflags,

const char *devname,

void *dev_id)

irq
是要申请的硬件中断号。

handler 是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags 是中断处理的属性

若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;

若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)

devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。

dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL

request_irq()返回0表示成功返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

(二)

首先在open函数里面会获得设备信息,并且会动态的申请内存为每一个button都创建一个定时器。再有就是动态的创建存储状态status的buf。然后初始化让所有按键的状态为BUTTON_UP以及调用Setup_timer初始化定时器以及设置定时器的回调函数button_timer_handler.,s3c2410_gpio_cfgpin把相应的管脚设置为IRQ中断模式(否则可能是GPIO模式),irq_set_irq_type把相应的中断号设置为下降沿触发的方式。然后request_irq()把中断注册给内核。一旦发生中断则调用s3c_button_intterupt这个中断处理程序。

紧接着来到s3c_button_intterupt处理程序:通过判断获取具体的中断号之后便进行消抖的处理。(此时通过按键的状态不管是否按下依然为BUTTON_up状态,这是我们最初认为设定的)紧接着通过mod_timer激活定时器,在超时之后,然后进入定时器原本设定好的定时器中断处理程序button_timer_handler中正式的处理这个中断请求。也就是说中断处理程序s3c_button_intterupt()只是确认按键是否有效,真正处理中断的程序是定时器里面的button_timer_handler(
)

再看Button_timer_handler函数:因为当按下的时候进入了s3c_button_intterupt函数然后定时器超时调用到了button_timer_handler里,此时为低电平。然后我们这时候将他设置为BUTTON_DOWN状态。且唤醒等待队列让设备进行读取ev_press为按键按下的发生标识,按下ev_press即为1也通过ev_press参数值来设置工作模式,选定阻塞或者是非阻塞模式。

对于read函数来说:获取了按键的设备信息之后通过ev_press来剔除非阻塞模式选择阻塞模式,在阻塞模式下读取且没按键按下则让等待队列进入睡眠,直到ev_press为1。通过位运算来判断哪一个按键按下并保存状态值到status中。

另外还有poll函数,类似于应用层select,是通过轮询方式不断的监听。对于socket编程自己还没有怎么熟悉,晚上学习学习再说。

(三)

个人觉得这之中最大的难点是在中断以及通过ev_press来选择阻塞方式这。起初看程序有两个中断程序,以为注册中断后发生中断返回的中断服务程序是正牌。其实不然,对于高级的CPU都是会找个定时器来帮助处理中断。就好比领导不会何事都亲力亲为一样。那样浪费时间,不小心就把领导累死了。。。有了中断,从中断服务程序获得了具体的设备号且为有效按键中断之后就由定时器代理领导来全盘接手。如果要处理中断就会调用定时器的handler中断处理程序来处理。

还有在消抖处理那段程序时,习惯性的想的太智能,忘记了status的状态值是代码中起初自己设定好的,即使那个时候你按键是按下的,状态也是status_UP。当时困扰了很久,想着若是按下后状态自然就应该是down和低电平%……&**¥#@

起初看到setup _timer是初始化定时器,一直在纳闷,搞不明白到底在哪里给定时器赋了初始值,后面看消抖调用mod_timer搞了半天才明白原来这个初始化的真正意思其实是说:把每个最初的定时器赋予超时便返回到指定的处理函数的功能。这也是初始化,只是说没有具体给这个定时器马上赋初始值而已。

下面是按键测试程序:

/*********************************************************************************
 *      Copyright:  (C) 2015 songyong<handy_skyoutlook.com>
 *                  All rights reserved.
 *
 *       Filename:  copy.c
 *    Description:  This file
 *
 *        Version:  1.0.0(2015年04月18日)
 *         Author:  sky <[email protected]>
 *      ChangeLog:  1, Release initial version on "2015年04月18日 13时17分14秒"
 *
 ********************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/time.h>

#define BUTTON_STATUS  4
#define KEY1  0x1
#define KEY2  0x2
#define KEY3  0x4
#define KEY4  0x8
/********************************************************************************
 *  Description:
 *   Input Args:
 *  Output Args:
 * Return Value:
 ********************************************************************************/
int main (int argc, char **argv)
{
    int i = 0;
    int button_fd;
    int ret;
    int current_button;

    button_fd = open("/dev/button",0);

    if(button_fd < 0)
    {
        printf("Open buttons device faild!\n");
        exit(1);
    }
    while(1)
    {
         ret = read(button_fd,¤t_button,sizeof(BUTTON_STATUS));

    if (ret != sizeof(current_button) )
         {
           printf("Read button device faild.\n");
         }
    else
        {
    switch(current_button)
            {
                case KEY1: printf("KEY1 Down.!\n");break;
                case KEY2: printf("KEY2 Down.!\n");break;
                case KEY3: printf("KEY3 Down.!\n");break;
                case KEY4: printf("KEY4 Down.!\n");break;//其实在驱动代码的定时器中断处理程序handler中已有输出打印代码
                default: printf("kkey error\n");
            }
        }
    }
    return 0;
} /* ----- End of main() ----- */

接下来弄按键点亮LED灯^。^

时间: 2024-08-07 08:24:05

Linux设备驱动之button按键驱动学习与小结的相关文章

linux系统下标准GPIO按键驱动

前言: linux下platform平台驱动是为了方便隔离bsp与driver,利于移植.体现好代码的高内聚,低耦合.Linux设备驱动模型中,关心总线,设备和驱动三个实体.总线将设备和驱动绑定.在系统每注册一个设备的时候,都会寻找与之相匹配的驱动,相反的,每加载一个驱动的时候,也会寻找与之匹配的设备.匹配由总线完成.linux发明了一种虚拟的总线,称之为platform总线,相应的设备称之为platform_device,驱动为platform_driver. 基于这个模型,又根据面向对象的思

Linux input 子系统应用之按键驱动

硬件平台:s5pv210 软件平台:Linux2.6.35.7 应用程序:inputk2_app.c #include <stdio.h> #include <fcntl.h> #include <linux/input.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char** argv) { int fd; int count; int i = 0; int

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备

【转】深入浅出:Linux设备驱动之字符设备驱动

深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称

Linux嵌入式学习-烟雾传感器驱动-字符设备驱动-按键驱动

MQ-2烟雾气敏传感器模块在X210v3开发板上的驱动. 现在需要一个MQ-2烟雾气敏传感器模块的驱动.其检测烟雾超过一定的标准后,会返回一个不同的电平,和按键驱动差不多. 但是在编写驱动的时候,需要用GPH2_3号引脚.但是在内核中先ioremap地址然后配置,发现无法控制gpio,也无法进入中断. 后来发现,如果需要使用gpio,需要先申请,然后才能使用. 具体程序如下: #include <linux/module.h> #include <linux/init.h> #in

Linux Platform设备驱动学习与小结

Platform 设备先被注册然后platfrom驱动加载时会调用驱动程序中的probe()入口函数,扫描系统中已注册的设备,通过.Name域找到匹配设备后将驱动和设备绑定.一个驱动可以对应多个设备,但是一个设备只对一个驱动.Linux下的虚拟总线platform对应设备platform_device,对应的驱动为platform_driver.一个很不恰当的例子:设备好比男人,驱动好比女人,platform作为媒人,将两个对上眼的(name域相同)的相匹配到一起.然后男人(device)到她(

Linux设备驱动开发学习(1):前言

虽然网络上已经有很多Linux设备驱动开发学习的文章和博客,更是有很多经典的Linux设备驱动开 发的书籍,写这些博文似乎意义不大,但把自己的学习过程.学习心得记录下来,一方面有着强化巩固的 意义,另一方面也是把所学知识转化为自己所得的必要途径之一,这是我写这些的博客的原始动力.

linux设备驱动的学习之一

由于项目上要用到,于是乎我要学习linux设备驱动的编写,开始的时候还比较清楚,能够对简单的GPIO控制操作实现出来,但是项目上要用到的是SPI和GPIO的输入中断来读取AD的电压值,然后就陷入到了一个庞大的设备代码阅读中去了,尤其是platform device的学习,到现在都还没有理清其中的关系,虽然搜索了很多网上的文章,但庆幸的是我有一种比着框框买鸭蛋的精神,我想要比着这些源码画一个出来.以前没有在LPC1768上使用过SPI,导致对SPI是一个完全陌生的状态,不清楚他的传输方式,这也是学

Hasen的linux设备驱动开发学习之旅--异步通知

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:异步通知 * Date:2014-11-05 */ 一.异步通知的概念和作用 阻塞和非阻塞访问.poll()函数提供了较好地解决设备访问的机制,但是如果有了异步通知整套机制就更 加完整了. 异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这 一点非常类似于硬件上"中断"的概