嵌入式ARM平台下的Linux字符设备驱动实例.doc
Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-date嵌入式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_tablei, led_cfg_tablei) 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 -EINVAL; switch(cmd) case IOCTL_LED_ON: s3c2410_gpio_setpin(led_tablearg, 0); return 0; case IOCTL_LED_OFF: s3c2410_gpio_setpin(led_tablearg, 1); return 0; default: return -EINVAL; /*这个结构是字符设备驱动程序的核心 *当应用程序操作设备文件时调用的 open、read等函数, *最终会调用这个结构中指定的对应函数 static sturct file_operations 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 numbern"); return ret; printk(DEVICE_NAME "initializedn"); 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(argv1, "%d", &led_no) != 1 | sscanf(argv2,"%d", &on) != 1 | on < 0 | on > 1 | led_no < 1 | led_no > 4) fprintf(stderr, "Usage: leds led_no 0|1n");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灯亮被点亮。-