6.1 下面以一个名为S3C2440_leds.c”的简单控制目标板LED亮灭的驱动为例进行分析。(目标板为天嵌TQ2440;Linux2.6.25.8)。主要功能是通过应用程序调用该驱动来按制目标板的四个LED灯的亮灭。
驱动源程序如下:
#include #include #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 -EINVAL; } 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 -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 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 -> 然后再使用命令#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 int main(int argc, char **argv) { } 因为这只是一个简单的应用程序所以没有必要编写Makefile文件,直接使用arm-linux-gcc 命令编译并将其传到目标板上运行即可! 在终端中输入:./leds 2 0 则目标板上的第二个LED灯亮被点亮。 int on; int led_no; int fd; if (argc != 3 || sscanf(argv[1], \"%d\ 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\if (fd < 0) { perror(\"open device leds\"); } exit(1); ioctl(fd, on, (led_no-1)); close(fd); return 0; 因篇幅问题不能全部显示,请点此查看更多更全内容