There are two main tasks for a device driver:
1. Accessing the device's memory
2. Interruption of processing equipment
For the first task, the UIO core implements the Mmap () to handle the physical memory (physical memory), the logical RAM (logical memories),
Virtual memory. UiO driver Writing is no need to consider these cumbersome details.
For the second task, the answer to the device interrupt must be in kernel space. So there's a small piece of code in the kernel space
Used to answer interrupts and prohibit interrupts, but the rest of the work is left to the user for space processing.
If the user space waits for a device to break, it simply needs to be blocked on the read () operation on the/dev/uiox.
The read () operation returns immediately when the device generates an interrupt. UIO also implements the poll () system call, which you can use
Select () to wait for the interrupt to occur. Select () has a timeout parameter that can be used to allow for a limited time to wait for interrupts.
The control of the device can also be completed by reading and writing the various files under the/sys/class/uio. Your registered UiO device will appear in this directory.
If your UiO device is uio0 then the mapped device memory file appears in/SYS/CLASS/UIO/UIO0/MAPS/MAPX, which reads and writes to the file
Read and write to device memory.
The following figure depicts the kernel portion of the UiO drive, the user-space section, and the UiO framework and the kernel intrinsics.
structUio_portio {structKobject Kobj;structUio_port *port;};/** * struct uio_port-description of a uio Port region * @name: Name of the port region for identification * @ Start:start of Port Region * @size: Size of Port region * @porttype: Type of the port (see uio_port_* below) * @portio: For use by the UIO core only. */structUio_port {Const Char*name;unsigned LongStartunsigned LongSizeintPortTypestructUio_portio *portio;};/ * defines for Uio_port->porttype * /#define Uio_port_none 0#define UIO_PORT_X86 1#define UIO_PORT_GPIO 2#define Uio_port_other 3 /* struct uio_mem-description of a UiO memory region * @name: Name of the memory region for identification * @addr: Address of the device ' s memory * @size: Size of IO * @memtype: type of memory addr points to * @internal_addr: ioremap-ped version of addr, for driver internal use * @map: for use by the UIO core only. */structUio_mem {Const Char*name;//memory-mapped name unsigned LongAddr//memory block address unsigned LongSizeThe size of the memory block pointed to by the//ADDR intMemtype;//uio_mem_phys,uio_mem_logical (Kmalloc ()), uio_mem_virtual (VIRTUAL memory) void__iomem *internal_addr;//If you had to access this memory region from within your kernel module, //You'll want to map it internally by using the something like Ioremap (). structUio_map *map;};structUio_map {structKobject Kobj;structUio_mem *mem;};Static Const structVm_operations_struct Uio_vm_ops = {. Open= Uio_vma_open,. Close= Uio_vma_close,. Fault= Uio_vma_fault,};Static structDevice_attribute uio_class_attributes[] = {__attr (name, S_irugo, Show_name,NULL), __attr (version, S_irugo, Show_version,NULL), __attr (event, S_irugo, Show_event,NULL), {}};/ * UIO class infrastructure * /Static structClass Uio_class = {. Name="UiO",///sys/class/uio . Dev_attrs= Uio_class_attributes,};Static Const structFile_operations Uio_fops = {. Owner= This_module,. Open= Uio_open,. Release= Uio_release,. Read= Uio_read,. Write= Uio_write,. Mmap= Uio_mmap,. Poll= Uio_poll,. Fasync= Uio_fasync,. Llseek= Noop_llseek,};/ * Protect IDR accesses * /StaticDefine_mutex (Minor_lock);StaticDEFINE_IDR (UIO_IDR);//about the IDR mechanism, see http://blog.csdn.net/ganggexiongqi/article/details/6737389structUio_device {structModule *owner;structDevice *dev;//Initialize in __uio_register_device intMinor//Secondary Device ID number, Uio_get_minoratomic_t event;//Interrupt Event Count structFasync_struct *async_queue;//Asynchronous wait queue on the device// //About "Asynchronous notifications"//See LDD3, chapter sixthwait_queue_head_t wait;//Waiting queue on the device, initializing when registering the device (__uio_register_device) intVma_count;structUio_info *info;//point to the user registered Uio_info, in the __uio_register_device is assigned the value of the structKobject *map_dir;structKobject *portio_dir;};/* struct Uio_info-uio device capabilities * @uio_dev: The UiO device this info belongs to * @name: D Evice name * @version: Device driver version * @mem: List of mappable memory regions, size==0 for end of Lis T * @port: List of port regions, size==0 for end of list * @irq: Interrupt number or Uio_irq_custom * @irq_fl Ags:flags for REQUEST_IRQ () * @priv: Optional Private Data * @handler: The device ' s IRQ handler * @mmap : mmap operation for the UiO device * @open: Open operation for this UiO device * @release: Release op Eration for the UiO device * @irqcontrol: disable/enable IRQs when 0/1 is written to/dev/uiox */ structUio_info {structUio_device *uio_dev;//Initialize in __uio_register_device Const Char*name;//must initialize before calling __uio_register_device Const Char*version;//must initialize before calling __uio_register_device structUio_mem Mem[max_uio_maps];structUio_port Port[max_uio_port_regions];LongIrq//The interrupt number assigned to the UiO device, which must be initialized before calling __uio_register_device unsigned LongIrq_flags;//must initialize before calling __uio_register_device void*priv;//Irqreturn_t (*handler) (intIrqstructUio_info *dev_info);called in//uio_interrupt for interrupt processing //must initialize before calling __uio_register_device int(*mmap) (structUio_info *info,structVm_area_struct *VMA);//is called in Uio_mmap, //Perform device to open specific actions int(*open) (structUio_info *info,structInode *inode);//called in Uio_open to perform device open specific operation int(*release) (structUio_info *info,structInode *inode);//called in Uio_device to perform device open specific operation int(*irqcontrol) (structUio_info *info, S32 irq_on);//is called in the Uio_write method to perform a user-driven //specific operation. };
function: Static int __init uio_init (void)
Function: Apply the character device number, device, and register to the system, register uio_class to the system
Calling module: Init_uio_class ()
Execution process:
Apply the character device number, device, and register to the system, register Uio_class to the system//init_uio_class
Create "/sys/class/uio"
Function: Uio_exit
Parameters:
return value:
Function: Unregister uio_class, unregister character device number, delete device
Calling module: Release_uio_class
Execution process:
Unregister Uio_class, unregister character device number, remove device//release_uio_class
function: static void Release_uio_class (void)
Parameters:
return value:
Function: Unregister uio_class, unregister character device number, delete device
Calling module:
Execution process:
Logout Uio_class//class_unregister
Unregister character device number, delete device//uio_major_cleanup
function: static int init_uio_class (void)
Parameters:
return value:
Function: Apply the character device number, device, and register to the system, register uio_class to the system
Calling module: Uio_major_init ()
Class_register ()
Execution process:
Request a character device number, device, and initialize//uio_major_init
Register class type global variable Uio_class to system//class_register
Ls-l/sys/class View
function: static int uio_major_init (void)
Parameters:
return value:
Function: Request character device number, device, and initialize
Calling module: Alloc_chrdev_region ()
Cdev_alloc ()
Kobject_set_name ()
Cdev_add ()
Execution process:
Request character device number (multiple)//alloc_chrdev_region
2^uio_max_devices a Slave device
The device's name is "UiO"
Assigns a CDEV structure that represents a character device//cdev_alloc
Initializes the File_operations type field of the CDEV structure//controls various operations of the CDEV device,
such as open, close, read, write ...
The Kobj field of the CDEV structure is set to the name UiO//kobject_set_name
Adding a character device to the system//cdev_add, when the call succeeds, our device is "alive".
Cat/proc/devices, you can view the assigned to main device number
Save main device number to global variable Uio_major
Save device pointer to global variable Uio_cdev
Return
function: static void Uio_major_cleanup (void)
Parameters:
return value:
Function: Unregister character device number, delete device
Calling module: unregister_chrdev_region
Execution process:
Logoff character device number//unregister_chrdev_region
Remove Device Uio_cdev//cdev_del
File_operations
7.
function: Static int uio_open (struct inode *inode, struct file *filep)
parameter: inode:
Filep:
return Value:
Function: Get and secondary device number off Uio_device pointer, create an auxiliary variable listener, and call the Open method in the UIO_INFO structure that
Info points to
Call module:
Execution flow:
Get lock for protection UIO_IDR//mutex_ The lock
Gets the secondary number//iminor
from the inode structure to get the Uio_device pointer associated with the secondary number//idr_find where to set it up???
//Assign the secondary device number in Uio_get_minor and set the association
discard the lock//mutex_unlock
Increase the reference count of the module that the Uio_device type pointer points to//try_module_get
assigns a Uio_listener Type Listener//kmalloc
Associate Listener and Uio_device pointers
Get Uio_device point to device event count values and deposit listener//atomic_read
Save the Listener pointer to the Filep->private_data field
Call the Open method in the Uio_info that the info field of the Uio_device refers to// *
function: Static int uio_release (struct inode *inode, struct file *filep)
Parameters: Inode
Filep
return value:
Function: The release method in the Uio_info that calls the Uio_device field info points
Releasing the auxiliary structural Body listener
Calling module:
Execution process:
Gets the listener pointer saved in Uio_open from Filep->private_data.
Use listener pointer to find pointer to Uio_device type structure
This invokes the release method in the Uio_info that uio_device the field info points to.
Reduce the reference count of the module that the Uio_device type pointer points to//module_put
Release listener structural Body//kfree
function: Static int uio_fasync (int fd, struct file *filep, int on)
Parameters:
Fd
Filep
on:0, delete, non-zero, add
return value:
Function: Manage the async_queue of Uio_device
Calling module: Fasync_helper ()
Execution process:
Gets the listener pointer saved in Uio_open from Filep->private_data.
Use listener pointer to find pointer to Uio_device type structure
Set the async_queue//fasync_helper of Uio_device
function: Static unsigned int uio_poll (struct file *filep, poll_table *wait)
Parameter: Filep
Wait
return value:
Function: Causes the process to wait on the waiting queue that corresponds to all file descriptors that are passed to the system call.
and returns a bitmask that can be executed immediately without blocking
Calling module:
Execution process:
Gets the listener pointer saved in Uio_open from Filep->private_data.
Use listener pointer to find pointer to Uio_device type structure
The IRQ member that determines the info field (Uio_info type) with the Uio_device type pointer is not 0, then continues,
Otherwise, an IO error is returned
Add the Uio_device type pointer to the wait table of the poll_table type to the wait queue for the structure//poll_wait
//!!!! Note that Poll_wait does not block
If the event count value in listener Event_count and Uio_device
The event count value count is inconsistent when//Uio_interrupt calls the uio_event_notify pair
Interrupt Event Counter Increment one
Returns the "usual" data-readable bit mask
function: Static ssize_t uio_read (struct file *filep, char __user *buf,
size_t count, loff_t *ppos)
Parameters:
Filep
Buf
Count
PPOs
return value:
Function: Copy the value of the UiO device interrupt event counter to user space
Calling module:
Execution process:
Get the listener pointer saved in Uio_open from Filep->private_data
Use listener pointer to find pointer to Uio_device type structure
Create an item waiting for the queue//declare_waitqueue
Check to confirm that the UiO device's device info interrupt number (0) is nonzero
Add this process to the wait queue on the UiO device wait on//Add_wait_queue
Wake-up call uio_event_notify by Uio_interrupt
REP: Sets the "Interruptible flag" for the current process
Check to see if an interrupt event occurs,
If there is an interrupt event (listener in the Interrupt event count value Event_count) and the UiO device
Counter value is inconsistent), the value of the device interrupt counter is copied to the user space
and updates the Interrupt event count value in listener to the device's interrupt event count value
Sets the current process to the task_running State,
and deletes the current process from the wait queue of the UiO device
If the O_NONBLOCK flag is set when the file is read,
Then, set the current process to the task_running State,
and deletes the current process from the wait queue of the UiO device
Back to-eagain
Check if the current process has signal processing//signal_pending
http://blog.chinaunix.net/space.php?uid=20746501&do=blog&cuid=1820175
If so, set the current process to the task_running State,
and deletes the current process from the wait queue of the UiO device
and return to-erestartsys
Execution Schedule//schedule
JMP REP
.
Function: Static irqreturn_t uio_interrupt (int irq, void *dev_id) is called by Who??? __uio_register_device
Parameter: IRQ
dev_id
Return value:
Function: Call the handler interrupt handler that is registered in Uio_info, increase the interrupt event counter for the device by one
and notify the read-in A data-readable
Calling module:
Execution process:
Get listener pointer saved in Uio_open from Filep->private_data
Call the info field of the Uio_device type pointer (uio_ Info Type Handler
If it is an interrupt for this device and has already been processed in handler
then increase the interrupt event counter for the device by one,
and notify the read process, with data readable//uio_event_notify
.
Function: void uio_event_notify (struct uio_info *info)
Parameter:
return value:
Function: "Trigger" an interrupt event, add one to the interrupt event counter of the device, and notify the read process, there is Data
Readable
Call module:
Execution Flow:
Get listener pointer saved in Uio_open from Filep->private_data
Add one
to interrupt event counter wake up blocking on device wait queue Wai The read process on T//wake_up_interruptible
//The process on the queue is added in Uio_read
to the asynchronous wait queue async_queue emit a readable signal//kill_fasync
14.
Function: Static ssize_t uio_write (struct file *filep, const char __user *buf,
size_t count, loff_t *ppos)
Parameters:
return value:
Function: Reads the value of the user space and calls the Uio_device registered Irqcontrol function
Call module:
Execution Flow:
Get Uio_ from Filep->private_data The listener pointer saved in open
calls the handler
of the Info field (uio_info type) of the Uio_device type pointer to verify the interrupt number of the Info field (uio_info type) IRQ
Read the 32-bit value passed from user space//copy_from_user
calls the Irqcontrol function of the info field (uio_info type) to pass in the 32-bit value passed by user space
as a parameter.
function: Static int uio_mmap (struct file *filep, struct vm_area_struct *vma)
Parameters:
return value:
Function:
Calling module:
Execution process:
Get the listener pointer saved in Uio_open from Filep->private_data
The handler of the Info field (Uio_info type) that invokes the Uio_device type pointer
Save uio_device Type pointer to VMA Vm_private_data
Returns the index of the mapped area (for example, MapX, x)//uio_find_mem_index
Calculate the actual number of pages and the number of pages requested
Returns-einval if the actual number of pages is less than the requested number of pages
If the UiO device is registered with a mmap function, call it
When the type of memory area is Uio_mem_phys,
Uio_mmap_physical
When the type of memory area is uio_mem_logical/uio_mem_virtual,
Set the operation for the virtual memory locale, and tell the memory not to
The area is swapped out, and the access counter increases by one//uio_mmap_logical
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
UIO mechanism of Linux device driver (ii.)