【Linux】【驱动】第一个相对完整的驱动编写
- 续
- 1.驱动部分的代码
- 2 app 代码
- 3 操作相关的代码
续
这个章节会讲述去直接控制一个GPIO,高低电平。
因为linux不允许直接去操作寄存器,所以在操作寄存器的时候就需要使用到函数:ioremap 和iounmap
来作为寄存器的声明和注销
ioremap 做为地址的声明,如下图使用
CCM_CCGR1 = ioremap(0x20C406C, 4);
iounmap 作为取消声明。
iounmap(CCM_CCGR1);
1.驱动部分的代码
- 在函数的前面对寄存器的名称进行了说明,
- misc_init 中实现对GPIO的配置, 使能 GPIO5,设置 GPIO5_IO03 用于 GPIO,设置 GPIO5_IO03 作为 output 引脚
- 在misc_write 中实现了对GPIO的控制
PS:此代码还有一些不完善的地方,所以在实际的使用中可能会出现一些异常,带之后改正
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
unsigned int *vir_gpio5_dr ;
static volatile unsigned int *CCM_CCGR1 ;
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
static volatile unsigned int *GPIO5_GDIR ;
static volatile unsigned int *GPIO5_DR ;
int misc_open(struct inode *inode, struct file *file)
{
printk("misc_open\n");
return 0;
}
int misc_release(struct inode *inode, struct file *file)
{
printk("misc_release\n");
return 0;
}
ssize_t misc_read(struct file *file,char __user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[512] = "haha";
if(copy_to_user(ubuf,kbuf,strlen(kbuf))!=0)
{
printk("error copying\n");
return -1;
}
return 0;
}
ssize_t misc_write(struct file *file,const char __user *ubuf,size_t size,loff_t *loff_t)
{
char kbuf[512] = {0};
if(copy_from_user(kbuf,ubuf,size)!= 0)
{
printk("misc_write error\n");
return -1;
}
printk("kbuf = %d\n",kbuf[0]);
if(kbuf[0] == 1)
{
*GPIO5_DR |=(1<<3);//设置GPIO
printk(" kbuff = 1\n");
}
else if(kbuf[0] == 0)
{
*GPIO5_DR &= ~(1<<3);//设置GPIO
printk(" kbuff = 0\n");
}
return 0;
}
struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write
};
struct miscdevice misc_dev =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "hello_misc",
.fops = &misc_fops
};
//drivers for init
static int misc_init(void)
{
unsigned int val;
int ret = 0;
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc_register is failed\n");
return -1;
}
printk("misc registe is succeed \n");
//vir_gpio5_dr = ioremap(GPIO5_DR,4);
CCM_CCGR1 = ioremap(0x20C406C, 4);
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4);
GPIO5_GDIR = ioremap(0x020AC000 + 0x4, 4);
GPIO5_DR = ioremap(0x020AC000 + 0, 4);
*CCM_CCGR1 |= (3<<30);//使能 GPIO5
//设置 GPIO5_IO03 用于 GPIO
val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
val &= ~(0xf);
val |= (5);
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
//设置 GPIO5_IO03 作为 output 引脚
*GPIO5_GDIR |= (1<<3);
/*
if(vir_gpio5_dr==NULL)
{
printk("vir_gpio5_dr ioremap error ");
return -EBUSY;
}*/
printk("GPIO5_DR ioremap ok\n");
return 0;
}
//drivers for exit
static void misc_exit(void)
{
//
misc_deregister(&misc_dev);
iounmap(CCM_CCGR1);
iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
iounmap(GPIO5_GDIR);
iounmap(GPIO5_DR);
printk("misc exit \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
2 app 代码
- 通过atoi 函数实现对命令框指令的读写,
- 通过write来是线对buf数字的传递
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int fd;
char buf[64] = {0};
//fd = open(argv[1], O_RDONLY);
fd = open("/dev/hello_misc", O_RDWR);
if(fd < 0)
{
perror("open error");
return fd;
}
buf[0] = atoi(argv[1]);
write(fd,buf,sizeof(buf));
close(fd);
return 0;
}
3 操作相关的代码
编译app 代码
arm-buildroot-linux-gnueabihf-gcc -o miscApp miscApp.c
编译驱动代码
make
清除驱动代码
make clean
挂载nfs
mount -t nfs -o nolock,vers=3 192.168.5.15:/home/book/nfs_rootfs /mnt
删除文件
rm -f + chrdevbase.ko
传递文件,将misc.ko 传到 /home/book/nfs_rootfs/
cp misc.ko /home/book/nfs_rootfs/
允许PrintK
echo "7 4 1 7"> /proc/sys/kernel/printk
安装驱动
insmod misc.ko
列出驱动列表
lsmod
移除驱动
rmmod misc
给驱动传递数据1
./miscApp 1