Design of PCI driver based on Linux Platform (4)

Source: Internet
Author: User
Article title: Linux-based PCI device driver design (4 ). Linux is a technology channel of the IT lab in China. Includes basic categories such as desktop applications, Linux system management, kernel research, embedded systems, and open source.
. 4 module compilation and loading
We can use makefile to compile the target code that can be loaded by the kernel. (For more information about the usage, see makefile ). If the number of compiled modules is not very large and the number of target code files is small, there is also a simpler method to compile the target code of the Module: use gcc directly to compile the target code. of course, when using gcc, it must contain all the parameters required for compiling the kernel module, such as-DMODULE,-D_KERNEL _, and-DLINUX.
After the module is compiled, there are two ways to load the module: one is to manually load the module using the command insmod; the other is more flexible, and is to automatically load the module as needed, when the kernel finds that a module needs to be loaded, it requires the kernel daemon to load the corresponding module.
The kernel daemon is a process with super user permissions. it mainly serves to load and uninstall modules. it also performs other tasks, such as opening and closing PPP connections. The kernel daemon does not do this in person, but calls the corresponding program (such as insmod) to complete it. it is just a kernel proxy that automatically schedules various tasks.
The method for uninstalling a module is simple. run the rmmod command. However, when a module is no longer needed, kerneld automatically deletes it from the system.
Chapter 4 driver framework
Before writing a driver, we need to determine the capabilities that the driver can provide to the user program.
The drivers for these devices are applicable to most simple PCI devices.
4.1 obtain the master device number
When adding a driver to the system, you need to assign it a master device number. This assignment process should be completed during driver initialization. Call the following function to complete this process. This function is defined in :
Int register_chrdev (unsigned int major,
Const char * name,
Struct file_operatoins * fops );
If an error occurs, a negative value is returned. if the error succeeds, a zero or positive value is returned. The major parameter is the requested master device number, and the name is the device name. it will appear in/proc/devices, and fops is a pointer to the jump table, use this jump table to call the device function.
The next question is how to give the program a name of the device driver they can request. The name must be in the/dev directory and be connected to the driver's master and secondary device numbers. Use the mknod command to create a device node in the file system, for example:
Mknod/dev/mydevice c 120 0
A character device (c) named "mydevice" is created. the master device number is 120, and the secondary device number is 0.
The above is the method for static allocation of the master device number. if you select the master device number for the device in advance, there will be a problem-you can configure more devices than the master device number, and the master device number may not be allocated enough.
We can also use the dynamic allocation mechanism to obtain the master device number.
Because the dynamic allocation mechanism cannot ensure that the master device numbers are always the same each time, it seems that it is impossible to create a device node in advance. In fact, once a device number is assigned, we can always read it from/proc/devices. Therefore, we can first obtain the assigned master device number from/proc/devices and then create a node. The above process requires a script program.
4.2 Release the master device number
When a module is detached from the system, the master device number occupied by the module should be released. This operation can be completed by calling the following function in cleanup_module:
Int unregister_chrdev (unsigned int major, const char * name );
The major parameter is the master device number to be released, and the name is the corresponding device name.
You also need to delete the device node when detaching the driver. If a device node is created when it is loaded, you can write a simple script to delete it when it is detached.
4.3 file operations
The Linux kernel uses the file structure to identify the device. it represents an "opened file", which is defined in .
The following is my system File structure prototype:
Struct file {
Struct file * f_next, ** f_pprev;
Struct dentry * f_dentry;
Struct file_operations * f_op;
Mode_t f_mode;
Loff_t f_pos;
Unsigned int f_count, f_flags;
Unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
Struct fown_struct f_owner;
Unsigned int f_uid, f_gid;
Int f_error;
Unsigned long f_version;
/* Needed for tty driver, and maybe others */
Void * private_data;
};
The important structural items are listed as follows:
Mode_t f_mode;
You need to check the read/write permissions in the ioctl function. However, because the kernel has checked the permissions before calling the read and write operations of the driver, you do not need to check the permissions in these two methods. For example, an unsupported write operation is denied by the kernel when the driver is unknown.
Loff_t f_pos;
Set the location of the current file for the next read/write operation. Loff_t is a 64-bit value. If the driver needs this value, you can directly read this field. If the lseek method is defined, update the f_pos value. When transmitting data, read and write should also update this value.
Unsigned int f_flags;
File flag, such as O_RDONLY, O_NONBLOCK, and O_SYNC. The driver needs to check this flag to support non-blocking operations. Note that you should check the read/write permissions for f_mode instead of f_flags. All these labels are defined in .
Struct file_operations * f_op;
Pointer corresponding to file operations. The kernel assigns a value to this pointer when it completes open, and then accesses this pointer when it needs to perform operations on the file. The value in f_op is not saved. that is to say, you can modify the operation corresponding to the file as needed. The next time you call the corresponding operation to open the file, a new method is called. This technique helps easily identify devices with the same master device number without increasing the burden of system calls, which is called method overload in object-oriented programming technology ".
Void * private_data;
The system sets this pointer to NULL before calling the open method of the driver. The driver can use this field for any purpose, or ignore this field. The driver can use this field to point to the allocated data, but it must be cleared in the release method before the file structure is released by the kernel.
The following describes what operations the driver can perform on the devices it manages.
We can imagine that there is an interface between the driver and the operating system kernel, which is completed through the data structure file_operations. The kernel uses this structure to access the driver's functions.
The following lists some operations that an application can perform on devices. these operations are usually called "methods". if they return 0, they indicate success. If an error occurs, a negative error code is returned.
Loff_t (* llseek) (struct file *, off_t, int );
The function of llseek is to modify the current read/write location of a file and return the new location as a positive return value. If an error occurs, a negative value is returned.
Ssize_t (* read) (struct file *, char *, size_t, loff_t *);
Used to read data from devices. When it is a NULL pointer, the read system returns-EINVAL ("Invalid parameter "). If the function returns a non-negative value, it indicates the number of bytes read successfully.
Ssize_t (* write) (struct file *, const char *, size_t, loff_t *);
Send data to the device. If this function is not available, the write system calls-EINVAL. If the returned value is not negative, it indicates the number of bytes successfully written.
Int (* readdir) (struct file *, void *, filldir_t );
For a device node, this field should be NULL because it is only used for directories.
Int (* ioctl) (struct inode *, struct file *, unsigned int, unsigned long );
Ioctl is called by the system to call device-related commands (for example, the formatting command of a floppy disk is neither a read operation nor a write operation ). In addition, the kernel recognizes some ioctl commands without calling ioctl in file_operations. If the device does not provide an ioctl entry point, the ioctl system will return-EINVAL for any requests not defined by the kernel. When the call is successful, a non-negative value is returned to the calling program.
Int (* mmap) (struct file *, struct vm_area_struct *);
Mmap is used to map the device memory to the process memory. If the device does not support this method, the mmap system will return-ENODEV.
Int (* open) (struct inode *, struct file *);
Although this method is always the first step required to operate the device node, the driver is not required to declare this method. If this parameter is set to NULL, the device is always successfully enabled, but the system does not notify the driver.
Void (* release) (struct inode *, struct file *);
This operation is called when the node is closed. Similar to open, you do not need to declare release.
Int (* fsync) (struct file *, struct dentry *);
The function is to refresh the device. If the driver is not supported, the fsync system returns-EINVAL.
Int (* fasync) (int, struct file *, int );
This operation is used to notify devices of changes to the FASYNC flag. Fasync calls are returned only after the device has completely refreshed the data. If the device does not support asynchronous triggering, this field can be NULL.
Int (* check_media_change) (kdev_t dev );
The check_media_change method is only used for block devices. The kernel calls this method to determine whether the physical medium (such as a floppy disk) in the device has changed since the last operation (1 is returned) or has not (0 is returned ). Character devices do not need to implement this function.
Int (* revalidate) (kdev_t dev );
This is the same as the method mentioned above, and only applies to block devices. Revalidate is related to the cache area.
The following describes the five methods of open, release, write, read, and ioctl described above and what content should be included in the interrupt processing.
Open Method
The open method is used by the driver to complete initialization preparation for future operations. In addition, open also increases the device count value to prevent files from being detached from the kernel before being closed.
Open:
Check for device-related errors (such as the device is not ready or similar hardware problems ).
Initialize the device if it is enabled for the first time.
The device number of the specified time. if necessary, update the f_op pointer.
Allocate and fill in the data structure to be placed in filp-> private_data.
Increase the usage count.
Release method
The release method is opposite to open, which is also called close. It completes the following tasks:
Use count minus 1.
Release the memory allocated by open to private_data.
Disable the device during the last close operation.
Read and write methods
The read/write device means to transmit data from the kernel space to the user's process Space. the following functions can complete these functions:
Void memcpy_fromfs (void * to, const void * from, unsigned long count );
Void m

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.