驱动函数
.read() .write()
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
驱动程序
/*===============================================* 文件名称: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/cdev.h>
#define MA 300
#define MI 0static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};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)
{memcpy(ubuf,mbuf,len);printk("now read\n"); return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{memcpy(mbuf,ubuf,len);printk("%s\n",ubuf);printk("now write\n"); return len;
}
static const struct file_operations myfops={.release = myrelease,.open = myopen,.read = myread,.write = mywrite,};//文件操作集
//2.init/exit fun
static int myinit(void)
{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:hardwareprintk("myinit ok\n");return 0;
}
static int myexit(void)
{cdev_del(&mydev);unregister_chrdev_region(no,count);printk("myexit ok\n");return 0 ;
}
//3.reg kernel
module_init(myinit);
module_exit(myexit);
//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>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;}write(fd,wbuf,5);ret = read(fd,rbuf,5);if(ret < 0){perror("read");return -1;}if(ret == 0){printf("read is finish\n");}printf("%s\n",rbuf);close(fd);return 0;
}
memcpy()
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{memcpy(mbuf,ubuf,len);printk("%s\n",ubuf);printk("now write\n"); return len;
}
其中char __user *ubuf中的ubuf对应应用程序中 write(fd,wbuf,sizeof(wbuf))的wbuf,而不是对应fd中的内容ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{memcpy(ubuf,mbuf,len);printk("now read\n"); return len;
}
其中char __user *ubuf中的ubuf对应应用程序中 read(fd,rbuf,sizeof(rbuf))的rbuf,而不是对应fd中的内容void * memcpy(void * dest, const void *src, size_t n);
copy_to_user(),copy_from_user()
static inline long copy_from_user(void *to,const void __user * from, unsigned long n);
static inline long copy_to_user(void __user *to,const void *from, unsigned long n)
类似于memcopy,但比memcopy快
ioremap() , iounmap()
自定义命令去设置---->设备特有的功能
提前协商好一个命令:
eg:led_on
应用层:ioctl(fd,cmd,..)
驱动:unlocked_ioctl( cmd );if(cmd == led_on)执行led on;void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)void iounmap(volatile void __iomem *addr_in)
writel(),readl()
writel() 往内存映射的 I/O 空间上写数据,wirtel() I/O 上写入 32 位数据 (4字节)。readl() 从内存映射的 I/O 空间读取数据,readl 从 I/O 读取 32 位数据 ( 4 字节 )。
驱动控制LED闪烁
-
用户需求:写一个led的驱动,实现led2的闪烁
-
驱动需求:设备:led2 功能:亮 、灭
-
寄存器操作:
-
原理图: 设备–>pin–>设备控制芯片
驱动需求(led2亮灭) --> 设备需求(gpx1_1高/低电平)
-
芯片手册:设备控制芯片–>寄存器
人 —> 二进制代码 —> CPU芯片 —> 设备控制芯片 —> 寄存器 —> 设备
-
-
编写驱动:
//头文件
//函数实现
//函数注册
//信息描述
驱动函数
/*===============================================* 文件名称: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/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "cmd.h"#define MA 300
#define MI 0static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static int *vaddr={0},*vaddr1={0};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:printk("led on\n");writel(readl(vaddr1)|(0x1<<4),vaddr1);break;case LED_OFF:printk("led off\n");writel(readl(vaddr1)&~(0x1<<4),vaddr1);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(void)
{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:hardwareprintk("myinit ok\n");//1.映射,内核的物理地址转换为虚拟地址paddr-->vaddrprintk("121212\n");vaddr = ioremap(GPF3CON,4);vaddr1 = ioremap(GPF3DAT,4);//2.dev initwritel((readl(vaddr)) & ~(0xf<<16) | (0x1<<16),vaddr);return 0;
}
static int myexit(void)
{//和内核相关cdev_del(&mydev);unregister_chrdev_region(no,count);printk("myexit ok\n");//和硬件相关//1.解除映射iounmap(vaddr);iounmap(vaddr1);return 0 ;
}
//3.reg kernel
module_init(myinit);
module_exit(myexit);
//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>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;}write(fd,wbuf,5);ret = read(fd,rbuf,5);if(ret < 0){perror("read");return -1;}if(ret == 0){printf("read is finish\n");}printf("%s\n",rbuf);close(fd);return 0;
}
/*===============================================
* 文件名称:cmd.h
* 创 建 者: memories
* 创建日期:2023年07月07日
* 描 述:have a nice day
================================================*/
#ifndef __cmd_H_
#define __cmd_H_#define LED_ON _IOW('L',0,int)//某个类型,第几个,转换类型
#define LED_OFF _IOW('L',1,int)
#define GPF3CON 0x114001E0
#define GPF3DAT 0x114001E4#endif