驱动程序设计 平台驱动、Linux内存映射、Linux中断、按键中断控制 7.13

news2024/10/6 2:20:30

平台驱动

模块驱动: 一对多管理,系统管理效率低 加载卸载方便
设备模型:分层分级的管理
		4个重要的组成部分:class device driver bus(总线)
		层级:kobj-->kset/kobj-->kset-->kset
class:一类相同属性的设备的集合
device:抽象出的设备对象的基类,设备的属性
driver:抽象出的所以驱动的基类,驱动的逻辑
bus(总线):连接设备和驱动的作用
cd /sys/bus/pci/devices/

CPU
--------------------------(总线):匹配设备和驱动
drv0 dev0 dev1 dev2 drv1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wIxWLQPe-1689585684572)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230712160707515.png)]

最底层的设备有专门的文件描述符为:kobject

不能独立存在,描述设备对象的一个基类,从不独立存在,只是依附在某些设备中

上一级为:kset(但作为被管理时也为 kobject)

再上一级也为:kset

------------------自创:平台总线(platform bus) (plateform device)(plateform driver)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adHiszWI-1689585684573)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230713092121599.png)]

修改设备树

添加设备:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4a48AXM-1689585684573)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230713102649856.png)]

保存编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LoJ5Ulwf-1689585684574)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230712172147971.png)]

//头文件

#include <linux/init.h>

#include <linux/module.h>

#include <linux/of.h>

#include <linux/platform_device.h>

//函数实现

int myinit(struct platform_device *pdev)
{
//获取设备资源
struct resource *res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    vaddr = ioremap(res->start,4);

}
int myexit(struct platform_device *pdev)

//注册

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hp7XarC7-1689585684574)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230712173137290.png)]

//注册
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
	{ .compatible = "fs,myled", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif

static struct platform_driver myled_driver = {
	.driver	= {
		.name    = "myled",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(myled_of_matches),
	},
	.probe   = myinit,
	.remove  = myexit,
};

module_platform_driver(myled_driver);

//模块信息描述

MODULE_LICENSE("GPL");

驱动程序

/*===============================================
 *   文件名称:mod.c
 *   创 建 者: memories
 *   创建日期:2023年07月06日
 *   描    述:have a nice day
 ================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "cmd.h"
#define MA 300
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static int *gpf3con=NULL,*gpf3dat=NULL;

void addr_map(struct platform_device* pdev)
{
    struct resource* conres = platform_get_resource(pdev,IORESOURCE_MEM,0);
    struct resource* datres = platform_get_resource(pdev,IORESOURCE_MEM,1);
    gpf3con = ioremap(conres->start,4);
    gpf3dat = ioremap(datres->start,4);
}
void addr_unmap(void)
{
    iounmap(gpf3con);
    iounmap(gpf3dat);
}

void dev_init(void)
{
    writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
    printk("led on\n");
    writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
    printk("led off\n");
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
int myopen(struct inode *pi,struct file *pf)
{
    printk("kernel open\n");
    return 0;
}

int myrelease(struct inode *pi,struct file *pf)
{
    printk("kernel close\n");
    return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_to_user(ubuf,mbuf,len);
    if(ret != 0)
        return -1;
    printk("now read\n");   
    return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_from_user(mbuf,ubuf,len);
    if(ret != 0)
        return -1;
    printk("now write\n");    
    return len;
}
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            led_on();
            break;
        case LED_OFF:
            led_off();
            break;
    };
    return 0;
}

static const struct file_operations myfops={
    .release = myrelease,
    .open = myopen,
    .read = myread,
    .write = mywrite,
    .unlocked_ioctl = myioctl,

};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
    int ret = 1;
    //up: kernel
    //1.registed 把设备对象注册到系统中
    no = MKDEV(MA,MI);//组合主次设备号
    ret = register_chrdev_region(no,count,name);
    if(ret != 0)
    {
        printk("reg is error\n");
        return -1;
    }
    //2.init    设备初始化,抽象出来一个对象
    cdev_init(&mydev,&myfops);
    //3.add     添加设备
    ret = cdev_add(&mydev,no,count);
    if(ret != 0)
    {
        unregister_chrdev_region(no,count);
        return -1;
    }
    //down:hardware
    printk("myinit ok\n");
    //1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
    printk("121212\n");
    addr_map(pdev);
    //2.dev init
    dev_init();
    return 0;
}
static int myexit(struct platform_device* pdev)
{
    //和内核相关
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("myexit ok\n");
    //和硬件相关
    //1.解除映射
    addr_unmap();
    return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
	{ .compatible = "fs,myled", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif

static struct platform_driver myled_driver = {
	.driver	= {
		.name    = "myled",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(myled_of_matches),
	},
	.probe   = myinit,
	.remove  = myexit,
};

module_platform_driver(myled_driver);

//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");

应用程序

/*===============================================
*   文件名称:mainopen.c
*   创 建 者: memories
*   创建日期:2023年07月06日
*   描    述:have a nice day
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "cmd.h"

int main(int argc, char *argv[])
{ 
    char wbuf[20]="12122122142";
    char rbuf[20]={0};
    int ret = 0;
    int fd = open("/dev/mydev",O_RDWR);
    if(fd < 0)
    {
        printf("open failed fd is %d\n",fd);
        return -1;
    }
    while(1)
    {
    ioctl(fd,LED_ON);
    sleep(1);
    ioctl(fd,LED_OFF);
    sleep(1);
    }
    close(fd);
    return 0;
} 

Linux内存映射

物理内存地址从0x40000000开始
虚拟内存地址从0开始,因为全地址覆盖0~2^32次方
4k称为一个✌页
虚拟地址空间---------------mmu(映射表)--------------物理内存地址

Linux用户空间内存分配

_ malloc()
_ calloc()
_ realloc()
free();

linux内核分配空间

按页分配:_ _get_free_pages()
    物理内存空间连续的
_ kmalloc():请求精确字节的内存 32~128k
_ vmalloc():物理内存不一定连续,与kmalloc同

IO与内存访问

1.CPU访问不到寄存器,所以把寄存器映射到内存,让CPU访问
2.CPU访问IO空间,通过端口访问寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wC1A3DNG-1689585684574)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230713134046352.png)]

{//—mmap 文件映射到内存
//?mmap是什么

​ mmap是把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等操作。

//?为什么用mmap
{
	1. 用mmap替代文件操作(read,write)访问设备,效率高.   它是用户空间访问内核空间的一种高效率方式。
      mmap        --   映射文件到虚拟内存 
      read,write  --   copy_to_user  拷贝
      对比read write,mmap无需每次都copy_to_user拷贝一次. 它仅需一次映射,以后都直接操作内存buf,效率高。
	2. 用共享内存方式,方便进程间通讯,且效率高。 
       采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
     对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,
     而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件		      
}
//mmap原型
{

   void* mmap (  void * addr ,   //指定映射的起始地址, 通常设为NULL, 由系统指定 
                 size_t len ,    //映射到内存的文件长度
                 int prot ,      //映射区的保护方式, PROT_EXEC: 映射区可被执行 PROT_READ: 可读  PROT_WRITE: 可写
                 int flags ,     //MAP_SHARED:写入映射区的数据会复制回文件, 且允许其他映射该文件的进程共享。
                                 //MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write), 对此区域所做的修改不会写回原文件。
                 int fd ,        //由open返回的文件描述符, 代表要映射的文件
                 off_t offset    //以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射
               )           
}
{//?mmap 怎么用
	#include <stdio.h>
	#include<sys/types.h>
	#include<sys/stat.h>
	#include<fcntl.h>
	#include<unistd.h>
	#include<sys/mman.h>
	
	int main()
	{
	 int fd;
	 char *start;
	 //char buf[PAGE_SIZE];
	 char *buf;
	 
	 /*打开文件*/
	 fd = open("/dev/mydev",O_RDWR);     
	 buf = (char *)malloc(PAGE_SIZE);
	 memset(buf, 0, PAGE_SIZE);
	 start=mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	 
	 /* 读出数据 */
	 strcpy(buf,start);
	 sleep (1);
	 printf("buf 1 = %s\n",buf); 
        
     /* 写入数据 */
	 strcpy(start,"Buf Is Not Null!");     
     
	 /* 再次读出数据*/
     memset(buf, 0, PAGE_SIZE);
	 strcpy(buf,start);
	 sleep (1);
	 printf("buf 2 = %s\n",buf);

	 munmap(start,PAGE_SIZE); /*解除映射*/
	 free(buf);
	 close(fd); 
	 return 0; 
	}	
}

驱动:
char *kbuf = (char *)kmalloc(PAGE_SIZE, GFP_KERNEL);

int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
    vma->vm_flags |= VM_IO;//表示对设备IO空间的映射  
    vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出  
    if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里  
                       vma->vm_start,//虚拟空间的起始地址  
                       virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位  
                       vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍  
                       vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等  
    {  
        return -EAGAIN;  
    }  
    return 0;  
}

static struct file_operations myops = {
    .open = myled_open,
    .release = myled_release,
    .mmap = myled_mmap
};

}

Linux中断

只需要设置设备树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bDSGzseN-1689585684574)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230713152633943.png)]

中断注册到设备里面

申请IRQ:
irq_map(pdev);
irq_unmap();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IAWZJuGt-1689585684574)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230713154327046.png)]

驱动程序

/*===============================================
 *   文件名称:mod.c
 *   创 建 者: memories
 *   创建日期:2023年07月06日
 *   描    述:have a nice day
 ================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "cmd.h"
#define MA 300
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static char *kbuf;
struct resource* irqres = NULL;

irqreturn_t handler(int irqno,void *arg)
{
    printk("okokok\n");
    return IRQ_HANDLED;
}

int irq_map(struct platform_device* pdev)
{
    struct resource* irqres = platform_get_resource(pdev,IORESOURCE_IRQ,0);
    int ret = request_irq(irqres->start,handler,irqres->flags,"myirq",NULL);
    if(ret != 0)
        return ret;
    return 0;
}

void irq_unmap(void)
{
    free_irq(irqres->start,NULL);
}

/*
void dev_init(void)
{
    writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
    printk("led on\n");
    writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
    printk("led off\n");
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}

*/
int myopen(struct inode *pi,struct file *pf)
{
    return 0;
}

int myrelease(struct inode *pi,struct file *pf)
{
    return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_to_user(ubuf,mbuf,len);
    if(ret != 0)
        return -1;
    printk("now read\n");   
    return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_from_user(mbuf,ubuf,len);
    if(ret != 0)
        return -1;
    printk("now write\n");    
    return len;
}
/*
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            led_on();
            break;
        case LED_OFF:
            led_off();
            break;
    };
    return 0;
}
*/

int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
    vma->vm_flags |= VM_IO;//表示对设备IO空间的映射
    vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出
    if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
                       vma->vm_start,//虚拟空间的起始地址
                       virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
                       vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
                       vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等
    {
        return -EAGAIN;
    }
    return 0;
}

static const struct file_operations myfops={
    .release = myrelease,
    .open = myopen,
    .read = myread,
    .write = mywrite,
   // .unlocked_ioctl = myioctl,
   // .mmap = myled_mmap,

};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
    int ret = 1;
    kbuf = (char *)kmalloc(32, GFP_KERNEL);
    //up: kernel
    //1.registed 把设备对象注册到系统中
    no = MKDEV(MA,MI);//组合主次设备号
    ret = register_chrdev_region(no,count,name);
    if(ret != 0)
    {
        printk("reg is error\n");
        return -1;
    }
    //2.init    设备初始化,抽象出来一个对象
    cdev_init(&mydev,&myfops);
    //3.add     添加设备
    ret = cdev_add(&mydev,no,count);
    if(ret != 0)
    {
        unregister_chrdev_region(no,count);
        return -1;
    }
    //down:hardware
    printk("myinit ok\n");
    //1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
    printk("121212\n");
    irq_map(pdev);
    //2.dev init
   // dev_init();
    return 0;
}
static int myexit(struct platform_device* pdev)
{
    //和内核相关
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("myexit ok\n");
    //和硬件相关
    //1.解除映射
    irq_unmap();
    return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
	{ .compatible = "fs,mykey", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif

static struct platform_driver myled_driver = {
	.driver	= {
		.name    = "mykey",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(myled_of_matches),
	},
	.probe   = myinit,
	.remove  = myexit,
};

module_platform_driver(myled_driver);

//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");

利用按键中断,完成开关灯操作

exynos4412-fs4412---------------> key2 ------------->LED5

驱动程序

/*===============================================
 *   文件名称:mod.c
 *   创 建 者: memories
 *   创建日期:2023年07月06日
 *   描    述:have a nice day
 ================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "cmd.h"
#define MA 301
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static char *kbuf;
struct resource* irqres = NULL;
static int flag = 0;

irqreturn_t handler(int irqno,void *arg)
{
    int ret = 0;
    printk("okokok\n");
    if(flag == 0)
    {
    ret = copy_from_user(mbuf,"on",32); 
    printk("mbuf= %s\n",mbuf);
    if(ret != 0)
        return -1;
    flag = 1;
    }
    else
    {
    ret = copy_from_user(mbuf,"of",32); 
    printk("mbuf= %s\n",mbuf);
    if(ret != 0)
        return -1;
    flag = 0;
    }
    return IRQ_HANDLED;
}

int irq_map(struct platform_device* pdev)
{
    struct resource* irqres = platform_get_resource(pdev,IORESOURCE_IRQ,0);
    int ret = request_irq(irqres->start,handler,irqres->flags,"myirq",NULL);
    if(ret != 0)
        return ret;
    return 0;
}

void irq_unmap(void)
{
    free_irq(irqres->start,NULL);
}

/*
void dev_init(void)
{
    writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
    printk("led on\n");
    writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
    printk("led off\n");
    writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}

*/
int myopen(struct inode *pi,struct file *pf)
{
    return 0;
}

int myrelease(struct inode *pi,struct file *pf)
{
    return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_to_user(ubuf,mbuf,len);
    printk("qudong read\n");
    if(ret != 0)
        return -1;
    printk("now read\n");   
    return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = 0;
    ret = copy_from_user(mbuf,ubuf,len);
    if(ret != 0)
        return -1;
    printk("now write\n");    
    return len;
}
/*
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            led_on();
            break;
        case LED_OFF:
            led_off();
            break;
    };
    return 0;
}
*/

int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
    vma->vm_flags |= VM_IO;//表示对设备IO空间的映射
    vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出
    if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
                       vma->vm_start,//虚拟空间的起始地址
                       virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
                       vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
                       vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等
    {
        return -EAGAIN;
    }
    return 0;
}

static const struct file_operations myfops={
    .release = myrelease,
    .open = myopen,
    .read = myread,
    .write = mywrite,
   // .unlocked_ioctl = myioctl,
   // .mmap = myled_mmap,

};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
    int ret = 1;
    kbuf = (char *)kmalloc(32, GFP_KERNEL);
    //up: kernel
    //1.registed 把设备对象注册到系统中
    no = MKDEV(MA,MI);//组合主次设备号
    ret = register_chrdev_region(no,count,name);
    if(ret != 0)
    {
        printk("reg is error\n");
        return -1;
    }
    //2.init    设备初始化,抽象出来一个对象
    cdev_init(&mydev,&myfops);
    //3.add     添加设备
    ret = cdev_add(&mydev,no,count);
    if(ret != 0)
    {
        unregister_chrdev_region(no,count);
        return -1;
    }
    //down:hardware
    printk("myinit ok\n");
    //1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
    printk("121212\n");
    irq_map(pdev);
    //2.dev init
   // dev_init();
    return 0;
}
static int myexit(struct platform_device* pdev)
{
    //和内核相关
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("myexit ok\n");
    //和硬件相关
    //1.解除映射
    irq_unmap();
    return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
	{ .compatible = "fs,mykey", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif

static struct platform_driver myled_driver = {
	.driver	= {
		.name    = "mykey",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(myled_of_matches),
	},
	.probe   = myinit,
	.remove  = myexit,
};

module_platform_driver(myled_driver);

//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");

应用程序

/*===============================================
 *   文件名称:mainopen.c
 *   创 建 者: memories
 *   创建日期:2023年07月06日
 *   描    述:have a nice day
 ================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include "cmd.h"

int main(int argc, char *argv[])
{ 
    char *start;
    char wbuf[20]="12122122142";
    char rbuf[32]={0};
    int ret = 0;
    int fd1 = 0;
    int fd = open("/dev/mydev",O_RDWR);
    if(fd < 0)
    {
        printf("open failed fd is %d\n",fd);
        return -1;
    }
    while(1)
    {
        printf("yingyong\n");
        sleep(1);
        ret = read(fd,rbuf,32);
        if(ret < 0)
        {
            perror("read");
            return -1;
        }
        printf("rbuf=%s\n",rbuf);
        if(strncmp(rbuf,"on",2) == 0)
        {
            int fd1 = open("/dev/mydev1",O_RDWR);
            if(fd1 < 0)
            {
                printf("open failed fd1 is %d\n",fd1);
                break;
            }
            printf("open led\n");
            ioctl(fd1,LED_ON);
        }
        else if(strncmp(rbuf,"of",2) == 0)
        {
            int fd1 = open("/dev/mydev1",O_RDWR);
            if(fd1 < 0)
            {
                printf("open failed fd1 is %d\n",fd1);
                break;
            }
            printf("close led\n");
            ioctl(fd1,LED_OFF);
        }
        memset(rbuf,0,32);
    }
    close(fd);
    close(fd1);
    return 0;
} 
    return -1;
}
while(1)
{
    printf("yingyong\n");
    sleep(1);
    ret = read(fd,rbuf,32);
    if(ret < 0)
    {
        perror("read");
        return -1;
    }
    printf("rbuf=%s\n",rbuf);
    if(strncmp(rbuf,"on",2) == 0)
    {
        int fd1 = open("/dev/mydev1",O_RDWR);
        if(fd1 < 0)
        {
            printf("open failed fd1 is %d\n",fd1);
            break;
        }
        printf("open led\n");
        ioctl(fd1,LED_ON);
    }
    else if(strncmp(rbuf,"of",2) == 0)
    {
        int fd1 = open("/dev/mydev1",O_RDWR);
        if(fd1 < 0)
        {
            printf("open failed fd1 is %d\n",fd1);
            break;
        }
        printf("close led\n");
        ioctl(fd1,LED_OFF);
    }
    memset(rbuf,0,32);
}
close(fd);
close(fd1);
return 0;

}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/763217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

资产管理简单实用技巧,让你告别加班!

资产管理系统在现代商业环境中扮演着关键的角色。随着企业资产规模的不断扩大和多样化&#xff0c;有效地管理和跟踪资产变得至关重要。 随着企业竞争的加剧和资产管理的重要性日益凸显&#xff0c;资产管理系统将继续在各行各业中发挥着不可或缺的作用。无论是生产设备、办公设…

BottomSheetDialog无法设置圆角的解决问题

1、设置background为透明 <style name"BottomSheetDialog" parent"Theme.Design.Light.BottomSheetDialog"><item name"bottomSheetStyle">style/bottomSheetStyleWrapper</item></style><style name"bottomShe…

Redis的缓存问题

说起Redis的缓存&#xff0c;我们知道前端发出的请求到后端&#xff0c;后端先从Redis中查询&#xff0c;如果查询到了则直接返回&#xff0c;如果Redis中未查询到&#xff0c;就去数据库中查询&#xff0c;如果数据库中存在&#xff0c;则返回结果并且更新到Redis缓存当中&…

西贝柳斯Sibelius2023旗舰版曲谱大师必备音乐软件

乐谱太复杂&#xff0c;打起来太费时间&#xff1f;革命性的省时功能&#xff0c;如磁性布局和动态分谱&#xff0c;能够快速创作复杂的乐谱。音色库太简陋&#xff0c;找起来麻烦&#xff1f;收藏丰富的音色库供您直接使用&#xff0c;涵盖最广泛的专业级乐器&#xff0c;支持…

RK3399/RK3588+pcie+Zynq 多核架构可穿戴设备设计方案

在很多领域&#xff0c;人们对可穿戴设备的可靠性有着非常高的要求。这些使用场景 不仅丰富多样&#xff0c;而且复杂多变。这使得可穿戴设备不仅需要应对应用和系统本身 的状态变化&#xff0c;也要考虑到设备所处环境所带来的异常情况。所以&#xff0c;针对不同安全 等级…

Windows搭建SVN环境

VisualSVN Server下载 https://www.visualsvn.com/products VisualSVN Server安装创建仓库创建项目创建用户创建组项目分配组VisualSVN下载 https://www.visualsvn.com/products VisualSVN安装项目检出项目检出路径&#xff1a;https://changwq:8443/svn/dev/InterfaceManage 项…

【C++初阶】类和对象(上)

文章目录 前言一、类的引入二、类的定义三、类的访问限定符及封装四、类的作用域五、类的实例化六、类对象模型七、this指针 前言 &#x1f4d6;面向过程 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。以…

linux之Ubuntu系列(-)常见指令

Ubuntu 中文 版本 注意点 通过修改语言改成英文 在终端录入&#xff1a;export LANGen_US 在终端录入&#xff1a;xdg-user-dirs-gtk-update 单用户和多用户 命令格式 command [-选项] [参数] –查看命令的帮助 命令 --help man 命令 |操作键| 功能| |空格键|-显示手册的下…

[LINUX]之字符串去掉前后空格

去掉字符串前后空格通过使用awk $1$1命令实现 echo " test " | awk $1$1

Vulnhub: Momentum: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.154 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.154 查看目标80端口的main.js发现信息 feroxbuster -k -d 1 --url http://192.168.111.154 -w /opt/zidian/SecLists-202…

白名单配置

白名单配置 关于如何将github-copilot 相关地址设置到白名单中 domain:githubusercontent.com, domain:example-example.com, domain:example-example2.com 选择配置 绕过白名单 结尾 记录自己点点滴滴&#xff0c;学习总结

二叉树题目:二叉树的最大深度

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树的最大深度 出处&#xff1a;104. 二叉树的最大深度 难度 3 级 题目描述 要求 给定一个二叉树&#xff…

(ceph)CephFS 文件系统 MDS接口

创建 CephFS 文件系统 MDS 接口 //服务端操作 1&#xff09;在管理节点创建 mds 服务 cd /etc/ceph ceph-deploy mds create node01 node02 node032&#xff09;查看各个节点的 mds 服务 ssh rootnode01 systemctl status ceph-mdsnode01 ssh rootnode02 systemctl status cep…

定时器处理非活动连接(五)

1 基础知识 非活跃&#xff0c;是指客户端&#xff08;这里是浏览器&#xff09;与服务器端建立连接后&#xff0c;长时间不交换数据&#xff0c;一直占用服务器端的文件描述符&#xff0c;导致连接资源的浪费。 非活跃&#xff0c;是指固定一段时间之后触发某段代码&#xf…

学习率的选择

学会画图去看学习率是否符合 梯度下降算法收敛所需要的迭代次数根据模型的不同而不同&#xff0c;我们不能提前预知&#xff0c;我们可以绘制迭代次数和代价函数的值的图表来观测算法在何时趋于收敛。 -自动测试方法 也有一些自动测试是否收敛的方法&#xff0c;例如将代价函数…

python_day9_继承

继承 单继承 class Phone:id Noneproducer "HW"def call_4g(self):print("4g通话")class Phone2023(Phone):face_id "1001"def call_45g(self):print("4.5g")phone Phone2023() print(phone.producer) phone.call_4g() phone.ca…

Leetcode-每日一题【109.有序链表转换二叉搜索树】

题目 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为高度平衡的二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。 示例 1: 输入: head [-10,-3,0,5,9]输出: [0,-3,9,-…

【Linux基础】gcc编译器

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…

【IMX6ULL - psplash应用】修改uboot启动阶段的背景颜色

文件路径&#xff1a;psplash/psplash-colors.h 修改框起来的这两个宏定义就可以改变底部颜色了&#xff0c;参数代表是RGB的16进制颜色

Linux 支持 U盘 NTFS 文件系统格式

Linux 支持 U盘 NTFS 文件系统格式 1、在线&#xff08;可以连接外网&#xff09;方式&#xff1a; 1.1、RHEL/CentOS/Anolis/openEuler yum install ntfs-3g1.2、Debian/Ubuntu/Deepin apt install ntfs-3g2、离线方式 下载 ntfs-3g 安装包&#xff0c;离线环境安装 ntfs…