免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1069 | 回复: 0
打印 上一主题 下一主题

我写的第一个设备模块 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-07 22:25 |只看该作者 |倒序浏览

                                                                暑假的时候看了<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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP