1.LED.c
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/io.h> #include <linux/uaccess.h> static int major = 99; static int minor = 0; static dev_t devno; static struct class *cls; static struct device *test_device; #define PB_CFG 0x01c20824 //PB口控制寄存器 #define PB_DAT 0x01c20834 //PB口数据寄存器 #define DEVICE_MINOR_NUM 2 #define DEVICE_NAME "led" static int *PBcfg; static int *PBdat; void fs4412_led_off(int num) //关灯 { switch (num)//这里只要将管脚对应的位置1即可如pb4 那么或上0001 0000即可 { case 1: iowrite32(ioread32(PBdat) | (1<<4),PBdat);//置高关灯 break; case 2: iowrite32(ioread32(PBdat) | (1<<5),PBdat); break; default: break; } } void fs4412_led_on(int num) //开灯程序 { switch (num)//这里只要将管脚对应的位置0即可如pb4 那么与上1110 1111即可 { case 1: iowrite32(ioread32(PBdat) &(~(1<<4)),PBdat);//置低开灯 break; case 2: iowrite32(ioread32(PBdat) &(~(1<<5)),PBdat);//置低开灯 break; default: fs4412_led_off(1);//如果输入错误那么都关灯 fs4412_led_off(2); break; } } static int led_open(struct inode *inode, struct file *filep)//文件打开时默认都关灯 { //open fs4412_led_off(1); fs4412_led_off(2); return 0; } static int led_release(struct inode *inode, struct file *filep)//文件关闭时默认都关灯 { //close fs4412_led_off(1); fs4412_led_off(2); return 0; } static ssize_t led_read(struct file *filep, char __user *buf, size_t len, loff_t *pos) { return 0; } static ssize_t led_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos) { int led_num; if (len != 4) { return -EINVAL; } if (copy_from_user(&led_num, buf, len)) { return -EFAULT; } fs4412_led_on(led_num); //printk(KERN_INFO "led_num =%d ", led_num); return 0; } static struct file_operations hello_ops = { .open = led_open, .release = led_release,//当执行close()函数时会调用release() .read = led_read, .write = led_write, }; static void fs4412_led_init(void) { PBcfg = ioremap(PB_CFG, 4); //映射到物理地址 PBdat = ioremap(PB_DAT, 4); //配置io口为输出模式 //先左移12位取反得 FFFF0FFF 相与 再或上 0x1<<12 ioread32就是调用readl writel((ioread32(PBcfg) & ~(7 << 16)) | (1 << 16), PBcfg); //PB4 设定out writel((ioread32(PBcfg) & ~(7 << 20)) | (1 << 20), PBcfg); //PB5 设定out } static int led_init(void) { int ret; if (major)//静态申请方法 { devno = MKDEV(major, minor); ret = register_chrdev(major,DEVICE_NAME, &hello_ops);// } else//动态申请方法 { ret=alloc_chrdev_region(&devno,minor,DEVICE_MINOR_NUM,DEVICE_NAME);//这个好像还没有添加file_operation major=MAJOR(devno); minor=MINOR(devno); ret = register_chrdev(major,DEVICE_NAME, &hello_ops); printk(KERN_INFO "alloc region %d ",major); } cls = class_create(THIS_MODULE, "myclass");//创建类 if (IS_ERR(cls)) { unregister_chrdev(major, DEVICE_NAME); printk(KERN_ERR "class create failed "); return -EBUSY; } printk(KERN_INFO "class create successs "); //创建设备节点 test_device = device_create(cls, NULL, devno, NULL, DEVICE_NAME); //mknod /dev/led if (IS_ERR(test_device)) { class_destroy(cls); unregister_chrdev(major,DEVICE_NAME); printk(KERN_ERR "create /dev/led failed "); return -EBUSY; } printk(KERN_INFO "create /dev/led successs "); fs4412_led_init(); //初始化io return 0; } void fs4412_led_unmap(void)//内存取消映射 { iounmap(PBcfg); iounmap(PBdat); } static void led_exit(void) { fs4412_led_unmap();//先取消映射 device_destroy(cls, devno); class_destroy(cls); unregister_chrdev(major,DEVICE_NAME); printk(KERN_INFO "led_exit "); } MODULE_AUTHOR("Zheng qihang <zqh18268832867@gmail.com>"); MODULE_DESCRIPTION("LED driver for V3s controllers"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("module:leds-V3s"); module_init(led_init); module_exit(led_exit);
2.main.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(void) { int led_fd,i,lednum; led_fd=open("/dev/led",O_RDWR); if(led_fd<0) { perror("open failed! "); return -1; } for(i=0;i<10;i++)//循环10次 { lednum=0; write(led_fd,&lednum,sizeof(int)); lednum=i%2+1; write(led_fd,&lednum,sizeof(int)); sleep(1); } close(led_fd); return 0; }
3.Makefile
#General Purpose Makefile for cross compile Linux Kernel module ifneq ($(KERNELRELEASE),) obj-m := led.o #+=是连接字符串 else OBJ := led ARCH := arm CROSS_COMPILE := /usr/local/arm/arm-linux-gnueabihf-4.9/bin/arm-linux-gnueabihf- KERN_DIR := /home/zqh/lichee/linux-zero-4.14.y #选择内核路径 SOURCE := main.c TARGET := test_led PWD =$(shell pwd) #当前路径 FILE_PWD=$(strip $(PWD)) LICHEDIR := /root/led_driver/ all: make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERN_DIR) M=$(PWD) modules $(CROSS_COMPILE)gcc $(SOURCE) -o $(TARGET) .PHONY : clean clean : rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order .*.o.ko.cmd .*.ko.cmd .*.mod.o.cmd .*.o.cmd $(TARGET) install: scp $(FILE_PWD)/$(OBJ).ko root@172.24.41.12:$(LICHEDIR) scp $(FILE_PWD)/$(TARGET) root@172.24.41.12:$(LICHEDIR) endif