在串口工具进行输入:
echo 1 > /dev/myled0 ---->led1灯点亮
echo 0 > /dev/myled0 ---->led1灯熄灭
echo 1 > /dev/myled1 ---->led2灯点亮
echo 0 > /dev/myled1 ---->led2灯熄灭
echo 1 > /dev/myled2 ---->led3灯点亮
echo 0 > /dev/myled2 ---->led3灯熄灭
要求:
1)分部实现注册字符设备驱动
2)自动创建设备节点
3)通过结构体对led灯地址进行映射
4)次设备号完成私有数据传参
- #ifndef __LED_H__
- #define __LED_H__
- #define CNAME "myled"
- typedef struct
- {
- volatile unsigned int MODER;
- volatile unsigned int OTYPER;
- volatile unsigned int OSPEEDR;
- volatile unsigned int PUPDR;
- volatile unsigned int IDR;
- volatile unsigned int ODR;
- }gpio_t;
- #define GPIOE (0x50006000)
- #define GPIOF (0x50007000)
- #define RCC (0x50000A28)
-
- #endif
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/cdev.h>
- #include <linux/fs.h>
- #include <linux/device.h>
- #include <linux/slab.h>
- #include <linux/uaccess.h>
- #include <linux/io.h>
- #include "led.h"
-
- struct cdev *cdev;
- struct class *cls;
- struct device *dev;
- #if 1
- unsigned int major=0;
- #else
- unsigned int major=500;
- #endif
- int minor = 0;
- const int count = 3;
- volatile unsigned int* vir_rcc;
- volatile gpio_t* vir_gpioe;
- volatile gpio_t* vir_gpiof;
-
- int mycdev_open(struct inode *inode,struct file *file)
- {
- file->private_data = (void*)(MINOR(inode->i_rdev));
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- ssize_t mycdev_read(struct file *file,char __user *ubuf,size_t size,loff_t *loffs)
- {
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- ssize_t mycdev_write(struct file *file,const char __user *ubuf,size_t size,loff_t *loffs)
- {
- char kbuf;
- int ret;
- int a;
- a = (int)file->private_data;
-
- ret = copy_from_user(&kbuf,ubuf,sizeof(char));
- if(ret)
- {
- printk("copy from user is error...\n");
- return -EIO;
- }
- if(kbuf=='1')
- {
- switch (a)
- {
- case 0:
- vir_gpioe->ODR |= (0x1<<10);
- break;
- case 1:
- vir_gpiof->ODR |= (0x1<<10);
- break;
- case 2:
- vir_gpioe->ODR |= (0x1<<8);
- break;
- default:
- break;
- }
- }
- else
- {
- switch (a)
- {
- case 0:
- vir_gpioe->ODR &= (~(0x1<<10));
- break;
- case 1:
- vir_gpiof->ODR &= (~(0x1<<10));
- break;
- case 2:
- vir_gpioe->ODR &= (~(0x1<<8));
- break;
- default:
- break;
- }
- }
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
-
- return 0;
- }
- int mycdev_close(struct inode *inode,struct file *file)
- {
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- const struct file_operations fops = {
- .open=mycdev_open,
- .write=mycdev_write,
- .read=mycdev_read,
- .release=mycdev_close,
- };
- static int __init mycdev_init(void)
- {
- int i;
- int ret;
- dev_t devt;
- //分步实现字符设备驱动
- cdev = cdev_alloc();
- if(NULL==cdev)
- {
- printk("cdev alloc is error...\n");
- goto ERR1;
- }
- cdev_init(cdev,&fops);
- if(major>0)
- {
- ret = register_chrdev_region(MKDEV(major,minor),count,CNAME);
- if(ret)
- {
- printk("register chrdev region is error...\n");
- goto ERR2;
- }
- }
- else
- {
- ret = alloc_chrdev_region(&devt,0,count,CNAME);
- if(ret)
- {
- printk("alloc chrdev region is error\n");
- goto ERR2;
- }
- major=MAJOR(devt);
- minor=MINOR(devt);
- }
- ret = cdev_add(cdev,MKDEV(major,minor),count);
- if(ret)
- {
- printk("cdev add is error...\n");
- goto ERR3;
- }
- //自动创建设备节点
- cls = class_create(THIS_MODULE,CNAME);
- if(IS_ERR(cls))
- {
- printk("class create is error...\n");
- ret = PTR_ERR(cls);
- goto ERR4;
- }
- for(i=0;i<count;i++)
- {
- dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
- if(IS_ERR(dev))
- {
- printk("device create is error...\n");
- goto ERR5;
- }
- }
- //对LED灯地址进行映射
- vir_rcc = ioremap(RCC,4);
- if(NULL==vir_rcc)
- {
- printk("rcc ioremap is error\n");
- return -ENOMEM;
- }
- vir_gpioe = ioremap(GPIOE,sizeof(GPIOE));
- if(NULL==vir_gpioe)
- {
- printk("gpioe ioremap is error\n");
- return -ENOMEM;
- }
- vir_gpiof = ioremap(GPIOF,sizeof(GPIOF));
- if(NULL==vir_gpiof)
- {
- printk("gpiof ioremap is error\n");
- return -ENOMEM;
- }
- *vir_rcc |= (0x3<<4);
- vir_gpioe->MODER &= (~(0x3<<20));
- vir_gpioe->MODER |= (0x1<<20);
- vir_gpiof->MODER &= (~(0x3<<20));
- vir_gpiof->MODER |= (0x1<<20);
- vir_gpioe->MODER &= (~(0x3<<16));
- vir_gpioe->MODER |= (0x1<<16);
- return 0;
-
- 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),count);
- ERR2:
- kfree(cdev);
- ERR1:
- return -EIO;
- }
- static void __exit mycdev_exit(void)
- {
- int i;
- for(i=0;i<count;i++)
- {
- device_destroy(cls,MKDEV(major,i));
- }
- class_destroy(cls);
- cdev_del(cdev);
- unregister_chrdev_region(MKDEV(major,minor),count);
- kfree(cdev);
- //取消映射
- iounmap(vir_rcc);
- iounmap(vir_gpioe);
- iounmap(vir_gpiof);
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- MODULE_LICENSE("GPL");
现象:

