1. Understanding udev
udev: A mechanism for automatically creating device nodes. The logic of creating device nodes is in user space.
2. Analysis of the process of creating device nodes by udev mechanism
3. Directory information creation and deletion functions
#include<linux/device.h> 1. Submit directory information upwards struct class * class_create(struct module *owner,const char *name); Function: Apply for a device class and initialize it, submit directory information upwards parameter: Parameter 1: owner: a module pointer pointing to the current kernel module itself, fill in THIS_MODULE Parameter 2: name: directory name submitted upwards Return value: The first address of the applied struct class object space is returned successfully, and the error code pointer is returned if failed. /* 4K space will be reserved at the top level of the kernel space. When the struct class function call fails, the function will return a pointer to this 4K space. bool __must_check IS_ERR(__force const void *ptr) Function: Determine whether the pointer points to the 4K reserved space Parameter: pointer to be judged Return value: Returns logical true if pointing to 4K reserved space, otherwise returns logical false long __must_check PTR_ERR(__force const void *ptr) Function: Get the error code through the error code pointer ex:struct class_create *cls=struct class_create(THIS_MODULE,"mycdev"); if(IS_ERR(cls)) { printk("Failed to submit directory upward\ "); return -PRT_ERR(cls); } */ 2. Destroy the directory void class_destroy(struct class *cls) Function: Destroy directory information Parameters: cls: pointer to class object Return value: None
4. Node information creation and deletion functions
1. Submit node information upwards struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) Function: Create a device object and submit device node information upwards parameter: Parameter 1: cls: the class object pointer when submitting the directory upwards Parameter 2: parent: The address of the previous node of the currently applied object. If you don’t know, fill in NULL. Parameter 3: devt: device number major device number <<20 | minor device number /* MKDEV (major device number, minor device number): Get the device number based on the major device number and minor device number MAJOR(dev): Get the major device number based on the device number MINOR(dev): Get the minor device number based on the device number */ Parameter 4: dridata: the private data of the device object applied for, fill in NULL Parameter 5: fmt: device node name submitted upwards ...: variable length parameters Return value: Successfully returns the first address of the device object applied for. Failure returns an error code pointer, pointing to the 4K reserved space. 2. Destroy device node information void device_destroy(struct class *class, dev_t devt) Function: Destroy device node information parameter: class: The class object pointer obtained when submitting the directory upwards devt: The device number submitted when submitting device node information upwards Return value: None
5. Automatically create device node instances
1. Driver
#include <linux/init.h> #include <linux/module.h> #include<linux/fs.h> #include<linux/io.h> #include<linux/device.h> #include"head.h" int major; char kbuf[128]={0}; gpio_t *vir_led1; gpio_t *vir_led2; gpio_t *vir_led3; unsigned int *vir_rcc; struct class *cls; struct device *dev; int mycdev_open(struct inode *inode, struct file *file) { printk("%s:%s:%d\ ",__FILE__,__func__,__LINE__); return 0; } ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof) { printk("%s:%s:%d\ ",__FILE__,__func__,__LINE__); unsigned long ret; //Read copy to user space if(size>sizeof(kbuf))//The size that the user space expects to read cannot be satisfied by the kernel, then give the maximum size supported by the kernel. size=sizeof(kbuf); ret=copy_to_user(ubuf,kbuf,size); if(ret)//copy failed { printk("copy_to_user filed\ "); return ret; } return 0; } ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof) { unsigned long ret; //Read data from user space if(size>sizeof(kbuf))//The size that the user space expects to read cannot be satisfied by the kernel, then give the maximum size supported by the kernel. size=sizeof(kbuf); ret=copy_from_user(kbuf,ubuf,size); if(ret)//copy failed { printk("copy_to_user filed\ "); return ret; } switch(kbuf[0]){ case '1'://LED1 if(kbuf[1]=='0')//Turn off the light vir_led1->ODR & amp;= (~(1<<10)); else//turn on the light vir_led1->ODR |= 1<<10; break; case '2'://LED2 if(kbuf[1]=='0')//Turn off the light vir_led2->ODR & amp;= (~(1<<10)); else//turn on the light vir_led2->ODR |= 1<<10; break; case '3'://LED3 if(kbuf[1]=='0')//Turn off the light vir_led3->ODR & amp;= (~(1<<8)); else//turn on the light vir_led3->ODR |= 1<<8; break; } return 0; } int mycdev_close(struct inode *inode, struct file *file) { printk("%s:%s:%d\ ",__FILE__,__func__,__LINE__); return 0; } //Define operation method structure variables and assign values struct file_operations fops={ .open=mycdev_open, .read=mycdev_read, .write=mycdev_write, .release=mycdev_close, }; int all_led_init(void) { //Register address mapping vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t)); if(vir_led1==NULL) { printk("ioremap filed:%d\ ",__LINE__); return -ENOMEM; } vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t)); if(vir_led2==NULL) { printk("ioremap filed:%d\ ",__LINE__); return -ENOMEM; } vir_led3=vir_led1; vir_rcc=ioremap(PHY_RCC_ADDR,4); if(vir_rcc==NULL) { printk("ioremap filed:%d\ ",__LINE__); return -ENOMEM; } printk("Physical address mapping successful\ "); //Initialization of register //rcc (*vir_rcc) |= (0X3<<4); //led1 vir_led1->MODER & amp;= (~(3<<20)); vir_led1->MODER |= (1<<20); vir_led1->ODR & amp;= (~(1<<10)); //led2 vir_led2->MODER & amp;= (~(3<<20)); vir_led2->MODER |= (1<<20); vir_led2->ODR & amp;= (~(1<<10)); //led3 vir_led3->MODER & amp;= (~(3<<16)); vir_led1->MODER |= (1<<16); vir_led1->ODR & amp;= (~(1<<8)); printk("Register initialization successful\ "); return 0; } static int __init mycdev_init(void) { //Character device driver registration major=register_chrdev(0,"mychrdev", & amp;fops); if(major<0) { printk("Character device driver registration failed\ "); return major; } printk("Character device driver registration successful: major=%d\ ",major); //Register mapping and initialization all_led_init(); //Submit directory upward cls=class_create(THIS_MODULE,"mychrdev"); if(IS_ERR(cls)) { printk("Failed to submit directory upward\ "); return -PTR_ERR(cls); } printk("Submit directory upward successfully\ "); //Submit device node information upwards int i; for(i=0;i<3;i + + ) { dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i); if(IS_ERR(dev)) { printk("Failed to submit device node information upward\ "); return -PTR_ERR(dev); } } printk("Submit device node information upward successfully\ "); return 0; } static void __exit mycdev_exit(void) { /*Destroy device node information*/ int i; for(i=0;i<3;i + + ) { device_destroy(cls,MKDEV(major,i)); } //Destroy directory information class_destroy(cls); //Cancel address mapping iounmap(vir_led1); iounmap(vir_led2); iounmap(vir_rcc); //Unregister the character device driver unregister_chrdev(major,"mychrdev"); } module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL");
2. Application
#include<stdlib.h> #include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<unistd.h> #include<string.h> int main(int argc, char const *argv[]) { char buf[128]={0}; int fd=open("/dev/mychrdev0",O_RDWR); if(fd<0) { printf("Failed to open device file\ "); exit(-1); } while(1) { //read from terminal printf("Please enter two characters\ "); printf("First character: 1(LED1) 2(LED2) 3(LED3)\ "); printf("Second character: 0 (lights off) 1 (lights on)\ "); printf("Please enter >"); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]='\0'; //Write to device file write(fd,buf,sizeof(buf)); } close(fd); return 0; }
3.Header file
#ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{ unsigned int MODER; unsigned int OTYPER; unsigned int OSPEEDR; unsigned int PUPDR; unsigned int IDR; unsigned int ODR; }gpio_t; #define PHY_LED1_ADDR 0X50006000 #define PHY_LED2_ADDR 0X50007000 #define PHY_LED3_ADDR 0X50006000 #define PHY_RCC_ADDR 0X50000A28 #endif