The previous look at the Linux drive related books, vaguely remember the physical address has dynamic mapping and static mapping, when the write driver is thinking of their own writing, so a hands-on look at the dynamic mapping good, on their own drive using dynamic mapping, the register address mapped to memory, that is called Ioremap function. In the single-line combat time ioremap really good, do not need to change the other parts of the kernel, directly to the physical address you want to map to memory and operation. But many times when our devices need to be used in the global scope, IOREMAP will be more awkward, other C files want to manipulate the virtual address of the device will be more troublesome, and static mapping will be more convenient.
Recently these two days in writing a buzzer driver, this time I try to give up single-line combat, using the system-supplied buzzer driver (DRIVER/INPUT/MISC/PWM-BEEPER.C), to try to understand the idea of kernel drivers.
Add a platform device to a mach-smdk4x12.c file
static struct Platform_device Samsung_bp_device = {
. Name= "Pwm-beeper",
. dev= {
. Parent = &s3c_device_timer[1].dev,
. Platform_data = 1,
},
. id= 1,
};
Use the Platform_device_register function to register the device into the platform bus, so that the driver pwm-beeper.c through the bus to obtain the corresponding device information. Generally speaking, the driver is basically ready to use as long as the driver successfully obtains the information of the BEEPER device via the platform bus. In this drive, the buzzer corresponding to the PWM pin to be set to the corresponding function, such as in 4412 will be set to gpiod0_1 the success of 2, that is, PWM output. Write an application test like this, and the buzzer is basically ready to use. But I was looking at the buzzer driver pwm-beeper.c process, did not see the physical address mapping function, we all know that the kernel is not able to read and write the physical address, all the way to track the operation of the address in the drive, and finally in plat-samsung/include/plat/ Map-base.h see that the address of the # define S3c_addr_base 0XF6000000,PWM is an offset address with s3c_addr_base as the base At first glance, the driver of the buzzer is simply reading and writing an immediate number defined by a define, so the address defined by this define is either a physical address or a virtual address. From datasheet to see the PWM register address is 0x139d0000, then this address should be a virtual address, which caused me to the physical address of the static mapping interest, because the static map after the virtual address is too convenient to use. The following describes the static mapping of the physical address, because it involves the MMU, page table and other complex things, so only a cursory talk.
Static mappings of physical addresses are completed during system startup, and the process of static mapping can be seen in the Mach-exynos/common.c file. Take S3c_va_timer as an example to populate the MAP_DESC structure with a defined virtual address, physical address, requisition address size, and address type.
static struct Map_desc exynos4_iodesc[] __initdata = {
{
. Virtual = (unsigned long) S3c_va_timer,
. PFN = __PHYS_TO_PFN (Exynos4_pa_timer),
. length = sz_16k,
. type = Mt_device,
},
......
}
The filled MAP_DESC structure finally passes the function iotable_init, the correspondence relation of physical address and virtual address is added to the MMU page table, the page table has the correspondence relation of virtual address and physical address, so that the virtual address can be finally mapped to the actual physical address, and the static mapping is completed.
Iotable_init (Exynos4_iodesc, Array_size (EXYNOS4_IODESC));