A Linux device model can be better understood through various stages of a device's life cycle in the kernel. I will analyze the source code of ldquo and sculld to understand the integration of each link in the Linux device model. The integration of the (PCI Bus) in ldd3 serves as a reference, because embedded Linux uses less PCI bus. First, you must familiarize yourself with the source code of ldquo and sculld.
1. ldquo module: add the registration function of the bus, and export the bus device and device driver.The ldd_bus_type subsystem declares a bus_type structure called ldd_bus_type. The source code initializes this struct during compilation. The source code is as follows:
/* * And the bus type. */struct bus_type ldd_bus_type = {.name = "ldd",.match = ldd_match,.uevent = ldd_uevent,};
The source code for loading and detaching the ldquo subsystem to and from the kernel is as follows:
Static int _ init ldd_bus_init (void) {int ret; ret = bus_register (& ldd_bus_type);/* register the bus. After calling this function, the ldd_bus_type struct will be registered with the kernel, the LDD folder appears in/sys/bus, which contains two directories: devices and drivers */If (RET) return ret; If (bus_create_file (& ldd_bus_type, & bus_attr_version )) /* Add the bus attribute. The version attribute file */printk (kern_notice "unable to create version attribute will appear in the/sys/bus/LDD directory! \ N "); ret = device_register (& ldd_bus);/* register the bus as a device. Because the bus can also be a device, for example, in the S3C2440, the SPI bus controller is actually a peripherals compared with the ARM920T core. After this function is called, The ldd0 directory */If (RET) printk (kern_notice "unable to register ldd0 will appear in/sys/devices! \ N "); printk (kern_notice" Mount ld1_ OK! \ Nbus device is ldd0! \ Nyou can see me in sys/module/, sys/devices/and sys/bus /! \ N "); return ret;} static void ldd_bus_exit (void) {device_unregister (& ldd_bus); bus_unregister (& register);} module_init (ldd_bus_init); module_exit (ldd_bus_exit );
The main part of the ldquo module is this, which is very simple. Because this is just a virtual bus, there is no actual driver. The module also exports the registration and logout functions required for loading bus devices and bus drivers. For the actual bus, the read and write routines of the bus should also be exported. Place the bus device and driver registration function in the ldw.gov.cn module and export it to other bus drivers. This is because the information of the bus structure is required for registering bus devices and drivers, these registration functions are the same for all bus devices and drivers. As long as the bus driver is loaded, other bus drivers can register bus devices and drivers by calling these functions, facilitating the author of bus device drivers and reducing code redundancy. These registration functions call the driver_register, device_register, driver_unregister, and device_unregister functions.
Ii. sculld module: add the device and driver registration and logout functions based on scull.The sculld module basically implements the same functions as the scull module. For more information, see sculld provided by ldd3. The main changes are as follows (other minor changes ):
// ****** Add the following code in the declaration phase of the source code to add the device and driver struct ***** struct sculld_dev * sculld_devices; /* allocated in scull_init_module * // * Device Model stuff */static struct ldd_driver sculld_driver = {. version = "$ revision: 1.21-tekkamanninja $ ",. module = this_module ,. driver = {. name = "sculld ",},}; //************************************** * ********************** // ******* adds the device registration function and device number attributes. * ********************************* static Ssize_t sculld_show_dev (struct device * ddev, struct device_attribute * ATTR, char * BUF) {struct sculld_dev * Dev = ddev-> driver_data; return print_dev_t (BUF, Dev> c. Dev. dev);} static device_attr (Dev, s_irugo, sculld_show_dev, null); static void sculld_register_dev (struct sculld_dev * Dev, int index) {sprintf (Dev-> devname, "sculld % d", index); Dev-> ldev. name = Dev-> devname; Dev-> ldev. driver = & sculld_drive R; Dev-> ldev. dev. driver_data = dev; register_ldd_device (& Dev-> ldev); If (device_create_file (& Dev-> ldev. dev, & dev_attr_dev) printk ("unable to create Dev attribute! \ N ");} //************************************** * **************************/* You must also initialize the function and clear the function in the module. add the registration and logout functions for devices and drivers */sculld_register_dev (sculld_devices + I, i); register_ldd_driver (& sculld_driver); unregister_ldd_device (& sculld_devices [I]. ldev); unregister_ldd_driver (& sculld_driver );
After modification, the module can export information to the sysfs file system.
3. Analyze the device and driver registration and cancellation of core functions to understand the general registration and cancellation processes.
The following section also describes the analysis of the PCI driver in ldd3.
(1) Registration of devicesThe core functions for device registration in the driver are:
int device_register(struct device *dev){ device_initialize(dev);return device_add(dev);}
In the device_register function, the driver core initializes many members of the device struct and registers the kobject of the device with the kobject core (resulting in hot swapping events ), add the device to the device linked list owned by its parent node. After that, all devices can be accessed in the correct order and know which of them are at the device level. The device is then added to the linked list of bus-related devices (including all the devices registered with the bus. Then, the driver core traverses the linked list and calls the match function of the bus for each driver. The match function converts the struct device and struct device_driver passed to the driver core into a specific device and driver struct, and checks the device's specific information to determine whether the driver supports the device: if not, the function returns 0 to the driver core, so that the driver core moves to the next driver in the linked list. If supported, the function returns 1 to the driver core, point the driver pointer in the driver core settings in struct device to this driver and call the probe function specified in struct device_driver. the probe function (again) converts the struct device and struct device_driver passed to the driver core to a specific device and driver struct, and verifies whether the driver supports the device again, increase the reference count of the device, and then call the probe function of the bus driver: if the bus probe function considers that it cannot process the device, a negative error value is returned to the driver core, In this way, the drive core moves to the next device in the linked list. If the probe function can process the device, initialize the device and return 0 to the drive core. This will add the driver core to the device linked list bound to the specific driver, and create a symbolic link (pointing to a device in/sys/devices) to the DRIVERS directory in the/sys/bus directory ), allows users to know exactly which driver is bound to which device.
(2) device CancellationThe core function for logging out of a device in the driver is:
void device_unregister(struct device * dev)
In the device_unregister function, the driver core deletes the Symbolic Link (if any) of the device to the device and deletes the device from its internal device linked list, call kobject_del with the struct kobject pointer in the device structure as the parameter. The kobject_del function is called by hotplug in the user space, indicating that kobject is now deleted from the system, and then all sysfs files and directories created and associated with this kobject are deleted. The kobject_del function also removes the reference of the device's own kobject. After that, all sysfs portals associated with the device are removed and the memory associated with the device is released.
(3) Registration of driversThe core functions for registering the driver in the driver are:
int driver_register(struct device_driver * drv)
The driver_register function initializes the struct device_driver struct (including a device linked list and its addition/deletion object function and a spin lock), and then calls the bus_add_driver function. Bus_add_driver: (1) Find the bus associated with the driver: If not found, the negative error value is returned immediately;
(2) Create the sysfs directory of the Driver Based on the driver name and associated bus;
(3) obtain the internal locks of the bus, traverse all the devices that have registered with the bus, and call the match function for these devices. If the function is successful, perform the remaining binding process. (Similar to the registered device, do not go into details)
(4) logout of the driverDeleting a driver is a simple process. The core function of canceling a driver in the driver is:
void driver_unregister(struct device_driver * drv)
The deiver_unregister function cleans up the sysfs attributes connected to the driver entry in the sysfs tree to complete some basic management work. Then, traverse all the devices that belong to the driver and call the release function for them (similar to the function called when a device is deleted from the system ). After all devices are detached from the driver, the following two functions are usually used in the driver:
down(&drv->unload_sem);up(&drv->unload_sem);
They are completed before the function is returned to the caller. This is because before the secure return, the code needs to wait for all references to this driver to count as 0.
When the module is uninstalled, The driver_unregister function is usually called as the exit method. As long as the driver is referenced by the device and waits for the lock, the module needs to be kept in the memory. This allows the kernel to know when the driver can be safely deleted from the memory.
Iv. Experiment on the arm9board
Experiment source code:Http://blogimg.chinaunix.net/blog/upfile2/080109150139.rar
Experiment process:
[Tekkaman2440@SBC2440V4]#insmod /lib/modules/lddbus.koMount lddbus ok !Bus device is ldd0 !You can see me in sys/module/ , sys/devices/ and sys/bus/ ![Tekkaman2440@SBC2440V4]#tree -AC /sys/module/lddbus/ /sys/devices/ldd0/ /sys/bus/ldd//sys/module/lddbus/├── holders├── initstate├── refcnt└── sections ├── __ksymtab └── __ksymtab_strings/sys/devices/ldd0/├── power│ └── wakeup└── uevent/sys/bus/ldd/├── devices├── drivers├── drivers_autoprobe├── drivers_probe└── version5 directories, 9 files[Tekkaman2440@SBC2440V4]#cat /sys/bus/ldd/versionRevision: 1.9-tekkamanninja[Tekkaman2440@SBC2440V4]#rmmod lddbusThe LDD bus device ldd_bus_release : lddbus [Tekkaman2440@SBC2440V4]#ls /sys/module /sys/devices /sys/bus/sys/bus:i2c ide mmc platform serio spi usb/sys/devices:platform system/sys/module:8250 loop rd snd_seq usbnetatkbd mac80211 redboot snd_seq_oss v4l1_compatcdrom mousedev rfd_ftl snd_soc_core vtdm9000 nfs rtc_ds1307 snd_timer yaffshid ohci_hcd s3c2410_wdt spidev zc0301ide_cd printk snd sunrpckeyboard psmouse snd_pcm tcp_cubiclockd rcupdate snd_pcm_oss usbcore[Tekkaman2440@SBC2440V4]#insmod /lib/modules/sculld.kosculld: Unknown symbol register_ldd_devicesculld: Unknown symbol register_ldd_driversculld: Unknown symbol unregister_ldd_driversculld: Unknown symbol unregister_ldd_deviceinsmod: cannot insert '/lib/modules/sculld.ko': Unknown symbol in module (-1): No such file or directory[Tekkaman2440@SBC2440V4]#insmod /lib/modules/lddbus.koMount lddbus ok !Bus device is ldd0 !You can see me in sys/module/ , sys/devices/ and sys/bus/ ![Tekkaman2440@SBC2440V4]#insmod /lib/modules/sculld.ko[Tekkaman2440@SBC2440V4]#tree -AC /sys/module/lddbus/ /sys/devices/ldd0/ /sys/bus/ldd/ /sys/module/sculld//sys/module/lddbus/├── holders│ └── sculld -> http://www.cnblogs.com/../module/sculld├── initstate├── refcnt└── sections ├── __ksymtab └── __ksymtab_strings/sys/devices/ldd0/├── power│ └── wakeup├── sculld0│ ├── bus -> http://www.cnblogs.com/../bus/ldd│ ├── dev│ ├── driver -> http://www.cnblogs.com/../bus/ldd/drivers/sculld│ ├── power│ │ └── wakeup│ ├── subsystem -> http://www.cnblogs.com/../bus/ldd│ └── uevent├── sculld1│ ├── bus -> http://www.cnblogs.com/../bus/ldd│ ├── dev│ ├── driver -> http://www.cnblogs.com/../bus/ldd/drivers/sculld│ ├── power│ │ └── wakeup│ ├── subsystem -> http://www.cnblogs.com/../bus/ldd│ └── uevent├── sculld2│ ├── bus -> http://www.cnblogs.com/../bus/ldd│ ├── dev│ ├── driver -> http://www.cnblogs.com/../bus/ldd/drivers/sculld│ ├── power│ │ └── wakeup│ ├── subsystem -> http://www.cnblogs.com/../bus/ldd│ └── uevent├── sculld3│ ├── bus -> http://www.cnblogs.com/../bus/ldd│ ├── dev│ ├── driver -> http://www.cnblogs.com/../bus/ldd/drivers/sculld│ ├── power│ │ └── wakeup│ ├── subsystem -> http://www.cnblogs.com/../bus/ldd│ └── uevent└── uevent/sys/bus/ldd/├── devices│ ├── sculld0 -> http://www.cnblogs.com/../devices/ldd0/sculld0│ ├── sculld1 -> http://www.cnblogs.com/../devices/ldd0/sculld1│ ├── sculld2 -> http://www.cnblogs.com/../devices/ldd0/sculld2│ └── sculld3 -> http://www.cnblogs.com/../devices/ldd0/sculld3├── drivers│ └── sculld│ ├── bind│ ├── sculld0 -> http://www.cnblogs.com/http://www.cnblogs.com/devices/ldd0/sculld0│ ├── sculld1 -> http://www.cnblogs.com/http://www.cnblogs.com/devices/ldd0/sculld1│ ├── sculld2 -> http://www.cnblogs.com/http://www.cnblogs.com/devices/ldd0/sculld2│ ├── sculld3 -> http://www.cnblogs.com/http://www.cnblogs.com/devices/ldd0/sculld3│ ├── unbind│ └── version├── drivers_autoprobe├── drivers_probe└── version/sys/module/sculld/├── holders├── initstate├── parameters│ ├── scull_major│ ├── scull_minor│ ├── scull_nr_devs│ ├── scull_qset│ └── scull_quantum├── refcnt└── sections ├── __ex_table └── __param38 directories, 33 files[Tekkaman2440@SBC2440V4]#cat /sys/bus/ldd/version /sys/devices/ldd0/sculld*/dev /sys/bus/ldd/drivers/sculld/versionRevision: 1.9-tekkamanninja252:0252:1252:2252:3$Revision: 1.21-tekkamanninja $[Tekkaman2440@SBC2440V4]#rmmod sculld[Tekkaman2440@SBC2440V4]#tree -ACd /sys/module/lddbus/ /sys/devices/ldd0/ /sys/bus/ldd/ /sys/module//sys/module/lddbus/├── holders└── sections/sys/devices/ldd0/└── power/sys/bus/ldd/├── devices└── drivers/sys/module/├── 8250│ └── parameters├── atkbd│ └── drivers│ └── serio:atkbd -> http://www.cnblogs.com/../bus/serio/drivers/atkbd├── cdrom├── dm9000│ └── parameters├── hid│ └── parameters├── ide_cd│ └── parameters├── keyboard│ └── parameters├── lddbus│ ├── holders│ └── sections├── lockd│ └── parameters├── loop├── mac80211│ └── parameters├── mousedev│ └── parameters├── nfs│ └── parameters├── ohci_hcd├── printk│ └── parameters├── psmouse│ ├── drivers│ │ └── serio:psmouse -> http://www.cnblogs.com/../bus/serio/drivers/psmouse│ └── parameters├── rcupdate├── rd├── redboot├── rfd_ftl├── rtc_ds1307├── s3c2410_wdt├── snd│ └── parameters├── snd_pcm│ └── parameters├── snd_pcm_oss│ └── parameters├── snd_seq│ └── parameters├── snd_seq_oss│ └── parameters├── snd_soc_core├── snd_timer│ └── parameters├── spidev│ └── parameters├── sunrpc│ └── parameters├── tcp_cubic│ └── parameters├── usbcore│ ├── drivers│ │ ├── usb:hub -> http://www.cnblogs.com/../bus/usb/drivers/hub│ │ └── usb:usbfs -> http://www.cnblogs.com/../bus/usb/drivers/usbfs│ └── parameters├── usbnet├── v4l1_compat│ └── parameters├── vt│ └── parameters├── yaffs│ └── parameters└── zc0301 ├── drivers │ └── usb:zc0301 -> http://www.cnblogs.com/../bus/usb/drivers/zc0301 └── parameters79 directories[Tekkaman2440@SBC2440V4]#insmod /lib/modules/sculld.ko[Tekkaman2440@SBC2440V4]#rmmod lddbusrmmod: lddbus: Resource temporarily unavailable[Tekkaman2440@SBC2440V4]#rmmod sculld[Tekkaman2440@SBC2440V4]#rmmod lddbusThe LDD bus device ldd_bus_release : lddbus [Tekkaman2440@SBC2440V4]#
Add the "Tree" command to the SystemThe common Linux Command"
TreeIf you use busybox, you may not have this command. In this case, you can download the source code of this command, compile it, and put it in the/bin directory of the root file system. In the calmarrow blog can download: http://blog.chinaunix.net/u/21948/showart_297101.html (because of the source code ftp://mama.indstate.edu/linux/tree/ I can not go straight,
Thank you, calmarrow.)