Mdev usage and principles
Mdev is a simplified udev that comes with busybox and is suitable for Embedded Application merge. It is easy to use. It is used in system startup and hot swapping.
Or when the driver is dynamically loaded, the node files required by the driver are automatically generated. It is optimal to use busybox to build an embedded linux root file system.
.
Use mdev
The mdev.txt document of mdevs used in busyboxhas been described in detail. But as an example, I will briefly talk about my use process:
(1) added mdev support during compilation (I am using busybox1.10.1 ):
Linux system utilities --->
Mdev
Support/etc/mdev. conf
Support Command Execution At device addition/removal
(2) Add the mdev command at startup:
I added the following command to the/linuxrc file in the self-created root file system (NFS:
# Mount/sys as sysfs File System
Echo "---------- Mount/sys as sysfs"
/Bin/Mount-T tmpfs mdev/dev
/Bin/Mount-T sysfs/sys
Echo "---------- starting mdev ......"
/Bin/ECHO/sbin/mdev>/proc/sys/kernel/hotplug
Mdev-S
Note: It is/bin/ECHO/sbin/mdev>/proc/sys/kernel/hotplug, not/bin/ECHO/bin/mdev>/proc/sys/kernel/hotplug.
The document of busybox is incorrect !!
(3) add support for Class Device interfaces to your driver.
In the initialization function of the driver, you can use the following similar statements to add an attribute file named "Dev" containing the device number under the category Device directory. And through mdev
Generate the gpio_dev0 device node file in the/dev directory.
My_class = class_create (this_module, "gpio_class ");
If (is_err (my_class )){
Printk ("Err: failed in creating class./N ");
Return-1;
}
/* Register Your Own Device in sysfs, and this will cause mdev to create corresponding device node */
Class_device_create (my_class, mkdev (gpio_major_number, 0), null, "gpio_dev % d", 0 );
In the driver's Purge section, add the following statement to complete the cleanup.
Class_device_destroy (my_class, mkdev (gpio_major_number, 0 ));
Class_destroy (my_class );
The required header file is Linux/device. H. Therefore, add the following statement to the beginning of the program:
# Include <Linux/device. h>
In addition, my_class is a struct pointer of the class type, which must be declared as a global variable at the beginning of the program.
Struct class * my_class;
Gpio_major_number in the above program is the master node number of the device. You can change it to the required node number. Gpio_dev is the name of the final generated device node file. % D is
Used for automatic numbering with the same device. Gpio_class is the name of the created class. After the driver is loaded, you can see it in the/sys/class directory.
The preceding statements do not have to be used in the initialization and clearing phases. They can be used elsewhere as needed.
(4) As for the/etc/mdev. conf file, it is optional and does not affect usage, but only adds some functions.
For how to use mdev, I found a Chinese version on the Internet. You can download it from my uploaded resources.
To make good use of mdev, it is essential to know how it works. Let's briefly introduce the mdev principle:
Execute mdev-S
: Call with '-S' as the parameter
Mdev written in the/sbin directory (in fact, it is a link to pass parameters to the busybox program in the/bin directory and call it), mdev scans/sys/class and
/Sys/block
If the directory contains a file named "Dev" and the file contains a device number, mdev uses this information
Create a device node file. Generally, "mdev-s" is executed only once at startup ".
Hot swapping event: Due to running at startup
Command: ECHO/sbin/mdev>/proc/sys/kernel/hotplug, the kernel will call
/Sbin directory mdev. In this case, mdev uses the action and
Devpath (these two variables are included in the system) to determine the actions of the hot swapping event and the directory in/sys. Then we will check whether there is any
"Dev" attribute file, if any, uses this information
This device creates a device node file under/dev.
Finally, I have attached a simple gpio control driver that I wrote at work. This program has no function, mainly used for testing. If you are interested, you can use
It tests the above mdev usage. I am using a friendly company's mini2440 Development Board.
# Include <Linux/config. h>
# Include <Linux/module. h>
# Include <Linux/moduleparam. h>
# Include <Linux/init. h>
# Include <Linux/kernel. h>/* printk ()*/
# Include <Linux/fs. h>/* everything ...*/
# Include <Linux/cdev. h>
# Include <Linux/interrupt. h>/* request_irq ()*/
# Include <ASM/ARCH/regs-gpio.h>
# Include <ASM/ARCH/regs-irq.h>
# Include <ASM/IO. h>
# Include <ASM/uaccess. h>/* copy_to_user ()*/
# Include <Linux/delay. h>/* mdelay ()*/
# Include <Linux/device. h>/* class_create ()*/
# Include <ASM/arch-s3c2410/regs-gpio.h>
# Include <ASM/arch-s3c2410/regs-timer.h>
# Define version_string "gpio driver for jm_xcontrol"
# Define device_name "jm_xcontrol_gpio"
/* Use 0xe0 as magic number */
# Define xray_ioc_magic 0xe0
# Define xray_ioclcdbacklight _ IO (xray_ioc_magic, 0)
# Define xray_ioc485rec _ IO (xray_ioc_magic, 1)
# Define xray_ioc485trc _ IO (xray_ioc_magic, 2)
# Define xray_iocbuzzer _ IO (xray_ioc_magic, 3)
# Define xray_ioc_maxnr 12
Module_author ("hugerat ");
Module_license ("dual BSD/GPL ");
Module_description (version_string );
Unsigned int gpio_major_number = 0;
Struct cdev gpio_dev;
Struct class * my_class;
Static int gpio_ioctl (struct inode * inode, struct file * file, unsigned int cmd, unsigned long Arg)
{
Int err = 0;
Unsigned long TMP;
// ------- The following check Command ---------//
If (_ ioc_type (CMD )! = Xray_ioc_magic) Return-enotty;
If (_ ioc_nr (CMD)> xray_ioc_maxnr) Return-enotty;
If (_ ioc_dir (CMD) & _ ioc_read)
Err =! Access_ OK (verify_write, (void _ User *) Arg, _ ioc_size (CMD ));
Else if (_ ioc_dir (CMD) & _ ioc_write)
Err =! Access_ OK (verify_read, (void _ User *) Arg, _ ioc_size (CMD ));
If (ERR)
Return-efault;
//--------------------------//
Switch (CMD)
{
Case xray_ioclcdbacklight: // control the LCD backlight Switch
If (ARG = 0)
{
S3c2410_gpio_setpin (s3c2410_gpb1, 1 );
}
Else
{
S3c2410_gpio_setpin (s3c2410_gpb1, 0 );
}
Break;
Case xray_ioc485rec:
If (ARG = 0)
{
S3c2410_gpio_setpin (s3c2410_gpg10, 1 );
}
Else
{
S3c2410_gpio_setpin (s3c2410_gpg10, 0 );
}
Break;
Case xray_ioc485trc:
If (ARG = 0)
{
S3c2410_gpio_setpin (s3c2410_gpg12, 0 );
}
Else
{
S3c2410_gpio_setpin (s3c2410_gpg12, 1 );
}
Break;
Case xray_iocbuzzer:
If (ARG = 0)
{
S3c2410_gpio_setpin (s3c2410_gpb0, 0 );
}
Else
{
S3c2410_gpio_setpin (s3c2410_gpb0, 1 );
}
Break;
Default:
Break;
}
Return 0;
}
Static struct file_operations gpio_fops = {
. Owner = this_module,
//. Open = xray_open,
//. Release = xray_release,
//. Read = xray_read,
//. Write = xray_write,
. IOCTL = gpio_ioctl,
//. Fasync = xray_fasync,
};
Static int _ init gpio_init (void)
{
Int ret, devno;
Dev_t dev;
Unsigned long TMP;
Ret = alloc_chrdev_region (& Dev, 0, 1, device_name );
Gpio_major_number = major (Dev );
Printk (kern_info "Initial jm_xcontrol_gpio driver! /N ");
If (Ret <0 ){
Printk (kern_warning "gpio: Can't Get Major Number % d/N", gpio_major_number );
Return ret;
}
Devno = mkdev (gpio_major_number, 0 );
Cdev_init (& gpio_dev, & gpio_fops );
Gpio_dev.owner = this_module;
Gpio_dev.ops = & gpio_fops;
Ret = cdev_add (& gpio_dev, devno, 1 );
If (RET ){
Unregister_chrdev_region (Dev, 1 );
Printk (kern_notice "error % d adding gpio device/N", RET );
Return ret;
}
My_class = class_create (this_module, "gpio_class ");
If (is_err (my_class )){
Printk ("Err: failed in creating class./N ");
Return-1;
}
/* Register Your Own Device in sysfs, and this will cause mdev to create corresponding device node */
Class_device_create (my_class, mkdev (gpio_major_number, 0), null, "gpio_dev % d", 0 );
// LCD Backlight
S3c2410_gpio_cfgpin (s3c2410_gpb1, s3c2410_gpb1_outp );
S3c2410_gpio_setpin (s3c2410_gpb1, 0 );
// Buzzer
S3c2410_gpio_cfgpin (s3c2410_gpb0, s3c2410_gpb0_outp );
S3c2410_gpio_setpin (s3c2410_gpb0, 0 );
// 485 send and receive control
S3c2410_gpio_cfgpin (s3c2410_gpg10, s3c2410_gpg10_outp ); //
S3c2410_gpio_setpin (s3c2410_gpg10, 0 );
S3c2410_gpio_cfgpin (s3c2410_gpg12, s3c2410_gpg12_outp); // send
S3c2410_gpio_setpin (s3c2410_gpg12, 0 );
Return 0;
}
Static void _ exit gpio_cleanup (void)
{
Unsigned long TMP;
Dev_t Dev = mkdev (gpio_major_number, 0 );
Cdev_del (& gpio_dev );
Class_device_destroy (my_class, mkdev (gpio_major_number, 0 ));
Class_destroy (my_class );
Unregister_chrdev_region (Dev, 1 );
S3c2410_gpio_setpin (s3c2410_gpb1, 1); // turn off the backlight
S3c2410_gpio_setpin (s3c2410_gpb0, 0); // close the buzzer
S3c2410_gpio_setpin (s3c2410_gpg10, 1); // close the 485 Packet
S3c2410_gpio_setpin (s3c2410_gpg12, 0); // turn off the 485 release
Printk (kern_info "unregistered the % s/n", device_name );
}
Module_init (gpio_init );
Module_exit (gpio_cleanup );