-
开发环境
- Ubuntu版本:Ubuntu14.04 64位,使用内核 linux-headers-4.4.0-31-generic
- 开发板内核版本:linux-4.1.18
- 开发板:基于am3352某控制器
-
开发步骤
- 编写globalmem虚拟驱动程序,在Ubuntu环境中测试
- 新建globalmem文件夹,进入文件夹,新建globalmem.c和Makefile,代码如下:
- globalmem.c:
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <linux/slab.h> #include <linux/uaccess.h> #define GLOBALMEM_SIZE 0x1000 #define MEM_CLEAR 0X1 #define GLOBALMEM_MAJOR 230 static int globalmem_major = GLOBALMEM_MAJOR; module_param(globalmem_major,int,S_IRUGO); /* globalmem设备结构体 */ struct globalmem_dev { struct cdev cdev; unsigned char mem[GLOBALMEM_SIZE]; }; struct globalmem_dev *globalmem_devp; /* 文件打开函数 */ int globalmem_open(struct inode *inode, struct file *filp) { /* */ filp->private_data = globalmem_devp; return 0; } /* 文件释放函数 */ static int globalmem_release(struct inode *inode, struct file *filp) { return 0; } /* ioctl 设备控制函数 */ #if 1 static long globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { // struct globalmem_dev *dev = filp->private_data;/* 获得设备结构体指针 */ switch (cmd){ case MEM_CLEAR: memset(dev->mem, 0, GLOBALMEM_SIZE); printk(KERN_INFO "globalmem is set to zero\n"); break; default: return - EINVAL; } return 0; } #endif /* 读函数 */ static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data;/* 获得设备结构体指针 */ if (p >= GLOBALMEM_SIZE) return 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; /* 内核空间--> 用户空间 */ if (copy_to_user(buf, (void *)(dev->mem + p), count)) { ret = EFAULT; }else { *ppos += count; ret = count; printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p); } return ret; } /*写函数*/ static ssize_t globalmem_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev =filp->private_data; /*获得设备结构体指针*/ /*分析和获取有效的写长度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; /*用户空间->内核空间*/ if (copy_from_user(dev->mem + p, buf,count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p); } return ret; } /* seek文件定位函数 */ static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) { loff_t ret = 0; switch (orig) { case 0: /*相对文件开始位置偏移*/ if (offset < 0) { ret = - EINVAL; break; } if ((unsigned int)offset >GLOBALMEM_SIZE) { ret = - EINVAL; break; } filp->f_pos = (unsigned int)offset; ret = filp->f_pos; break; case 1: /*相对文件当前位置偏移*/ if ((filp->f_pos + offset) >GLOBALMEM_SIZE) { ret = - EINVAL; break; } if ((filp->f_pos + offset) < 0) { ret = - EINVAL; break; } filp->f_pos += offset; ret = filp->f_pos; break; default: ret = - EINVAL; break; } return ret; } /* 文件操作结构体 */ static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .llseek = globalmem_llseek, .read = globalmem_read, .write = globalmem_write, .unlocked_ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release, }; /* 初始化并注册cdev */ static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) { int err, devno = MKDEV(globalmem_major, index); cdev_init(&dev->cdev, &globalmem_fops); dev->cdev.owner = THIS_MODULE; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding globalmem %d", err, index); } /* 设备驱动模块加载函数 */ int globalmem_init(void) { int result; dev_t devno = MKDEV(globalmem_major, 0); /* devno = (250<<20) | 0 */ /* 申请设备号 */ if (globalmem_major) result = register_chrdev_region(devno, 1, "globalmem"); else { /* 动态申请设备号 */ result = alloc_chrdev_region(&devno, 0, 1, "globalmem"); globalmem_major = MAJOR(devno); } if (result < 0) return result; /* 动态申请设备结构体的内存 */ globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL); if (!globalmem_devp) { /* 申请失败 */ result = - ENOMEM; goto fail_malloc; } memset (globalmem_devp, 0, sizeof(struct globalmem_dev)); globalmem_setup_cdev(globalmem_devp, 0); return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } /* 模块卸载函数 */ void globalmem_exit(void) { cdev_del(&globalmem_devp->cdev); /* 注销CDEV */ kfree(globalmem_devp); /* 释放设备结构体内存 */ unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /* 释放设备号 */ } MODULE_AUTHOR("Fourier"); MODULE_LICENSE("Dual BSD/GPL"); //module_param(globalmem_major, int, S_IRUGO); module_init(globalmem_init); module_exit(globalmem_exit);
- Makefile:
obj-m := globalmem.o KERNEL_DIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: make -C $(KERNEL_DIR) M=$(PWD) modules clean: make -C $(KERNEL_DIR) M=$(PWD) clean
- globalmem.c:
-
make,如下:
- 运行insmod globalmem.ko,globalmem模块已被加载。通过cat /proc/devices,可以看到多出了主设备号为230的“globalmem”字符设备驱动。运行mknod /dev/globalmem c 230 0创建设备节点,运行echo “hello globalmem” > /dev/globalmem,cat /dev/globalmem,可以看到字符串被正确写入字符设备。
- 新建globalmem文件夹,进入文件夹,新建globalmem.c和Makefile,代码如下:
- Makefile、Kconfig配置
- 进入内核drivers目录,新建globalmem文件夹,进入文件夹,新建globalmem.c、Makefile、Kconfig三个文件,代码如下
- globalmem.c:同上
- Makefile:
obj-$(CONFIG_GLOBALMEM) += globalmem.o
- Kconfig:
menu "GLOBALMEM TEST Driver" comment "GLOBALMEM TEST Driver Config" config GLOBALMEM tristate "globalmem module test" default m help This is the globalmem test driver --by zheng. endmenu
- 修改内核drivers目录的Makefile、Kconfig,如下:
- Makefile:添加obj-$(CONFIG_GLOBALMEM) += globalmem/
- Kconfig:添加source "drivers/globalmem/Kconfig"
- 修改arch/arm/Kconfig:添加source "drivers/globalmem/Kconfig"
- 进入内核drivers目录,新建globalmem文件夹,进入文件夹,新建globalmem.c、Makefile、Kconfig三个文件,代码如下
- menuconfig配置:运行make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig,可以配置驱动为编译进内核(Y)、编译成内核模块(M)、不编译(N),这里我选择M
- 保存后退出,运行make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules,可以看到在drivers/globalmem文件夹下生成了globalmem.ko
- 使用tftp将globalmem.ko传至开发板,按照在ubuntu环境中的方法测试:
- 编写globalmem虚拟驱动程序,在Ubuntu环境中测试
如何在Linux内核中新增自己的驱动代码
最新推荐文章于 2024-07-25 11:18:30 发布