Requirements:
Code writing:
Header file
#ifndef __MYCDEV_H__ #define __MYCDEV_H__ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/device.h> #define CNAME "myled" //GPIOx group controller structure typedef struct { volatile unsigned int MODER; // 0x00 volatile unsigned int OTYPER; // 0x04 volatile unsigned int OSPEEDR; // 0x08 volatile unsigned int PUPDR; // 0x0C volatile unsigned int IDR; // 0x10 volatile unsigned int ODR; // 0x14 volatile unsigned int BSRR; // 0x18 volatile unsigned int LCKR; // 0x1C volatile unsigned int AFRL; // 0x20 volatile unsigned int AFRH; // 0x24 volatile unsigned int BRR; // 0x28 volatile unsigned int res; volatile unsigned int SECCFGR; // 0x30 }gpio_t; char kbuf[128] = {0}; //Initialize rcc, GPIOE, GPIOF, GPIOZ group controllers unsigned int* AHB4_virt_rcc; unsigned int* AHB5_virt_rcc; gpio_t* virt_gpioe; gpio_t* virt_gpiof; gpio_t* virt_gpioz; struct class* c; struct device* d; //Specify the GPIOE group base address #define PHY_GPIOE_ADDR 0x50006000 //Specify the GPIOF group base address #define PHY_GPIOF_ADDR 0x50007000 //Specify the GPIOZ group base address #define PHY_GPIOZ_ADDR 0x54004000 //AHB4_RCC base address: 0x50000A28 #define PHY_RCC_AHB4 0x50000A28 //AHB5_RCC base address: 0x50000A28 #define PHY_RCC_AHB5 0x54000210 //LED lighting command code #define LED_ON _IOW('a',1,int) // LED off command code #define LED_OFF _IOW('a',0,int) //LED flip command code #define LED_TOGGLE _IOW('a',2,int) //LED1~6 flip #define LED1_TOGGLE (virt_gpioe->ODR ^= (0x1 << 10)) #define LED2_TOGGLE (virt_gpiof->ODR ^= (0x1 << 10)) #define LED3_TOGGLE (virt_gpioe->ODR ^= (0x1 << 8)) #define LED4_TOGGLE (virt_gpioz->ODR ^= (0x1 << 5)) #define LED5_TOGGLE (virt_gpioz->ODR ^= (0x1 << 6)) #define LED6_TOGGLE (virt_gpioz->ODR ^= (0x1 << 7)) //LED1 is on #define LED1_ON (virt_gpioe->ODR |= (0x1 << 10)) //LED1 off #define LED1_OFF (virt_gpioe->ODR &= (~(0x1 << 10))) //LED2 is on #define LED2_ON (virt_gpiof->ODR |= (0x1 << 10)) //LED2 off #define LED2_OFF (virt_gpiof->ODR & amp;= (~(0x1 << 10))) //LED3 is on #define LED3_ON (virt_gpioe->ODR |= (0x1 << 8)) //LED3 off #define LED3_OFF (virt_gpioe->ODR & amp;= (~(0x1 << 8))) //LED4 is on #define LED4_ON (virt_gpioz->ODR |= (0x1 << 5)) //LED4 off #define LED4_OFF (virt_gpioz->ODR & amp;= (~(0x1 << 5))) //LED5 is on #define LED5_ON (virt_gpioz->ODR |= (0x1 << 6)) //LED5 off #define LED5_OFF (virt_gpioz->ODR & amp;= (~(0x1 << 6))) //LED6 is on #define LED6_ON (virt_gpioz->ODR |= (0x1 << 7)) //LED6 off #define LED6_OFF (virt_gpioz->ODR & amp;= (~(0x1 << 7))) enum { LED1, LED2, LED3, LED4, LED5, LED6, }; #endif
source file
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/slab.h> #include "mycdev.h" struct cdev* cdev; dev_t devno; #if 0 unsigned int major = 0; #else unsigned int major = 500; #endif unsigned int minor = 0; struct class* cls; struct device* dev; int mycdev_open(struct inode* inode, struct file* file) { printk("%s:%s:%d\\ ",__FILE__,__func__,__LINE__); return 0; } ssize_t mycdev_read(struct file* file, char* ubuf, size_t size, loff_t *off) { printk("%s:%s:%d\\ ",__FILE__,__func__,__LINE__); return 0; } ssize_t mycdev_write(struct file* file, const char* ubuf, size_t size, loff_t *off) { printk("%s:%s:%d\\ ",__FILE__,__func__,__LINE__); return 0; } int mycdev_close(struct inode* inode, struct file* file) { printk("%s:%s:%d\\ ",__FILE__,__func__,__LINE__); return 0; } long mycdev_ioctl(struct file* file, unsigned int cmd, unsigned long args) { //1. Judgment cmd switch(cmd) //2. Determine which light to operate and flip copy_from_user int whitch; int ret; switch(cmd) { //LED lights up case LED_ON: ret = copy_from_user( & amp;whitch,(void*)args,sizeof(int)); if(ret) { printk("copy_from_user failed\\ "); return -EIO; } switch (whitch) { case LED1: LED1_ON; break; case LED2: LED2_ON; break; case LED3: LED3_ON; break; case LED4: LED4_ON; break; case LED5: LED5_ON; break; case LED6: LED6_ON; break; } break; // LED off case LED_OFF: ret = copy_from_user( & amp;whitch,(void*)args,sizeof(int)); if(ret) { printk("copy from user is error\\ "); return -EIO; } switch (whitch) { case LED1: LED1_OFF; break; case LED2: LED2_OFF; break; case LED3: LED3_OFF; break; case LED4: LED4_OFF; break; case LED5: LED5_OFF; break; case LED6: LED6_OFF; break; } break; //LED flip case LED_TOGGLE: ret = copy_from_user( & amp;whitch,(void*)args,sizeof(int)); if(ret) { printk("copy from user is error\\ "); return -EIO; } switch (whitch) { case LED1: LED1_TOGGLE; break; case LED2: LED2_TOGGLE; break; case LED3: LED3_TOGGLE; break; case LED4: LED4_TOGGLE; break; case LED5: LED5_TOGGLE; break; case LED6: LED6_TOGGLE; break; } } return 0; } const struct file_operations fops = { .unlocked_ioctl = mycdev_ioctl, .open = mycdev_open, .read = mycdev_read, .write = mycdev_write, .release = mycdev_close, }; static int __init mycdev_init(void) { int ret, i; //Map physical address to virtual address AHB4_virt_rcc = ioremap(PHY_RCC_AHB4,4); if(NULL == AHB4_virt_rcc) { printk("rcc ioremap is failed\\ "); return -ENOMEM; } AHB5_virt_rcc = ioremap(PHY_RCC_AHB5,4); if(NULL == AHB5_virt_rcc) { printk("rcc ioremap is failed\\ "); return -ENOMEM; } virt_gpioe = ioremap(PHY_GPIOE_ADDR, sizeof(gpio_t)); { if(NULL == virt_gpioe) { printk("gpioe ioremap is failed\\ "); return -ENOMEM; } } virt_gpiof = ioremap(PHY_GPIOF_ADDR, sizeof(gpio_t)); { if(NULL == virt_gpiof) { printk("gpioe ioremap is failed\\ "); return -ENOMEM; } } virt_gpioz = ioremap(PHY_GPIOZ_ADDR, sizeof(gpio_t)); { if(NULL == virt_gpioz) { printk("gpioz ioremap is failed\\ "); return -ENOMEM; } } //RCC enable GPIO E F Z *AHB4_virt_rcc |= (0x3 << 4); *AHB5_virt_rcc |= (0x1); //LED1 PE10 virt_gpioe->MODER &= (~(0x3 << 20)); virt_gpioe->MODER |= (0x1 << 20); virt_gpioe->ODR &= (~(0x1 << 10)); //LED2 PF10 virt_gpiof->MODER & amp;= (~(0x3 << 20)); virt_gpiof->MODER |= (0x1 << 20); virt_gpiof->ODR &= (~(0x1 << 10)); //LED3 PE8 virt_gpioe->MODER &= (~(0x3 << 16)); virt_gpioe->MODER |= (0x1 << 16); virt_gpioe->ODR & amp;= (~(0x1 << 8)); // //LED4 PZ5 virt_gpioz->MODER &= (~(0x3 << 10)); virt_gpioz->MODER |= (0x1 << 10); virt_gpioz->ODR &= (~(0x1 << 5)); //LED5 PZ6 virt_gpioz->MODER &= (~(0x3 << 12)); virt_gpioz->MODER |= (0x1 << 12); virt_gpioz->ODR &= (~(0x1 << 6)); //LED6 PZ7 virt_gpioz->MODER &= (~(0x3 << 14)); virt_gpioz->MODER |= (0x1 << 14); virt_gpioz->ODR &= (~(0x1 << 7)); /* 1. Assign object 2. Object initialization 3. Application for equipment resources (equipment number) 4. Register 5. Submit directory up 6. Submit the device node information upward */ //1. Assign object cdev = cdev_alloc(); if(NULL == cdev) { printk("Failed to allocate object space\\ "); ret=-ENOMEM; goto ERR1; } printk("Successful allocation of object space\\ "); //2. Initialize the driver object cdev_init(cdev, &fops); //3. Application for device resources (device number) if(0 == major) { ret = alloc_chrdev_region( & devno,minor,3,"mycdev"); if(ret) { printk("Dynamic application for device number failed\\ "); goto ERR2; } major = MAJOR(devno); minor = MINOR(devno); } else if(major > 0) { ret = register_chrdev_region(MKDEV(major,minor),3,"mycdev"); if(ret) { printk("Static application device number failed\\ "); goto ERR2; } } //4. Register object ret = cdev_add(cdev,MKDEV(major,minor),3); if(ret) { printk("Failed to register the driver object into the kernel\\ "); goto ERR3; } printk("The driver object is successfully registered into the kernel\\ "); //5. Submit directory up cls = class_create(THIS_MODULE,"mycdev"); if(IS_ERR(cls)) { printk("Failed to submit directory up\\ "); goto ERR4; } printk("submit directory successfully\\ "); //6. Submit device node information upward for(i=0;i<3;i ++ ) { dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i); if(IS_ERR(dev)) { printk("Upward submission of node information failed\\ "); goto ERR5; } printk("Upward submission of node information successfully\\ "); } printk("Submit the device node up successfully\\ "); printk("major = %d\\ ",major); return 0; //Release resources according to ERR level ERR5: for(--i;i>=0;i--) { device_destroy(cls,MKDEV(major,i)); } class_destroy(cls); ERR4: cdev_del(cdev); ERR3: unregister_chrdev_region(MKDEV(major,minor),3); ERR2: kfree(cdev); ERR1: return ret; } static void __exit mycdev_exit(void) { /* 1. Destroy the device node 2. Destroy the directory 3. Unregister the drive object 4. Release device resources (device number) 5. Release object space 6. Unmap */ //1. Destroy the device node int i; for(i=0;i<3;i ++ ) { device_destroy(cls,MKDEV(major,i)); } //2. Destroy the directory class_destroy(cls); //3. Unregister the driver object cdev_del(cdev); //4. Release device resources (device number) unregister_chrdev_region(MKDEV(major,minor),3); //5. Release object space kfree(cdev); //6. Unmap iounmap(AHB4_virt_rcc); iounmap(AHB5_virt_rcc); iounmap(virt_gpioe); iounmap(virt_gpiof); iounmap(virt_gpioz); } module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL");
Test file
#include <sys/ioctl.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdlib.h> #define LED_ON _IOW('a',1,int) #define LED_OFF _IOW('a',0,int) #define LED_TOGGLE _IOW('a',2,int) enum { LED1, LED2, LED3, LED4, LED5, LED6, }; void menu_set(); void menu_toggle(); void ioctl_cmd_set(int,int); void ioctl_cmd_toggle(int,int); int main(int argc, const char * argv[]) { char buf[128] = {0}; int cmd; int fd = -1; fd = open("/dev/mycdev0",O_RDWR); if(fd == -1) { perror("open is error\\ "); return -1; } int whitch; while (1) { //menu_set(); menu_toggle(); //Print command list fgets(buf, sizeof(buf), stdin); cmd = atoi(buf); printf("cmd = %d\\ ",cmd); //ioctl_cmd_set(fd,cmd); ioctl_cmd_toggle(fd,cmd); //Send toggle command system("clear"); } close(fd); return 0; } void menu_set() { printf("Command 1: **********LED1 is on*********\\ "); printf("Command 2: **********LED1 off**********\\ "); printf("Command 3: **********LED2 is on**********\\ "); printf("Command 4: **********LED2 off********\\ "); printf("Command 5: **********LED3 is on**********\\ "); printf("Command 6: **********LED3 off**********\\ "); printf("Command 7: **********LED4 lights up**********\\ "); printf("Command 8: **********LED4 off********\\ "); printf("Command 9: **********LED5 is on********\\ "); printf("Command 10: **********LED5 off**********\\ "); printf("Command 11: **********LED6 lights up**********\\ "); printf("Command 12: **********LED6 off**********\\ "); printf("Please enter the command >>>>>>>"); } void menu_toggle() { printf("Command 1: **********LED1 Flip********\\ "); printf("Command 2: **********LED2 Flip********\\ "); printf("Command 3: **********LED3 rollover********\\ "); printf("Command 4:********LED4 Flip********\\ "); printf("Command 5:********LED5 Flip********\\ "); printf("Command 6: **********LED6 Flip********\\ "); printf("Please enter the command >>>>>>>"); } void ioctl_cmd_toggle(int fd, int cmd) { int whitch; switch (cmd) { case 1: whitch = LED1; ioctl(fd, LED_TOGGLE, &whitch); break; case 2: whitch = LED2; ioctl(fd, LED_TOGGLE, &whitch); break; case 3: whitch = LED3; ioctl(fd, LED_TOGGLE, &whitch); break; case 4: whitch = LED4; ioctl(fd, LED_TOGGLE, &whitch); break; case 5: whitch = LED5; ioctl(fd, LED_TOGGLE, &whitch); break; case 6: whitch = LED6; ioctl(fd, LED_TOGGLE, &whitch); break; } } void ioctl_cmd_set(int fd, int cmd) { int whitch; switch(cmd) { case 1: whitch = LED1; ioctl(fd, LED_ON, &whitch); break; case 3: whitch = LED2; ioctl(fd, LED_ON, &whitch); break; case 5: whitch = LED3; ioctl(fd, LED_ON, &whitch); break; case 7: whitch = LED4; ioctl(fd, LED_ON, &whitch); break; case 9: whitch = LED5; ioctl(fd, LED_ON, &whitch); break; case 11: whitch = LED6; ioctl(fd, LED_ON, &whitch); break; case 2: whitch = LED1; ioctl(fd, LED_OFF, &whitch); break; case 4: whitch = LED2; ioctl(fd, LED_OFF, &whitch); break; case 6: whitch = LED3; ioctl(fd, LED_OFF, &whitch); break; case 8: whitch = LED4; ioctl(fd, LED_OFF, &whitch); break; case 10: whitch = LED5; ioctl(fd, LED_OFF, &whitch); break; case 12: whitch = LED6; ioctl(fd, LED_OFF, &whitch); break; } }
Code implementation: