Learning record - based on teacher Wei Dongshan's tutorial
- String driven development process
(1) Determine the main equipment number
(2) Define your own file_operation structure
(3) Implement the corresponding drv_open,drv_write and other functions
(4) Write an entry function to register the driver
(5) Write an exit function to unload the driver - Steps of led development
(1) Look at the schematic diagram to determine whether the led is on or off at GPIO port and output high and low levels
(2) Enable: CCM is used to set the clock provided to GPIO module, Clock Controller Module, find the corresponding chip manual and change the value of the corresponding bit of the corresponding register
(3) Set the pin operating mode to GPIO mode
(4) Set pin direction (GPIOx_GDIR): each pin corresponds to one pin, 1-output, 0-input
(5) Set output pin level (GPIOx_DR): each pin corresponds to one pin, 1-high level and 0-low level
(6) Read pin level (GPIOx_PSR): each pin corresponds to one pin, 1-high level and 0-low level - Driver programming
(1) Add the header file, open the source code of the Linux kernel, open a driver at random, and copy the header file contained therein;
(2) determining the main equipment number can be set to zero first and then call register_. Chrdev() function, which returns a valid device group;
(3) Define file_operation structure: similarly, find a driver to imitate and define the structure you need.
static const struct file_operations led_fops = { .owner = THIS_MODULE, .write = led_write, .open = led_open, };
(4) Implement the corresponding driver function:
/* write function */ static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char val; int retu; /* copy_from_user: get data from app */ retu = copy_from_user(&val, buf, 1); /* to set gpio register: 1/0 */ if (val){ /* set gpio to let led on */ *GPIO5_DR &= ~(1<<3); } else { /*set gpio to let led off */ *GPIO5_DR |= (1<<3); } return 0; } /* open function */ static int led_open(struct inode *inode, struct file *file) { /* * enable gpio * configure gpio5_io3 as gpio * configure gpio5_io3 as output */ *IOMUXC_GPIO5_IO03 &= ~0xf; *IOMUXC_GPIO5_IO03 |= 0x5; *GPIO5_GDIR |= (1<<3); return 0; }
(5) In the driver development, the hardware address cannot be directly used, but the actual address needs to be mapped with the ioremap() function for reuse. In this example, because the GPIO module is enabled by default and there is no need to check the level, the corresponding two steps are omitted.
/* register */ // IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 Address: 229_0000h base + 14h offset = 229_0014h 0x2290000+0x14 static volatile unsigned int *IOMUXC_GPIO5_IO03; // gpio5 020A_C000 // GPIO direction register input/output Address: Base address + 4h offset 0x20AC004 static volatile unsigned int *GPIO5_GDIR; // GPIO data register 0/1 Address: Base address + 0h offset 0X20AC000 static volatile unsigned int *GPIO5_DR; /* ioremap Map actual address */ // IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 Address: 229_0000h base + 14h offset = 229_0014h 0x2290000+0x14 IOMUXC_GPIO5_IO03 = ioremap(0x2290000+0x14, 4); // gpio5 020A_C000 // GPIO direction register input/output Address: Base address + 4h offset 0x20AC004 GPIO5_GDIR = ioremap(0x20AC004, 4); // GPIO data register 0/1 Address: Base address + 0h offset 0X20AC000 GPIO5_DR = ioremap(0X20AC000, 4);
(6) Write entry function‘
/* Entry function */ static int __init led_init(void) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); /* Register driver */ major = register_chrdev(0, "yuelong_led", &led_fops); //Receive the returned master device number for exit function destruction /* ioremap Map actual address */ // IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 Address: 229_0000h base + 14h offset = 229_0014h 0x2290000+0x14 IOMUXC_GPIO5_IO03 = ioremap(0x2290000+0x14, 4); // gpio5 020A_C000 // GPIO direction register input/output Address: Base address + 4h offset 0x20AC004 GPIO5_GDIR = ioremap(0x20AC004, 4); // GPIO data register 0/1 Address: Base address + 0h offset 0X20AC000 GPIO5_DR = ioremap(0X20AC000, 4); /* Create classes and nodes */ led_class = class_create(THIS_MODULE, "myled"); device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); // Device node with / dev/myled created return 0; }
(7) Write exit function
/* Exit function */ static void __exit led_exit(void) { /* Clearly map the actual address */ iounmap(IOMUXC_GPIO5_IO03); iounmap(GPIO5_GDIR); iounmap(GPIO5_DR); /* Destroy nodes and classes */ device_destroy(led_class, MKDEV(major, 0)); class_destroy(led_class); /* Unregister driver */ unregister_chrdev(major, "yuelong_led"); }
(8) Only by declaring the above entry and exit functions can we truly register and uninstall the driver, and the life GPL protocol:
// Declare the entry and exit functions of the appeal module_init(led_init); module_exit(led_exit); // GPL protocol MODULE_LICENSE("GPL");