头文件
#ifndef __LED_H__
#define __LED_H__#define PHY_LED1_MODER 0X50006000
#define PHY_LED1_ODR 0X50006014
#define PHY_LED1_RCC 0X50000A28#define PHY_LED2_MODER 0X50007000
#define PHY_LED2_ODR 0X50007014
#define PHY_LED2_RCC 0X50000A28#define PHY_LED3_MODER 0X50006000
#define PHY_LED3_ODR 0X50006014
#define PHY_LED3_RCC 0X50000A28
//风扇
#define PHY_FAN_MODER 0X50006000
#define PHY_FAN_ODR 0X50006014
#define PHY_FAN_RCC 0X50000A28
//蜂鸣器
#define PHY_BUZZER_MODER 0X50003000
#define PHY_BUZZER_ODR 0X50003014
#define PHY_BUZZER_RCC 0X50000A28
//马达
#define PHY_MOTOR_MODER 0X50007000
#define PHY_MOTOR_ODR 0X50007014
#define PHY_MOTOR_RCC 0X50000A28
//功能码
#define LED_ON _IO('l',1)
#define LED_OFF _IO('l',0)
#define FAN_ON _IO('f',1)
#define FAN_OFF _IO('f',0)
#define BUZZER_ON _IO('b',1)
#define BUZZER_OFF _IO('b',0)
#define MOTOR_ON _IO('m',1)
#define MOTOR_OFF _IO('m',0)
#endif
驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include "head.h"
unsigned int *vir_led1_moder;
unsigned int *vir_led1_odr;
unsigned int *vir_led1_rcc;
unsigned int *vir_led2_moder;
unsigned int *vir_led2_odr;
unsigned int *vir_led2_rcc;
unsigned int *vir_led3_moder;
unsigned int *vir_led3_odr;
unsigned int *vir_led3_rcc;
struct cdev* cdev;
struct class* cls;
struct device* dev;
unsigned int major = 500;
unsigned int minor = 0;
dev_t devno;
char kbuf[128] = {0};// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{int a = inode->i_rdev;file->private_data = (void *)MINOR(a);printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{long ret;if(size>sizeof(kbuf)){size = sizeof(kbuf);}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);ret = copy_to_user(ubuf, kbuf, size);if (ret){printk("copy_to_user filed\n");return -EIO;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{if(size>sizeof(kbuf)){size = sizeof(kbuf);}long ret;printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);ret = copy_from_user(kbuf, ubuf, size);if (ret){printk("copy_from_user filed\n");return -EIO;}return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
long mychrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ unsigned int a;printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);a = (unsigned int)file->private_data;switch(a){case 0:if(cmd == LED_ON){*vir_led1_odr |= (0x1 << 10);}else{*vir_led1_odr &= (~(0x1 << 10));}break;case 1:if(cmd == LED_ON){*vir_led2_odr |= (0x1 << 10);}else{*vir_led2_odr &= (~(0x1 << 10));}break;case 2:if(cmd == LED_ON){*vir_led3_odr |= (0x1 << 8);}else{*vir_led3_odr &= (~(0x1 << 8));}break;}return 0;
}
//对设备文件进行操作的结构体
struct file_operations fops = {.open = mycdev_open,//打开.read = mycdev_read,//读.write = mycdev_write,//写.unlocked_ioctl = mychrdev_ioctl,//硬件功能的选择.release = mycdev_close,//关闭
};int led_init(void)
{vir_led1_moder = ioremap(PHY_LED1_MODER, 4);if (vir_led1_moder == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led1_odr = ioremap(PHY_LED1_ODR, 4);if (vir_led1_odr == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led1_rcc = ioremap(PHY_LED1_RCC, 4);if (vir_led1_rcc == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}(*vir_led1_rcc) |= (0x1 << 4);(*vir_led1_moder) &= (~(0x3 << 20));(*vir_led1_moder) |= (0x1 << 20);(*vir_led1_odr) &= (~(0x1 << 10));vir_led2_moder = ioremap(PHY_LED2_MODER, 4);if (vir_led2_moder == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led2_odr = ioremap(PHY_LED2_ODR, 4);if (vir_led2_odr == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led2_rcc = ioremap(PHY_LED2_RCC, 4);if (vir_led2_rcc == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}(*vir_led2_rcc) |= (0x1 << 5);(*vir_led2_moder) &= (~(0x3 << 20));(*vir_led2_moder) |= (0x1 << 20);(*vir_led2_odr) &= (~(0x1 << 10));vir_led3_moder = ioremap(PHY_LED3_MODER, 4);if (vir_led3_moder == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led3_odr = ioremap(PHY_LED3_ODR, 4);if (vir_led3_odr == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}vir_led3_rcc = ioremap(PHY_LED3_RCC, 4);if (vir_led3_rcc == NULL){printk("映射物理内存失败%d\n", __LINE__);return -EFAULT;}printk("映射物理内存成功\n");// 硬件寄存器的初始化(*vir_led3_rcc) |= (0x1 << 4);(*vir_led3_moder) &= (~(0x3 << 16));(*vir_led3_moder) |= (0x1 << 16);(*vir_led3_odr) &= (~(0x1 << 8));return 0;
}static int __init mycdev_init(void)
{//************分布注册驱动设备*********************int ret;//1、为驱动对象申请空间cdev = cdev_alloc();if(cdev == NULL){printk("申请空间失败\n");ret = -EFAULT;goto OUT1;}//2、对象的初始化cdev_init(cdev,&fops);//3、申请设备号if(major == 0)//动态{ret = alloc_chrdev_region(&devno,minor,3,"mychrdev");if(ret){printk("动态申请设备号失败\n");goto OUT2;}//统一后边的操作major = MAJOR(devno);//根据设备号获取主设备号minor = MINOR(devno);}else{ret = register_chrdev_region(MKDEV(major,minor),3,"mychrdev");if(ret){printk("静态申请设备号失败\n");goto OUT2;}}//4、注册驱动对象if(cdev_add(cdev,MKDEV(major,minor),3)){printk("注册驱动对象失败\n");goto OUT3;}//************自动申请设备节点*********************//1、向上提交目录cls = class_create(THIS_MODULE, "mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret = -PTR_ERR(cls);goto OUT4;}printk("向上提交目录成功\n");// 2、向上提交设备节点信息int i;for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mychrdev%d", i);if (IS_ERR(dev)){printk("提交设备信息失败\n");ret = -PTR_ERR(dev);goto OUT5;}}printk("提交设备信息成功\n");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)
{iounmap(vir_led1_moder);iounmap(vir_led1_odr);iounmap(vir_led1_rcc);iounmap(vir_led2_moder);iounmap(vir_led2_odr);iounmap(vir_led2_rcc);iounmap(vir_led3_moder);iounmap(vir_led3_odr);iounmap(vir_led3_rcc);printk("取消映射成功\n");//1.销毁设备信息int i;for(i=0;i<3;i++){device_destroy(cls,MKDEV(major,i));}//2.销毁目录信息class_destroy(cls);//3.注销驱动对象cdev_del(cdev);//4.释放设备号unregister_chrdev_region(MKDEV(major,minor),3);//5.释放对象空间kfree(cdev);
}
// 用于向内核报备当前内核模块入口函数的地址
module_init(mycdev_init);
// 用于向内核报备当前内核模块出口函数的地址
module_exit(mycdev_exit);
// 生命当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");
应用程序
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"
int main(int argc, char const *argv[])
{char buf[128] = {0};int led1_fd, led2_fd, led3_fd;// 打开led1设备文件led1_fd = open("/dev/mychrdev0", O_RDWR);if (led1_fd < 0){printf("打开led1设备文件失败\n");exit(-1);}// 打开led2设备文件led2_fd = open("/dev/mychrdev1", O_RDWR);if (led2_fd < 0){printf("打开led2设备文件失败\n");exit(-1);}// 打开led3设备文件led3_fd = open("/dev/mychrdev2", O_RDWR);if (led3_fd < 0){printf("打开myled3设备文件失败\n");exit(-1);}int a, b;while (1){printf("请选择要控制的器件: 1(led灯1) 2 (led灯2) 3 (led灯3) ");scanf("%d", &a);printf("请输入指令:0(关闭) 1 (打开)");scanf("%d", &b);switch (b){case 1:switch (a){case 1:ioctl(led1_fd, LED_ON);break;case 2:ioctl(led2_fd, LED_ON);break;case 3:ioctl(led3_fd, LED_ON);break;}break;case 0:switch (a){case 1:ioctl(led1_fd, LED_OFF);break;case 2:ioctl(led2_fd, LED_OFF);break;case 3:ioctl(led3_fd, LED_OFF);break;}break;}}close(led1_fd);close(led2_fd);close(led3_fd);return 0;
}