当前位置:文档之家› 嵌入式ARM平台下的Linux字符设备驱动实例

嵌入式ARM平台下的Linux字符设备驱动实例

嵌入式ARM平台下的Linux字符设备驱动实例
6.1 下面以一个名为S3C2440_leds.c”的简单控制目标板LED亮灭的驱动为例进行分析。

(目标板为天嵌TQ2440;Linux2.6.25.8)。

主要功能是通过应用程序调用该驱动来按制目标板的四个LED灯的亮灭。

驱动源程序如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到
的设备名称*/
#define LED_MAJOR 231 /* 主设备号*/
/* 应用程序执行ioctl(fd, cmd, arg)时的第2 个参数*/
#define IOCTL_LED_ON 0
#define IOCTL_LED_OFF 1
/* 用来指定LED 所用的GPIO 引脚*/
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
/* 用来指定GPIO 引脚的功能:输出*/
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
/*应用程序对设备文件/dev/leds 执行open()时,
*就会调用s3c24xx_leds_open */
static int s3c24xx_leds_open(struct inode *inode, struct file *file)
{
int i;
for(i=0; i<4; i++)
{
s3c2410_gpio_cfpin(led_table[i], led_cfg_table[i])
}
return 0;
}
/*应用程序对设备文件/dev/leds 执行iotcl()时,
*就会调用s3c24xx_leds_iotcl
*/
static int s3c24xx_leds_iotcl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (arg > 4)
{
return -EINV AL;
}
switch(cmd) {
case IOCTL_LED_ON:
s3c2410_gpio_setpin(led_table[arg], 0);
return 0;
case IOCTL_LED_OFF:
s3c2410_gpio_setpin(led_table[arg], 1);
return 0;
default:
return -EINV AL;
}
}
/*这个结构是字符设备驱动程序的核心
*当应用程序操作设备文件时调用的open、read等函数,
*最终会调用这个结构中指定的对应函数
static sturct s3c24xx_leds_fops = {
.owner = THIS_MODULE,
.open = s3c24xx_leds_open,
.ioctl = s3c24xx_leds_ioctl
};
/*模块的初始化函数*/
static int __init s3c24xx_leds_init(void)
{
int ret;
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
if(ret < 0)
{
printk(DEVICE_NAME "can't register major number\n");
return ret;
}
printk(DEVICE_NAME "initialized\n");
return 0;
}
/*模块的撤销函数*/
static void __exit s3c24xx_leds_exit(void)
{
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
}
/*指定驱动程序的初始化函数和卸载函数*/
module_init(s3c24xx_leds_init);
module_exit(s3c24xx_leds_exit);
/*加入描述信息*/
MODULE_AUTHOR("ckz");
MODULE_DESCRIPTION("S3C2440 LED Driver");
MODULE_LICENSE("GPL");
写好的驱动放在内核源文件目录下:linux2.6.25.8]#drivers/char/
6.2 以模块形式编译及加载
修改同目录下的“Kconfig”文件,在合适的地方添加如下内容:
Config S3C2440_LEDS
tristate “S3C2440 LEDS Driver”
depends on ARCH_S3C2440
help
LEDS on S3C2440
然后再通目录下修改“Makefile”,添加如下内容:
Obj-$(CONFIG_ S3C2440_LEDS) += S3C2440_leds o
添加完成以上内容之后,输入#make menuconfig,然后配置如下
Device Drivers -
Character devices ->
<M> S3C2440 LEDS Driver
将其选择为“M”,然后保存配置,编译出内核镜像烧写到开发板中。

然后再使用命令#make SUBDIR=drivers/char modules,编译出驱动模块,在内核目录下的“drivers/char”下面,名为S3C2440_leds.Ko,将其复制到开发板中的/lib目录中。

加载、卸载驱动到目标系统中。

在/lib目录下:
***] insmod S3C2440_leds.KO /***加载驱动***/
***] rmmod S3C2440_leds.KO /***卸载驱动***/
6.3 下面编写简单的应用程序来测试刚才的驱动程序,新建名为leds.c的文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 || on < 0 || on > 1 || led_no < 1 || led_no > 4) {
fprintf(stderr, "Usage: leds led_no 0|1\n");
exit(1);
}
fd = open("/dev/GPIO-Control", 0);
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd, on, (led_no-1));
close(fd);
return 0;
}
因为这只是一个简单的应用程序所以没有必要编写Makefile文件,直接使用arm-linux-gcc 命令编译并将其传到目标板上运行即可!
在终端中输入:./leds 2 0
则目标板上的第二个LED灯亮被点亮。

相关主题