要求
使用三个线程完成任务
1、一个线程让三个LED实现跑马灯
2、一个线程让蜂鸣器周期蜂鸣
3、一个线程根据输入的值控制风扇的开关
4、使用ioctl进行驱动控制
5、实现设备文件的自动创建
6、使用设备树对设备的管理
简述
本次是上次的升级版,上次在实现的过程中需要自己手动创建设备文件 ,在这次的实现中,我们可以使用class_create和class_destroy进行一类设备的创建,在使用device_create和device_destroy进行对应设备的设备文件创建
//所需头文件
#include<linux/device.h>
struct class *class_create(struct module *owner,const char *name)
功能:向上提交设备类信息,创建一个struct class类型的结构体对象
参数:
owner:指向当前模块自身的指针,我们填写THIS_MODULE即可
name:向上提交的设备类名
返回值:成功返回申请到的结构体变量首地址,失败返回错误码指针
void class_destroy(struct class *cls)
功能:设备类的销毁
参数:
cls:创建的class对象指针
返回值:无
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
功能:向上提交设备信息
参数:
class:创建的class对象指针
parent:父设备对象指针,填NULL即可
devt:要创建的设备文件对应的设备号
drvdata:当前设备对象的私有数据,填NULL
fmt:要创建的设备文件的名字,名字里面可以包含格式控制符
...:当上一个参数中包含格式控制符的时候,这个参数需要填写格式控制符对应的目标值
返回值:成功返回创建成功的struct device对象指针,失败返回错误码指针
void device_destroy(struct class *class, dev_t devt)
功能:销毁设备信息
参数:
class:创建的class对象指针
devt:向上提交设备信息时填写的设备号
返回值:无
使用设备树对设备的管理,这样我们就不用进行内存映射,这要的效率会大大提升,但是我们需要对系统内核的设备树文件进行编辑添加我们的设备,所以我们要回写设备树文件的语法,这里不展开,下面是要用到的设备树节点解析的API
//所需头文件
#include<linux/of.h>
struct device_node *of_find_node_by_name(struct device_node *from, const char *name)
功能:根据设备树节点的名字来解析指定的设备树节点
参数:
from:当前要解析的设备树节点所在子树的根节点路径,不知道就填NULL,默认从根节点/进行解析
name:要解析的设备树节点的名字(名字是@之前的名字 mynode)
返回值:成功返回解析到的设备树节点指针,失败返回NULL
struct device_node *of_find_node_by_path(const char *path)
功能:根据设备树节点的路径解析指定设备树节点
参数:
path:要解析的设备树节点的路径 /mynode@0X12345678
返回值:成功返回解析到的设备树节点的指针,失败返回NULL
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compat);
功能:根据设备树节点的compatible值对设备树节点信息进行解析
参数:
from:当前要解析的设备树节点所在子树的根节点路径,不知道就填NULL,默认从根节点/进行解析
type:设备树节点填写的设备类型,默认填NULL
compat:要解析的设备树节点的compatible值
返回值:成功返回解析到的设备树节点的指针,失败返回NULL
__u32 __be32_to_cpup(const __be32 *p)
功能:将大端字节序32位的数据转换成主机字节序
参数:要转换的数据指针
返回值:返回转换后的主机字节序的数据
其次,我们需要对芯片的GPIO接口进行调用解析和操作,下面是GPIO子系统的相关API
//所需的头文件
#include<linux/of.h>
struct device_node *of_find_node_by_path(const char *path)
功能:获取设备树节点信息通过路径
参数:
path:节点路径("/mynode@0x12345678")
返回值:成功返回目标节点的信息结构体地址,失败返回NULL
还可以通过设备树节点的名字或者设备树节点的compatible值解析相关的设备信息
//所需的头文件
#include<linux/of_gpio.h>
int of_get_named_gpio(struct device_node *np, const char *propname, int index)
功能:根据gpio管脚设备树节点解析获取GPIO编号
参数:
np:节点结构体首地址
proname:键名
index:索引号
返回值:成功返回GPIO编号,失败返回错误码
//所需的头文件
#include<linux/gpio.h>
int gpio_request(unsigned gpio, const char *label)
作用:申请指定GPIO编号的使用权
参数:gpio:目标GPIO编号
label:一般填写NULL
成功返回0,失败返回错误码
void gpio_free(unsigned gpio)
作用:释放申请的GPIO编号
参数:目标GPIO编号
int gpio_direction_output(unsigned gpio, int value)
作用:设置GPIO为输出
参数:
gpio:GPIO编号
value:1:高电平 0:低电平
返回值:成功返回0,失败返回错误码
int gpio_direction_input(unsigned gpio)
作用:设置GPIO为输入
参数:
gpio:GPIO编号
返回值:成功返回0,失败返回错误码
int gpio_get_value(unsigned int gpio)
功能:获取GPIO电平状态
参数:
GPIO编号
返回值:1:高电平 0:低电平
void gpio_set_value(unsigned int gpio, int value)
作用:让GPIO输出高低电平
参数:
gpio:GPIO编号
value:1:高电平 0:低电平
返回值:无
设备树文件所需添加内容
leds{
led-gpio = <&gpioe 10 0>, <&gpiof 10 0>, <&gpioe 8 0>;
};
fans{
fan-gpio = <&gpioe 9 0>;
};
buzzers{
buzzer-gpio = <&gpiob 6 0>;
};
驱动文件
led.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 <linux/gpio.h>
#include <linux/of_gpio.h>
#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)
unsigned int major;//全局保存主设备号
char kbuf[128] = {};
struct device_node *np;
int led_gpio[3];
// leds{
// led-gpio = <&gpioe 10 0>, <&gpiof 10 0>, <&gpioe 8 0>;
// };
struct device *dev;
struct class *cls;
int mydev_open(struct inode *inode, struct file* file){
unsigned int minor;
minor = MINOR(inode->i_rdev);
file->private_data = (void*)minor;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mydev_read(struct file* file, char __user *ubuf, size_t size, loff_t *lft){
unsigned long ret = copy_to_user(ubuf, kbuf, size);
if(ret)
{
printk("copy_to_user filad\n");
return -ret;
}
return 0;
}
ssize_t mydev_write(struct file* file, const char __user *ubuf, size_t size, loff_t *lft){
unsigned long ret = copy_from_user(kbuf, ubuf, size);
if(ret)
{
printk("copy_from_user filad\n");
return -ret;
}
return 0;
}
int mydev_close(struct inode *inode, struct file* file){
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg){
switch (cmd)
{
case LED_ON:
switch ((unsigned int)file->private_data)
{
case 0:
gpio_set_value(led_gpio[0], 1);
break;
case 1:
gpio_set_value(led_gpio[1], 1);
break;
case 2:
gpio_set_value(led_gpio[2], 1);
break;
default:
break;
}
break;
case LED_OFF:
switch ((unsigned int)file->private_data)
{
case 0:
gpio_set_value(led_gpio[0], 0);
break;
case 1:
gpio_set_value(led_gpio[1], 0);
break;
case 2:
gpio_set_value(led_gpio[2], 0);
break;
default:
break;
}
break;
default:
break;
}
return 0;
}
struct file_operations fops={
.open = mydev_open,
.read = mydev_read,
.write = mydev_write,
.unlocked_ioctl = mydev_iocrl,
.release = mydev_close,
};
int all_led_init(void){
int i;
np = of_find_node_by_name(NULL, "leds");
if (np == NULL)
{
printk("leds not found\n");
return -1;
}
printk("find leds\n");
for (i = 0; i < 3; i++)
{
led_gpio[i] = of_get_named_gpio(np, "led-gpio", i);
if (led_gpio[i] < 0)
{
printk("get gpio failed\n");
return -1;
}
printk("gpio[%d] = %d\n", i, led_gpio[i]);
if(gpio_request(led_gpio[i], NULL) < 0){
printk("gpio_request failed\n");
return -1;
}
gpio_direction_output(led_gpio[i], 0);
}
return 0;
}
int all_dev_create(void){
int i;
cls = class_create(THIS_MODULE, "myled");
if(IS_ERR(cls)){
printk("class_create filed\n");
return PTR_ERR(cls);
}
for (i = 0; i < 3; i++)
{
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
if(IS_ERR(dev)){
printk("device_create filed\n");
class_destroy(cls);
return PTR_ERR(dev);
}
printk("device_create myled%d success\n", i);
}
return 0;
}
int all_dev_destroy(void){
int i;
for (i = 0; i < 3; i++)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
return 0;
}
static int __init mydev_init(void){
major = register_chrdev(0, "myled", &fops);
if(major < 0){
printk("register_myled faile\n");
}else{
printk("register_myled success, major = %d\n", major);
}
if(all_dev_create()){
return 0;
}
if(all_led_init()){
return 0;
}
return 0;
}
static void __exit mydev_exit(void){
int i;
for (i = 0; i < 3; i++)
{
gpio_free(led_gpio[i]);
}
printk("free led_gpio success\n");
unregister_chrdev(major, "myled");
all_dev_destroy();
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
fan.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 <linux/gpio.h>
#include <linux/of_gpio.h>
#define FAN_ON _IO('f', 1)
#define FAN_OFF _IO('f', 0)
unsigned int major; // 全局保存主设备号
char kbuf[128] = {};
struct device_node *np;
int fan_gpio;
// fans{
// fan_gpio = <&gpioe 9 0>;
// };
struct device *dev;
struct class *cls;
int myled_open(struct inode *inode, struct file *file)
{
unsigned int minor;
minor = MINOR(inode->i_rdev);
file->private_data = (void *)minor;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{
// printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
unsigned long ret = copy_to_user(ubuf, kbuf, size);
if (ret)
{
printk("copy_to_user filad\n");
return -ret;
}
return 0;
}
ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{
// printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
unsigned long ret = copy_from_user(kbuf, ubuf, size);
if (ret)
{
printk("copy_from_user filad\n");
return -ret;
}
return 0;
}
int myled_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case FAN_ON:
gpio_set_value(fan_gpio, 1);
break;
case FAN_OFF:
gpio_set_value(fan_gpio, 0);
break;
default:
break;
}
return 0;
}
struct file_operations fops = {
.open = myled_open,
.read = myled_read,
.write = myled_write,
.unlocked_ioctl = mydev_iocrl,
.release = myled_close,
};
int all_fan_init(void)
{
np = of_find_node_by_name(NULL, "fans");
if (np == NULL)
{
printk("fans not found\n");
return -1;
}
printk("find fans\n");
fan_gpio = of_get_named_gpio(np, "fan-gpio", 0);
if (fan_gpio < 0)
{
printk("get gpio failed\n");
return -1;
}
printk("fan_gpio = %d\n", fan_gpio);
if (gpio_request(fan_gpio, NULL) < 0)
{
printk("gpio_request failed\n");
return -1;
}
gpio_direction_output(fan_gpio, 0);
return 0;
}
int all_dev_create(void)
{
cls = class_create(THIS_MODULE, "myfan");
if (IS_ERR(cls))
{
printk("class_create filed\n");
return PTR_ERR(cls);
}
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myfan");
if (IS_ERR(dev))
{
printk("device_create filed\n");
class_destroy(cls);
return PTR_ERR(dev);
}
printk("device_create myfan success\n");
return 0;
}
int all_dev_destroy(void)
{
device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
return 0;
}
static int __init mydev_init(void)
{
major = register_chrdev(0, "myfan", &fops);
if (major < 0)
{
printk("register_myfan faile\n");
}
else
{
printk("register_myfan success, major = %d\n", major);
}
if (all_dev_create())
{
return 0;
}
if (all_fan_init())
{
return 0;
}
return 0;
}
static void __exit mydev_exit(void)
{
gpio_free(fan_gpio);
printk("free fan_gpio success\n");
unregister_chrdev(major, "myfan");
all_dev_destroy();
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
buzzer.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 <linux/gpio.h>
#include <linux/of_gpio.h>
#define BUZZER_ON _IO('b', 1)
#define BUZZER_OFF _IO('b', 0)
unsigned int major;//全局保存主设备号
char kbuf[128] = {};
// buzzers{
// buzzer-gpio = <&gpiob 6 0>;
// };
struct device_node *np;
int buzzer_gpio;
struct device *dev;
struct class *cls;
int myled_open(struct inode *inode, struct file* file){
unsigned int minor;
minor = MINOR(inode->i_rdev);
file->private_data = (void *)minor;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t myled_read(struct file* file, char __user *ubuf, size_t size, loff_t *lft){
//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
unsigned long ret = copy_to_user(ubuf, kbuf, size);
if(ret)
{
printk("copy_to_user filad\n");
return -ret;
}
return 0;
}
ssize_t myled_write(struct file* file, const char __user *ubuf, size_t size, loff_t *lft){
//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
unsigned long ret = copy_from_user(kbuf, ubuf, size);
if(ret)
{
printk("copy_from_user filad\n");
return -ret;
}
return 0;
}
int myled_close(struct inode *inode, struct file* file){
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg){
switch (cmd)
{
case BUZZER_ON:
gpio_set_value(buzzer_gpio, 1);
break;
case BUZZER_OFF:
gpio_set_value(buzzer_gpio, 0);
break;
default:
break;
}
return 0;
}
struct file_operations fops={
.open = myled_open,
.read = myled_read,
.write = myled_write,
.unlocked_ioctl = mydev_iocrl,
.release = myled_close,
};
int all_buzzer_init(void){
np = of_find_node_by_name(NULL, "buzzers");
if (np == NULL)
{
printk("buzzers not found\n");
return -1;
}
printk("find buzzers\n");
buzzer_gpio = of_get_named_gpio(np, "buzzer-gpio", 0);
if (buzzer_gpio < 0)
{
printk("get gpio failed\n");
return -1;
}
printk("fan_gpio = %d\n", buzzer_gpio);
if (gpio_request(buzzer_gpio, NULL) < 0)
{
printk("gpio_request failed\n");
return -1;
}
gpio_direction_output(buzzer_gpio, 0);
return 0;
}
int all_dev_create(void)
{
cls = class_create(THIS_MODULE, "mybuzzer");
if (IS_ERR(cls))
{
printk("class_create filed\n");
return PTR_ERR(cls);
}
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mybuzzer");
if (IS_ERR(dev))
{
printk("device_create filed\n");
class_destroy(cls);
return PTR_ERR(dev);
}
printk("device_create mybuzzer success\n");
return 0;
}
int all_dev_destroy(void)
{
device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
return 0;
}
static int __init mydev_init(void){
major = register_chrdev(0, "mybuzzer", &fops);
if(major < 0){
printk("register_mybuzzer faile\n");
}else{
printk("register_mybuzzer success, major = %d\n", major);
}
if(all_buzzer_init()){
return 0;
}
if(all_dev_create()){
return 0;
}
return 0;
}
static void __exit mydev_exit(void){
gpio_free(buzzer_gpio);
printk("free buzzer_gpio success\n");
unregister_chrdev(major, "mybuzzer");
all_dev_destroy();
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
程序文件
app.c
#include <stdio.h> // 标准输入输出库
#include <stdlib.h> // 标准库
#include <sys/types.h> // 系统数据类型库
#include <sys/stat.h> // 文件状态库
#include <fcntl.h> // 文件控制库
#include <unistd.h> // UNIX 标准库
#include <string.h> // 字符串操作库
#include <pthread.h> // 线程库
#include <sys/ioctl.h> // IO 控制库
#define FAN_ON _IO('f', 1)
#define FAN_OFF _IO('f', 0)
#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)
#define BUZZER_ON _IO('b', 1)
#define BUZZER_OFF _IO('b', 0)
void* flowing_led_thread(void *arg){
int *led_fd = (int*)arg;
int count = 0;
while (1)
{
count %= 3;
if(count == 0){
ioctl(led_fd[0], LED_ON);
ioctl(led_fd[1], LED_OFF);
ioctl(led_fd[2], LED_OFF);
}else if(count == 1){
ioctl(led_fd[0], LED_OFF);
ioctl(led_fd[1], LED_ON);
ioctl(led_fd[2], LED_OFF);
}else if(count ==2){
ioctl(led_fd[0], LED_OFF);
ioctl(led_fd[1], LED_OFF);
ioctl(led_fd[2], LED_ON);
}
count++;
sleep(1);
}
pthread_exit(NULL);
}
void* buzzer_thread(void *arg){
int buzzer_fd = *((int*)arg);
int count = 0;
while (1)
{
count %= 2;
if(count == 0){
ioctl(buzzer_fd, BUZZER_ON);
}else if(count == 1){
ioctl(buzzer_fd, BUZZER_OFF);
}
count++;
sleep(1);
}
pthread_exit(NULL);
}
void* fan_thread(void *arg){
int fan_fd = *((int*)arg);
char cmd_buf[32] = {0};
while (1)
{
scanf("%s", cmd_buf);
if(strcmp(cmd_buf, "FAN_ON") == 0){
ioctl(fan_fd, FAN_ON);
}else if(strcmp(cmd_buf, "FAN_OFF") == 0){
ioctl(fan_fd, FAN_OFF);
}
}
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
int led0_fd = open("/dev/myled0", O_RDWR);
if(led0_fd < 0)
{
printf("filed in open myled0\n");
return led0_fd;
}
int led1_fd = open("/dev/myled1", O_RDWR);
if(led1_fd < 0)
{
printf("filed in open myled1\n");
return led1_fd;
}
int led2_fd = open("/dev/myled2", O_RDWR);
if(led2_fd < 0)
{
printf("filed in open myled2\n");
return led2_fd;
}
int fan_fd = open("/dev/myfan", O_RDWR);
if(fan_fd < 0)
{
printf("filed in open myfan\n");
return fan_fd;
}
int buzzer_fd = open("/dev/mybuzzer", O_RDWR);
if(buzzer_fd < 0)
{
printf("filed in open mybuzzer\n");
return buzzer_fd;
}
int led_fd[3] = {led0_fd, led1_fd, led2_fd};
pthread_t flowing_led_tid;
pthread_t buzzer_tid;
pthread_t fan_tid;
int led_thread_creat_res = pthread_create(&flowing_led_tid, NULL, flowing_led_thread, (void*)led_fd);
if(led_thread_creat_res != 0){
printf("create led thread filed\n");
}
int buzzer_thread_creat_res = pthread_create(&buzzer_tid, NULL, buzzer_thread, (void*)&buzzer_fd);
if(led_thread_creat_res != 0){
printf("create led thread filed\n");
}
int fan_thread_creat_res = pthread_create(&fan_tid, NULL, fan_thread, (void*)&fan_fd);
if(fan_thread_creat_res != 0){
printf("create fan thread filed\n");
}
pthread_join(flowing_led_tid, NULL);
pthread_join(buzzer_tid, NULL);
pthread_join(fan_tid, NULL);
close(led0_fd);
close(led2_fd);
close(led2_fd);
close(fan_fd);
close(buzzer_fd);
return 0;
}