linux device driver registration

Each character device in the kernel corresponds to a variable of the cdev structure, the following is its definition:
linux -2.6.22/include/linux/cdev.h
struct cdev {
struct kobject kobj; // 
Each  cdev is a
 kobject
struct 
module  *owner; // Point to the module that implements the driver

const struct file_operations *ops; // 
Method for manipulating this character device file
struct list_head list; //  The
linked list head of inode->i_devices of  the character device file corresponding to cdev
dev_t dev; // 
Starting device number
unsigned int count; // 
Device range number size
};

A cdev generally has two defined initialization methods: static and dynamic.
Static memory definition initialization:
struct cdev my_cdev;
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;

dynamic memory definition initialization:
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &fops;
my_cdev->owner = THIS_MODULE

; The function is the same, but the memory area used is different, which generally depends on the actual data structure requirements.
The code for both functions is posted below to see the differences in detail.
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 ;
}
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
   memset(cdev, 0, sizeof *cdev); 
Note 1 ;

   INIT_LIST_HEAD(&cdev->list);
   kobject_init(&cdev->kobj, &ktype_cdev_default);
   cdev->ops = fops;
}
It can be seen that the functions of the two functions are basically the same, except that cdev_init() also assigns an additional cdev- >value of ops.

It should be noted here that the space after kzalloc does not need to execute memset, because it itself contains this operation. And memset generally acts on the space that already exists.

From this, we basically have a basic concept of these two functions: the cdev_alloc function is for operations that require space allocation, and cdev_init is for operations that do not require space allocation; so if you define a pointer, you only need to use cdev_alloc function and do an ops assignment after it; if you define a structure instead of a pointer, then just use the cdev_init function.

I saw that some codes use the cdev_alloc function after defining a pointer, and then use the cdev_init function. This process will not cause errors, but it just does some repetitive and useless work, which is actually completely unnecessary.


After initializing cdev, it needs to be added to the system. To do this, the cdev_add() function can be called. Pass in a pointer to a cdev structure, a starting device number, and a range of device numbers.

Name

cdev_add — add a char device to the system

Synopsis

int fsfunc   cdev_add ( struct cdev * p,
  dev_t dev,
  unsigned count);
 

Arguments

p

the cdev structure for the device

dev

the first device number for which this device is responsible

count

the number of consecutive minor numbers corresponding to this device

Description

cdev_add adds the device represented by p to the system, making it live immediately. A negative error code is returned on failure.


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);
}

关于kobj_map()函数就不展开了,我只是大致讲一下它的原理。内核中所有的字符设备都会记录在一个 kobj_map结构的 cdev_map变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map()函数就是用来把字符设备编号和 cdev结构变量一起保存到 cdev_map这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup()函数,根据设备编号就可以找到cdev结构变量,从而取出其中的ops字段。

 

 


当一个字符设备驱动不再需要的时候(比如模块卸载),就可以用 cdev_del()函数来释放 cdev占用的内存。

Name

cdev_del — remove a cdev from the system

Synopsis

void fsfunc cdev_del ( struct cdev * p);
 

Arguments

p

the cdev structure to be removed

Description

cdev_del removes p from the system, possibly freeing the structure itself.


void cdev_del(struct cdev *p)
{
  cdev_unmap(p->dev, p->count);
  kobject_put(&p->kobj);
}

其中cdev_unmap()调用 kobj_unmap()来释放 cdev_map散列表中的对象。kobject_put()释放 cdev结构本身。
1
Memset  用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’‘/0’
:chara[100];memset(a, '/0', sizeof(a));
memcpy  用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。
例:chara[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。
Strcpy   就只能拷贝字符串了,它遇到'/0'就结束拷贝。
例:chara[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘/0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。

memset主要应用是初始化某个内存空间。
memcpy是用于copy源空间的数据到目的空间中。
strcpy用于字符串copy,遇到‘/0’,将结束。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325565824&siteId=291194637