一些设备驱动内核API (1)

//cdev_add将字符设备 p 添加入Linux系统内核,并通过 dev 设置设备号
//返回 0 代表添加成功
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
int error;


p->dev = dev;
p->count = count;


error = kobj_map(cdev_map, dev, count, NULL,
exact_match, exact_lock, p);
if (error)
return error;


kobject_get(p->kobj.parent);


return 0;
}


//cdev_del将字符设备 p 从Linux内核系统中移除
void cdev_del(struct cdev *p)
{
cdev_unmap(p->dev, p->count);
kobject_put(&p->kobj);
}


//向Linux动态申请一个新的字符设备
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj, &ktype_cdev_dynamic);
}
return p;
}
struct cdev {
struct kobject kobj; //设备的引用计数
struct module *owner;//属于哪个模块
const struct file_operations *ops;//字符设备的操作函数指针
struct list_head list;//对应的字符设备文件inode->i_devices的链表的表头
dev_t dev;//字符设备的设备号
unsigned int count;//设备编号范围的大小
};


//【cdev->owner对象需要自己初始化,cdev_init不管这事儿】
//初始化字符设备的各种操作函数
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
struct file_operations {
struct module *owner;//拥有该结构的模块
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//设备中读数据
                                                                 //需要提供字符串指针
                                                                //用以存放所读数据
//向字符设备写入数据  
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
void (*mremap)(struct file *, struct vm_area_struct *);

//打开设备
int (*open) (struct inode *, struct file *);

int (*flush) (struct file *, fl_owner_t id);

//关闭设备,释放设备资源
int (*release) (struct inode *, struct file *);

int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
  loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
};


//register_chrdev 先调用 cdev_alloc 动态申请一个字符设备,其次调用 cdev_add 将其加入到内核中
static inline int register_chrdev(unsigned int major, const char *name,
                  const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
int __register_chrdev(unsigned int major, unsigned int baseminor,
              unsigned int count, const char *name,
              const struct file_operations *fops)
{
struct char_device_struct *cd;
struct cdev *cdev;
int err = -ENOMEM;


cd = __register_chrdev_region(major, baseminor, count, name);
if (IS_ERR(cd))
return PTR_ERR(cd);


cdev = cdev_alloc();
if (!cdev)
goto out2;


cdev->owner = fops->owner;
cdev->ops = fops;
kobject_set_name(&cdev->kobj, "%s", name);


err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
if (err)
goto out;


cd->cdev = cdev;


return major ? 0 : cd->major;
out:
kobject_put(&cdev->kobj);
out2:
kfree(__unregister_chrdev_region(cd->major, baseminor, count));
return err;
}


//删除一个字符设备,释放其占有的内存空间
static inline void unregister_chrdev(unsigned int major, const char *name)
{
__unregister_chrdev(major, 0, 256, name);
}
void __unregister_chrdev(unsigned int major, unsigned int baseminor,
             unsigned int count, const char *name)
{
struct char_device_struct *cd;


cd = __unregister_chrdev_region(major, baseminor, count);
if (cd && cd->cdev)
cdev_del(cd->cdev);
kfree(cd);
}

你可能感兴趣的:(一些设备驱动内核API (1))