Basic Framework for PCI driver development in Linux

Source: Internet
Author: User
PCI is a widely used bus standard. It provides many new features that are better than other bus standards (such as EISA) and has become the most widely used computer system, and the most common bus standard. Linux's inner nuclear energy well supports the PCI bus. This paper focuses on the intel 386 architecture and discusses the basic framework for developing the PCI device driver program in Linux.
  
   1. architecture of the PCI bus system
  
PCI is the abbreviation of Peripheral Component Interconnect. As a common bus interface standard, PCI is widely used in computer systems. PCI provides a complete set of bus interface specifications to describe how to connect peripheral devices in computer systems in a structured and structured manner, it also depicts the electrical characteristics and behavior conventions of peripheral devices during connection, and defines in detail how different components in a computer system interact correctly.
  
Whether on an Intel chip-based PC or an alpha chip-based workstation, PCI is undoubtedly the most widely used bus interface standard. Unlike the old ISA bus, PCI completely separates bus subsystems in computer systems from storage subsystems) to complete the interaction with the bus subsystem, as shown in figure 1.
  
   
  
Figure 1 architecture of the PCI Subsystem
  
Because a higher clock frequency is used, the PCI bus can achieve better overall performance than the ISA bus. The clock frequency of the PCI bus is generally within the range of 25 MHz to 33 MHz. Some of them can even reach 133 MHz or 266 MHz, while the maximum clock frequency is MHz in 64-bit systems. Although most PCI devices currently use a 32-bit data bus, the PCI specification has provided 64-bit extension implementation, so that the PCI bus can better achieve platform independence, PCI bus is now available in architectures such as IA-32, Alpha, PowerPC, sparc64 and IA-64.
  
The PCI bus has three significant advantages, enabling it to ultimately replace the historical mission of the ISA bus:
  
Better performance in data transmission between computers and peripherals;
  
Be independent from specific platforms as much as possible;
  
You can easily implement plug and play.
  
Figure 2 is a typical computer system logic based on the PCI bus. each part of the system is connected by the PCI bus and the PCI-PCI bridge. It is not hard to see that the CPU and ram need to be connected to the PCI bus 0 (that is, the primary PCI Bus) through the PCI bridge, and the graphics card with the PCI interface can be directly connected to the primary PCI bus. The PCI-PCI Bridge is a special PCI device that connects PCI bus 0 and PCI Bus 1 (that is, from the PCI Main Line) together, usually PCI Bus 1 is called the downstream of the PCI-PCI bridge (downstream), while PCI bus 0 is called the upstream of the PCI-PCI bridge (upstream ). In the figure, scsicard And ethernet card are connected from the PCI bus. To be compatible with the old ISA bus standard, the PCI bus can also be connected through a PCI-ISA bridge to support previous ISA devices. The ISA bus is connected with a multi-functional I/O controller to control the keyboard, mouse, and soft drive.
  
  
Figure 2 PCI system
  
Here I only give a general introduction to the architecture of the PCI bus system, if you want to learn more, David A rusling in the Linux kernel (http://tldp.org/LDP/tlk/dd/pci.html) the Linux PCI subsystem is described in detail.
  
   Ii. Linux driver framework
  
Linux regards all external devices as a special type of files, which are called "Device Files". If a system call is an interface between the Linux kernel and applications, the device driver can be seen as an interface between the Linux kernel and external devices. The device driver shields the application from the implementation details of the hardware, so that the application can operate the external device like an ordinary file.
  
1. Character devices and block Devices
  
Linux abstracts the processing of hardware. All hardware devices can be viewed as common files: they can use the same standard system call interfaces as operating files to complete open, close, read/write, and I/O control operations, the main task of the driver is to implement these System Call functions. All hardware devices in Linux are represented by a special device file. For example, the first IDE hard disk in the system is represented by/dev/hda. Each device file pair should have two device numbers: one is the master device number, which identifies the device type and the driver used by the device; the other is the secondary device number, identifies different hardware devices that use the same device driver. The master device number of the device file must be the same as the master device number applied by the device driver when you log on to the device. Otherwise, the user process will not be able to access the device driver.
  
In Linux, there are two main types of device files: character devices and Block devices. Character devices perform I/O operations one by one in bytes. When a read/write request is sent to a character device, the actual hardware I/O occurs immediately, generally, the cache in character devices is dispensable and does not support random access. A block device uses a piece of system memory as the buffer. When a user process requests read and write requests to the device, the driver first checks the content in the buffer, if the data in the buffer can meet the user's requirements, the corresponding data will be returned. Otherwise, the corresponding request function will be called for actual I/O operations. Block devices are designed for disks and other slow devices. The objective is to avoid excessive CPU time consumption to wait for the Operation to complete. Generally, PCI cards generally belong to character devices.
  
The primary device numbers of all registered hardware devices (I .e. drivers loaded) can be obtained from the/proc/devices file. You can use the mknod command to create a device file of the specified type and assign the corresponding primary device number and secondary device number to the file. For example, the following command:
  
[Root @ Gary root] # mknod/dev/lp0 C 6 0
  
A device file with the primary device number 6 and the secondary device number 0 is created. When an application calls a device file, the Linux kernel calls the corresponding Driver Based on the device type and master device Number of the file and enters the core State from the user State, then, the driver determines the device number, and finally completes the operation on the corresponding hardware.
  
2. Device Driver Interface
  
The I/O subsystem in Linux provides a unified standard device interface to other parts of the kernel, which is completed through the data structure file_operations in include/Linux/fs. h:
  
  
Struct file_operations {
Struct module * owner;
Loff_t (* llseek) (struct file *, loff_t, INT );
Ssize_t (* read) (struct file *, char *, size_t, loff_t *);
Ssize_t (* write) (struct file *, const char *, size_t, loff_t *);
INT (* readdir) (struct file *, void *, filldir_t );
Unsigned int (* poll) (struct file *, struct poll_table_struct *);
INT (* IOCTL) (struct inode *, struct file *, unsigned int, unsigned long );
INT (* MMAP) (struct file *, struct vm_area_struct *);
INT (* open) (struct inode *, struct file *);
INT (* flush) (struct file *);
INT (* release) (struct inode *, struct file *);
INT (* fsync) (struct file *, struct dentry *, int datasync );
INT (* fasync) (INT, struct file *, INT );
INT (* Lock) (struct file *, Int, struct file_lock *);
Ssize_t (* readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
Ssize_t (* writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
Ssize_t (* sendpage) (struct file *, struct page *, Int, size_t, loff_t *, INT );
Unsigned long (* get_unmapped_area) (struct file *, unsigned long, unsigned long );
};
  
When an application performs operations on device files such as open, close, read, and write, the Linux kernel accesses the functions provided by the driver through the file_operations structure. For example, when an application reads a device file, the kernel calls the READ function in the file_operations structure.
  
2. Device Driver Module
  
In Linux, device drivers can be compiled in two ways. One is to directly and statically compile the program into a part of the kernel, and the other is to compile the program into a module that can be dynamically loaded. If it is compiled into the kernel, the size of the kernel will be increased, and the source file of the kernel will be changed, and it cannot be dynamically uninstalled, which is not conducive to debugging. We recommend that you use the module method.
  
In essence, a module is also a part of the kernel. Unlike common applications, it cannot call C or C ++ library functions in user mode, you can only call functions provided by the Linux kernel. You can view all functions provided by the kernel in/proc/ksyms.
  
When writing a driver in the module mode, you must implement two essential functions: init_module () and cleanup_module (), which must contain at least two header files. When compiling the kernel module with GCC, you need to add the-dmodule-d1_kernel _-dlinux parameters to compile the generated modules (generally. o file) You can use the command insmod to load the Linux kernel to become an integral part of the kernel. At this time, the kernel will call the function init_module () in the module (). When this module is not required, run the rmmod command to uninstall the module. The cleanup_module () function in the module is called in the kernel (). You can run the lsmod command to view the loaded modules and the number of users using the modules at any time.
  
3. device driver structure
  
Understanding the basic structure (or framework) of the device driver is very important for developers. the Linux device driver can be roughly divided into the following parts: driver registration and cancellation, device opening and releasing, device read/write operations, device control operations, device interruption and polling processing.
  
Driver registration and logout
  
Adding a driver to the system means giving it a master device number. This can be done by calling register_chrdev () or register_blkdev () during the driver initialization process. When you disable a character device or block device, you must call unregister_chrdev () or unregister_blkdev () to log out the device from the kernel and release the occupied master device number.
 
Related Article

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.