Kernel device driver API _ register_chrdev_region,
Kernel device driver API _ register_chrdev_region
_ Register is used to register a separate master device number and a slave device number within a range. The source code analysis is as follows: static struct char_device_struct * _ register_chrdev_region (unsigned int major, unsigned int baseminor, int minorct, const char * name) {struct char_device_struct * cd, ** cp; int ret = 0; int I; # apply for a char_device_struct struct cd = kzarloc (sizeof (struct char_device_struct), GFP_KERNEL); if (cd = NULL) return ERR_PTR (-ENOMEM); mutex_lock (& chrdevs_lock ); If the parameter major is zero, a master device number is dynamically allocated if (major = 0) {ret = find_dynamic_major (); if (ret <0) {pr_err ("CHRDEV \" % s \ "dynamic allocation region is full \ n", name); goto out;} major = ret ;} # the master device number cannot exceed the maximum value of 255if (major> = CHRDEV_MAJOR_MAX) {pr_err ("CHRDEV \" % s \ "major requested (% d) is greater than the maximum (% d) \ n ", name, major, CHRDEV_MAJOR_MAX); ret =-EINVAL; goto out;} # assign the initial value cd-> major = major; cd-> baseminor = basemino R; cd-> minorct = minorct; strlcpy (cd-> name, name, sizeof (cd-> name); # here is actually a mod operation, it also prevents the master device number from exceeding 255i = major_to_index (major); # check whether there is a conflict with the existing master device number for (cp = & chrdevs [I]; * cp; cp = & (* cp)-> next) if (* cp)-> major | (* cp) -> major = major & (* cp)-> baseminor> = baseminor) | (* cp)-> baseminor + (* cp) -> minorct> baseminor) break;/* Check for overlapping minor ranges. */# Check whether the slave devices of the master device overlap if (* cp && (* Cp)-> major = major) {int old_min = (* cp)-> baseminor; int old_max = (* cp)-> baseminor + (* cp) -> minorct-1; int new_min = baseminor; int new_max = baseminor + minorct-1;/* New driver overlaps from the left. */if (new_max> = old_min & new_max <= old_max) {ret =-EBUSY; goto out;}/* New driver overlaps from the right. */if (new_min <= old_max & new_min> = old_min) {ret =-EBUSY; goto out ;}# submit the newly applied cp Connect to the pointer cd-> next = * cp; * cp = cd; mutex_unlock (& chrdevs_lock); return cd; out: mutex_unlock (& chrdevs_lock); kfree (cd ); return ERR_PTR (ret);} Let's take a look at how the system dynamically assigns a static int find_dynamic_major (void) {int I if the number of the primary device passed by the user is zero; struct char_device_struct * cd; # first check the device whose device is null in the chrdevs array. If this device number is not used, the system returns the primary device number for (I = ARRAY_SIZE (chrdevs) -1; I> CHRDEV_MAJOR_DYN_END; I --) {if (chrdevs [I] = NULL) return I ;}# if the master device number in chrdevs is both If it is not used, query CHRDEV_MAJOR_DYN_EXT_START = 511 ~ Primary device number before 384 for (I = CHRDEV_MAJOR_DYN_EXT_START; I> CHRDEV_MAJOR_DYN_EXT_END; I --) {for (cd = chrdevs [major_to_index (I)]; cd; cd = cd-> next) # if (cd-> major = I) break is found when the master device number is used; # if (cd-> major = I) is not used, the primary device ID if (cd = NULL | cd-> major! = I) return I;} return-EBUSY;} using this function, we can know that the range of the dynamically assigned master device number is 255 ~ 234, and 511 ~ 384