- 论坛徽章:
- 0
|
暑假的时候看了<Linux设备驱动开发详解>的理论篇,觉得这本书的总结性不错,但对字符设备驱动的框架讲解得不是很透澈,后来看了一下LDD3,顿时开朗了很多~~
写下了这个全局内存设备驱动模块,以后再改写个LED、KEY之类的~~
以下是文件memdev.c
/**********************************************************
* file: memdev.c
* description: a mem device driver module
*
* author: jiaojinxing wyoujtg@163.com
* date: 2009-9-27
*
*********************************************************/
/**********************************************************
* 包含头文件
*********************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**********************************************************
* 版权
*********************************************************/
MODULE_LICENSE("Dual BSD/GPL");
/**********************************************************
* 全局变量
*********************************************************/
//内存设备的主设备号
static int devmajor = 0;
//主设备号可作为模块插入参数,以指定内存设备的主设备号
module_param(devmajor, int, S_IRUGO);
//该变量用于记录内存设备初始化是否成功
static bool is_setup_ok = false;
//内存设备的数目,有2个
#define MAX_MEMDEV_NUM 2
//内存设备的缓冲区的大小,为128个字节
#define MEMDEV_BUF_SIZE 128
//内存设备支持的命令
#define MEM_CLEAR 0x01
#define MEM_SET 0x02
//自定义的内存设备结构
struct mem_dev_t
{
struct cdev cdev; //字符设备
unsigned char buff[MEMDEV_BUF_SIZE];//缓冲区
struct semaphore sem;//读写操作互斥用信号量
};
//MAX_MEMDEV_NUM个内存设备的数组
struct mem_dev_t memdev[MAX_MEMDEV_NUM];
/**********************************************************
* function: mem_dev_open
* description: 打开内存设备
*********************************************************/
static int mem_dev_open(struct inode *inode, struct file *filp)
{
struct mem_dev_t *p;
//p指向与字符设备对应的内存设备结构
p = container_of(inode->i_cdev, struct mem_dev_t, cdev);
//对文件私有数据指针进行赋值
filp->private_data = p;
return 0;
}
/**********************************************************
* function: mem_dev_read
* description: 从内存设备读取数据
*********************************************************/
static ssize_t mem_dev_read(struct file *filp, char __user * buff, size_t count, loff_t *offp)
{
struct mem_dev_t *p;
//要读取的起始位置
unsigned long off = *offp;
//p指向与文件对应的内存设备结构
p = filp->private_data;
//偏移太大,返回0
if (off > MEMDEV_BUF_SIZE)
return 0;
//如果要读的数目太大,调整要读的数目
if (off + count > MEMDEV_BUF_SIZE)
count = MEMDEV_BUF_SIZE - off;
//可打断方式获取信号量
if (down_interruptible(&(p->sem)))
return -ERESTARTSYS;
//更新读写指针,这个会影响filp->f_pos!!
*offp = off + count;
//拷贝缓冲区的内容到用户空间
count -= copy_to_user(buff, p->buff+off, count);
//释放信号量
up(&(p->sem));
//返回成功读取的数目
return count;
}
/**********************************************************
* function: mem_dev_write
* description: 写数据到内存设备
*********************************************************/
static ssize_t mem_dev_write(struct file *filp, const char __user * buff, size_t count, loff_t *offp)
{
struct mem_dev_t *p;
//要写的起始位置
unsigned long off = *offp;
//p指向与文件对应的内存设备结构
p = filp->private_data;
//偏移太大,返回0
if (off > MEMDEV_BUF_SIZE)
return 0;
//如果要写的数目太大,调整要写的数目
if (off + count > MEMDEV_BUF_SIZE)
count = MEMDEV_BUF_SIZE - off;
//可打断方式获取信号量
if (down_interruptible(&(p->sem)))
return -ERESTARTSYS;
//更新读写指针,这个会影响filp->f_pos!!
*offp = off + count;
//拷贝用户空间的内容到缓冲区
count -= copy_from_user(p->buff+off, buff, count);
//释放信号量
up(&(p->sem));
//返回成功写入的数目
return count;
}
/**********************************************************
* function: mem_dev_llseek
* description: 调整内存设备的读写指针
*********************************************************/
static ssize_t mem_dev_llseek(struct file *filp, loff_t off, int orig)
{
switch (orig)
{
case 0: //相对起始位置
if (off > MEMDEV_BUF_SIZE || off f_pos = (unsigned int)off;//直接对f_pos赋值
return off;
case 1: //相对当前读写位置
if (filp->f_pos + off > MEMDEV_BUF_SIZE)//超出上限
return -EINVAL;
if (filp->f_pos + off f_pos += off;//加上偏移(可正可负)
return filp->f_pos;
default:
return -EINVAL;
}
return 0;
}
/**********************************************************
* function: mem_dev_ioctl
* description: control mem dev
*********************************************************/
static int mem_dev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
struct mem_dev_t *p;
//p指向与文件对应的内存设备结构
p = filp->private_data;
switch (cmd)
{
case MEM_CLEAR://清空缓冲区
if (down_interruptible(&(p->sem)))//可打断方式获取信号量
return -ERESTARTSYS;
memset(p->buff, 0, MEMDEV_BUF_SIZE);//缓冲区置0
up(&(p->sem));//释放信号量
break;
case MEM_SET://设置缓冲区
if (down_interruptible(&(p->sem)))//可打断方式获取信号量
return -ERESTARTSYS;
memset(p->buff, arg, MEMDEV_BUF_SIZE);//缓冲区置arg
up(&(p->sem));//释放信号量
break;
default:
return -EINVAL;
}
return 0;
}
/**********************************************************
* description: 内存设备的操作
*********************************************************/
struct file_operations memdev_ops = {
.owner = THIS_MODULE,//文件操作的拥有者为该模块
.open = mem_dev_open, //设备打开函数
.read = mem_dev_read,//设备读取函数
.write = mem_dev_write,//设备写函数
.ioctl = mem_dev_ioctl,//设备IO控制函数
.llseek = mem_dev_llseek,//设备读写指针调整函数
};
/**********************************************************
* function: memdev_setup
* description: 设置所有的内存设备
*********************************************************/
static void memdev_setup(void)
{
int i;
int err;
dev_t devindex;
if (devmajor == 0) //devmajor=0,即没有指定,动态分配设备号
{
err = alloc_chrdev_region(&devindex, 0, MAX_MEMDEV_NUM, "memdev");//分配MAX_MEMDEV_NUM个设备号
devmajor = MAJOR(devindex); //生成主设备号
}
else
{
devindex = MKDEV(devmajor, 0); //生成起始设备号
err = register_chrdev_region(devindex, MAX_MEMDEV_NUM, "memdev");//注册MAX_MEMDEV_NUM个设备号
}
if (err == 0)
{
is_setup_ok = true;
for (i = 0; i /dev/memdev0
cat /dev/memdev0
以下是文件test.c 用于测试的~~
#include
#include
#include
#include
#include
#define ME "jiaojinxing"
int main(void)
{
//定义缓冲区并清空
char buf[128];
memset(buf, 0, 128);
//以可读写方式打开/dev/memdev0这个内存设备
int fd = open("/dev/memdev0", O_RDWR);
if (fd == 0)
exit(0);
//写入数据到/dev/memdev0
write(fd, ME, sizeof(ME));
//调整文件读写指针为0,因为之前写了,文件读写指针不为0
lseek(fd, 0, 0);
//从/dev/memdev0读出数据
read(fd, buf, sizeof(ME));
//显示读出的数据,如果没错应该为ME的内容
puts(buf);
//清除/dev/memdev0的内容
ioctl(fd, 1, 0);
//调整文件读写指针为0,因为之前读了,文件读写指针不为0
lseek(fd, 0, 0);
//从/dev/memdev0读出数据
read(fd, buf, sizeof(ME));
//显示读出的数据,实际没有任何数据,因为上面清除了/dev/memdev0的内容
puts(buf);
//关闭该设备
close(fd);
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/49274/showart_2065412.html |
|