Devices typically provide a set of registers to control the device, read and write devices, and acquire device status, both controlling registers, data registers, and status registers, which may be in I/O space or in memory space. When in I/O space, usually referred to as the I/O port, when in memory space, the corresponding memory space is called I/O memory (which is now generally a unified address)
1. For I/O port
There are specialized functions that provide data on the read port, such as read-write byte ports (8 bytes wide)
Unsigned inb (Unsigned port);
Unsigned Outb (Unsigned char byte,unsignedport);
2. For I/O memory
Before accessing I/O memory in the kernel, you first use the Ioremap () function to map the physical address of the device to the virtual address, and the prototype for Ioremap () is as follows:
void* ioremap (unsigned long offset,unsignedlong size);
Ioremap (), like Vmalloc (), also needs to create a new page table, but it does not perform the memory allocation behavior that is performed in Vmalloc (). Ioremap () Returns a special virtual address that can be used to access a specific range of physical addresses. The virtual address obtained through IOREMAP () should be freed by the Iounmap () function,
Void Iounmap (void* addr);
After the physical address of the device is mapped to the virtual address, although you can access these addresses directly through pointers, you can use the following set of functions of the Linux kernel to read and write the virtual addresses of the device memory mappings, as follows:
A) read I/O memory
Unsigned Intioread8 (void* addr);
Unsigned intioread16 (void* addr);
Unsigned intioread32 (void* addr);
b) write I/O memory
void Iowrite8 (U8value, void * addr);
void Iowrite16 (U16value, void * addr);
void Iowrite32 (U32value, void * addr);
3. Map I/O ports to memory space
Void*ioport_map (unsigned long port,unsigned int count);
This function allows you to remap the count of successive I/O ports starting with Port to a "memory space". These I/O ports can then be accessed on the address they return as if they were accessing I/O memory. When this mapping is not required, you need to call the following function to undo
Voidioport_unmap (void* addr);
Ioport_map () Mapping to memory space behavior actually creates an illusion for the developer and does not map to the kernel virtual address, just so that the engineer can access the I/O port using the same I/O Memory Access interface
4. Request and release the device I/O port and I/O memory
I/O port request
Struct resource* request_region (unsignedlong first,unsigned long n,const char* name);
This function applies to the kernel for N ports, which start with the first, the name parameter is the device names, and if the assignment succeeds the return value is not NULL
Void relese_region (unsigned longstart,unsigned long n);
I/O memory request
Struct resoutce* request_mem_region (unsignedlong start,unsigned long len,char* name);
Request n memory addresses from the kernel, starting with the name parameter for the device
Void relese_mem_region (unsigned longstart,unsigned long len);
5. Device I/O port and I/O memory access process
A) I/O port access method:
Use the I/O port operation function to request an I/O port when the device is open or the drive module is loaded, then access it using INB () Outb (), and then release the I/O port range when the device is closed or the drive is unloaded
Another way is to map the I/O port to memory for access, to request the I/O Port region and map to memory using Ioport_map () when the device is open or the driver module is loaded, and then use the I/O memory function for port access. Finally, release I/O and use the mapping when the device shuts down or the drive is unloaded
c) How I/O memory is accessed
First use Request_mem_region () to request the resources, and then the register address through IOREMAP () mapped to the virtual address of the kernel space, then you can access the programming interface through the Linux device access to the registers of these devices, after the completion of access, using the Ioremap () The requested virtual address is released and frees the I/O memory resource for the relese_mem_region () request
6. Map device address to user space
In general, user space cannot and should not be directly accessible to the device, however, the device driver can implement the mmap () function, the function of the user space can directly access the physical address of the device, mmap () to implement the user space of a piece of memory and device Memory Association, When the user accesses the user space, the address actually translates to access to the device. If the user space can be directly accessed through memory mapping, the pixel of the screen frame will no longer need a copy process from user space to kernel space, mmap () must be mapped in page_size units
The prototype of the mmap () function in the drive can be seen from the File_operatoions file operation structure:
Int (*mmap) (struct file*,structvm_area_struct*);
The user's call is:
caddr_t mmap (caddr_t addr,size_t len,intport, int flags,int fd,off_t offset);
When the user calls Mmap (), the kernel handles the following:
Find a piece of VMA in the virtual space of the process
Map this piece of VMA
If the file_operations of a device driver or file system defines a mmap () operation, it is called
Insert this VMA into the VMA linked list of the process
The first parameter of the mmap () function in File_operations is the one found in step 1 VMA
As for File_operations, mmap () requires a different system call Remap_pfn_range ()
Most device drivers do not need to provide device memory to user space mapping capabilities, because, for the serial port and other flow-oriented devices, the implementation of this mapping is meaningless, and for display, video and other devices, mapping can reduce the user space and kernel space between the memory copy
Reference: Linux device Driver Development detailed
Linux Driver Development--I/O memory Access process