Before getting into LED driving, we must first introduce the concept of MMU. The full name of MMU is Memory Manage Unit. The main functions of MMU include:
1. Complete the mapping from virtual space to physical space;
2. Memory protection, set memory access permissions, and set the buffer characteristics of virtual storage space.
Conventional Linux requires an MMU (there used to be a ucLinux that could run on MCUs without an MMU, but I have the impression that few people use it now). One of the differences between a CPU and an MCU is the MMU.
According to the conventional Linux character device driver writing steps, LED drivers are introduced one by one:
1. Determine the device number
Determine the device number 200, and then register the character device driver.
retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
if(retvalue < 0){
printk("register chrdev failed!\r\n");
return -EIO;
}
2. Define the file_operations structure
Create a structure to define the operation interface provided by the character device driver. Mainly including led open, read, write, and release interfaces.
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
3. Implement the operation function
Implement the operation function defined in the character device driver and perform corresponding operations according to the requirements of the device.
The concept of MMU virtual memory address introduced earlier is used. How to calculate the address of LED needs to refer to the hardware design. The LED address here is as follows:
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)
Let's look at the implementation function of led write, which is used to light up/turn off the LED.
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue;
unsigned char databuf[1];
unsigned char ledstat;
retvalue = copy_from_user(databuf, buf, cnt);
if(retvalue < 0) {
printk("kernel write failed!\r\n");
return -EFAULT;
}
ledstat = databuf[0]; /* 获取状态值 */
if(ledstat == LEDON) {
led_switch(LEDON); /* 打开LED灯 */
} else if(ledstat == LEDOFF) {
led_switch(LEDOFF); /* 关闭LED灯 */
}
return 0;
}
4. Register and unregister character devices
Use register_chrdev() function to register the device and put it in the led initialization function.
retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
if(retvalue < 0){
printk("register chrdev failed!\r\n");
return -EIO;
}
Use the unregister_chrdev() function to unregister the device and place it in the driver exit function.
unregister_chrdev(LED_MAJOR, LED_NAME);