ubuntu10.04下led驱动的测试,虚拟机是vmware8.0.1,使用的是友善提供的Linux2.6.29.4内核 led_driver.c: #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/types.h> #include <linux/ioctl.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <asm/io.h> #include <mach/regs-gpio.h> //*********************** 定义设备结构体及相关宏 ********************** #define DEVICE_NAME "led" //定义设备名 #define DEVICE_MAJOR 212 //手动定义 LED 设备的主设备号为 212 static int led_major = DEVICE_MAJOR ;
#define LED1 S3C2410_GPB5 //定义LED1 对应 S3C2410 的 GPB5 端口 ,这个地方要注意,mini2440使用的是GPB5端口 #define LED1_OUTP S3C2410_GPB5_OUTP
#define LED_ON 0 //给端口低电平(0)时,LED 亮 #define LED_OFF 1 //给端口高电平(1)时,LED 灭
//定义 LED 设备结构体 struct s3c2410_led_dev { struct cdev cdev; //LED 设备对应一个字符设备结构体 int status; //LED 状态标识,0 代表灭,1 代表亮 }; static struct s3c2410_led_dev dev;
//***************************** 函数声明 ******************************** void s3c2410_led_InitIO(void); //初始化 IO 端口的函数 //***************************** 函数定义 ******************************** void s3c2410_led_InitIO(void) { int i; //配置 LED 对应的端口为输出 s3c2410_gpio_cfgpin(LED1, LED1_OUTP); //配置 LED 初始为熄灭状态 s3c2410_gpio_setpin(LED1, LED_OFF); }
static int s3c2410_led_open(struct inode *inode,struct file *filp) { return 0; }
static int s3c2410_led_release(struct inode *inode,struct file *filp) { return 0; }
//IO控制函数 static int s3c2410_led_ioctl(struct inode *inode,struct file *filp, unsigned int cmd,unsigned long arg) { switch(cmd) { case LED_ON: s3c2410_gpio_setpin(LED1, LED_ON); dev.status = 1; break; case LED_OFF: s3c2410_gpio_setpin(LED1, LED_OFF); dev.status = 0; break; default: return -EINVAL; } return 0; }
//读LED static ssize_t s3c2410_led_read(struct file *filp,char *buffer, size_t count,loff_t *ppos) { put_user(dev.status,(int *)buffer); //读取 LED 状态 return 1; }
//写LED static ssize_t s3c2410_led_write(struct file *filp,char *buffer, size_t count,loff_t *ppos) { get_user(dev.status,(int *)buffer); if(dev.status == 0) //灭 s3c2410_gpio_setpin(LED1, LED_OFF); else if(dev.status == 1)//亮 s3c2410_gpio_setpin(LED1, LED_ON); return 1; }
//设备文件操作结构 static struct file_operations s3c2410_led_fops = { .owner = THIS_MODULE, .open = s3c2410_led_open, .release = s3c2410_led_release, .ioctl = s3c2410_led_ioctl, .read = s3c2410_led_read, .write = s3c2410_led_write, };
//安装LED static void led_setup_cdev(void) { int err ,devno = MKDEV (led_major , 0); cdev_init(&dev.cdev,&s3c2410_led_fops); dev.cdev.owner = THIS_MODULE; dev.cdev.ops = &s3c2410_led_fops; //建立设备文件操作与系统调用之间的连接 err = cdev_add(&dev.cdev,devno,1); //向系统添加该设备 if(err) printk("Error %d adding LED %d",err); }
//LED初始化 static int s3c2410_led_init(void) { int result; dev_t devno = MKDEV(led_major,0);//根据主设备号得到dev_t类型的设备号 devno if(led_major) //如果手动分配了主设备号 result = register_chrdev_region(devno,1,"DEVICE_NAME"); //向系统申请该设备号 else { //否则动态获取设备号 result = alloc_chrdev_region(&devno ,0 ,1,"DEVICE_NAME"); led_major = MAJOR(devno); } if(result < 0) return result; led_setup_cdev(); // 注册 LED 设备 s3c2410_led_InitIO(); // 初始化 IO 端口 // initialize the vals; dev.status = 0; //LED 的初始状态是灭 printk(DEVICE_NAME " initialized\n"); return 0; }
//LED卸载 static void s3c2410_led_exit(void) { cdev_del(&dev.cdev); //注销设备 unregister_chrdev_region(MKDEV(led_major,0),1); //释放设备号 }
module_init(s3c2410_led_init); module_exit(s3c2410_led_exit); MODULE_LICENSE("GPL"); //设备许可
Makefile: KERNELDIR = /opt/mini2440/linux-2.6.29 PWD := $(shell pwd) INSTALLDIR = $PWD
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux- CC = $(CROSS_COMPILE)gcc
obj-m := led_driver.o
modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install: cp led_driver.ko $(INSTALLDIR)
clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY:modules modules_install clean
led_test.c: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "sys/types.h" #include "sys/ioctl.h" #include "stdlib.h" #include "termios.h" #include "sys/stat.h" #include "fcntl.h" #include "sys/time.h"
#define LED_ON 0 #define LED_OFF 1
int main() { int fd,i=0,j=0; int led_status = 0; //初始状态为熄灭 fd = open("/dev/led", O_RDWR); //打开设备 if (fd < 0) { //如果打开设备失败,退出 perror("open device led failed !"); exit(1); } printf("led test show. press ctrl+c to exit \n"); ioctl(fd,LED_OFF);
while(1){//主循环 read (fd,&led_status,1); //读取 LED1 的当前状态到 led_status if(led_status ==0) //如果是灭的 ioctl(fd,LED_ON); //点亮 else if(led_status ==1) //如果是亮的 ioctl(fd,LED_OFF); //熄灭 printf("led: on and off\n"); for(i=0;i<300;i++) for(j=0;j<10000;j++); } close(fd); //关闭设备 return 0; }
使用4.3.2版本的交叉编译器交叉编译,然后移植到板子上运行即可看到运行效果。
在移植Linux2.6.29内核时,注意不要将内核里drivers/char/下的mini2440_leds.c文件编译进内核,否则会与我们编译的led模块产生冲突
删除模块前需要存在一个目录,/lib/modules/2.6.29.4,根据自己需要修改,安装模块:insmod module.ko,卸载模块:rmmod module
|