2117.03.06备注:在恢复文章时代码的格式丢失,请匆阅读此文,以免误导.
本文简略地分析总结了一下linux的字符型设备驱动编写流程,以满足一些简单的驱动编写,如驱动硬件IO等操作.
除了要包含的那一堆头文件外,linux的字符型驱动主要程序实际上只有两个接口:
1 2 3 |
module_initmydev_init; module_exitmydev_exit; |
module_init与module_ext分别用来指明内核在初始化与卸载驱动时所指向的函数入口. 在指明了函数入口后,就须要编写这两个函数的具估内容了.
首先:拿mydev_init来说:
1 2 3 4 5 6 7 |
static int __init mydev_initvoid; int ret; some_codes; ret=register_chrdevXXX_MAJOR,DEVICE_NAME,&XXX_fops; some_codes; |
其中mydev_init的函数格式为固定的static int __init mydev_init(void)
;
整个函数里最重要的一步当然是ret=register_chrdev(XXX_MAJOR,DEVICE_NAME,&XXX_fops)
;
作 用是向内核注册一个字符型设备驱动,其中第一个参数为主设备号(如果为0表示由系统分配),第二个为驱动名称(将会在/dev目录下升成这个文件),第三 个参数为file_operations结构函数地址.我们要做的工作就是去完成file_operations这个结构体里的各个成员,它们完成与应用 程序的沟通.
在file_operations结构体中有非常多的成员,我们只须要完成我们关心的部份即可,不须要完全是实现它.以下是一个适用于s3c2440控制IO的一个演示示例,这里我们假定GPG4上接有一个LED,我们的目的就是驱动它的亮灭:
1.创建文件csmekdev.c放到内核源码目录/drivers/char.内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/miscdevice.h> #include <linux/gpio.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <mach/regs-clock.h> #include <plat/regs-timer.h> #include <mach/regs-gpio.h> #include <linux/cdev.h> #include <linux/fs.h> #define DEVICE_NAME "csmekdev" //设备名csmekdev #define CSMEKDEV_MAJOR 220 //主设备号220 static int csmekdev_ioctlstruct inode *inode, struct file *file, unsigned int cmd, unsigned long arg s3c2410_gpio_setpinS3C2410_GPG4, cmd; static ssize_t dev_writestruct file *file, const char *buffer, size_t count, loff_t *ppos unsigned char stats; int ret; if count == 0 return count; ret = copy_from_user & stats, buffer, sizeof stats ? -EFAULT : 0; if ret return ret; stats &= 0x01; s3c2410_gpio_setpinS3C2410_GPG4, stats; return count; static struct file_operations csmekdev_fops = .owner = THIS_MODULE, .ioctl = csmekdev_ioctl, .write = dev_write, ; static int __init csmekdev_module_initvoid int ret; int i; ret = register_chrdevCSMEKDEV_MAJOR, DEVICE_NAME, &csmekdev_fops; if ret < 0 printkDEVICE_NAME " can't register major number\n"; return ret; s3c2410_gpio_cfgpinS3C2410_GPG4, S3C2410_GPIO_OUTPUT; /* s3c2410_gpio_setpin(S3C2410_GPG4, 0); */ printkDEVICE_NAME " initialized\n"; return 0; static void __exit csmekdev_module_exitvoid unregister_chrdevCSMEKDEV_MAJOR, DEVICE_NAME; printkDEVICE_NAME " removed\n"; module_initcsmekdev_module_init; module_exitcsmekdev_module_exit; |
2.然后修改Kconfig在文件最后加入
config CSMEKDEV_SMDK2440
tristate "CsmekDev on SMDK2440"
`
[MEDIUM]3.再修改makefile加入:[/MEDIUM]
“obj-$(CONFIG_CSMEKDEV_SMDK2440) += csmekdev.o”
然后menuconfig时,在 Device Drivers->Character devices中,将CsmekDev on SMDK2440编译进内核(即选择为* 不能是选择为M).然后编译,烧录.在开发板上运行”cat /proc/devices”可以看到我们的驱动已经注册到内核,如下图:
http–csmek.com-images-article-201110-proc
然后我们建立设备文件:”mknod /dev/csmekdev c 220 0″.
这 样就会在/dev目录下建立一个csmekdev的文件.我们对这个文件的操作就可完成一些动作比如: “echo 0 > /dev/csmekdev” 即GPG4置低,”echo 1 > /dev/csmekdev”置高GPIO,也可以使用IOCTL的方式,只需要我们去完善csmekdev_fops结构体成员.