代码如下:
//------------------led_drv.c------------------ //驱动程序代码 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/uaccess.h> #include <asm/io.h> #include <linux/slab.h> #include <asm/string.h> #define GPX2CON_ADDR 0x11000c40 #define GPX2_SIZE 8 const char led_dev_name[] = "led_dev"; struct led_desc { unsigned int dev_major; //主设备号 unsigned int dev_minor; //次设备号 struct class *cls; struct device* dev; //创建设备文件 void *reg_virt_base; //表示是寄存器地址到基准值 }; struct led_desc *led_dev; //表示一个全局的设备对象 int chr_drv_open (struct inode *inode, struct file *filp) { printk("------------%s----------\n",__FUNCTION__); return 0; } ssize_t chr_drv_read (struct file * filp, char __user *buf, size_t count, loff_t *fpos) { int buf_read = 666; int ret; ret = copy_to_user(buf,&buf_read,count); if(ret == 0) { printk("------------%s----------\n",__FUNCTION__); } else { printk("KERN:Error to read\n"); return -EFAULT; } return 0; } ssize_t chr_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos) { int buf_write = 0; int ret; unsigned int value; ret = copy_from_user(&buf_write,buf,count); if(ret == 0) { printk("__KERN__:%d\n",buf_write); if(buf_write == 0){ value = readl((led_dev->reg_virt_base + 4)); value &= ~(0x1<<7); writel(value,led_dev->reg_virt_base + 4); } else{ value = readl((led_dev->reg_virt_base + 4)); value |= (0x1<<7); writel(value,led_dev->reg_virt_base + 4); } } else { printk("KERN:Error to read\n"); return -EFAULT; } return 0; } int chr_drv_close (struct inode *inode, struct file *filp) { printk("------------%s----------\n",__FUNCTION__); return 0; } const struct file_operations major_fops = { .open = chr_drv_open, .read = chr_drv_read, .write = chr_drv_write, .release = chr_drv_close, }; static int __init my_chrdrv_init(void) { long ret; unsigned int value; //0. 实例化全局的设备对象--分配空间 // GFP_KERNEL 如果当前内存不够用到时候,该函数会一直阻塞(休眠) led_dev = (struct led_desc *)kmalloc(sizeof(struct led_desc),GFP_KERNEL); if(led_dev == NULL){ printk(KERN_ERR "malloc error\n"); return -ENOMEM; } memset((void*)led_dev,1,sizeof(struct led_desc)); //初始化led_dev //一般都是申请资源 //申请设备号 led_dev->dev_major = register_chrdev(0, led_dev_name, &major_fops); led_dev->dev_minor = 0; if (led_dev->dev_major < 0){ printk(KERN_ERR "register failed\n"); goto err0; } // 2,创建设备文件 led_dev->cls = class_create(THIS_MODULE,"led_cls"); //IS_ERR 用于内核判断指针合法性,包括指针是否为NULL,以及指针访问非法地址 //合法为0 非法不为0 if(IS_ERR(led_dev->cls)) { printk(KERN_ERR "class create failed\n"); ret = PTR_ERR(led_dev->cls); //将指针出错的具体原因转换成一个出错码 goto err1; } // /dev/led0 //下面的"mychr%d",0 等效于 "mychr0" led_dev->dev = device_create(led_dev->cls,NULL,MKDEV(led_dev->dev_major, led_dev->dev_minor),NULL,"myled%d",0); if(IS_ERR(led_dev->dev)) { printk(KERN_ERR "devic create failed\n"); ret = PTR_ERR(led_dev->dev); //将指针出错的具体原因转换成一个出错码 goto err2; } // 3,硬件初始化 // 对地址进行映射 led_dev->reg_virt_base = ioremap(GPX2CON_ADDR, GPX2_SIZE); //下面做判断也可以用IS_ERR() if(led_dev->reg_virt_base == NULL) { printk(KERN_ERR "ioremap error\n"); ret = -ENOMEM; goto err3; } // gpio的输出功能的配置 value = readl(led_dev->reg_virt_base); value &= ~(0xf << 28); value |= (0x1 << 28); writel(value,led_dev->reg_virt_base); return 0; err3: device_destroy(led_dev->cls,MKDEV(led_dev->dev_major, led_dev->dev_minor)); err2: class_destroy(led_dev->cls); err1: unregister_chrdev(led_dev->dev_major, led_dev_name); err0: kfree((void*)led_dev); return -ENOMEM; } static void __exit my_chrdrv_exit(void) { //一般都是释放资源 //释放设备号资源 iounmap(led_dev->reg_virt_base); device_destroy(led_dev->cls,MKDEV(led_dev->dev_major, led_dev->dev_minor)); class_destroy(led_dev->cls); unregister_chrdev(led_dev->dev_major, led_dev_name); kfree((void*)led_dev); } MODULE_LICENSE("GPL"); module_init(my_chrdrv_init); module_exit(my_chrdrv_exit);
//--------------led_test.c------------------- //APP 代码 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char **argv) { int fd; int buf = 233; fd = open("/dev/myled0",O_RDWR); if(fd < 0) { perror("open"); exit(1); } while(1){ buf = 0; write(fd, &buf, 4); sleep(1); buf = 1; write(fd, &buf, 4); sleep(1); } read(fd, &buf, 4); close(fd); return 0; }
#Makefile代码 ROOTFS_DIR = /home/linux/Level11 APP_NAME = led_test CROSS_COMPILE = arm-none-linux-gnueabi- CC = $(CROSS_COMPILE)gcc ifeq ($(KERNELRELEASE), ) KERNEL_DIR = /home/linux/Level10/day6/linux-5.4.79 CUR_DIR = $(shell pwd) all : make -C $(KERNEL_DIR) M=$(CUR_DIR) modules -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- $(CC) $(APP_NAME).c -o $(APP_NAME) clean : make -C $(KERNEL_DIR) M=$(CUR_DIR) clean clear install: cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/drv_module else obj-m += led_drv.o endif
[root@farsight ]# insmod led_drv.ko [root@farsight ]# ./led_test [ 1781.874456] ------------chr_drv_open---------- [ 1781.877516] __KERN__:0 [ 1782.880055] __KERN__:1 [ 1783.881074] __KERN__:0 [ 1784.882093] __KERN__:1 [ 1785.883115] __KERN__:0 [ 1786.884136] __KERN__:1 [ 1787.384514] ------------chr_drv_close---------- [root@farsight ]# rmmod led_drv.ko
灯一闪一闪,效果达成。