|
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周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|