一、安装arm-linux-gcc编译环境
拷贝天嵌光盘linux资源\linux平台开发工具包\EABI-4.3.3_EmbedSky_20100610.tar.bz2到linux虚拟机中的共享目录share(用户安装VMware tools后方可创建共享目录)。
#mkdir /opt/EmbedSky
#cp /mnt/hgfs/share/EABI-4.3.3_EmbedSky_20100610.tar.bz2 /opt/EmbedSky
#cd /opt/EmbedSky
#tar xvfj EABI-4.3.3_EmbedSky_20100610.tar.bz2 -C /
到目前为止可以就可以使用这个arm-linux-gcc命令,但是要使用这个命令的绝对位置。为了方便使用我们可以将这个命令的路径添加到系统默认路径PATH中去。
#su //进入管理员权限,/etc/profile只有管理员才能对其操作
#vim /etc/profile
# Path manipulation
if [ "$EUID" = "0" ]; then
pathmunge /sbin
pathmunge /usr/sbin
pathmunge /usr/local/sbin
pathmunge /opt/EmbedSky/4.3.3/bin//增加该项
#source /etc/profile//使设置生效
#arm-linux-gcc -v //可看到该编译器的信息
二、构建内核数
编译这个驱动的Makefile/*头文件路径,不同的内核相关的函数会略有不同*/
/*需找某个函数调用的头文件,可以用sourceinsight软件查询内核源码*/
#include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/irq.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/list.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <asm/unistd.h>
#define DEVICE_NAME "led_test"/*注册驱动时自动建立的设备名称*/ #define IOCTL_GPIO_ON 1 #define IOCTL_GPIO_OFF 0 /* 用来指定LED所用的GPIO引脚 */ static unsigned long gpio_table [] = { S3C2410_GPB5, S3C2410_GPB6, S3C2410_GPB7, S3C2410_GPB8, }; /* 用来指定GPIO引脚的功能:输出 */ static unsigned int gpio_cfg_table [] = { S3C2410_GPB5_OUTP, S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP, };
static int s3c2440_leds_open(struct inode *inode,struct file *filp)/*open函数实现的是led的灯的配置:输出*/ { int i; for(i=0;i<4;i++) { s3c2410_gpio_cfgpin(gpio_table[i],gpio_cfg_table[i]); } return 0; }
static int tq2440_gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)/*实现的是led灯的控制*/ { if (arg > 4) { return -EINVAL; } switch(cmd) { case IOCTL_GPIO_ON: s3c2410_gpio_setpin(gpio_table[arg], 0); // 设置指定引脚的输出电平为0 return 0; case IOCTL_GPIO_OFF: s3c2410_gpio_setpin(gpio_table[arg], 1);// 设置指定引脚的输出电平为1 return 0; default: return -EINVAL; } }
/*驱动框架必备,file_operations 是包含了对这个设备所能进行的操作*/
static struct file_operations dev_fops = {
.owner = THIS_MODULE, .ioctl = tq2440_gpio_ioctl, .open = s3c2440_leds_open, };
/*驱动框架必备,驱动信息的打包,用于该驱动程序的注册*/ static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, };
/*驱动框架必备,驱动初始化函数*/ static int __init dev_init(void)
{ int ret; ret = misc_register(&misc); printk (DEVICE_NAME" initialized\n"); return ret; }
/*驱动框架必备,驱动退出函数*/ static void __exit dev_exit(void)
{ misc_deregister(&misc);
printk (DEVICE_NAME" is over!\n"); }
/*驱动框架必备,模块初始化入口函数*/ module_init(dev_init);
/*驱动框架必备,模块结束入口函数*/ module_exit(dev_exit);
/*驱动框架必备,通用公共许可*/ MODULE_LICENSE("GPL");
KERN_DIR = /lib/modules/2.6.30.4-EmbedSky/build/ all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += leddrv.o
4.测试程序:
在pc机上分别编译好驱动和测试程序,/*调用系统的头文件*/
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h>
#define on 1 #define off 0 int main(int argc,char **argv) { int led_num;
/*检查输入的参数个数*/
/*第一个为函数名,第二个为开关,第三个为led灯的顺序*/ if (argc != 3) { printf("Usage: %s <ON/OFF> <led_num> \n", argv[0]); return 0; } int fd;
/*打开设备,获得它的文件描述符*/ fd = open("/dev/led_test", O_RDWR); if (fd < 0) { printf("open error\n"); return 0; }
/*将接受到的字符参数转换为数字参数*/ led_num=*(argv[2]+0)-48; if (!strcmp(argv[1], "on"))
/*调用ioctl函数,该函数会调用file_operations中的ioctl函数*/ ioctl(fd, on,(led_num-1)); else if (!strcmp(argv[1], "off")) ioctl(fd, off,(led_num-1)); return 0; }