//头文件 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm-generic/ioctl.h> #define LED_NUM_ON _IOW('L',0x1122,int) #define LED_NUM_OFF _IOW('L',0x3344,int) #define LED_ALL_ON _IO('L',0x1234) #define LED_ALL_OFF _IO('L',0x5678) //面向对象编程----设计设备的类型 struct s5pv210_led{ unsigned int major; struct class * cls; struct device * dev; int data; }; struct s5pv210_led *led_dev; volatile unsigned long *gpco_conf; volatile unsigned long *gpco_data; //实现设备操作接口 int led_open(struct inode *inode, struct file *filp) { printk("--------^_^ %s------------ ",__FUNCTION__); //将对应的管脚设置为输出 *gpco_conf &= ~(0xff<<12); //19--12清0 *gpco_conf |= 0x11<<12; //19---12赋值:00010001 return 0; } ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags) { int ret; printk("--------^_^ %s------------ ",__FUNCTION__); //应用空间数据转换为内核空间数据 ret = copy_from_user(&led_dev->data,buf,size); if(ret != 0){ printk("copy_from_user error! "); return -EFAULT; } if(led_dev->data){ //点灯 *gpco_data |= 0x3<<3; }else{ //灭灯 *gpco_data &= ~(0x3<<3); } return size; } long led_ioctl(struct file *filp, unsigned int cmd , unsigned long args) { int num = args+2; printk("--------^_^ %s------------ ",__FUNCTION__); switch(cmd){ case LED_NUM_ON: //将某个灯点亮 if(num != 3 && num != 4) return -EINVAL; else *gpco_data |= 0x1 << num; break; case LED_NUM_OFF: //将某个灯点灭掉 if(num != 3 && num != 4) return -EINVAL; else *gpco_data &= ~(0x1 << num); break; case LED_ALL_ON: //两个灯同时亮 *gpco_data |= 0x3<<3; break; case LED_ALL_OFF: //两个灯同时灭 *gpco_data &= ~(0x3<<3); break; default: printk("unknow cmd! "); } return 0; } int led_close(struct inode *inode, struct file *filp) { printk("--------^_^ %s------------ ",__FUNCTION__); //灭灯 *gpco_data &= ~(0x3<<3); return 0; } static struct file_operations fops = { .open = led_open, .write = led_write, .unlocked_ioctl = led_ioctl, .release = led_close, }; //加载函数和卸载函数 static int __init led_init(void) //加载函数-----在驱动被加载时执行 { int ret; printk("--------^_^ %s------------ ",__FUNCTION__); //0,实例化设备对象 //参数1 ---- 要申请的空间的大小 //参数2 ---- 申请的空间的标识 led_dev = kzalloc(sizeof(struct s5pv210_led),GFP_KERNEL); if(IS_ERR(led_dev)){ printk("kzalloc error! "); ret = PTR_ERR(led_dev); return -ENOMEM; } //1,申请设备号 #if 0 //静态申请主设备号 led_dev->major = 256; ret = register_chrdev(led_dev->major,"led_drv",&fops); if(ret < 0){ printk("register_chrdev error! "); return -EINVAL; } #else //动态申请主设备号 led_dev->major = register_chrdev(0,"led_drv",&fops); if(led_dev->major < 0){ printk("register_chrdev error! "); ret = -EINVAL; goto err_kfree; } #endif //2,创建设备文件-----/dev/led1 led_dev->cls = class_create(THIS_MODULE,"led_cls"); if(IS_ERR(led_dev->cls)){ printk("class_create error! "); ret = PTR_ERR(led_dev->cls); goto err_unregister; } led_dev->dev = device_create(led_dev->cls,NULL,MKDEV(led_dev->major,0),NULL,"led"); if(IS_ERR(led_dev->dev)){ printk("device_create error! "); ret = PTR_ERR(led_dev->dev); goto err_class; } //3,硬件初始化----地址映射 gpco_conf = ioremap(0xE0200060,8); gpco_data = gpco_conf+1; return 0; err_class: class_destroy(led_dev->cls); err_unregister: unregister_chrdev(led_dev->major,"led_drv"); err_kfree: kfree(led_dev); return ret; } static void __exit led_exit(void) //卸载函数-----在驱动被卸载时执行 { printk("--------^_^ %s------------ ",__FUNCTION__); device_destroy(led_dev->cls,MKDEV(led_dev->major,0)); class_destroy(led_dev->cls); unregister_chrdev(led_dev->major,"led_drv"); kfree(led_dev); } //声明和认证 module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL");
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #define LED_NUM_ON _IOW('L',0x1122,int) #define LED_NUM_OFF _IOW('L',0x3344,int) #define LED_ALL_ON _IO('L',0x1234) #define LED_ALL_OFF _IO('L',0x5678) int main(void) { int fd; fd = open("/dev/led",O_RDWR); if(fd < 0){ perror("open"); exit(1); } //闪灯 while(1){ //第一个灯闪 ioctl(fd,LED_NUM_ON,1); sleep(1); ioctl(fd,LED_NUM_OFF,1); sleep(1); //第二个灯闪 ioctl(fd,LED_NUM_ON,2); sleep(1); ioctl(fd,LED_NUM_OFF,2); sleep(1); //两个灯同时闪 ioctl(fd,LED_ALL_ON); sleep(1); ioctl(fd,LED_ALL_OFF); sleep(1); } close(fd); return 0; }
#指定内核源码路径 KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8 CUR_DIR = $(shell pwd) MYAPP = test all: #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c clean: #删除上面编译生成的文件 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean rm -rf $(MYAPP) install: cp *.ko $(MYAPP) /opt/rootfs/drv_module #指定当前目录下哪个文件作为内核模块编 obj-m = led_drv.o