Author: Joseph Yang <ganggexiongqi@gmail.com>
Content: introduction of UIO subsystem (UIO subsystem Introduction)
Note: linux-3.0
Last modified: 09-15-2011
Bytes -----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (Distributed Embedded System Lab, Lanzhou University)
========================================================== ======================================
------ 1 ------ why does UIO appear?
Hardware devices can be divided into network devices, Block devices, character devices, or devices connected to the CPU according to their functions.
It can be divided into PCI devices and USB devices. They are supported by different kernel subsystems. Driver compilation for these standard devices
Easy and easy to maintain. It is easy to add the source code tree of the main kernel.
However, many devices cannot be divided into these subsystems, such as I/O cards, fieldbus interfaces, or custom FPGAs.
Generally, drivers of these non-standard devices are implemented as character drivers. These drivers use many kernel internal functions and macros.
These internal functions and macros change. In this way, the driver writer must write a full kernel driver and maintain it all the time.
These codes. These drivers cannot enter the source code of the main kernel. As a result, the user space I/O framework (userspace I/O framework) appears ).
--------- 2----------uio how does it work?
A device driver has two main tasks:
1. Access the device's memory
2. Handle device interruptions
For the first task, the UIO core implements MMAP () to process physical memory (physical memory), logical memory (Logical Memory ),
Virtual Memory ). UIO driver compilation does not need to consider these complicated details.
In the second task, responses to device interruptions must be performed in the kernel space. Therefore, there is a small amount of code in the kernel space.
It is used to respond to and prohibit interruptions, but the rest of the work is left to the user space for processing.
If the user space is waiting for a device to be interrupted, it simply needs to block the read () operation on/dev/uiox.
When the device is interrupted, the read () operation returns immediately. UIO also implements the poll () system call. You can use
Select () to wait for the interruption to occur. Select () has a timeout parameter that can be used to wait for interruption within a limited period of time.
You can also control the reading and writing of each file in/sys/class/uio. The UIO device you registered will appear in this directory.
If your UIO device is uio0, the memory file mapped to the device appears in/sys/class/UIO/uio0/maps/MapX.
Read and Write the device memory.
The following figure describes the UIO driver kernel, user space, and the relationship between the UIO framework and the kernel's internal functions.
Figure 1: uio_architecture
For detailed UIO driver compilation, see the example of drivers/UIO/, and documentation/docbook/uio-howto.tmpl
// Files in tmpl format can be converted to PDF or HTML using docbook-utils (In Debian.
--------- 3 ----------- "the relationship between the implementation of UIO core and the kernel of UIO driver"
Important structure:
Struct uio_device {
Struct module * owner;
Struct device * dev; // initialize it in _ uio_register_device
Int minor; // device ID, uio_get_minor
Atomic_t event; // interrupt event count
Struct fasync_struct * async_queue; // asynchronous waiting queue on the device //
// For "asynchronous notification" // see Chapter 6 of ldd3
Wait_queue_head_t wait; // wait queue on the device, which is initialized when the device is registered (_ uio_register_device)
Int vma_count;
Struct uio_info * Info; // point to user-registered uio_info, which is assigned in _ uio_register_device
Struct kobject * map_dir;
Struct kobject * portio_dir;
};
/*
* Struct uio_info-UIO device capabilities
* @ Uio_dev: The UIO device this info belongs
* @ Name: Device Name
* @ Version: Device Driver version
* @ Mem: List of mappable memory regions, size = 0 for end of list
* @ Port: List of port regions, size = 0 for end of list
* @ IRQ: interrupt number or uio_irq_custom
* @ Irq_flags: Flags for request_irq ()
* @ Priv: Optional private data
* @ Handler: the device's IRQ Handler
* @ MMAP: MMAP operation for this UIO Device
* @ Open: open operation for this UIO Device
* @ Release: Release Operation for this UIO Device
* @ Irqcontrol: Disable/enable irqs when 0/1 is written to/dev/uiox
*/
Struct uio_info {
Struct uio_device * uio_dev; // initialize in _ uio_register_device
Const char * Name; // Initialization is required before calling _ uio_register_device
Const char * version; // Initialization is required before calling _ uio_register_device
Struct uio_mem [max_uio_maps];
Struct uio_port port [max_uio_port_regions];
Long IRQ; // The interrupt number assigned to the UIO device. It must be initialized before calling _ uio_register_device.
Unsigned long irq_flags; // Initialization is required before _ uio_register_device is called.
Void * priv ;//
Irqreturn_t (* Handler) (int irq, struct uio_info * dev_info); // call in uio_interrupt for Interrupt Processing
// Initialization is required before _ uio_register_device is called.
INT (* MMAP) (struct uio_info * info, struct vm_area_struct * VMA); // called in uio_mmap,
// Perform specific operations on the device
INT (* open) (struct uio_info * info, struct inode * inode); // It is called in uio_open to perform specific operations on the device.
INT (* release) (struct uio_info * info, struct inode * inode); // It is called in uio_device to execute specific operations on the device.
INT (* irqcontrol) (struct uio_info * info, s32 irq_on); // The uio_write method is called and the user-driven
// Specific operation.
};
First, let's look at a diagram of the relationship between the UIO core and the UIO device. The overall impression is as follows:
Figure 2: uio_core_device
The UIO core is a character device named "UIO" (hereinafter referred to as "UIO core character device"). User-driven Kernel
Use uio_register_device to register a UIO device with the UIO core. The core task of UIO is to manage these registered UIO
Device. The data structure used by these UIO devices is uio_device. And these device properties, such as name, open (),
Release () and other operations are stored in the uio_info structure. Before you use uio_register_device to register these drivers
Set uio_info.
UIO core character device registered
Uio_open
Uio_fasync
Uio_release
Uio_poll
Uio_read
Uio_write
In addition to completing related maintenance work, the related methods registered in uio_info are also called. For example
Uio_open calls the open method registered in uio_info.
So here is a question: how does the UIO core character device find the uio_device structure of the relevant device?
This involves the kernel IDR mechanism. For details about this mechanism, refer:
Http://blog.csdn.net/ganggexiongqi/article/details/6737389
Uio. C has the following definitions:
Static define_idr (uio_idr );
/* Protect IDR accesses */
Static define_mutex (minor_lock );
When you call uio_register_device (_ uio_register_device is called internally) to register your UIO device,
The uio_get_minor function is called in _ uio_register_device. In the uio_get_minor function
The IDR mechanism (idr_get_new) establishes a connection between the sub-device number and the uio_device type pointer. The uio_device pointer
Point to the kernel structure that represents the UIO device you registered. How to enable uio_open on the UIO core character device
First, the sub-device ID (iminor (inode) of the device is obtained, and then the idr_find method provided by the IDR mechanism is used.
Uio_device pointer. The pointer is stored in the uio_listener structure to facilitate future
.
---- 4 --- Handling Device interruptions
In _ uio_register_device, a unified interrupt processing function uio_interrupt is registered for the UIO device,
In this function, the handler (in the uio_info structure) function provided by the UIO device is called ).
The uio_event_notify function is called to add one to the interrupt event counter of the UIO device to notify each read process.
"Data is readable ". The interrupt handler function of each UIO device is registered separately.
Interrupt count: Uio_listener
Struct uio_listener {
Struct uio_device * dev; // Save the pointer of The UIO device for easy access
S32 event_count; // tracks the interrupt event counter of the UIO device.
};
Every registered UIO device (uio_device) is associated with such a structure.
It is used to track the interrupt event counter value of each UIO device (uio_device.
When a user space is opened, the uio_listener structure associated with the UIO device is allocated,
The pointer to it is saved in the private_data field of the filep pointer for other operations.
When a user space closes a file, the uio_listener structure associated with the UIO device is destroyed.
When a UIO device is registered, UIO core registers a universal interrupt processing function (uio_interrupt) for the device ),
In this function, the handler of The UIO device is called. When the interrupt occurs,
Uio_event_notify will be called to add one to the device interrupt event counter () and notify read processes,
Data is readable.
The uio_poll operation determines whether data is readable Based on the interrupt event Count value in the listener.
(Event_count) and the interrupt event counter value in the UIO device are inconsistent (the former is smaller than the latter ). Because
In addition to being assigned a value when executing the file opening operation, the listener value is only used in the uio_read operation.
The interrupt event counter value updated to the UIO device.
Question 1:
For the interrupt event counter, uio_device is defined as atomic_t and has
Typedef struct {
Int counter;
} Atomic_t;
Do you need to consider overflow issues?
The same problem exists in the event_count field of uio_listener.
In the uio_device event field uio_howto:
Event: the total number of interrupts handled by the driver since the last time the device Node
Was read.
[If the frequency of an interrupt event is MHz, the Counter will
Overflow. Therefore, counter-dependent operations may cause problems. // Supplement: the maximum frequency of interruption is kHz and is not MHz. Therefore, the assumption in [] is unreasonable, but overflow may occur, applications dependent on counter values may have problems !!
We can add a timer. In the timer processing function, call uio_event_notify to increase the counter value,
Overflow will soon be observed. <Example, not written yet (pai_^)
// In fact, you can get the uio_device pointer in our registered function, and you can directly modify the event value.
=========== About sysfs File Creation
The UIO-related file structure in sysfs is as follows:
sys ├───uio ├───uio0 │ ├───maps │ ├───mapX ├───uio1 ├───maps │ ├───mapX ├───portio ├───portX
When the UIO module is loaded, uio_init calls init_uio_class and calls class_register to register it in the kernel space.
There is a question about the method of this class, for example, in the show_event method,
Struct uio_device * IDEV = dev_get_drvdata (Dev); // UIO device-related information
How does this uio_device information relate to UIO class?
When _ uio_register_device is called to register a UIO device
IDEV-> Dev = device_create (& uio_class, parent,
Mkdev (uio_major, IDEV-> minor), IDEV,
"UIO % d", IDEV-> minor );
IDEV is a pointer of the uio_device type, which is passed in as drvdata,
Device_create calls device_create and device_create_vargs calls dev_set_drvdata.
In this way, you can use the show_event method of UIO class.
Struct uio_device * IDEV = dev_get_drvdata (Dev );
Obtains the pointer of The UIO device struct.
After device_create is called, The uiox folder representing the UIO device will appear under/sys/class/UIO,
X indicates the sub-device Number Of The UIO device.
Next, it will not be long-winded. Hope to help.
========================================================
Refer:
1, 2 references userspace I/O drivers in a realtime context Hans J. Koch, linutronix GmbH
3, 4 refer to the UIO. c analysis http://blog.csdn.net/ganggexiongqi/article/details/6737647