搜索
bottom↓
回复: 1

[I.P.LED][Innovation Practise Linux&Embedded Department][sbc2410按键驱动分

[复制链接]

出0入0汤圆

发表于 2008-8-3 15:34:01 | 显示全部楼层 |阅读模式
Makefile:
# The path of kernel source code
INCLUDEDIR = /home/study/part2/lesson3/linux-2.4.18/include/

# Compiler
CC = arm-linux-gcc

# Options
CFLAGS = -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
-mapcs -fno-strict-aliasing -fno-common -fno-common -pipe \
-mapcs-32 -march=armv4 -mtune=arm9tdmi -mshort-load-bytes \
-msoft-float  -I$(INCLUDEDIR)

# Target
OBJS = sbc2410_buttons.o

all: $(OBJS)

$(OBJS): sbc2410_buttons.c
        $(CC) $(CFLAGS) -c $<
        $(CC) app-button.c -static -o app-button       
       
install:
        insmod $(OBJS)

uninstall:
        rmmod sbc2410_buttons

.PHONY: clean
clean:
        rm -f *.o
        rm -f app-button


sbc2410_buttons.c
/*头文件*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/delay.h>

#include <asm/hardware.h>

#define DEVICE_NAME        "buttons"        /*设备的名字叫做buttons,可以在/dev下面看到*/
#define BUTTON_MAJOR 232                /*主设备号是232,可以在/proc/devices里面看到*/

static struct key_info {                /*定义一个关于按键信息的结构体*/
        int irq_no;                                        /*中断号*/
        unsigned int gpio_port;                /*端口*/
        int key_no;                                        /*按键编号*/
} key_info_tab[4] = {                        /*定义结构体变量*/
        { IRQ_EINT1, GPIO_F1, 1 },        /*四个按键的内容,端口号因为硬件连接关系所确定*/
        { IRQ_EINT2, GPIO_F2, 2 },
        { IRQ_EINT3, GPIO_F3, 3 },
        { IRQ_EINT7, GPIO_F7, 4 },
};

static int ready = 0;                        /*准备好了么*/
static int key_value = 0;                /*按键的值*/

/* 定义并初始化等待队列:queue-> buttons_wait*/
static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);

/*
函数名称:static void buttons_irq(int irq, void *dev_id, struct pt_regs *reg)
函数功能:按键中断处理程序
传入参数:int irq, void *dev_id, struct pt_regs *reg
传出参数:
说明:调用按键处理程序,传入参数是:中断号,设备号,寄存器参数
*/
static void buttons_irq(int irq, void *dev_id, struct pt_regs *reg)
{
        struct key_info *k;                /*定义指向按键结构体的指针*/
        int i;                                        /*变量*/
        int found = 0;                        /*发现了么*/
        int up;                                        /* up=1 按键没有被按下*/
        int flags;                                /*标志*/
       
       
        for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++)
        {/*循环,结构体数组总的大小除以一个成员的大小,得到一共有多少个成员*/
                k = key_info_tab + i;/*指向每一次循环的结构体变量*/
                if (k->irq_no == irq) /*按键结构体中的中断号和我们获得的一样么*/
                {
                        found = 1;/*如果一样了,我们标记发现了事件*/
                        break;/*跳出循环*/
                }
        }
        if (!found) /*如果没有发现按键事件*/
        {
                printk("bad irq %d in button\n", irq);/*内核打印信息,表示这个中断有问题*/
                return;/*返回*/
        }

        /* 由于是快速中断处理,所以认为可以不用关中断 */
        //save_flags(flags);
        //cli();
       
        /* 设置端口模式 按键结构体数组中变量中的成员的端口,设置成为输入状态*/
        set_gpio_mode_user(k->gpio_port, GPIO_MODE_IN);
       
        /* 判断是按键弹起还是按下 读取端口状态*/
        up = read_gpio_bit(k->gpio_port);
       
        /* 重设中断模式,同时也清除了中断标志位 设置中断号,双边沿触发,不用上拉电阻*/
        set_external_irq(k->irq_no, EXT_BOTH_EDGES, GPIO_PULLUP_DIS);
        //restore_flags(flags);
        if (up) /*按键没有被按下的时候是大数*/
                key_value = k->key_no + 0x80;/*加一个128而已*/
        else /*按键被按下了是按键的编号*/
                key_value = k->key_no;

               ready = 1;/*判断到了有中断,有数据可读*/
              
               /* 唤醒等待的进程 */
        wake_up_interruptible(&buttons_wait);
}

/*
函数名称:static int request_irqs(void)
函数功能:按键的中断请求程序
传入参数:没有
传出参数:
说明:该函数将调用按键中断处理程序
*/
static int request_irqs(void)
{
        struct key_info *k;                /*定义指向按键结构体的指针*/
        int i;                                        /*变量*/
        /* 为4个键分别注册中断 */
        for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++)
        {
                k = key_info_tab + i;
                /* 设置中断标志,考虑如果设置成单沿中断,或者使用上拉电阻会有什么影响? */
                set_external_irq(k->irq_no, EXT_BOTH_EDGES, GPIO_PULLUP_DIS);
                /*set_external_irq(int irq, int edge, int pullup)是系统函数
                方式的话有: EXT_LOWLEVEL                0
                                                  EXT_HIGHLEVEL                1
                                                  EXT_FALLING_EDGE        2
                                                  EXT_RISING_EDGE        4
                                                  EXT_BOTH_EDGES        6
                                                  GPIO_PULLUP_DIS
                                                  GPIO_PULLUP_EN
                                                  
                */
                if (request_irq(k->irq_no, &buttons_irq, SA_INTERRUPT, DEVICE_NAME, &buttons_irq))
                /*申请中断,修改中断向量表,接管中断处理程序*/
                        return -1;
        }
        return 0;
}

/*
函数名称:static void free_irqs(void)
函数功能:释放中断
传入参数:没有
传出参数:
说明:
*/
static void free_irqs(void)
{
        struct key_info *k;
        int i;
        for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++)
        {
                k = key_info_tab + i;
                free_irq(k->irq_no, buttons_irq);
        }
}

/*
函数名称:static int sbc2410_buttons_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
函数功能:读按键
传入参数:struct file * file, char * buffer, size_t count, loff_t *ppos
传出参数:
说明:
*/
static int sbc2410_buttons_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
{/*传入的参数有 文件指针,缓冲区,大小,位置*/
        static int key;
        int flags;
        int repeat;
       
        /* 判断是否有数据可读 */
        if (!ready)
                return -EAGAIN;
        
        if (count != sizeof key_value)
                return -EINVAL;
       
        /*
        save_flags(flags);
       
        if (key != key_value)
        {
                key = key_value;
                repeat = 0;
        }
        else
        {
                repeat = 1;
        }
       
       
        restore_flags(flags);

        if (repeat) {
                return -EAGAIN;
        }
        */
        key = key_value;
       
        copy_to_user(buffer, &key, sizeof key);
        
        /* 清除准备好标志 */
        ready = 0;
        return sizeof key_value;
}

/*
函数名称:static unsigned int sbc2410_buttons_select(struct file *file, struct poll_table_struct *wait)
函数功能:POLL方法
传入参数:struct file *file, struct poll_table_struct *wait
传出参数:
说明:
*/
static unsigned int sbc2410_buttons_select(
        struct file *file,
        struct poll_table_struct *wait)
{
        /* 判断是否有按键中断产生 */
        if (ready)
                return 1;
        /*没有数据的时候阻塞*/
        poll_wait(file, &buttons_wait, wait);
        return 0;
}

/*操作结构体fs.h里面*/
static struct file_operations sbc2410_buttons_fops = {
        owner:        THIS_MODULE,
        poll: sbc2410_buttons_select,
        read: sbc2410_buttons_read,
};

static devfs_handle_t devfs_handle;
/*
函数名称:static int __init sbc2410_buttons_init(void)
函数功能:按键初始化
传入参数:没有
传出参数:
说明:
*/
static int __init sbc2410_buttons_init(void)
{
        int ret;

        ready = 0;
       
        /* 注册字符设备驱动程序 */
        ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &sbc2410_buttons_fops);
        /*int register_chrdev(unsigned int major, const char *name, struct file_operations *fops)*/
        if (ret < 0) {
          printk(DEVICE_NAME " can't register major number\n");
          return ret;
        }
       
        /* 注册中断处理程序 ,调用按键的中断请求程序*/
        ret = request_irqs();
        if (ret) {
                unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
                printk(DEVICE_NAME " can't request irqs\n");
                return ret;
        }
       
        /* 创建设备节点 */
        devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT,
                                BUTTON_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &sbc2410_buttons_fops, NULL);

        return 0;
}

/*
函数名称:static void __exit sbc2410_buttons_exit(void)
函数功能:注销
传入参数:没有
传出参数:
说明:
*/
static void __exit sbc2410_buttons_exit(void)
{
        devfs_unregister(devfs_handle);
        free_irqs();
        unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
        /*int unregister_chrdev(unsigned int major, const char *name)*/
}

module_init(sbc2410_buttons_init);
module_exit(sbc2410_buttons_exit);
MODULE_LICENSE("GPL");


app-button.c
/*
*      Buttons Example for Matrix V
*
*      Copyright (C) 2004 capbily - friendly-arm
*        capbily@hotmail.com
*/
/*头文件*/
#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;
        int key_value;
        /*打开设备文件*/
        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);        /*设置*/
                /*select调用*/
                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);
                        }
                               
                }
        }

        close(buttons_fd);
        return 0;
}


阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 18:58

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表