字符驱动设计----mini2440 LED驱动设计之路
字符驱动设计----mini2440 LED驱动设计之路
大多数书籍在介绍字符驱动过于理论化,纵览一章都是些文字,再附上一些零碎的代码,看的人头晕,时间长了自然就不想看了。 对于驱动的学习,刚开始不能过于理论化,一定要结合实际,要不然像空中楼台,住在上面,心里老感觉不踏实。那么如何入手呢?我觉得三点是很重要的:
1 驱动设计的总体框架(对于每种类型的驱动设计,最好画出模型图)
2 参考现有实例化的驱动
3 针对某一具体硬件,自己写驱动来实现
接下来以字符驱动设计为例,也是mini2440led驱动实现。
1 字符设备驱动模型如下图所示,这是一个总体调用框架图,具体的字符设备驱动模型参照另外一篇引用的文章【字符设备驱动模型】,驱动层主要做的工作是file_operations结构体中一些关键函数的实现,包括open,read,ioctl。本例中主要实现open,ioctl。
2 现有驱动模型实例
- #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++) {
- // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
- s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
- }
- return 0;
- }
- /* 应用程序对设备文件/dev/leds执行ioclt(...)时,
- * 就会调用s3c24xx_leds_ioctl函数
- */
- static int s3c24xx_leds_ioctl(
- struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
- {
- if (arg > 4) {
- return -EINVAL;
- }
- switch(cmd) {
- case IOCTL_LED_ON:
- // 设置指定引脚的输出电平为0
- s3c2410_gpio_setpin(led_table[arg], 0);
- return 0;
- case IOCTL_LED_OFF:
- // 设置指定引脚的输出电平为1
- s3c2410_gpio_setpin(led_table[arg], 1);
- return 0;
- default:
- return -EINVAL;
- }
- }
- /* 这个结构是字符设备驱动程序的核心
- * 当应用程序操作设备文件时所调用的open、read、write等函数,
- * 最终会调用这个结构中指定的对应函数
- */
- static struct file_operations s3c24xx_leds_fops = {
- .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
- .open = s3c24xx_leds_open,
- .ioctl = s3c24xx_leds_ioctl,
- };
- /*
- * 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数
- */
- static int __init s3c24xx_leds_init(void)
- {
- int ret;
- /* 注册字符设备驱动程序
- * 参数为主设备号、设备名字、file_operations结构;
- * 这样,主设备号就和具体的file_operations结构联系起来了,
- * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数
- * LED_MAJOR可以设为0,表示由内核自动分配主设备号
- */
- 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;
- }
- /*
- * 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数
- */
- 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("http://my.csdn.net/czxyhll."); // 驱动程序的作者
- MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver"); // 一些描述信息
- MODULE_LICENSE("GPL"); // 遵循的协议
|
评论暂时关闭