驱动 day10 作业

要求:platform驱动实现
在这里插入图片描述
现象:
在这里插入图片描述
test.c应用程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
int main(int argc, char const *argv[])
{
	int fd;
	char buf[10]={0};		
	fd = open("/dev/myplatform",O_RDWR);
	if(fd < 0)
	{
		printf("打开设备文件失败\n");
		exit(-1);
	}  
	while(1)
	{
		memset(buf,0,sizeof(buf));
		read(fd,buf,sizeof(buf));
		printf("buf[0]=%d\n",buf[0]);
	}  
	close(fd);
	return 0;
}

job.c驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include <linux/io.h>
#include<linux/of.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/uaccess.h>
#include<linux/mod_devicetable.h>
#include<linux/platform_device.h>

struct cdev *cdev;//字符设备驱动对象空间首地址
unsigned int major=200;//主设备号
unsigned int minor=0;//次设备号的起始值
dev_t devno;//设备号变量
char kbuf[128]={0};
struct class *cls;//存放向上提交目录的返回值
struct device *dev;//存放向上提交设备节点信息结构体
struct device_node *dnode;//设备数节点信息结构体
struct gpio_desc *gpiono;//GPIO信息结构体
char number = 0;
unsigned int irqno;//获取中断号
wait_queue_head_t wq_head;//定义一个等待队列头
unsigned int condition=0;
struct resource *res;//存放设备信息的数组首地址
unsigned int irqno;//软中断号
/*myplatform{
        compatible = "hqyj,myplatform";
        reg=<0X12345678 0X400>;
        interrupt-parent=<&gpiof>;
        interrupts=<9 0>;   //9表示引用中断父节点时的索引信息  0表示默认设置
        led1=<&gpioe 10 0>;
};*/
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)
{
	//size参数是用户期待读到的字节长度
    int ret;
    //把内核的数据再拷贝给进程
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
	kbuf[0] = number;
	if(file->f_flags & O_NONBLOCK){
        //非阻塞
        return -EINVAL;
    }else{
        //阻塞
        ret = wait_event_interruptible(wq_head,condition);
        if(ret < 0){
            printk("receive signal....\n");
            return ret;
        }
    }
    ret=copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("数据从内核向用户拷贝失败\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	condition = 0;
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{   
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    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 =
{
    .read = mycdev_read,
	.open = mycdev_open,
	.write = mycdev_write,
	.release = mycdev_close,
};

//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
    printk("key1 interrupt\n");
	number = !number;
	condition = 1;
	gpiod_set_value(gpiono,!gpiod_get_value(gpiono));
	wake_up_interruptible(&wq_head);
    return IRQ_HANDLED; 
}
//probe函数,匹配设备成功执行
int pdrv_probe(struct platform_device *pdev)
{
	int ret;
	//初始化等待队列头
	init_waitqueue_head(&wq_head);
    //1.分配字符设备驱动对象空间  cdev_alloc
    cdev = cdev_alloc();
    if (!cdev) {
        printk(KERN_ALERT "cdev_alloc failed\n");
        return -ENOMEM;
    }
    printk("字符设备驱动对象空间申请成功\n");
    //2.字符设备驱动对象部分初始化  cdev_init
    cdev_init(cdev, &fops);
    //3.申请设备号  register_chrdev_region/alloc_chrdev_region
    if(major>0)//静态申请设备号
    {
        ret=register_chrdev_region(MKDEV(major,minor),1,"myplatform");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    else//动态申请设备号
    {
        ret=alloc_chrdev_region(&devno,minor,1,"myplatform");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major=MAJOR(devno);//根据设备号得到主设备号
        minor=MINOR(devno);//根据设备号得到次设备号
    }
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象  cdev_add()
    ret=cdev_add(cdev,MKDEV(major,minor),1);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    //5.向上提交目录
    cls=class_create(THIS_MODULE,"myplatform");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret=-PTR_ERR(cls);
		goto out4;
	}
	printk("向上提交目录成功\n");
	//6.向上提交设备节点
	dev=device_create(cls,NULL,MKDEV(major,minor),NULL,"myplatform");
	if(IS_ERR(dev))
	{
		printk("向上提交节点信息失败\n");
		ret=-PTR_ERR(dev);
		goto out5;
	}
	printk("向上提交设备节点信息成功\n");
	/*res=platform_get_resource(pdev,IORESOURCE_MEM,0);
	if(res == NULL)
	{
		printk("获取资源失败\n");
		return -ENXIO;
	}
	printk("获取资源信息成功%x\n",res->start);*/
	irqno = platform_get_irq(pdev,0);
	if(irqno < 0)
	{
		printk("获取中断资源失败\n");
		return irqno;
	}
	printk("软中断号为%d\n",irqno);
	//pdev->dev.of_node  设备树匹配之后会把设备树节点结构体首地址赋值给dev的of_node成员
    gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"led1",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono))
    {
        printk("解析GPIO信息失败\n");
        return -PTR_ERR(gpiono);
    }
    //注册中断
    ret=request_irq(irqno,myirq_handler,IRQF_TRIGGER_FALLING,"myplatform",NULL);
    if(ret)
    {
        printk("注册驱动失败\n");
        return ret;
    }
    printk("中断注册成功\n");
	return 0;
out5:
	//销毁上面提交的设备信息
	device_destroy(cls,MKDEV(major,minor));
	class_destroy(cls);
out4:
	cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major,minor),1);
out2:
    kfree(cdev);
out1:
    return ret;
}
//remove 设备和驱动分离时执行
int pdrv_remove(struct platform_device *pdev)
{
 	//注销中断
    free_irq(irqno,NULL);
	//灭灯,注销gpio信息
	gpiod_set_value(gpiono,0);
	gpiod_put(gpiono);

	//1.销毁设备信息  device_destroy
	device_destroy(cls,MKDEV(major,minor));
	//2.销毁目录  class_destroy
    class_destroy(cls);
    //3.注销对象  cdev_del()
    cdev_del(cdev);
    //4.释放设备号   unregister_chrdev_region()
    unregister_chrdev_region(MKDEV(major,minor),1);
    //5.释放对象空间  kfree()
    kfree(cdev);
	return 0;
}
//用于通过设备树的形式匹配设备信息
struct of_device_id oftable[]={
    {.compatible="hqyj,myplatform",},
    {.compatible="hqyj,myplatform1",},
	{},
};

//驱动端结构体
struct platform_driver pdrv={
	.probe=pdrv_probe,
	.remove=pdrv_remove,
	.driver={
		.name="11111",
		.of_match_table=oftable,
	},
};

module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园悬赏任务平台对字典管理、论坛管理、任务资讯任务资讯公告管理、接取用户管理、任务管理、任务咨询管理、任务收藏管理、任务评价管理、任务订单管理、发布用户管理、管理员管理等进行集中化处理。经过前面自己查阅的网络知识,加上自己在学校课堂上学习的知识,决定开发系统选择小程序模式这种高效率的模式完成系统功能开发。这种模式让操作员基于浏览器的方式进行网站访问,采用的主流的Java语言这种面向对象的语言进行校园悬赏任务平台程序的开发,在数据库的选择上面,选择功能强大的Mysql数据库进行数据的存放操作。校园悬赏任务平台的开发让用户查看任务信息变得容易,让管理员高效管理任务信息。 校园悬赏任务平台具有管理员角色,用户角色,这几个操作权限。 校园悬赏任务平台针对管理员设置的功能有:添加并管理各种类型信息,管理用户账户信息,管理任务信息,管理任务资讯公告信息等内容。 校园悬赏任务平台针对用户设置的功能有:查看并修改个人信息,查看任务信息,查看任务资讯公告信息等内容。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。项目管理页面提供的功能操作有:查看任务,删除任务操作,新增任务操作,修改任务操作。任务资讯公告信息管理页面提供的功能操作有:新增任务资讯公告,修改任务资讯公告,删除任务资讯公告操作。任务资讯公告类型管理页面显示所有任务资讯公告类型,在此页面既可以让管理员添加新的任务资讯公告信息类型,也能对已有的任务资讯公告类型信息执行编辑更新,失效的任务资讯公告类型信息也能让管理员快速删除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值