基于X210的kernel完成LED驱动:
> 作者 : Scorpior
> 邮箱 : 641297548@qq.com
> 创建时间 : 2017/10/18
> 版权所有,转载请联系作者
1. 开发环境
Cpuinfo:
Processor : ARMv7 Processor rev 2 (v7l) BogoMIPS : 998.15 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 CPU implementer : 0x41 CPU architecture : 7 CPU variant : 0x2 CPU part : 0xc08 CPU revision : 2 Hardware : SMDKV210 |
Bordinfo:
Hardware : x210(SMDKV210) Machine :998 |
Systerm:
目标机:基于Linux2.6的x210v3 kernel 服务器:Ubuntu14.0(32位) 交叉编译工具链:gcc version 2009q3 |
FileSystem
友善之臂:rootfs_qtopia_qt4-20141223 NFS方式挂载:bootargs=root=/dev/nfs nfsroot=192.168.1.141:/root/rootfs/mini2440_rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200 |
硬件电路
2. 工作目的
(1) 熟悉并记录X210开发板上的驱动开发。
(2) 分析linux下的GPIO组成。
(3) 编写LED驱动,并分析,验证。
3. 编写代码
3.1功能代码的编写
1 #include <linux/miscdevice.h> 2 #include <mach/regs-gpio.h> 3 #include <linux/kernel.h> 4 #include <linux/module.h> 5 #include <linux/fs.h> 6 #include <linux/errno.h> //一些错误码 7 #include <linux/ioctl.h> 8 #include <linux/gpio.h> // 9 10 /* 11 * X210: 12 * 13 * LED1 -> D22 -> GPJ0_3 14 * LED2 -> D23 -> GPJ0_4 15 * LED3 -> D24 -> GPJ0_5 16 * LED4 -> D25 -> GPD0_1 17 */ 18 #define DEVICE_NAME "myx210_leds" 19 20 static unsigned long led_table [] = { 21 S5PV210_GPJ0(3), 22 S5PV210_GPJ0(4), 23 S5PV210_GPJ0(5), 24 S5PV210_GPD0(1), 25 }; 26 27 static const char *led_name [] = { 28 "x210_led0", 29 "x210_led1", 30 "x210_led2", 31 "x210_led3" 32 }; 33 34 static int s5pv210_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 35 { 36 switch(cmd) { 37 case 0: 38 case 1: 39 if (arg > 4) { 40 return -EINVAL; 41 } 42 gpio_direction_output(led_table[arg], !cmd); 43 return 0; 44 default: 45 return -EINVAL; 46 } 47 } 48 49 static struct file_operations dev_fops = { 50 .owner = THIS_MODULE, 51 .ioctl = s5pv210_leds_ioctl, 52 }; 53 54 static struct miscdevice misc = { 55 .minor = MISC_DYNAMIC_MINOR, 56 .name = DEVICE_NAME, 57 .fops = &dev_fops, 58 }; 59 60 static int __init dev_init(void) 61 { 62 int ret; 63 int i; 64 65 for (i = 0; i < 4; i++) { 66 ret = gpio_request(led_table[i], led_name[i]); 67 if(ret < 0){ 68 printk("gpio_request is error\n"); 69 return -1; 70 } 71 gpio_direction_output(led_table[i], 0); 72 } 73 ret = misc_register(&misc); 74 75 printk (DEVICE_NAME"\tinitialized\n"); 76 return ret; 77 } 78 79 static void __exit dev_exit(void) 80 { 81 int i =0; 82 83 for(i=0;i<4;i++) 84 { 85 gpio_free(led_table[i]); 86 } 87 misc_deregister(&misc); 88 } 89 90 module_init(dev_init); 91 module_exit(dev_exit); 92 MODULE_LICENSE("GPL"); 93 MODULE_AUTHOR("x210 Inc.");
3.2 Makefile部分的编写
#ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个 #KERN_VER = $(shell uname -r) #KERN_DIR = /lib/modules/$(KERN_VER)/build # 开发板的linux内核的源码树目录 KERN_DIR = /x210_kernel obj-m += leds-s5pv210.o all: make -C $(KERN_DIR) M=`pwd` modules cp: cp *.ko /root/rootfs/mini2440_rootfs/lib/modules/2.6.35.7/2.6.32.2-FriendlyARM -f .PHONY: clean clean: make -C $(KERN_DIR) M=`pwd` modules clean
3.3 驱动的编译和安装
(1)使用“make”命令编译。
(2)使用“make cp”将编译好的.ko文件cp到目标机中的制定目录
(3)在目标机中使用“insmod ***.ko”命令安装驱动
(4)在目标机中使用“lsmod”查看驱动是否安装成功
(5)使用“rmmod ***”卸载驱动(注:不能+.ko)
4. 框架分析
4.1misc 杂散类设备注册
4.1.1数据结构分析
(1)设备数据
/* * X210: * * LED1 -> D22 -> GPJ0_3 * LED2 -> D23 -> GPJ0_4 * LED3 -> D24 -> GPJ0_5 * LED4 -> D25 -> GPD0_1 */ #define DEVICE_NAME "myx210_leds" static unsigned long led_table [] = { S5PV210_GPJ0(3), S5PV210_GPJ0(4), S5PV210_GPJ0(5), S5PV210_GPD0(1), }; static const char *led_name [] = { "x210_led0", "x210_led1", "x210_led2", "x210_led3" };
(2)文件操作结构体:file_operations
static struct file_operations dev_fops = { .owner = THIS_MODULE, .ioctl = s5pv210_leds_ioctl, };
(3)misc杂散类设备设备结构体
static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, };
(4) misc杂散类设备的注册
ret = misc_register(&misc); if(ret < 0){ printk(KERN_ERR " func %s is error\n", "misc_register"); return ret; }
(5) misc杂散类设备的注销
ret = misc_deregister(&misc); if(ret != 0){ printk(KERN_ERR " func %s is error\n", "misc_register"); return ret; }
(6) 文件操作函数集:ioctl的实例化
static int s5pv210_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > 4) { return -EINVAL; } gpio_direction_output(led_table[arg], !cmd); return 0; default: return -EINVAL; } }
(7) 头文件包含
1.#include <linux/miscdevice.h>
路径: ./include/linux/miscdevice.h
作用:提供杂散类设备结构体,提供misc_register和misc_deregister函数API
2. #include <linux/delay.h>
路径:./include/linux/delay.h
作用:提供mdelay、udelay、ndelay、ssleep、msleep接口
3. #include <linux/fs.h>
路径:./include/linux/fs.h
作用:定义file_operations结构体,大量与文件操作有关的函数等。
4.#include <mach/regs-gpio.h>
路径:./arch/arm/mach-s5pv210/include/mach/regs-gpio.h
作用:定义chip的大量GPIO引脚的虚拟寄存器地址
5.#include <linux/module.h>
路径:./include/linux/module.h
作用:定义了MODULE_LICENSE、EXPORT_SYMBOL、EXPORT_SYMBOL_GPL、MODULE_VERSION等全局宏
6.#include <linux/gpio.h>
路径:./arch/arm/mach-s5pv210/include/mach/gpio.h
作用:定义芯片的gpio引脚号
5. 验证驱动
5.1测试功能代码编写
1 int main (int argc, char **argv) 2 { 3 int fd = 0; 4 int i = 0; 5 6 fd = open(DRV_PATHNAME,O_RDWR|O_TRUNC); 7 if(fd < 0) 8 { 9 perror("open :"); 10 return -1; 11 } 12 13 for(i=0;i<4;i++) 14 { 15 ioctl(fd,1,i); 16 sleep(1); 17 } 18 19 for(i=3;i>=0;i--) 20 { 21 ioctl(fd,0,1); 22 sleep(1); 23 } 24 25 close(fd); 26 return (0); 27 }
5.2 Makefile的编写
obj = s5pv210_leds_apps depend = s5pv210_leds_apps.c all: arm-linux-gcc -o $(obj) $(depend) cp: cp $(obj) /root/rootfs/mini2440_rootfs/my_drv_app_test -f .PHONY: clean clean: rm $(obj)