开发环境:
SYSTEM : Ubuntu-12.04
Board : Mini2440-t35
Bootloader : u-boot-1.1.6
Kernel : Linux-2.6.22.6
CROSS_COMPILE: arm-linux-gcc v3.4.5
一、搭建程序框架
点击(此处)折叠或打开
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <asm/arch/regs-gpio.h>
-
#include <asm/hardware.h>
-
-
#define DEVICE_NAME "MINI2440_BUTTONS" //设备名称
-
#define DEVICE_MAJOR 231 //主设备号
-
-
static struct file_operations buttons_polling_drv_fops = {
-
.owner = THIS_MODULE,
-
};
-
-
static int __init buttons_polling_drv_init(void)
-
{
-
int ret;
-
ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &buttons_polling_drv_fops);
-
if(ret < 0)
-
{
-
printk(DEVICE_NAME "\t can't register major number!\n");
-
}
-
printk(DEVICE_NAME"\t initialized!\n");
-
return 0;
-
}
-
static void __exit buttons_polling_drv_exit(void)
-
{
-
unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME);
-
}
-
-
module_init(buttons_polling_drv_init);
-
module_exit(buttons_polling_drv_exit);
- MODULE_LICENSE("GPL");
点击(此处)折叠或打开
-
KERN_DIR = /home/wangtisheng/work/kernel/linux-2.6.22.6-mini2440
-
-
all:
-
make -C $(KERN_DIR) M=`pwd` modules
-
-
clean:
-
make -C $(KERN_DIR) M=`pwd` modules clean
-
rm -rf modules.order
-
- obj-m += buttons_polling_drv.o
要操作S3C2440的IO口,首先要进行IO的初始化,根据MINI2440的原理图,应将按键对应GPIO口设置为输出模式,内核源码arch/arm/plat_s3c24xx/gpio.c中提供了初始化管脚功能的函数void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function),将初始化函数写在buttons_polling_drv_open函数中,代码如下:
添加读取按键对应GPIO口状态的函数,内核源码arch/arm/plat_s3c24xx/gpio.c中提供了设置GPIO状态的函数unsigned int s3c2410_gpio_getpin(unsigned int pin),s3c2410_gpio_getpin()的返回值是GPxDAT寄存器的值与所要读取的GPIO对应的bit mask相与以后的值,0表示该GPIO对应的bit为0, 非0表示该bit为1。根据MINI2440原理图,当按键无动作,即按键没有被按下时GPIO口状态为1,反之为0。
注:内核提供了专门的函数用于访问用户空间的指针:
int copy_from_user(void *to,const void __user *from,int n); //从用户空间拷贝数据到内核空间
int copy_to_user(void __user *to,const void *form,int n); //从内核区中读取数据到用户区
内核空间 :
Linux操作系统,特别是它的内核,用一种简单而有效的方法管理机器的硬件,给用户提供一个简捷而统一的编程接口。同样的,内核,特别是它的设备驱动程序,是连接最终用户/程序员和硬件的一座桥或者说是接口。任何子程序或者函数只要是内核的一部分(例如:模块,和设备驱动),那它也就是内核空间的一部分。
用户空间.:
最终用户的应用程序,像UNIX的shell或者其它的GUI的程序(例如,gedit),都是用户空间的一部分。很显然,这些应用程序需要和系统的硬件进行交互。但是,他们不是直接进行,而是通过内核支持的函数进行。
三、测试驱动程序buttons_polling_drv_test.c
执行如下命令即可得到测试程序的可执行文件:
arm-linux-gcc -o buttons_polling_drv_test buttons_polling_drv_test.c
四、驱动加载、测试
将模块
挂载模块
# insmod
# cat /proc/devices
至此即可看到驱动程序已挂载如下:
231 MINI2440_BUTTONS
创建该设备节点
# mknod /dev/
驱动测试:
执行 # ./buttons_polling_drv_test执行按键驱动测试程序,当有按键按下时出现如下结果,

将程序后台运行,使用top命令查看各进程的占用资源情况,可以看到
完整代码如下:
buttons_polling_drv.rar
点击(此处)折叠或打开
-
static unsigned long buttons_polling_table[] = {
-
S3C2410_GPG0,
-
S3C2410_GPG3,
-
S3C2410_GPG5,
-
S3C2410_GPG6,
-
S3C2410_GPG7,
-
S3C2410_GPG11,
-
};
-
static unsigned long buttons_polling_cfg_table[] = {
-
S3C2410_GPB0_INP,
-
S3C2410_GPB3_INP,
-
S3C2410_GPB5_INP,
-
S3C2410_GPB6_INP,
-
S3C2410_GPB7_INP,
-
S3C2410_GPB8_INP,
-
};
-
-
static int buttons_polling_drv_open(struct inode *inode, struct file *file)
-
{
-
int i;
-
-
for (i = 0; i < 6; i++) {
-
s3c2410_gpio_cfgpin(buttons_polling_table[i], buttons_polling_cfg_table[i]);
-
}
-
return 0;
- }
注:内核提供了专门的函数用于访问用户空间的指针:
int copy_from_user(void *to,const void __user *from,int n); //从用户空间拷贝数据到内核空间
int copy_to_user(void __user *to,const void *form,int n); //从内核区中读取数据到用户区
内核空间 :
Linux操作系统,特别是它的内核,用一种简单而有效的方法管理机器的硬件,给用户提供一个简捷而统一的编程接口。同样的,内核,特别是它的设备驱动程序,是连接最终用户/程序员和硬件的一座桥或者说是接口。任何子程序或者函数只要是内核的一部分(例如:模块,和设备驱动),那它也就是内核空间的一部分。
用户空间.:
最终用户的应用程序,像UNIX的shell或者其它的GUI的程序(例如,gedit),都是用户空间的一部分。很显然,这些应用程序需要和系统的硬件进行交互。但是,他们不是直接进行,而是通过内核支持的函数进行。
点击(此处)折叠或打开
-
ssize_t buttons_polling_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
-
{
-
unsigned char key_vals[6];
-
-
if(size != sizeof(key_vals))
-
return -EINVAL;
-
-
key_vals[0] = (s3c2410_gpio_getpin(S3C2410_GPG0) & (1<<0)) ? 1 : 0; //值为1表示按键没有被按下,反之按键被按下
-
key_vals[1] = (s3c2410_gpio_getpin(S3C2410_GPG3) & (1<<3)) ? 1 : 0;
-
key_vals[2] = (s3c2410_gpio_getpin(S3C2410_GPG5) & (1<<5)) ? 1 : 0;
-
key_vals[3] = (s3c2410_gpio_getpin(S3C2410_GPG6) & (1<<6)) ? 1 : 0;
-
key_vals[4] = (s3c2410_gpio_getpin(S3C2410_GPG7) & (1<<7)) ? 1 : 0;
-
key_vals[5] = (s3c2410_gpio_getpin(S3C2410_GPG11) & (1<<11)) ? 1 : 0;
-
-
copy_to_user(buf,key_vals,sizeof(key_vals));
-
-
return sizeof(key_vals);
- }
点击(此处)折叠或打开
-
#include <fcntl.h>
-
#include <stdio.h>
-
-
int main(int argc,char **argv)
-
{
-
int fd;
-
unsigned char key_vals[6];
-
int cnt = 0;
-
-
fd = open("/dev/MINI2440_BUTTONS", O_RDWR);
-
if(fd < 0)
-
{
-
printf("can't open\n");
-
}
-
-
while(1)
-
{
-
read(fd,key_vals,sizeof(key_vals));
-
if( !key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3] || !key_vals[4] || !key_vals[5] )
-
{
-
printf("%4d key pressed %d %d %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5]);
-
}
-
}
-
return 0;
- }
arm-linux-gcc -o buttons_polling_drv_test buttons_polling_drv_test.c
四、驱动加载、测试
将模块
buttons_polling_drv.ko
和测试程序buttons_polling_drv_test拷贝至根文件系统根目录,我的开发板mini2440采用NFS方式挂载根文件系统。挂载模块
# insmod
buttons_polling_drv.ko
# cat /proc/devices
至此即可看到驱动程序已挂载如下:
231 MINI2440_BUTTONS
创建该设备节点
# mknod /dev/
MINI2440_BUTTONS
c 231 0驱动测试:
执行 # ./buttons_polling_drv_test执行按键驱动测试程序,当有按键按下时出现如下结果,

将程序后台运行,使用top命令查看各进程的占用资源情况,可以看到
buttons_polling_drv_test进程占用了CPU的99%的资源,可见查询方式是非常消耗CPU资源的,下一步将该程序修改为中断方式实现。
完整代码如下:
