目录
copy_from_user改为用ioctl接口
将以前的beep杂项设备中的copy_from_user改为用ioctl接口,修改的代码是 linux驱动:(8)实战:用杂项设备完成蜂鸣器驱动 中的代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define GPIO5_DR 0x020AC00
unsigned int *vir_gpio5_dr;
int misc_open(struct inode * inode,struct file * file)
{
printk("hello misc_open\n");
return 0;
}
int misc_read(struct file *file,char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = "heheh";
if( copy_to_user(ubuf,kbuf,strlen(kbuf))!=0)
{
printk("copy_to_user error\n");
return -1;
}
return 0;
}
int misc_write(struct file *file,const char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = {0};
if( copy_from_user(kbuf,ubuf,size)!=0)
{
printk("copy_from_user error\n");
return -1;
}
printk("kbuf is %s\n",kbuf);
if(kbuf[0]==1)
{
*vir_gpio5_dr |= (1<<1);
}
else if
{
*vir_gpio5_dr &= ~(1<<1);
}
return 0;
}
struct const file_operation misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.write= misc_write,
.read = misc_read
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,//动态分配
.name ="hellomisc",//设备节点名字
.fops =&misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error\n");
return -1;
}
vir_gpio5_dr = ioremap(GPIO5_DR,4);
if(vir_gpio5_dr ==NULL)
{
printk("GPIO5_DR ioremap error\n");
return -EBUSY;
}
printk("GPIO5_DR ioremap ok\n");
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
iounmap(vir_gpio5_dr );
printk("misc goodbye");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
修改为ioctl读取无参数命令
- 先把关于GPIO5_DR 的部分删掉
- 编写测试.c,定义发送两个无参数命令
- ioctl函数中的参数对应驱动中的函数中的参数
- 在驱动.c中也要定义两个一样的无参数命令
- 在文件操作集中定义unlocked_ioctl函数
- 在函数中判断cmd命令是否等于我们自己定义的两个命令
测试.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IO('L',0)
#define CMD_TEST1 _IO('L',1)
int main(int argc,char *argv[])
{
int fd;
// 读取设备节点
fd = open("/dev/hello_misc",O_RDWR);
if (fd < 0)
{
perror("open error\n");
return fd;
}
while (1)
{
ioctl(fd,CMD_TEST0);
sleep(2);
ioctl(fd,CMD_TEST1);
sleep(2);
}
return 0;
}
驱动.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IO('L',0)
#define CMD_TEST1 _IO('L',1)
int misc_open(struct inode * inode,struct file * file)
{
printk("hello misc_open\n");
return 0;
}
int misc_read(struct file *file,char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = "heheh";
if( copy_to_user(ubuf,kbuf,strlen(kbuf))!=0)
{
printk("copy_to_user error\n");
return -1;
}
return 0;
}
int misc_write(struct file *file,const char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = {0};
if( copy_from_user(kbuf,ubuf,size)!=0)
{
printk("copy_from_user error\n");
return -1;
}
printk("kbuf is %s\n",kbuf);
return 0;
}
long misc_ioctl(struct file *file,unsigned int cmd, unsigned long value)
{
switch (cmd)
{
case CMD_TEST0:
printk("led on\n");
break;
case CMD_TEST1:
printk("led off\n");
break;
default:
break;
}
return 0;
}
struct const file_operation misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.write= misc_write,
.unlocked_ioctl= misc_ioctl,
.read = misc_read
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,//动态分配
.name ="hellomisc",//设备节点名字
.fops =&misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error\n");
return -1;
}
vir_gpio5_dr = ioremap(GPIO5_DR,4);
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc goodbye");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
效果
- 编译成模块,烧录到开发板中,加载驱动,运行测试.c
- 每隔两秒打印led on或者led off
修改为ioctl读取有参数命令
- 先把关于GPIO5_DR 的部分删掉
- 编写测试.c,定义发送两个有参数命令
- ioctl函数中的参数对应驱动中的函数中的参数
- 在驱动.c中也要定义两个一样的有参数命令
- 在文件操作集中定义unlocked_ioctl函数
- 在函数中判断cmd命令是否等于我们自己定义的两个命令
测试.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IOW('L',0,int)
#define CMD_TEST1 _IOW('L',1,int)
int main(int argc,char *argv[])
{
int fd;
// 读取设备节点
fd = open("/dev/hello_misc",O_RDWR);
if (fd < 0)
{
perror("open error\n");
return fd;
}
while (1)
{
ioctl(fd,CMD_TEST0,1);
sleep(2);
ioctl(fd,CMD_TEST1,0);
sleep(2);
}
return 0;
}
驱动.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IOW('L',0,int)
#define CMD_TEST1 _IOW('L',1,int)
int misc_open(struct inode * inode,struct file * file)
{
printk("hello misc_open\n");
return 0;
}
int misc_read(struct file *file,char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = "heheh";
if( copy_to_user(ubuf,kbuf,strlen(kbuf))!=0)
{
printk("copy_to_user error\n");
return -1;
}
return 0;
}
int misc_write(struct file *file,const char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = {0};
if( copy_from_user(kbuf,ubuf,size)!=0)
{
printk("copy_from_user error\n");
return -1;
}
printk("kbuf is %s\n",kbuf);
return 0;
}
long misc_ioctl(struct file *file,unsigned int cmd, unsigned long value)
{
switch (cmd)
{
case CMD_TEST0:
printk("led on\n");
printk("value is %d\n",value);
break;
case CMD_TEST1:
printk("led off\n");
printk("value is %d\n",value);
break;
default:
break;
}
return 0;
}
struct const file_operation misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.write= misc_write,
.unlocked_ioctl= misc_ioctl,
.read = misc_read
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,//动态分配
.name ="hellomisc",//设备节点名字
.fops =&misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error\n");
return -1;
}
vir_gpio5_dr = ioremap(GPIO5_DR,4);
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc goodbye");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
效果
- 编译成模块,烧录到开发板中,加载驱动,运行测试.c
- 每隔两秒打印led on或者led off,并会打印出value的值(0和1)
修改为ioctl发送有参数命令
- 先把关于GPIO5_DR 的部分删掉
- 编写测试.c,定义接收一个有参数命令
- ioctl函数中的参数对应驱动中的函数中的参数
- 在驱动.c中也要定义一个一样的有参数命令
- 在文件操作集中定义unlocked_ioctl函数
- 在函数中判断cmd命令是否等于我们自己定义的一个命令,是就通过copy_to_user进行发送
测试.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IOR('L',0,int)
int main(int argc,char *argv[])
{
int fd;
int value;
// 读取设备节点
fd = open("/dev/hello_misc",O_RDWR);
if (fd < 0)
{
perror("open error\n");
return fd;
}
while (1)
{
ioctl(fd,CMD_TEST0,&value);
printf("value is %d\n",value);
sleep(2);
}
return 0;
}
驱动.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IOR('L',0,int)
int misc_open(struct inode * inode,struct file * file)
{
printk("hello misc_open\n");
return 0;
}
int misc_read(struct file *file,char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = "heheh";
if( copy_to_user(ubuf,kbuf,strlen(kbuf))!=0)
{
printk("copy_to_user error\n");
return -1;
}
return 0;
}
int misc_write(struct file *file,const char _user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[64] = {0};
if( copy_from_user(kbuf,ubuf,size)!=0)
{
printk("copy_from_user error\n");
return -1;
}
printk("kbuf is %s\n",kbuf);
return 0;
}
long misc_ioctl(struct file *file,unsigned int cmd, unsigned long value)
{
int val;
switch (cmd)
{
case CMD_TEST0:
val = 12 ;
if( copy_to_user((int *)value,&val,sizeof(val))!=0)
{
printk("copy_to_user error\n");
return -1;
}
break;
default:
break;
}
return 0;
}
struct const file_operation misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.write= misc_write,
.unlocked_ioctl= misc_ioctl,
.read = misc_read
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,//动态分配
.name ="hellomisc",//设备节点名字
.fops =&misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error\n");
return -1;
}
vir_gpio5_dr = ioremap(GPIO5_DR,4);
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc goodbye");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
效果
- 编译成模块,烧录到开发板中,加载驱动,运行测试.c
- 每隔两秒打印驱动传出来的value值12