I. character device structure
Struct cdev {struct kobject kobj; // The struct module * owner of the kobject object; // The const struct file_operations * ops of the module owner; // The struct list_head list of the file operation function set; // The Head of the linked list dev_t dev; // device number unsigned int count; // number of times of reference };
2. Assign character device struct
Struct cdev * cdev_alloc (void) {struct cdev * P = kzarloc (sizeof (struct cdev), gfp_kernel); // allocate memory if (P) {init_list_head (& P-> list); kobject_init (& P-> kobj, & ktype_cdev_dynamic);} return P ;}
3. character device Initialization
Void cdev_init (struct cdev * cdev, const struct file_operations * FoPs) {memset (cdev, 0, sizeof * cdev); // initialize the cdev struct init_list_head (& cdev-> list ); // initialize the linked list header kobject_init (& cdev-> kobj, & ktype_cdev_default); // initialize the kobject object cdev-> Ops = fops; // specify the file operation function set}
4. Add character Devices
Int cdev_add (struct cdev * P, dev_t Dev, unsigned count) {P-> Dev = dev; // specify the device number p-> COUNT = count; // set reference count return kobj_map (cdev_map, Dev, Count, null, exact_match, exact_lock, P );}
5. delete character Devices
void cdev_del(struct cdev *p){cdev_unmap(p->dev, p->count);kobject_put(&p->kobj);}
Vi. Allocation and release of device numbers
1. statically allocate register_chrdev_region
Int register_chrdev_region (dev_t from, unsigned count, const char * Name) // parameter: Start master device number, number of devices, device name {struct char_device_struct * CD; dev_t to = from + count; dev_t N, next; For (n = from; n <to; n = NEXT) {next = mkdev (Major (n) + 1, 0); If (next>) next = to; Cd = _ register_chrdev_region (Major (N), minor (N), next-N, name); If (is_err (CD) goto fail ;} return 0; fail: To = N; For (n = from; n <to; n = NEXT) {next = mkdev (Major (n) + 1, 0 ); kfree (_ unregister_chrdev_region (Major (N), minor (N), next-N);} return ptr_err (CD );}
2. dynamically allocate alloc_chrdev_region
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;}
3. Release the device number unregister_chrdev_region.
void unregister_chrdev_region(dev_t from, unsigned count){dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}}
VII. Simple character device example
# Include <Linux/Fs. h> # include <Linux/module. h> # include <Linux/cdev. h> int test_major; dev_t test_dev; struct cdev * my_cdev; static int test_open (struct inode * inode, struct file * filp) {return 0 ;} static const struct file_operations test_fops = {// operation function set. owner = this_module ,. open = test_open,}; static int _ init test_init (void) {int ret = 0; my_cdev = cdev_alloc (); // assign the character device structure if (test_major) {// assign the device number test_dev = mkdev (test_major, 0); register_chrdev_region (test_dev, 0, "test");} else {ret = alloc_chrdev_region (& test_dev, 0, 0, "test"); test_major = major (test_dev);} cdev_init (my_cdev, & test_fops); // initialize the character device and bind the function set cdev_add (my_cdev, test_dev, 0 ); // Add a character device, bind the main device number return ret;} static void _ exit test_exit (void) {cdev_del (my_cdev); unregister_chrdev_region (mkdev (test_major, 0 ), 0);} module_init (test_init); module_exit (test_exit); module_license ("GPL ");