续
平台总线模式,将设备和驱动进行了区分,据说可以优化代码的可移植性
device:实现对设备寄存器的申明
dirver: 则从总线中取数据,取的时候可以检验是否被使用过,取完在去操作
主要就是三个文件
device
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
void beep_release(struct device *dev)
{
printk("beep_release\n");
}
struct resource beep_res[] = {
[0] ={
.start = 0x20AC000,
.end = 0x20AC003,
.flags = IORESOURCE_MEM,
.name = "GPIO5_DR"
},
[1] ={
.start = 0x20AC000 + 0x04,
.end = 0x20AC000 + 0x04 + 0x03,
.flags = IORESOURCE_MEM,
.name = "GPIO5_GDIR"
},
[2] ={
.start = 0x2290014,
.end = 0x2290017,
.flags = IORESOURCE_MEM,
.name = "IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3"
},
[3] ={
.start = 0x20C406C,
.end = 0x20C406C + 0x03,
.flags = IORESOURCE_MEM,
.name = "CCM_CCGR1"
}
};
struct platform_device beep_device =
{
.name = "beep_test",
.id = -1,
.resource = beep_res,
.num_resources = ARRAY_SIZE(beep_res),
.dev ={
.release = beep_release
}
};
//drivers for init
static int device_init(void)
{
printk("device_init \n");
return platform_device_register(&beep_device);
}
//drivers for exit
static void device_exit(void)
{
printk("device_exit \n");
return platform_device_unregister(&beep_device);;
}
module_init(device_init);
module_exit(device_exit);
MODULE_LICENSE("GPL");
driver
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
struct resource *beep_mem;
struct resource *beep_mem_tmp;
struct resource *beep_GDIR;
struct resource *beep_GDIR_tmp;
struct resource *beep_CCM_CCGR1;
struct resource *beep_CCM_CCGR1_tmp;
struct resource *beep_IOMUXC;
struct resource *beep_IOMUXC_tmp;
static volatile unsigned int *GPIO5_DR ;
static volatile unsigned int *GPIO5_GDIR ;
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 ;
static volatile unsigned int *CCM_CCGR1 ;
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
};
int beep_probe (struct platform_device *pdev)
{
int ret = 0;
unsigned int val;
printk("beep_probe \n");
//方案1,直接读取device中的数据
//printk ("beep_res is %s\n", pdev->resource[0].name);
//方案2 使用函数去读取
beep_mem = platform_get_resource (pdev,IORESOURCE_MEM,0);
if(beep_mem == NULL){
printk("platform_get_resource null \n");
return -EBUSY;
}
beep_GDIR = platform_get_resource (pdev,IORESOURCE_MEM,1);
if(beep_GDIR == NULL){
printk("platform_get_resource beep_GDIR null\n");
return -EBUSY;
}
beep_IOMUXC = platform_get_resource (pdev,IORESOURCE_MEM,2);
if(beep_IOMUXC == NULL){
printk("platform_get_resource beep_IOMUXC null\n");
return -EBUSY;
}
beep_CCM_CCGR1 = platform_get_resource (pdev,IORESOURCE_MEM,3);
if(beep_CCM_CCGR1 == NULL){
printk("platform_get_resource beep_IOMUXC null\n");
return -EBUSY;
}
/***********************************************************************/
printk(" platform_get_resource is ok \n");
printk(" beep_res start is 0x%x \n",beep_mem->start);
printk(" beep_res end is 0x%x \n",beep_mem->end);
// //有用过则会声明失败
// beep_mem_tmp = request_mem_region(beep_mem->start,beep_mem->end-beep_mem->start+1,"beep");
// if( beep_mem_tmp == NULL){
// printk("request_mem_region is error \n");
// goto err_region;
// }
// beep_GDIR_tmp = request_mem_region(beep_mem->start,beep_mem->end-beep_mem->start+1,"beep_GPIO5_GDIR");
// if( beep_GDIR_tmp == NULL){
// printk("request_mem_region is error \n");
// goto err_region;
// }
// beep_CCM_CCGR1_tmp = request_mem_region(beep_mem->start,beep_mem->end-beep_mem->start+1,"beep_CCM_CCGR1");
// if( beep_CCM_CCGR1_tmp == NULL){
// printk("request_mem_region is error \n");
// goto err_region;
// }
// beep_IOMUXC_tmp = request_mem_region(beep_mem->start,beep_mem->end-beep_mem->start+1,"beep_IOMUXC");
// if( beep_IOMUXC_tmp == NULL){
// printk("request_mem_region is error \n");
// goto err_region;
// }
/***********************************************************************/
GPIO5_DR = ioremap(beep_mem->start,4);
if(GPIO5_DR == NULL)
{
printk("GPIO5_DR is error \n");
return -EBUSY;
}
printk("GPIO5_DR ioremap OK \n");
GPIO5_GDIR = ioremap(beep_GDIR->start,4);
if(GPIO5_GDIR == NULL)
{
printk("GPIO5_GDIR is error \n");
return -EBUSY;
}
printk("GPIO5_GDIR ioremap OK \n");
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(beep_IOMUXC->start,4);
if(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 == NULL)
{
printk("IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 is error \n");
return -EBUSY;
}
printk("IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 ioremap OK \n");
CCM_CCGR1 = ioremap(beep_CCM_CCGR1->start,4);
if(CCM_CCGR1 == NULL)
{
printk("CCM_CCGR1 is error \n");
return -EBUSY;
}
printk("CCM_CCGR1 ioremap OK \n");
*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);
/***********************************************************************/
ret = misc_register(&misc_dev);
if(ret<0){
printk("misc_register is error \n");
return -1;
}
printk("misc registe is successed \n");
return 0;
// err_region:
// release_mem_region(beep_mem->start,beep_mem->end - beep_mem->start + 1);
// return -EBUSY;
}
int beep_remove (struct platform_device *pdev)
{
printk("beep_remove \n");
return 0;
}
const struct platform_device_id beep_id_table= {
.name = "beep_test",
};
struct platform_driver beep_device =
{
/* data */
.probe = beep_probe,
.remove = beep_remove,
.driver = {
.owner = THIS_MODULE,
.name = "123"
},
.id_table = &beep_id_table
};
//drivers for init
static int beep_driver_init(void)
{
int ret = 0;
ret = platform_driver_register(&beep_device);
if(ret < 0){
printk("platform_driver_register ERROR \n");
return ret;
}
printk("platform_driver_register OK\n");
return 0;
}
//drivers for exit
static void beep_driver_exit(void)
{
printk("beep_driver_exit exit \n");
platform_driver_unregister(&beep_device);
misc_deregister(&misc_dev);
iounmap(CCM_CCGR1);
iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
iounmap(GPIO5_GDIR);
iounmap(GPIO5_DR);
}
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");
app
#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;
}
操作指令
编译app代码
arm-buildroot-linux-gnueabihf-gcc -o app app.c
移动文件
cp misc.ko /home/book/nfs_rootfs/
允许printk
echo "7 4 1 7"> /proc/sys/kernel/printk
输入值到app中
./app 1
PS :待修正
文中使用了request_mem_region代码的位置,可能由于已经在系统中声明过,所以会出现报错的问题,后面需要寻找方式去消除
beep_mem_tmp = request_mem_region(beep_mem->start,beep_mem->end-beep_mem->start+1,"beep");
if( beep_mem_tmp == NULL){
printk("request_mem_region is error \n");
goto err_region;
}