作业要求:
paltform框架的驱动形式实现在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动
头文件:
#ifndef __MYLED_H__
#define __MYLED_H__
#define LED_1ON _IOW('a',1,int)
#define LED_2ON _IOW('a',2,int)
#define LED_3ON _IOW('a',3,int)
#endif
应用层源文件:
#include
#include
#include
#include
#include
#include
#include
#include
#include "test.h"
int main(int argc,const char * argv[])
{
char buf[128] = {0};
int whitch;
int fd = -1;
fd = open("/dev/myself0",O_RDWR);
if(fd == -1)
{
perror("open is error\n");
return -1;
}
printf("文件打开成功\n");
while(1)
{
ioctl(fd,LED_1ON,&whitch);
sleep(1);
ioctl(fd,LED_2ON,&whitch);
sleep(1);
ioctl(fd,LED_3ON,&whitch);
sleep(1);
}
close(fd);
return 0;
}
驱动源文件:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "test.h"
#define CNAME "myself"
struct device_node *dnode;
struct device_node *dnode1;
int irqno;
//tasklet对象分配
struct tasklet_struct tasklet;
//解析gpio编号
int gpiono[4];
struct class * cls;
struct device * dev;
unsigned int minor = 0;
#if 0
unsigned int major = 0; //动态申请主设备号
#else
unsigned int major = 495; //静态申请主设备号
#endif
int myled_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
printk("myled_open\n");
return 0;
}
ssize_t myled_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
printk("myled_read\n");
return 0;
}
ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
printk("myled_write\n");
return 0;
}
int myled_close (struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
printk("myled_close\n");
return 0;
}
long myled_ioctl (struct file *file, unsigned int cmd, unsigned long args)
{
//1.判断cmd switch(cmd)
//2.判断操作哪盏灯进行点亮 copy_from_user
switch(cmd)
{
case LED_1ON:
gpio_set_value(gpiono[0],1);
gpio_set_value(gpiono[1],0);
gpio_set_value(gpiono[2],0);
break;
case LED_2ON:
gpio_set_value(gpiono[0],0);
gpio_set_value(gpiono[1],1);
gpio_set_value(gpiono[2],0);
break;
case LED_3ON:
gpio_set_value(gpiono[0],0);
gpio_set_value(gpiono[1],0);
gpio_set_value(gpiono[2],1);
break;
}
return 0;
}
const struct file_operations fops = {
.open = myled_open,
.read = myled_read,
.write = myled_write,
.unlocked_ioctl = myled_ioctl,
.release = myled_close,
};
//对象指针
struct cdev *cdev_p = NULL;
int ret = 0;
int i = 0;
dev_t dev_val = 0;
//工作队列对象分配
struct work_struct work;
//底半部函数
void work_func(struct work_struct *work)
{
printk("工作队列\n");
gpio_set_value(gpiono[3],!gpio_get_value(gpiono[3]));
}
//中断 处理函数
irqreturn_t irq1_handler(int irqno, void *arg)
{
printk("key interrupt\n");
//开启中断底半部
schedule_work(&work);
return IRQ_HANDLED;
}
//分配对象并且初始化
//probe函数
int pdrv_probe(struct platform_device *pdev)
{
int i;
int j = 0;
printk("进入函数\n");
//1.分配对象
cdev_p = cdev_alloc();
if(NULL == cdev_p)
{
printk("分配对象空间失败\n");
ret = -ENOMEM;
goto ERR1;
}
printk("分配对象空间成功\n");
//2.对象初始化
cdev_init(cdev_p,&fops);
//3.设备资源的申请(设备号)
if(0 == major)
{
ret = alloc_chrdev_region(&dev_val,minor,3,"myself");
if(ret)
{
printk("动态申请设备号失败\n");
goto ERR2;
}
major = MAJOR(dev_val); //获取主设备号
minor = MINOR(dev_val); //获取次设备号
}
else if(major>0)
{
ret = register_chrdev_region(MKDEV(major,minor),3,"myself");
if(ret)
{
printk("静态申请设备号失败\n");
goto ERR2;
}
}
//4.注册
ret = cdev_add(cdev_p,MKDEV(major,minor),3);
if(ret)
{
printk("驱动对象注册进内核失败\n");
goto ERR3;
}
printk("驱动对象注册进内核成功\n");
//5.向上提交目录
cls = class_create(THIS_MODULE,"myself");
if(IS_ERR(cls))
{
printk("向上提交目录失败\n");
goto ERR4;
}
printk("向上提交目录成功\n");
//6.向上提交设备节点信息
for(i=0;i<3;i++)
{
dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myself%d",i);
if(IS_ERR(dev))
{
printk("向上提交节点信息失败\n");
goto ERR5;
}
}
printk("向上提交节点信息成功\n");
//解析设备树节点
dnode=of_find_node_by_name(NULL,"myplatform");
if(dnode==NULL)
{
printk("解析设备树节点失败\n");
return -EIO;
}
printk("解析设备树节点成功\n");
//根据设备树节点解析gpio编号
gpiono[0]= of_get_named_gpio(dnode,"led1",0);
if(gpiono[0]<0)
{
printk("1解析gpio编号失败\n");
return -EIO;
}
printk("1解析gpio编号成功\n");
gpiono[1]= of_get_named_gpio(dnode,"led2",0);
if(gpiono[1]<0)
{
printk("2解析gpio编号失败\n");
return -EIO;
}
printk("2解析gpio编号成功\n");
gpiono[2]= of_get_named_gpio(dnode,"led3",0);
if(gpiono[2]<0)
{
printk("3解析gpio编号失败\n");
return -EIO;
}
printk("3解析gpio编号成功\n");
gpiono[3]= of_get_named_gpio(dnode,"pwm1",0);
if(gpiono[3]<0)
{
printk("4解析gpio编号失败\n");
return -EIO;
}
printk("4解析gpio编号成功\n");
//申请gpio编号
//设置gpio为输出并且初始化数值为0
for(j=0;j<4;j++)
{
//申请gpio编号
gpio_request(gpiono[j],NULL);
//设置gpio为输出并且初始化数值为0
gpio_direction_output(gpiono[j],0);
}
//解析设备树节点
dnode1=of_find_node_by_name(NULL,"myirqs");
if(dnode==NULL)
{
printk("解析设备树节点失败\n");
return -EIO;
}
printk("解析设备树节点成功\n");
//根据设备树节点解析出软中断号
irqno=irq_of_parse_and_map(dnode1,0);
if(!irqno)
{
printk("获取软中断号失败\n");
return -ENXIO;
}
printk("解析设备树获取软中断号成功\n");
//注册中断
request_irq(irqno,irq1_handler,IRQF_TRIGGER_FALLING,"myirq",(void *)0);
//初始化工作队列对象
INIT_WORK(&work,work_func);
return 0;
ERR5:
for(--i;i>=0;i--)
{
device_destroy(cls,MKDEV(major,i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev_p);
ERR3:
unregister_chrdev_region(MKDEV(major,minor),3);
ERR2:
kfree(cdev_p);
ERR1:
return ret;
}
//remove函数
int pdrv_remove(struct platform_device *pdev)
{
int i;
printk("退出函数\n");
for(i=0;i<3;i++)
{
device_destroy(cls,MKDEV(major,i));
}
class_destroy(cls);
cdev_del(cdev_p);
unregister_chrdev_region(MKDEV(major,minor),3);
kfree(cdev_p);
for(i=0;i<4;i++)
{
gpio_free(gpiono[i]);
}
return 0;
}
//构建设备树匹配标配
struct of_device_id oftable[] =
{
{.compatible = "hqyj,platform"},
{.compatible = "hqyj,platform1"},
{},
};
//分配对象并且初始化
struct platform_driver pdrv={
.probe=pdrv_probe,
.remove=pdrv_remove,
.driver={
.name="aaaaa",
.of_match_table=oftable,//设置设备树匹配
},
};
//一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
实验现象: