编写一个字符设备驱动,在内核空间申请4KB的内存空间,供整个用户空间共享使用。应用程序通过read和write函数读取和写入数据,通过IOCTL可以清除4KB的内存空间。 在kernel/drivers/char/x4412目录下新建x4412-globalmem.c文件,编辑内容如下: - #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include <linux/device.h>
- #include <asm/uaccess.h>
- #define GLOBALMEM_SIZE 0x1000 /*全局内存最大4KB*/
- #define MEM_CLEAR 0x1 /*清零全局内存*/
- static int globalmem_major;
- static struct class *cdev_class;
- struct globalmem_dev
- {
- struct cdev 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;
- }
- int globalmem_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
- static long globalmem_ioctl(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;
- }
- 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 count ? -ENXIO: 0;
- if (count > GLOBALMEM_SIZE - p)
- count = GLOBALMEM_SIZE - p;
- /*内核空间→用户空间*/
- if (copy_to_user(buf, (void*)(dev->mem + p), count))
- {
- ret = - EFAULT;
- }
- else
- {
- ret = count;
- }
- 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
- {
- ret = count;
- }
- return ret;
- }
- static const struct file_operations globalmem_fops =
- {
- .owner = THIS_MODULE,
- .read = globalmem_read,
- .write = globalmem_write,
- .unlocked_ioctl = globalmem_ioctl,
- .open = globalmem_open,
- .release = globalmem_release,
- };
- 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;
- dev->cdev.ops = &globalmem_fops;
- err = cdev_add(&dev->cdev, devno, 1);
- if (err)
- printk(KERN_NOTICE "Error %d adding cdev%d", err, index);
- }
- int globalmem_init(void)
- {
- int result;
- dev_t devno;
- result = alloc_chrdev_region(&devno, 0, 1, "x4412-globalmem");
- if(result < 0)
- return result;
- globalmem_major = MAJOR(devno);
- 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);
- cdev_class = class_create(THIS_MODULE,"x4412-globalmem");
- if(IS_ERR(cdev_class))
- goto fail_class;
- device_create(cdev_class,NULL,devno,NULL,"x4412-globalmem");
- return 0;
- fail_class:
- class_destroy(cdev_class);
- fail_malloc:
- unregister_chrdev_region(devno, 1);
- return result;
- }
- void globalmem_exit(void)
- {
- device_destroy(cdev_class,MKDEV(globalmem_major,0));
- class_destroy(cdev_class);
- cdev_del(&globalmem_devp->cdev); /*注销 cdev*/
- kfree(globalmem_devp); /*释放设备结构体内存*/
- unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
- }
-
- MODULE_AUTHOR("www.9tripod.com");
- MODULE_LICENSE("GPL");
- module_init(globalmem_init);
- module_exit(globalmem_exit);
复制代码 在模块初始化函数globalmem_init中,通过alloc_chrdev_region函数动态申请设备号。驱动的最开始封装了结构体globalmem_dev,包含了cdev和mem两个成员,cdev为字符设备驱动的基本骨架,mem为驱动预留的4KB内存空间,用于应用程序的读写访问。globalmem_devp为定义的全局结构体指针,指向通过kmalloc函数申请的内存地址,供整个驱动调用。globalmem_setup_cdev函数通过调用cdev_init和cdev_add函数注册字符设备驱动,并关联file_operations结构体。class_create和device_create函数用于在驱动中自动创建设备节点,驱动加载后,在/dev目录下将会自动生成x4412-globalmem设备节点。如果通过模块形式加载驱动时没有自动生成节点,执行mdev –s指令即可。 在读函数globalmem_read中,首先判断读取文件的有效性。驱动限制了读取范围,只允许读取4096字节的数据,因此当读取的指针偏移ppos大于等于4096时继续读取,读函数将返回错误。当有效性校验通过后,通过copy_to_user函数将需要读取的字节数上报给上层应用。 在写函数globalmem_write中,同样首先判断写入文件的有效性。如果写入长度超过了4096个字节,也将会返回错误。当有效性校验通过后,通过copy_from_user函数从应用中读取需要写入的数据,并保存到4KB字节的内存中。 在ioctl函数globalmem_ioctl中,通过memset函数将预留的4K空间清零,即完成了清除工作。 在kernel/drivers/char/x4412/Kconfig中添加如下语句: - config X4412_GLOBALMEM_DRIVER
- tristate "x4412 global mem driver"
- default m
- help
- compile for x4412 global mem driver,y for kernel,m for module.
复制代码在kernel/drivers/char/x4412/Makefile中添加如下语句: - obj-$(CONFIG_X4412_GLOBALMEM_DRIVER) += x4412-globalmem.o
复制代码编译内核,将会在kernel/drivers/char/x4412目录下生成目标文件x4412-globalmem.ko文件。 使用指令测试驱动模块: - [root@x4412 mnt]# insmod x4412-globalmem.ko
- [root@x4412 mnt]# echo 'www.9tripod.com' > /dev/x4412-globalmem
- [root@x4412 mnt]# cat /dev/x4412-globalmem
- www.9tripod.com
复制代码也可以编写应用程序测试驱动模块,参考源码如下: - #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #define DEVICE_NAME "/dev/x4412-globalmem"
- #define MEM_CLEAR 0x1
-
- int main(int argc,char **argv)
- {
- int fd;
- char buf[30];
- char str[]="hello,x4412!";
-
- fd = open(DEVICE_NAME,O_RDWR);
- if(fd == -1)
- {
- printf("open device %s error \n",DEVICE_NAME);
- }
- else
- {
- write(fd,str,12);
- usleep(5000);
- read(fd,buf,12);
- printf("read from /dev/x4412-gloalmem:\r\n");
- printf("%s\r\n",buf);
- usleep(5000);
- ioctl(fd,MEM_CLEAR);
- read(fd,buf,12);
- printf("read from /dev/x4412-gloalmem later:\r\n");
- printf("%s\r\n",buf);
- close(fd);
- }
- return 0;
- }
复制代码 应用程序首先向驱动模块写入字符串“hello,x4412!”,再将它读取出来。接着调用ioctl函数将驱动模块的4KB内存清零,然后再读取4KB内存模块的前12个字节数据,判断内存是否已经被清零。 测试界面如下: - [root@x4412 mnt]# ./x4412-globalmem-app
- read from /dev/x4412-gloalmem:
- hello,x4412!
- [ 502.251039] globalmem is set to zero
- read from /dev/x4412-gloalmem later:
-
- [root@x4412 mnt]#
复制代码 可直接在x4412开发板或ibox卡片电脑上运行的驱动模块和应用程序映像:
x4412-globalmem.ko
(4.16 KB, 下载次数: 11)
x4412-globalmem-app
(6.58 KB, 下载次数: 11)
|