天天看點

Linux驅動開發之按鍵驅動程式

1、平台裝置

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <asm/arch/regs-gpio.h>

#include <linux/interrupt.h>

#include <linux/device.h>

#include <linux/io.h>

static struct resource s3c_buttons_resource[] = {

[0]={

.start = S3C24XX_PA_GPIO,

.end   = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,

.flags = IORESOURCE_MEM,       //IO記憶體

},

[1]={

.start = IRQ_EINT0,       //注冊外部中斷0的中斷号     

.end   = IRQ_EINT0,

.flags = IORESOURCE_IRQ,

},

[2]={

.start = IRQ_EINT2,        //注冊外部中斷2的中斷号

.end   = IRQ_EINT2,

.flags = IORESOURCE_IRQ,

},

[3]={

.start = IRQ_EINT11,       //注冊外部中斷11的中斷号

.end   = IRQ_EINT11,

.flags = IORESOURCE_IRQ,

},

[4]={

.start = IRQ_EINT19,        //注冊外部中斷19的中斷号

.end   = IRQ_EINT19,

.flags = IORESOURCE_IRQ,

}

};

static struct platform_device s3c_buttons = {

.name = "s3c2440-buttons",   //裝置的名稱

.id = 0,                   

.num_resources = ARRAY_SIZE(s3c_buttons_resource),  //資源數量

.resource =  s3c_buttons_resource,   //注冊到核心中的資源

 };

static int __init platform_init(void)

{

    platform_device_register(&s3c_buttons);

    return 0;

}

static void __exit platform_exit(void)

{

    platform_device_unregister(&s3c_buttons);  //登出裝置

}

module_init(platform_init);

module_exit(platform_exit);

MODULE_LICENSE("GPL");

MODULE_ALIAS("platform:s3c2440buttons");

2、平台驅動

#include <linux/module.h>

#include <linux/types.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/interrupt.h>

#include <linux/clk.h>

#include <linux/uaccess.h>

#include <linux/io.h>

#include <asm/arch/regs-gpio.h>

#include <linux/poll.h>

#include <linux/irq.h>

#include <asm/unistd.h>

#include <linux/device.h>

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

static volatile int ev_press = 0;

static int key_value;

static struct device     *buttons_dev;

static struct resource *buttons_mem;

static struct resource   *buttons_irq;

static void __iomem    *buttons_base;

static int button_irqs[4];

//中斷處理函數

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

int i;

for(i=0; i<4; i++){

if(irq == button_irqs[i]){

//printk("==>interrput number:%d\n",irq);  

key_value = i; //根據中斷号獲得鍵值

ev_press =1;  //标志位置1

wake_up_interruptible(&button_waitq);//在中斷裡面把讀程序喚醒

}

}

    return IRQ_RETVAL(IRQ_HANDLED);

}

static int s3c24xx_buttons_open(struct inode *inode, struct file *file)

{

int i;

int err = 0;

for(i=0; i<4; i++){

if (button_irqs[i] < 0) 

continue;

        err = request_irq(button_irqs[i],buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);

if(err)

 break;

}

if (err) {

i--;

for (; i >= 0; i--) {

if (button_irqs[i] < 0) {

continue;

}

disable_irq(button_irqs[i]);

free_irq(button_irqs[i], NULL);

}

return -EBUSY;

}

    ev_press = 0;   

    return 0;

}

static int s3c24xx_buttons_close(struct inode *inode, struct file *file)

{

    int i;    

    for (i=0; i<4; i++) {

if (button_irqs[i] < 0) {

continue;

}

free_irq(button_irqs[i],NULL); //登出中斷

    }

    return 0;

}

static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;

    if (!ev_press) {

if (filp->f_flags & O_NONBLOCK)  //判斷是否是非阻塞讀

return -EAGAIN;

else

wait_event_interruptible(button_waitq, ev_press);//阻塞讀

    }    

    ev_press = 0; //把标志位清零

    err = copy_to_user(buff, &key_value, sizeof(key_value));//把鍵值傳給使用者

    return sizeof(key_value);

}

static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)

{

    unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait);//把等待隊列添加到poll_table_struct

    if (ev_press){   //标志位,中斷控制的

        mask |= POLLIN | POLLRDNORM;

}

    return mask;

}

static struct file_operations s3c2440buttons_fops = {

    .owner   =   THIS_MODULE,

    .open    =   s3c24xx_buttons_open,

    .release =   s3c24xx_buttons_close,

    .read    =   s3c24xx_buttons_read,

    .poll    =   s3c24xx_buttons_poll,

};

static struct miscdevice s3c2440_miscdev = {

    .minor = MISC_DYNAMIC_MINOR, //自動配置設定混雜裝置的次裝置号

    .name ="buttons",            //裝置名字

    .fops = &s3c2440buttons_fops,

};

static int s3c2440_buttons_probe(struct platform_device *pdev)

{

struct resource *res;

struct device *dev;

int ret;

int size;

int i;

printk("probe:%s\n", __func__);

dev = &pdev->dev;

buttons_dev = &pdev->dev;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//獲得平台裝置注冊的IO記憶體資源

if (res == NULL) {

dev_err(dev, "no memory resource specified\n");

return -ENOENT;

}

size = (res->end - res->start) + 1;  //計算IO記憶體資源的大小

buttons_mem = request_mem_region(res->start, size, pdev->name);//申請IO記憶體資源

if (buttons_mem == NULL) {

dev_err(dev, "failed to get memory region\n");

ret = -ENOENT;

goto err_req;

}

buttons_base = ioremap(res->start, size);//把實體位址映射為虛拟位址 傳回值為虛拟位址

if (buttons_base == NULL) {

dev_err(dev, "failed to ioremap() region\n");

ret = -EINVAL;

goto err_req;

}

printk(KERN_DEBUG"probe: mapped buttons_base=%p\n", buttons_base);

  for(i=0; i<4; i++){                  //擷取中斷号

buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);//獲得平台裝置注冊的中斷資源

if(buttons_irq == NULL){

  dev_err(dev,"no irq resource specified\n");

 ret = -ENOENT;

 goto err_map;

}

button_irqs[i] = buttons_irq->start; //中斷資源裡面獲得中斷号

//printk("button_irqs[%d]=%d\n",i,button_irqs[i]);  

}

ret = misc_register(&s3c2440_miscdev);  //注冊混雜裝置

return 0;

 err_map:

iounmap(buttons_base); //解除映射

 err_req:

release_resource(buttons_mem);

kfree(buttons_mem);

return ret;

}

static int s3c2440_buttons_remove(struct platform_device *dev)//平台驅動移除的時候調用

{

iounmap(buttons_base);  //解除映射

misc_deregister(&s3c2440_miscdev); //登出混雜裝置

release_resource(buttons_mem); //登出資源

kfree(buttons_mem);

buttons_mem = NULL;

return 0;

}

static struct platform_driver s3c2440buttons_driver = {

.probe = s3c2440_buttons_probe,   //平台裝置和驅動比對的時候調用

.remove = s3c2440_buttons_remove,  //平台驅動移除的時候調用

.driver = {

.owner = THIS_MODULE,

.name = "s3c2440-buttons",    //平台驅動的名稱

},

};

static char banner[] __initdata =

"s3c2440 Buttons Driver\n";

static int __init buttons_init(void)

{

printk(banner);

platform_driver_register(&s3c2440buttons_driver);

return 0;

}

static void __exit buttons_exit(void)

{

platform_driver_unregister(&s3c2440buttons_driver);

}

module_init(buttons_init);

module_exit(buttons_exit);

MODULE_DESCRIPTION("s3c2440 Buttons Driver");

MODULE_LICENSE("GPL");

3、應用程式

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/select.h>

#include <sys/time.h>

#include <errno.h>

int main(void)

{

int buttons_fd=0;

int key_value;

buttons_fd = open("dev/buttons",O_RDWR);//打開裝置檔案

if (buttons_fd < 0) {

perror("open device buttons");

exit(1);

}

for (;;) {

fd_set rds;  //讀檔案描述符集

int ret;

FD_ZERO(&rds);  //清空讀檔案描述符集

FD_SET(buttons_fd, &rds); //把讀檔案描述符添加到檔案描述符集

ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);//條件不滿足阻塞

if (ret < 0) {

perror("select");

exit(1);

}

if (ret == 0) {

printf("Timeout.\n");

} else if (FD_ISSET(buttons_fd, &rds)) {//判斷檔案是否可讀

int ret = read(buttons_fd, &key_value, sizeof(key_value));

if (ret != sizeof(key_value)) {

if (errno != EAGAIN)

perror("read buttons\n");

continue;

} else {

printf("buttons_value: %d\n", key_value+1);

}

}

}

close(buttons_fd);

return 0;

}

繼續閱讀