免费注册 查看新帖 |

Chinaunix

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

二.LINUX字符设备驱动 [复制链接]

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

一.   cdev结构体:
struct cdev
{
       Struct kobject kobj;         //内嵌的kobject对象
       Struct module *owner;      //所属模块
       Struct file_operations *ops;   //文件操作结构体
       Struct list_head list;
       Dev_t dev;                //设备号
       Unsigned int count;
}

二.   使用下列宏可以从 dev_t获得主设备号和次设备号
MAJOR(dev_t dev)
MINOR(dev_t dev)

三.   使用下列宏则可以通过主设备号和设备号生成dev_t
MKDEV(int major, int minor)

四.   LINUX2.6内核提供了一组函数用于操作cdev结构体:
Void cdev_init(struct cdev *, struct file_operations *);   //初始化cdev成员
Struct cdev *cdev_alloc(void);         //动态申请一个cdev内存
Void cdev_put(struct cdev *p);         
Int cdev_add(struct cdev *,dev_t, unsigned);  //向系统添加一个cdev
Void cdev_del(struct cdev *);              //向系统删除一个cdev

五.   分配和释放设备号
1.       int register_chrdev_region(dev_t from, unsigned count, const char *name);  //申请设备号
2.       void unregister_chrdev_region(dev_t from, unsigned count);       //释放设备号

六.   globalmem设备驱动
1.       头文件.宏及设备结构体
#include
#include
#include
#include
#include
#include
#include
#include

#define GLOBALMEM_SIZE  0x1000       //全局内存大小
#define MEM_CLEAR       0x1          //清零全局内存
#define GLOBALMEM_MAJOR 254          //预设的globalmem的主设备号

static globalmem_major = GLOBALMEM_MAJOR;

struct globalmem_dev
{
       struct cdev cdev;
       unsigned char mem[GLOBALMEM_SIZE];
}

struct globalmem_dev  dev;       //设备结构体实例


2.       加载设备驱动:
static void globalmem_setup_cdev()
{
       int err, devno = MKDEV(globalmem_major, 0);
      
       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 globalmem", err);      
}

int globalmem_init(void)
{
       int result;
       dev_t devno = MKDEV(globalmem_major, 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
              return result;
      
       globalmem_setup_cdev();
       return 0;
}

3.       卸载设备驱动:
void globalmem_exit(void)
{
       cdev_del(&dev.cdev);
       unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
}

4.       file_operations结构体:
static const struct file_operations globalmem_fops =
{
       .owner = THIS_MODULE,
       .llseek = globalmem_llseek,
       .read = globalmem_read,
       .write = globalmem_wirte,
       .ioctl = gloalmem_ioctl,
};

5.       读函数:
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
       unsigned long p = *ppos;
       int ret = 0;
      
       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 {
              *ppos += count;
              ret = count;
              
              prink(KERN_INFO "read %d butes(s) from %d\n", count, p);
       }
      
       return ret;
}

6.       写函数:
static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
       unsigned long p = *ppos;
       int ret =0;
      
              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;
              
              prink(KERN_INFO "written %d butes(s) from %d\n", count, p);
       }
      
       return ret;
}

7.       seek函数
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
       loff_t ret;
      
       switch(orig)
       {
              case 0:
                      if (offset
                           ret = -EINVAL;
                           break;
                      }
                     
                      if ((unsigned int)offset > GLOBALMEM_SIZE) {
                          ret = - EINVAL;
                          break;
                      }
                     
                      filp->f_pos = (unsigned int) offset;
                      ret = file->f_pos;
                 %

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93882/showart_1899900.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP