head.h
#ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{ unsigned int MODER; unsigned int OTYPER; unsigned int OSPEEDR; unsigned int PUPDR; unsigned int IDR; unsigned int ODR; }gpio_t; #define GPIOE 0x50006000 #define GPIOF 0x50007000 #define GPIOB 0x50003000 #define RCC 0X50000A28 #define LED_ON_IOW('l',1,int) #define LED_OFF _IOW('l',0,int) #endif
test.c
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include "head.h" int main(int argc, char const *argv[]) { int a, s; char buf[128] = {0}; int fd1,fd2,fd; while (1) { printf("Please input operating device 0(led1) 1(led2) 2(led3)\ "); scanf("%d", &s); printf("execute function>"); printf("0(closed) 1(opened)\ "); printf("Please input>"); scanf("%d", &a); switch (s) { case 0: fd = open("/dev/myled0", O_RDWR); if (0 == a) ioctl(fd, LED_OFF, s); else if (1 == a) ioctl(fd, LED_ON, s); break; case 1: fd1 = open("/dev/myled1", O_RDWR); if (0 == a) ioctl(fd, LED_OFF, s); else if (1 == a) ioctl(fd, LED_ON, s); break; case 2: fd2 = open("/dev/myled2", O_RDWR); if (0 == a) ioctl(fd, LED_OFF, s); else if (1 == a) ioctl(fd, LED_ON, s); break; default: printf("Input error, re-enter\ "); break; } if (!(0 == s || 1 == s || 2 == s)) { continue; } if (fd < 0 || fd1 < 0 || fd2 < 0) { printf("Failed to open device file\ "); exit(-1); } } close(fd); close(fd1); close(fd2); return 0; }
mychrdev_led.c
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/cdev.h> #include "head.h" char kbuf[128] = {0}; gpio_t *vir_led1; gpio_t *vir_led2; gpio_t *vir_led3; unsigned int *vir_rcc; struct class *cls; struct device *dev; struct cdev* cdev; dev_t devno; unsigned int minor = 0; unsigned int major; int mycdev_open(struct inode *inode, struct file *file) { int a=inode->i_rdev;//Get the device number corresponding to the current device file file->private_data=(void *)MINOR(a);//Save the minor device number to the file structure of the current file 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 arg) { switch(cmd) { case LED_ON: switch(arg) { case 1: vir_led1->ODR|=(0x1 << 10); break; case 2: vir_led2->ODR|=(0x1 << 10); break; case 3: vir_led3->ODR|=(0x1 << 8); break; } break; case LED_OFF: switch(arg) { case 1: vir_led1->ODR|=(~(0x1 << 10)); break; case 2: vir_led2->ODR|=(~(0x1 << 10)); break; case 3: vir_led3->ODR|=(~(0x1 << 8)); break; } break; } return 0; } // Define the operation method structure variable and assign it struct file_operations fops = { .open = mycdev_open, .unlocked_ioctl=mycdev_ioctl, .release = mycdev_close, }; int led_init(void) { // Mapping of register addresses vir_led1 = ioremap(GPIOE, sizeof(gpio_t)); if (vir_led1 == NULL) { printk("ioremap filed:%d\ ", __LINE__); return -ENOMEM; } vir_led2 = ioremap(GPIOF, sizeof(gpio_t)); if (vir_led2 == NULL) { printk("ioremap filed:%d\ ", __LINE__); return -ENOMEM; } vir_led3 = ioremap(GPIOE, sizeof(gpio_t)); if (vir_led3 == NULL) { printk("ioremap filed:%d\ ", __LINE__); return -ENOMEM; } vir_rcc = ioremap(RCC, 4); if (vir_rcc == NULL) { printk("ioremap filed:%d\ ", __LINE__); return -ENOMEM; } printk("Physical address mapping successful\ "); // register initialization // rcc (*vir_rcc) |= (0x3 << 4); // led vir_led1->MODER & amp;= (~(0x3 << 20)); vir_led1->MODER |= (0x1 << 20); vir_led1->ODR &= (~(0x1 << 10)); vir_led2->MODER & amp;= (~(0x3 << 20)); vir_led2->MODER |= (0x1 << 20); vir_led2->ODR & amp;= (~(0x1 << 10)); vir_led3->MODER & amp;= (~(0x3 << 16)); vir_led3->MODER |= (0x1 << 16); vir_led3->ODR & amp;= (~(0x1 << 8)); printk("Register initialized successfully\ "); return 0; } static int __init mycdev_init(void) { int i; //1. Apply for object space cdev_alloc int ret; cdev = cdev_alloc(); if(NULL == cdev) { printk("Drive space application failed\ "); ret = -EFAULT; goto OUT1; } printk("Successful drive space application\ "); //2. Initialize the object cdev_init cdev_init(cdev, &fops); //3. Apply for device number register_chrdev_region()/alloc_chrdev_region() if(0 == major) { ret = alloc_chrdev_region( & devno,minor,3,"myled"); if(ret) { printk("Dynamic application for device number failed\ "); goto OUT2; } major = MAJOR(devno); minor = MINOR(devno); } else { ret = register_chrdev_region(MKDEV(major,minor),3,"myled"); if(ret) { printk("Static application device number failed\ "); goto OUT2; } } printk("Apply for device number successfully\ "); //4. Register the driver object cdev_add() ret=cdev_add(cdev,MKDEV(major,minor),3); if(ret) { printk("Failed to register device driver object\ "); goto OUT3; } printk("Device driver object registered successfully\ "); // Submit directory up cls = class_create(THIS_MODULE, "myled"); if (IS_ERR(cls)) { printk("Failed to submit directory up\ "); ret = -PTR_ERR(cls); goto OUT4; } printk("submit directory information successfully\ "); // Submit device node information upward for(i=0;i<3;i ++ ) { dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i); if (IS_ERR(dev)) { printk("Failed to submit device node information up\ "); ret = -PTR_ERR(dev); goto OUT5; } } printk("submit the device node up successfully\ "); // register map and initialization led_init(); return 0; OUT5: for (--i;i>=0;i--) { device_destroy(cls,MKDEV(major,i)); } class_destroy(cls); OUT4: cdev_del(cdev); OUT3: unregister_chrdev_region(MKDEV(major,minor),3); OUT2: kfree(cdev); OUT1: return ret; } static void __exit mycdev_exit(void) { // Cancel address mapping iounmap(vir_led1); iounmap(vir_led2); iounmap(vir_led3); iounmap(vir_rcc); //Destroy node information int i; for (i=0;i<3;i + + ) { device_destroy(cls,MKDEV(major,i)); } //Destroy directory information class_destroy(cls); // Unregister the driver object cdev_del(cdev); //Release the device number unregister_chrdev_region(MKDEV(major,minor),3); // release object space kfree(cdev); } module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL");