1.应用层代码控制规则
#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 select = 0;
char buf[128] = {0};
int fd;
int key = -1;
while (1)
{
printf("选择你要操作的硬件:1<指示灯>,2<蜂鸣器>,3<马达>,4<风扇>");
scanf("%d", &select);
if (select == 1)
{
// 打开LED灯的设备文件
fd = open("/dev/mychrdev", O_RDWR);
if (fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
// 控制灯的熄灭
// 控制哪个灯
int LED = -1;
/***LED的控制***/
printf("选择要实现的功能:1<亮灯>,0<熄灯>");
scanf("%d", &key);
// 亮灯
if (key == 1)
{
printf("选择要点亮哪个灯:1<LED1>,2<LED2>,3<LED3>");
scanf("%d", &LED);
ioctl(fd, LED_ON, &LED);
}
// 熄灯
else if (key == 0)
{
printf("选择要熄灭哪个灯:1<LED1>,2<LED2>,3<LED3>");
scanf("%d", &LED);
ioctl(fd, LED_OFF, &LED);
}
}
else if (select == 2)
{
// 打开蜂鸣器的设备文件
fd = open("/dev/fengming", O_RDWR);
if (fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
printf("蜂鸣器操作:1<响动>,2<安静>");
scanf("%d", &key);
if (key == 1)
{
ioctl(fd, FENGMING_ON);
}
else if (key == 0)
{
ioctl(fd, FENGMING_OFF);
}
}
else if (select == 3)
{
fd=-1;
// 打开mada的设备文件
fd = open("/dev/mada", O_RDWR);
if (fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
printf("mada操作:1<响动>,2<安静>");
scanf("%d", &key);
if (key == 1)
{
ioctl(fd, MADA_ON);
}
else if (key == 0)
{
ioctl(fd, MADA_OFF);
}
}
else if (select == 4)
{
fd=-1;
// 打开风扇的设备文件
fd = open("/dev/fengshan", O_RDWR);
if (fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
printf("风扇操作:1<响动>,2<安静>");
scanf("%d", &key);
if (key == 1)
{
ioctl(fd, FENGSHAN_ON);
}
else if (key == 0)
{
ioctl(fd, FENGSHAN_OFF);
}
}
}
close(fd);
return 0;
}
2.head 头文件的封装
#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 PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR 0X50000A28
#define PHY_FENGMING 0x50003000
#define PHY_FENGSHAN 0x50006000
#define PHY_MADA 0x50007000
//定义功能码
#define LED_ON _IOW('l',1,int)//开灯
#define LED_OFF _IOW('l',0,int)//关灯
#define FENGMING_ON _IO('a',1)//蜂鸣器输入高电频
#define FENGMING_OFF _IO('a',0)//蜂鸣器输入低电频
#define MADA_ON _IO('b',1)//马达输入高电频
#define MADA_OFF _IO('b',0)//马达输入低电频
#define FENGSHAN_ON _IO('c',1)//风扇输入高电频
#define FENGSHAN_OFF _IO('c',0)//风扇输入低电频
#endif
3.驱动代码执行运行逻辑
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
//判断哪个硬件
char sum;
int major;
int major_fm;
int major_md;
int major_fs;
char kbuf[128] = {0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
gpio_t *vir_fengming;
gpio_t *vir_mada;
gpio_t *vir_fengshan;
unsigned int *vir_rcc;
struct class *cls;
struct class *cls_fm;
struct class *cls_md;
struct class *cls_fs;
struct device *dev;
int mycdev_open(struct inode *inode, struct file *file)
{
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)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
unsigned long ret;
// 向用户空间读取拷贝
if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
unsigned long ret;
// 从用户空间读取数据
if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size = sizeof(kbuf);
ret = copy_from_user(&sum, ubuf, size);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret, select;
// LED指示灯
if (cmd == LED_ON || cmd == LED_OFF)
{
ret = copy_from_user(&select, (void *)arg, sizeof(int));
if (ret)
{
printk("copy_form_user_led flied\n");
return -EIO;
}
switch (cmd)
{
case LED_ON:
switch (select)
{
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 (select)
{
case 1:
vir_led1->ODR &= (~(0x1 << 10));
break;
case 2:
vir_led2->ODR &= (~(0x1 << 10));
break;
case 3:
vir_led3->ODR &= (~(0x1 << 8));
break;
}
}
}
//蜂鸣器控制
else if(cmd==FENGMING_ON||cmd==FENGMING_OFF)
{
printk("蜂鸣器\n");
if(cmd==FENGMING_ON)
{
vir_fengming->ODR|= (1<<6);
}
else if(cmd==FENGMING_OFF)
{
vir_fengming->ODR &= (~(1<<6));
}
}
//马达的控制
else if(cmd==MADA_ON||cmd==MADA_OFF)
{ printk("马达\n");
if(cmd==MADA_ON)
{
vir_mada->ODR |=(1<<6);
}
else if(cmd==MADA_OFF)
{
vir_mada->ODR &= (~(1<<6));
}
}
//风扇的控制
else if(cmd==FENGSHAN_ON||cmd==FENGSHAN_OFF)
{
printk("风扇\n");
if(cmd==FENGSHAN_ON)
{
vir_fengshan->ODR |=(1<<9);
printk("风扇启动\n");
}
else if(cmd==FENGSHAN_OFF)
{
vir_fengshan->ODR &= (~(1<<9));
}
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
int all_led_init(void)
{
// 寄存器地址的映射
vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
if (vir_led1 == NULL)
{
printk("ioremap filed:%d\n", __LINE__);
return -ENOMEM;
}
vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
if (vir_led2 == NULL)
{
printk("ioremap filed:%d\n", __LINE__);
return -ENOMEM;
}
vir_led3 = vir_led1;
vir_rcc = ioremap(PHY_RCC_ADDR, 4);
if (vir_rcc == NULL)
{
printk("ioremap filed:%d\n", __LINE__);
return -ENOMEM;
}
/*风扇马达蜂鸣器*/
vir_fengshan=vir_led1;
vir_mada=vir_led2;
vir_fengming=ioremap(PHY_FENGMING,sizeof(gpio_t));
printk("物理地址映射成功\n");
// 寄存器的初始化
// rcc
(*vir_rcc) |= (3 << 4);
(*vir_rcc) |= (1<<1);
// led1
vir_led1->MODER &= (~(3 << 20));
vir_led1->MODER |= (1 << 20);
vir_led1->ODR &= (~(1 << 10));
// led2
vir_led2->MODER &= (~(3 << 20));
vir_led2->MODER |= (1 << 20);
vir_led2->ODR &= (~(1 << 10));
// led3
vir_led3->MODER &= (~(3 << 16));
vir_led1->MODER |= (1 << 16);
vir_led1->ODR &= (~(1 << 8));
//蜂鸣器
vir_fengming->MODER &= (~(3<<12));
vir_fengming->MODER |= (1<<12);
vir_fengming->ODR &=(~(1<<6));
//马达
vir_mada->MODER &=(~(3<<12));
vir_mada->MODER |=(1<<12);
vir_mada->ODR &=(~(1<<6));
//风扇
vir_fengshan->MODER &= (~(3<<18));
vir_fengshan->MODER |= (1<<18);
vir_fengshan->ODR &= (~(1<<9));
printk("寄存器初始化成功\n");
return 0;
}
// 定义操作方法结构体变量并赋值
struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
.unlocked_ioctl = mycdev_ioctl,
};
static int __init mycdev_init(void)
{
/****LED灯驱动***/
// 字符设备驱动注册
printk("LED灯驱动安装\n");
major = register_chrdev(0, "mychrdev", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功:major=%d\n", major);
// 向上提交目录
cls = class_create(THIS_MODULE, "mychrdev");
if (IS_ERR(cls))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls);
}
printk("向上提交目录成功\n");
// 向上提交设备信息
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mychrdev");
if (IS_ERR(dev))
{
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
/****蜂鸣器驱动***/
// 蜂鸣器驱动注册
printk("蜂鸣器驱动安装\n");
major_fm = register_chrdev(0, "fengming", &fops);
if (major_fm < 0)
{
printk("字符设备驱动注册失败\n");
return major_fm;
}
printk("字符设备驱动注册成功:major_fm=%d\n", major_fm);
// 向上提交目录
cls_fm = class_create(THIS_MODULE, "fengming");
if (IS_ERR(cls_fm))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls_fm);
}
printk("向上提交目录成功\n");
// 向上提交设备信息
dev = device_create(cls_fm, NULL, MKDEV(major_fm, 0), NULL, "fengming");
if (IS_ERR(dev))
{
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
/****马达驱动***/
// 马达驱动注册
printk("马达驱动安装\n");
major_md = register_chrdev(0, "mada", &fops);
if (major_md < 0)
{
printk("字符设备驱动注册失败\n");
return major_md;
}
printk("字符设备驱动注册成功:major_md=%d\n", major_md);
// 向上提交目录
cls_md = class_create(THIS_MODULE, "mada");
if (IS_ERR(cls_md))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls_md);
}
printk("向上提交目录成功\n");
// 向上提交设备信息
dev = device_create(cls_md, NULL, MKDEV(major_md, 0), NULL, "mada");
if (IS_ERR(dev))
{
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
/****风扇驱动驱动***/
// 字符设备驱动注册
printk("风扇驱动安装\n");
major_fs = register_chrdev(0, "fengshan", &fops);
if (major_fs < 0)
{
printk("字符设备驱动注册失败\n");
return major_fs;
}
printk("字符设备驱动注册成功:major_fs=%d\n", major_fs);
// 向上提交目录
cls_fs = class_create(THIS_MODULE, "fengshan");
if (IS_ERR(cls_fs))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls_fs);
}
printk("向上提交目录成功\n");
// 向上提交设备信息
dev = device_create(cls_fs, NULL, MKDEV(major_fs, 0), NULL, "fengshan");
if (IS_ERR(dev))
{
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
all_led_init();
return 0;
}
static void __exit mycdev_exit(void)
{
// 取消地址映射
iounmap(vir_led1);
iounmap(vir_led2);
iounmap(vir_rcc);
iounmap(vir_fengming);
// 销毁设备信息
device_destroy(cls, MKDEV(major, 0));
device_destroy(cls_fm, MKDEV(major_fm, 0));
device_destroy(cls_fs, MKDEV(major_fs, 0));
device_destroy(cls_md, MKDEV(major_md, 0));
// 销毁目录
class_destroy(cls);
class_destroy(cls_fm);
class_destroy(cls_md);
class_destroy(cls_fs);
// 注销字符设备驱动
unregister_chrdev(major, "mychrdev");
unregister_chrdev(major_fm, "fengming");
unregister_chrdev(major_md, "mada");
unregister_chrdev(major_fs, "fengshan");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");