基于S3C2440的linux驱动

发布者:玄幻剑客最新更新时间:2016-05-04 来源: eefocus关键字:S3C2440  linux驱动 手机看文章 扫描二维码
随时随地手机看文章

MINI2440_BUTTON.C

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define DEVICE_NAME     "buttons"  

#define BUTTON_MAJOR    232        

 

struct button_irq_desc {

    int irq;

       int pin;

       int pin_setting;

       int number;

    char *name;   

};

 

 

static struct button_irq_desc button_irqs [] = {

    {IRQ_EINT8, S3C2410_GPG0, S3C2410_GPG0_EINT8, 0, "KEY1"},

    {IRQ_EINT11, S3C2410_GPG3,  S3C2410_GPG3_EINT11,  1, "KEY2"},

    {IRQ_EINT13,  S3C2410_GPG5,  S3C2410_GPG5_EINT13,   2, "KEY3"},

    {IRQ_EINT14,  S3C2410_GPG6,  S3C2410_GPG6_EINT14,   3, "KEY4"},

    {IRQ_EINT15,  S3C2410_GPG7,  S3C2410_GPG7_EINT15,   4, "KEY5"},

    {IRQ_EINT19,  S3C2410_GPG11,  S3C2410_GPG11_EINT19,   5, "KEY6"},

};

 

 

static volatile int key_values [] = {0, 0, 0, 0, 0, 0};

 

 

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

 

 

static volatile int ev_press = 0;

 

 

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

    int up = s3c2410_gpio_getpin(button_irqs->pin);

 

       if (up)

              key_values[button_irqs->number] = (button_irqs->number + 1) + 0x80;

       else

              key_values[button_irqs->number] = (button_irqs->number + 1);

      

    ev_press = 1;                 

    wake_up_interruptible(&button_waitq);  

   

    return IRQ_RETVAL(IRQ_HANDLED);

}

 

 

 

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

{

    int i;

    int err;

   

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

        // 注册中断处理函数

              s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting);

        err = request_irq(button_irqs[i].irq, buttons_interrupt, NULL,

                          button_irqs[i].name, (void *)&button_irqs[i]);

              set_irq_type(button_irqs[i].irq, IRQT_BOTHEDGE);

        if (err)

            break;

    }

 

    if (err) {

        // 释放已经注册的中断

        i--;

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

                     disable_irq(button_irqs[i].irq);

            free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

        }

        return -EBUSY;

    }

   

    return 0;

}

 

 

 

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

{

    int i;

   

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

        // 释放已经注册的中断

              disable_irq(button_irqs[i].irq);

        free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

    }

 

    return 0;

}

 

 

 

static int mini2440_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, (const void *)key_values, min(sizeof(key_values), count));

    memset((void *)key_values, 0, sizeof(key_values));

 

    return err ? -EFAULT : min(sizeof(key_values), count);

}

 

 

static unsigned int mini2440_buttons_poll(

        struct file *file,

        struct poll_table_struct *wait)

{

       unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait);

    if (ev_press)

        mask |= POLLIN | POLLRDNORM;

    return mask;

}

 

 

 

static struct file_operations mini2440_buttons_fops = {

    .owner    THIS_MODULE,   

    .open     mini2440_buttons_open,

    .release =   mini2440_buttons_close,

    .read     mini2440_buttons_read,

       .poll =   mini2440_buttons_poll,

};

 

 

static int __init mini2440_buttons_init(void)

{

    int ret;

 

   

    ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &mini2440_buttons_fops);

    if (ret < 0) {

      printk(DEVICE_NAME " can't register major number\n");

      return ret;

    }

       devfs_mk_cdev(MKDEV(BUTTON_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);

   

    printk(DEVICE_NAME " initialized\n");

    return 0;

}

 

 

static void __exit mini2440_buttons_exit(void)

{

   

       devfs_remove(DEVICE_NAME);

    unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);

}

 

 

module_init(mini2440_buttons_init);

module_exit(mini2440_buttons_exit);

 

 

MODULE_AUTHOR("http://www.arm9.net");             // 驱动程序的作者

MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver");   // 一些描述信息

MODULE_LICENSE("GPL");                              // 遵循的协议

 

总结一下,程序框架。

按键的驱动主要是多了中断的处理,关于中断主要的处理函数是

 

request_irq(button_irqs[i].irq, buttons_interrupt, NULL,

button_irqs[i].name, (void *)&button_irqs[i]);

第二个参数是主要的中断处理函数。

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

    int up = s3c2410_gpio_getpin(button_irqs->pin);

 

       if (up)

              key_values[button_irqs->number] = (button_irqs->number + 1) + 0x80;

       else

              key_values[button_irqs->number] = (button_irqs->number + 1);

      

    ev_press = 1;                 

    wake_up_interruptible(&button_waitq);  

   

    return IRQ_RETVAL(IRQ_HANDLED);

}

另外还用到了两个重要的结构体:

static struct button_irq_desc button_irqs [] = {

    {IRQ_EINT8, S3C2410_GPG0, S3C2410_GPG0_EINT8, 0, "KEY1"},

    {IRQ_EINT11, S3C2410_GPG3,  S3C2410_GPG3_EINT11,  1, "KEY2"},

    {IRQ_EINT13,  S3C2410_GPG5,  S3C2410_GPG5_EINT13,   2, "KEY3"},

    {IRQ_EINT14,  S3C2410_GPG6,  S3C2410_GPG6_EINT14,   3, "KEY4"},

    {IRQ_EINT15,  S3C2410_GPG7,  S3C2410_GPG7_EINT15,   4, "KEY5"},

    {IRQ_EINT19,  S3C2410_GPG11,  S3C2410_GPG11_EINT19,   5, "KEY6"},

};

struct button_irq_desc {

    int irq;

       int pin;

       int pin_setting;

       int number;

    char *name;   

};

而驱动程序中的最重要的部分,file_operations为

static struct file_operations mini2440_buttons_fops = {

    .owner    THIS_MODULE,   

    .open     mini2440_buttons_open,

    .release =   mini2440_buttons_close,

    .read     mini2440_buttons_read,

       .poll =   mini2440_buttons_poll,

};

程序中其他的任务就是丰满这个机构体,使得应用程序在调用open,close等的时候可以在

驱动中找到对应的项。

这里的request_irq在open函数里调用的。

至于注册的部分跟LEDS那些是一样的,就不多说啦。

再附个应用程序供参考:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

int main(void)

{

       int i;

       int buttons_fd;

       int key_value[4];

 

      

       buttons_fd = open("/dev/buttons", 0);

       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 {

                           

                            for (i = 0;i < sizeof(key_value)/sizeof(key_value[0]); i++)

                                printf("K%d %s, key value = 0x%02x\n", i+1, (key_value[i] & 0x80) ? "released"     : \

                                                                                        key_value[i] ? "pressed down" : "", \

                                                                                key_value[i]);

                     }

                           

              }

       }

 

      

       close(buttons_fd);

       return 0;

 

}

关键字:S3C2440  linux驱动 引用地址:基于S3C2440的linux驱动

上一篇:基于S3C2440嵌入式Linux系统下的一个DS18B20驱动
下一篇:ARM-Linux驱动移植--DM9000网卡驱动移植

推荐阅读最新更新时间:2024-03-16 14:52

基于嵌入式Linux的TFT LCD IP及驱动的设计
系统总体设计方案 本系统的总体设计框图如图1所示。 图1 系统框图 Nios II处理器在SDRAM中开辟帧缓冲(Frame buffer),可以是单缓冲也可以是双缓冲。以单缓冲为例。处理器将一帧图像数据(640×480×2Bytes,RGB565,16bit)存入帧缓冲,然后将帧缓冲的首地址写入到LCD控制器,并启动LCD控制器。该控制器自动从传来的首地址处开始读取数据,并按照TFT的格式输出。图中各模块由 Avalon Bus连接在一起。Avalon Bus是一种简单的总线结构,Nios II处理器和各种外设都是通过Avalon Bus连接在一起。由图1可以看出,作为Slaver的SDRAM Controller分别
[单片机]
基于嵌入式<font color='red'>Linux</font>的TFT LCD IP及<font color='red'>驱动</font>的设计
S3C2440读取NAND Flash的总结
在网上找了一些资料,又结合自己的经历谈一下我对NAND Flash 的了解。 S3C2440 板的Nand Flash 支持由两部分组成:Nand Flash 控制器(集成在S3C2440 CPU)和Nand Flash 存储芯片(K9F1208U0B)两大部分组成。当要访问Nand Flash中的数据时,必须通过Nand Flash控制器发送命令才能完成。所以, Nand Flash相当于S3C2440的一个外设,而不位于它的内存地址区. NAND Flash 的数据是以bit 的方式保存在memory cell,一般来说,一个cell 中只能存储一个bit。这些cell 以8 个或者16 个为单位,连成bit line,
[单片机]
对<font color='red'>S3C2440</font>读取NAND Flash的总结
linux2.6.32.2 mini2440平台移植--LCD 背光驱动
1.3.1 LCD 背光控制原理 到目前为止,我们一直都在命令行下移植,查看结果,在 mini2440/micro2440 开发板中,LCD 背光是通过 CPU 的 LCD_PWR 引脚来控制的,从原理图中可以看出,它对应于 GPG4 。 当 LCD_PWR 输出为高电平 1 时,将打开背光;当输出为低电平 0 时,将关闭背光(注意:这里只是打开和关闭背光,而并没有背光亮度的调节作用)。 1.3.2 在内核中添加背光驱动程序 现在,我们需要增加一个简单的背光驱动,以便能够通过软件便可简单的控制背光的开关。我们要达到的目的是:在命令终端通过向背光设备发送偶数比如 0 便可关闭背光,发送奇数比如 1 便可打开背光,这样
[单片机]
S3C2440之UART操作(FIFO中断模式)
3个独立的串口,每一个都可以利用DMA 和中断方式操作。每个包含2个64字节FIFO,一个接,一个发。 非FIFO模式相当于FIFO模式的一个寄存器缓冲模式。 每一个UART有7种状态,overrun错误,校验错误,帧错误,断点,接收缓冲区准备好,发送缓冲区为空,发送移位寄存器为空。 当接收移位寄存器中的数据传给FIFO的时候,且接收的数据触发了Rx FIFO的阀值,Rx中断产生了。 发送器中FIFO的还未发得数据到达Tx FIFO阀值的时候,Tx中断产生了。(我觉得应该理解为:发送器中FIFO发送结束,即为空的时候产生中断。) 功能:在串口上输入16字节,包括回车,然后会把输入的字符回显在串口终端
[单片机]
S3C2440代码重定位分析
一、NAND启动 此处NAND大小为256M,当从NAND启动时,0地址为片内SRAM,NOR不可见。由于NAND不支持XIP,所以在启动时,硬件自动复制NAND的前4K内容到片内4K的SRAM,若bin文件小于4K,则可以直接在SRAM上运行,若bin文件大于4K,片内SRAM已经满足不了需求,我们需要做的是利用这前4K的代码,完成将所有代码重定位至SDRAM(位于BANK6地址0X30000000,大小64M),然后CPU在SDRAM上运行代码。 二、NOR启动 此处的NOR大小为2M,当从NOR启动时,0地址为NOR,片内SRAM的地址为0X40000000,由于NOR支持XIP,所以低于2M的bin文件可以直接在NOR
[单片机]
s3c2440存储控制器和地址以及启动的理解
1.首先应该先了解Flash ROM的种类 NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来。 NAND Flash地址线和数据线在一起,需要用程序来控制,才能出数据。 通俗的说,只给地址不行,要先命令,再给地址,才能读到NAND的数据,在一个总线完成的。 结论是:ARM无法从NAND直接启动。除非装载完程序,才能使用NAND Flash. 2.Nand Flash的命令、地址、数据都通过I/O口发送,管脚复用,这样做做的好处是,可以明显减少NAND FLASH的管脚数目,将来如果设计者想将NAND FLASH更换为更高密度、更大容量的,也不必改动电路板。在S3C2440中NANDFLASH的控制依靠NAND F
[单片机]
S3C2440的启动
本文章是学习过一段时间S3C2440所写,如有错误之处请指正。将不胜感激! S3C2440有两种启动模式 一、NandFlash启动模式 NangFlash的价格便宜,但是它不是直接连到CPU的总线上。但是在S3C2440中有NandFlash控制器,通过控制器来访问外部的NandFlash。由于CPU不能通过地址和数据总线直接访问NandFlash,那么当设置为该启动方式时,CPU从哪里调程序呐? 在S3C2440中有一个4KB的Step-Stone,它是为NandFlash的启动而存在。当设置为 该模式时,会将4KB的Step-Stone映射到0地址,然后将NandFlash中前4KB复制到 Step-Stone中,这样系统启
[单片机]
CAN能信卡的Linux设备驱动程序设计实现
    摘要: 介绍了Linux下设备驱动程序的结构,描述了CAN通信卡设备驱动程序的软件框架以及如何将CAN设备驱动程序加入到Linux系统内核中。讨论了具体实现中为了提高通信效率和通信能力,改进设备驱动程序的缓冲区管理以及利用Linux的特点合理设计中断处理程序。     关键词: Linux操作系统 设备驱动程序 CAN通信卡 中断处理程序 目前,许多工业现场如电力系统、化工系统等大量使用控制器局部网(CAN-Controller Area Network)现场总线网络,CAN通信卡作为计算机的外设将计算机接入CAN网络。市场上有不少CAN通信卡,但基本上都不带Linux驱动程序,当需要在Linu
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多每日新闻
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved