驱动函数
.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 0
static 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:hardware
printk("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 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 *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:hardware
printk("myinit ok\n");
//1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
printk("121212\n");
vaddr = ioremap(GPF3CON,4);
vaddr1 = ioremap(GPF3DAT,4);
//2.dev init
writel((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