Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1599860
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4427
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: Android平台

2013-03-08 17:07:34

自己写的一个小总结,主要是看了《深入linux设备驱动程序机制》和http://blog.chinaunix.net/uid-20543672-id-3203690.html
/*字符设备号管理结构*/
#define CHRDEV_MAJOR_HASH_SIZE 255

static struct char_device_struct {
 struct char_device_struct *next;
 unsigned int major;
 unsigned int baseminor;
 int minorct;
 char name[64];
 struct cdev *cdev;  /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];


int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
 struct char_device_struct *cd;
 dev_t to = from + count;
 dev_t n, next;

 for (n = 128; n < 130; n = next) {
  next = MKDEV(MAJOR(n)+1, 0);
  if (next > to)
   next = to;
  cd = __register_chrdev_region(MAJOR(n), MINOR(n),
          next - n, name);
  if (IS_ERR(cd))
   goto fail;
 }
 return 0;
}


/*动态分配*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
   const char *name)
{
 struct char_device_struct *cd;
 cd = __register_chrdev_region(0, baseminor, count, name);
 if (IS_ERR(cd))
  return PTR_ERR(cd);
 *dev = MKDEV(cd->major, cd->baseminor);
 return 0;
}

 /*字符设备cdev的管理,和字符设备号相同过的管理方法*/
 static struct kobj_map *cdev_map;
 struct kobj_map {
 struct probe {
  struct probe *next;
  dev_t dev;
  unsigned long range;
  struct module *owner;
  kobj_probe_t *get;
  int (*lock)(dev_t, void *);
  void *data;//指向注册的cdev
 } *probes[255];
 struct mutex *lock;
};

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
 p->dev = dev;
 p->count = count;
 return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}


//下面是用户空间到驱动空间的交互过程
/******************************************************************/
struct task_struct {
 ........
 /* open file information */
 struct files_struct *files;
 .........
}

struct files_struct {
 ....
 struct fdtable fdtab;
 ......
};

struct fdtable {
 unsigned int max_fds;
 struct file __rcu **fd;      /* 文件描述符数组 */
 fd_set *close_on_exec;
 fd_set *open_fds;
 struct rcu_head rcu;
 struct fdtable *next;
};

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
 do_sys_open(AT_FDCWD, filename, flags, mode);
  fd = get_unused_fd_flags(flags);//获得一个未用的fd,作为struct file __rcu **fd;的索引值
  if(fd > 0)
  {
   /*找一个空的file,放入fd指向的空间中*/
   struct file *f = do_filp_open(dfd, tmp, &op, lookup);
     filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);// 分配filep
      filp = do_last(nd, &path, op, pathname);
        filp = nameidata_to_filp(nd);
          filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, NULL, cred);
          inode = dentry->d_inode;//查找到该设备节点对应的inode
          f->f_op = fops_get(inode->i_fop);//取出inode的的默认操作函数,赋值给file
          if (!open && f->f_op)
           open = f->f_op->open;//调用该默认操作的open函数
          if (open) {
           error = open(inode, f);//默认的open函数如下
           if (error)
            goto cleanup_all;
          }
  }
 
/*字符设备的操作函数*/
const struct file_operations def_chr_fops = {
 .open = chrdev_open,
 .llseek = noop_llseek,
};

/*特定的文件系统调用该函数*/
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
 inode->i_mode = mode;
 if (S_ISCHR(mode)) {//如果是字符设备
  inode->i_fop = &def_chr_fops;//字符设备的操作函数
  inode->i_rdev = rdev;
 } else if (S_ISBLK(mode)) {
  inode->i_fop = &def_blk_fops;
  inode->i_rdev = rdev;
 }
 ...........
}

//下面接着分析chrdev_open函数
static int chrdev_open(struct inode *inode, struct file *filp)
{
 struct cdev *p;
 struct cdev *new = NULL;

 if (!p) {
  struct kobject *kobj;
  kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);//由创建节点的主设备号i_rdev,查找到对应的probes
  new = container_of(kobj, struct cdev, kobj);

  /* Check i_cdev again in case somebody beat us to it while
     we dropped the lock. */
  p = inode->i_cdev;
  if (!p) {
   inode->i_cdev = p = new;
   list_add(&inode->i_devices, &p->list);
   new = NULL;
  }
  filp->f_op = fops_get(p->ops);//把驱动的操作赋值给file的操作函数

  if (filp->f_op->open) {//调用驱动个的open函数
   ret = filp->f_op->open(inode,filp);
   if (ret)
    goto out_cdev_put;
  }

 }
}

阅读(1504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~