练习
1.编写LED灯的驱动,可以控制三个灯,应用程序中编写控制灯的逻辑,要使用自动创建设备节点机制
驱动头文件 ledHead.h
#ifndef __HEAD_H__
#define __HEAD_H__
#define PHY_GPIOE_MODER 0X50006000
#define PHY_GPIOE_ODR 0X50006014
#define PHY_RCC 0X50000A28
#define PHY_GPIOF_MODER 0X50007000
#define PHY_GPIOF_ODR 0X50007014
#endif
驱动demo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "ledHead.h"
int major;
char buf[128];
unsigned int *vir_gpioe_moder;
unsigned int *vir_gpioe_odr;
unsigned int *vir_gpiof_moder;
unsigned int *vir_gpiof_odr;
unsigned int *vir_rcc;
struct class *cls;
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) {
int ret = copy_to_user(ubuf, buf, size);
if (ret) {
printk("内核read失败: %d \n", ret);
}
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof) {
int ret = copy_from_user(buf, ubuf, size);
if (ret) {
printk("内核write失败: %d \n", ret);
return ret;
}
if (buf[0] == '1' && buf[1] == '1') {
//LED1开灯
(*vir_gpioe_odr) |= (0x1 << 10);
} else if (buf[0] == '1' && buf[1] == '0') {
//LED1关灯
(*vir_gpioe_odr) &= (~(0x1 << 10));
} else if (buf[0] == '2' && buf[1] == '1') {
//LED2开灯
(*vir_gpiof_odr) |= (0x1 << 10);
} else if (buf[0] == '2' && buf[1] == '0') {
//LED2关灯
(*vir_gpiof_odr) &= (~(0x1 << 10));
} else if (buf[0] == '3' && buf[1] == '1') {
//LED1开灯
(*vir_gpioe_odr) |= (0x1 << 8);
} else if (buf[0] == '3' && buf[1] == '0') {
//LED1关灯
(*vir_gpioe_odr) &= (~(0x1 << 8));
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file) {
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
};
static int __init mycdev_init(void) {
major = register_chrdev(0, "mychrdev", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功major=%d\n", major);
/**
* 向上提交目录信息
*/
cls = class_create(THIS_MODULE, "mycdev");
if (IS_ERR(cls)) {
printk("向上提交目标信息失败\n");
return -PTR_ERR(cls);
}
printk("向上提交目录信息成功\n");
//向上提交设备信息
int i;
for (i=0; i<3; i++) {
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
if (IS_ERR(dev)) {
printk("向上提交设备节点失败\n");
return -PTR_ERR(cls);
}
}
printk("向上提交设备节点信息成功\n");
/*
*完成硬件寄存器物理映射
*/
vir_gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
if (vir_gpioe_moder == NULL) {
printk("物理内存映射失败%d\n", __LINE__);
return -EFAULT;
}
vir_gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
if (vir_gpioe_odr == NULL) {
printk("物理内存映射失败%d\n", __LINE__);
return -EFAULT;
}
vir_gpiof_moder = ioremap(PHY_GPIOF_MODER, 4);
if (vir_gpiof_moder == NULL) {
printk("物理内存映射失败%d\n", __LINE__);
return -EFAULT;
}
vir_gpiof_odr = ioremap(PHY_GPIOF_ODR, 4);
if (vir_gpiof_odr == NULL) {
printk("物理内存映射失败%d\n", __LINE__);
return -EFAULT;
}
vir_rcc = ioremap(PHY_RCC, 4);
if (vir_rcc == NULL) {
printk("物理内存映射失败%d\n", __LINE__);
return -EFAULT;
}
printk("物理内存映射成功\n");
//硬件寄存器初始化
//设置LED1
(*vir_gpioe_moder) &= (~(0x3 << 20));
(*vir_gpioe_moder) |= (0x1 << 20);
//设置LED2
(*vir_gpiof_moder) &= (~(0x3 << 20));
(*vir_gpiof_moder) |= (0x1 << 20);
//设置LED3
(*vir_gpioe_moder) &= (~(0x3 << 16));
(*vir_gpioe_moder) |= (0x1 << 16);
//rcc使能
(*vir_rcc) |= (0x1 << 4);
(*vir_rcc) |= (0x1 << 5);
//默认关灯
//LED1
(*vir_gpioe_odr) &= (~(0x1 << 10));
//LED2
(*vir_gpiof_odr) &= (~(0x1 << 10));
//LED3
(*vir_gpioe_odr) &= (~(0x1 << 8));
return 0;
}
static void __exit mycdev_exit(void) {
/**
* 取消物理内存的映射
*/
iounmap(vir_gpioe_moder);
iounmap(vir_gpioe_odr);
iounmap(vir_gpiof_moder);
iounmap(vir_gpiof_odr);
iounmap(vir_rcc);
/**
* 销毁设备信息
*/
int i;
for (i=0; i<3; i++) {
device_destroy(cls, MKDEV(major, i));
}
/**
* 销毁目录信息
*/
class_destroy(cls);
unregister_chrdev(major, "mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
应用层测试代码 test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
int main(int argc, const char *argv[]) {
char buf[128] = {};
int fd = open("/dev/mycdev0", O_RDWR);
if (fd < 0) {
printf("打开设备文件失败\n");
return -1;
}
int fds[3] = {-1};
int i;
for (i=0; i<3; i++) {
char str[20];
sprintf(str, "/dev/mycdev%d", i);
fds[i] = open(str, O_RDWR);
if (fds[i] < 0) {
printf("打开设备文件%d失败", i);
return -1;
}
}
while(1) {
printf("选择LED1控制方式: 1(开灯), 0(关灯) > \n");
printf("请输入要实现的逻辑 > \n");
printf("11: LED1亮");
printf("10: LED1灭");
printf("21: LED2亮");
printf("20: LED2灭");
printf("31: LED3亮");
printf("30: LED3灭");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if (buf[0] == '1') {
write(fds[0], buf, sizeof(buf));
} else if (buf[0] == '2') {
write(fds[1], buf, sizeof(buf));
} else if (buf[0] == '3') {
write(fds[2], buf, sizeof(buf));
}
}
close(fd);
return 0;
}
结果展示: