1建立驱动工程,设置eclipse 打开eclipse如下图
2建议将工程目录选择在NFS共享的那个目录,这样方便从开发板加载驱动或者执行程序,新建一个C项目,空项目
3一直下一步,直到下图位置,填好自己的arm-linux-gcc的路径。
5到这一步新建工程完成了,先别急着添加.c文件。在工程上面右键,属性,到 C/C++常规---->Code Analysis---->路径和符号
6点击下方ExportSettings,将设置导出为xml文件.
7点击确定 应用 退出即可。到开那个.xml文件,用文本编辑器打开即可,
8现在我们还需要将autoconf.h中的宏定义加入到Eclipse中,执行如下步骤打开内核的这个目录 include/generated/ ,我的是 cd /home/cfan/linux/linux-3.0.1/include/generated/ ,另外打开一个终端 cd到这个目录
9在刚刚这个终端中执行[cpp] view plaincopycat autoconf.h |grep define |awk '{print '' $2 '' $3 ''}' > symbo
10打开这个目录/home/cfan/linux/linux-3.0.1/include/generated,会多了一个文件
11将 symbol.xml这个文件用文本编辑器打开
12此时文本编辑器里面打开了两个xml文件了,将之前导出eclipse的那个xml文件打开,需要添加一行代码,在这两行代码之间(如果有两个,是下面的那个)[html] view plaincopy 添加[html] view plaincopy__KERNEL__1 如下图
14再将刚刚那个symbol.xml文件里面的所有代码复制到[html] view plaincopy__KERNEL__1 这行的下一行,如下图
15在上面的一个[html] view plaincopy 添加[cpp] view plaincopy/home/cfan/linux/linux-3.0.1/include /home/cfan/linux/linux-3.0.1/arch/arm/include /home/cfan/linux/linux-3.0.1/arch/arm/plat-samsung/include /home/cfan/linux/linux-3.0.1/arch/arm/mach-s3c64xx/include 这里面的路径要看自己实际的内核路径进行修改,也可以在工程属性中一个一个的添加,就是添加一个linux有关的路径而已。
16保存退出即可。再打开eclipse的刚刚那个导出的位置,现在将导出的文件导入即可
17点击完成即可,如果导入出问题了,仔细对照我的教程。应用,退出即可,导入后会多了几个路径,内核目录里面的头文件路径
19代码是之前写的[cpp] view plaincopy/**************************************************************************************************************** * 文件名称 : led_drive.c //系统头文件 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //--------------------------// #include #include #include //--------------------------// #include #include #include /////////////////////////////////////////////// //驱动模块名称 #define DEVICE_NAME 'OK6410_LED' //函数声明 /////////////////////////////////////////////// static long OK6410_LED_ioctl( struct file *file, unsigned int cmd, unsigned long arg); static ssize_t OK6410_LED_write( struct file *file, const char __user *buff, size_t size, loff_t *loff); static ssize_t OK6410_LED_read( struct file *file, char __user *buff, size_t size, loff_t *loff); /////////////////////////////////////////////////// /* 这个结构是字符设备驱动的核心 * 当应用程序操作设备文件所提供的open,read,write等函数, * 最终会调用到这个结构中的对应函数 */ static struct file_operations dev_fops = { .owner = THIS_MODULE, //这是一个宏,指向编译模块时自动创建的__this_module变量 .unlocked_ioctl = OK6410_LED_ioctl, .read = OK6410_LED_read, .write = OK6410_LED_write }; //注册驱动所使用的相关信息 static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, //驱动模块名称 .fops = &dev_fops, }; //LED设备访问信号量 struct semaphore led_sem; /**************************************************************************************************************** *函数名 : static int __init OK6410_LED_init(void) *功能 : LED模块初始化函数 *参数 : 无 *返回 : 0:成功;<0:失败 *依赖 : linux底层宏定义 *作者 : 异灵元(cp1300@139.com) *创建时间 : 2012/08/27 17:28 *最后修改时间: 2012/08/27 17:28 *说明 : 初始化LED硬件,注册LED驱动 ****************************************************************************************************************/ static int __init OK6410_LED_init(void) { int ret; unsigned int reg; //GPIOM0-3 推挽输出 reg = readl(S3C64XX_GPMCON); //获取GPIOM寄存器数据 reg &= (~0xffff); //清除之前设置 reg |= 0x1111; //推挽输出 writel(reg,S3C64XX_GPMCON); //配置IO模式 reg = readl(S3C64XX_GPMDAT); //读取输出寄存器之前数据 reg |= 0xf; writel(reg,S3C64XX_GPMDAT); //写入1,让所有的灯都熄灭 ret = misc_register(&misc); //注册驱动 if(ret < 0) { printk(DEVICE_NAME ' can't initialized LED!\n'); return ret; } init_MUTEX(&led_sem); //注册信号量 printk(DEVICE_NAME ' initialized\n'); return 0; //返回成功 } /**************************************************************************************************************** *函数名 : static long OK6410_LED_ioctl( struct file *file, unsigned int cmd, unsigned long arg) *功能 : 发送命令给LED驱动模块,无实际作用,直接返回0 *参数 : 无作用 *返回 : 0 *依赖 : 无 *作者 : 异灵元(cp1300@139.com) *创建时间 : 2012/08/27 17:28 *最后修改时间: 2012/08/27 17:28 *说明 : 无 ****************************************************************************************************************/ static long OK6410_LED_ioctl( struct file *file, unsigned int cmd, unsigned long arg) { return 0; } /**************************************************************************************************************** *函数名 : static ssize_t OK6410_LED_write( struct file *file, const char __user *buff, size_t size, loff_t *loff) *功能 : 写数据到LED驱动模块,低电平灯亮 *参数 : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 *返回 : 0:成功;<0:失败 *依赖 : linux底层宏 *作者 : 异灵元(cp1300@139.com) *创建时间 : 2012/08/27 17:43 *最后修改时间: 2012/08/27 17:43 *说明 : 点灯函数,低电平亮,0-3BIT有效;对应4个LED ****************************************************************************************************************/ static ssize_t OK6410_LED_write( struct file *file, const char __user *buff, size_t size, loff_t *loff) { unsigned int reg; if(down_interruptible(&led_sem)) //获取信号量 return -ERESTARTSYS; reg = readl(S3C64XX_GPMDAT); reg &= (~0xf); reg |= buff[0] & 0xf; writel(reg,S3C64XX_GPMDAT); up(&led_sem); //释放信号量 return 0; } /**************************************************************************************************************** *函数名 : static ssize_t OK6410_LED_read( struct file *file, char __user *buff, size_t size, loff_t *loff) *功能 : 读LED状态,低电平灯亮 *参数 : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 *返回 : 0:成功;<0:失败 *依赖 : linux底层宏 *作者 : 异灵元(cp1300@139.com) *创建时间 : 2012/08/27 17:48 *最后修改时间: 2012/08/27 17:48 *说明 : 读取灯的状态,低电平灯亮,0-3bit有效;对应4个LED ****************************************************************************************************************/ static ssize_t OK6410_LED_read( struct file *file, char __user *buff, size_t size, loff_t *loff) { unsigned int reg; if(down_interruptible(&led_sem)) //获取信号量 return -ERESTARTSYS; reg = readl(S3C64XX_GPMDAT); buff[0] = reg | 0xfffffff0; up(&led_sem); //释放信号量 return 0; } /**************************************************************************************************************** *函数名 : static void __exit OK6410_LED_exit(void) *功能 : 卸载LED驱动 *参数 : 无 *返回 : 无 *依赖 : linux底层宏 *作者 : 异灵元(cp1300@139.com) *创建时间 : 2012/08/27 17:50 *最后修改时间: 2012/08/27 17:50 *说明 : 卸载驱动 ****************************************************************************************************************/ static void __exit OK6410_LED_exit(void) { unsigned int reg; //GPIOM0-3 输入 reg = readl(S3C64XX_GPMCON); //获取GPIOM寄存器数据 reg &= (~0xffff); //清除之前设置 writel(reg,S3C64XX_GPMCON); //配置IO模式 misc_deregister(&misc); //卸载驱动 } //动态加载驱动接口(必须) module_init(OK6410_LED_init); module_exit(OK6410_LED_exit); //其它信息(非必需) MODULE_AUTHOR('cp1300@139.com'); //驱动程序作者 MODULE_DESCRIPTION('OK6410(S3C6410) LED Driver'); //一些描述信息 MODULE_LICENSE('GPL'); //遵循的协议 此时会有警告,不管他。
20在工程属性中将自动生成makefile选项去掉
213.新建一个makefile文件修改makefile,编译驱动文件[cpp] view plaincopyARCH=arm CROSS_COMPILE=arm-linux- obj-m := led.o KDIR :=/home/cfan/linux/linux-3.0.1 PWD :=$(shell pwd) all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean led.o文件就是你的编译文件的名称,按照自己实际情况修开
22保存后按 ctrl+B编译工程。完成后会发现目录里面多了一个led.ko,这就是编译好的LED驱动模块。在开发板上面加载驱动,没有NFS的将led.ko复制到开发板中,不管是SD卡还是U盘,有NFS的就好办了,在串口终端中CD到工程目录
23执行 insmod led.ko 加载驱动,加载成功后会发现LED灯都灭了,后面会添加这个驱动的测试程序
24到这里使用eclipse编写驱动就完成了,其实一共就三步,只不过我写的比较详细而已,以后每次建立工程可以直接复制工程或者导入之前的那个xml文件皆可,。 在嵌入式驱动开发过程中需要频繁的加载卸载驱动,但是使用rmmod的时候你会发现,驱动无法卸载,如 rmmod led,卸载的时候不需要.ko,直接是模块名。