除了platform传地址,其他的跟指定入口地址和指定出口地址没区别
platform和指定入口地址不能同时存在,一直报错模块初始化重定义,半个小时搞完程序没问题,这个重复定义因为代码太多没看懂错误,删了又加没试出来怎么改错。
1.myled.h
#ifndef __MYLED_H__
#define __MYLED_H__enum{LED1, //0LED2, //1LED3, //2
};
typedef struct {volatile unsigned int MODER; // 0x00volatile unsigned int OTYPER; // 0x04volatile unsigned int OSPEEDR; // 0x08volatile unsigned int PUPDR; // 0x0Cvolatile unsigned int IDR; // 0x10 volatile unsigned int ODR; // 0x14volatile unsigned int BSRR; // 0x18volatile unsigned int LCKR; // 0x1C volatile unsigned int AFRL; // 0x20 volatile unsigned int AFRH; // 0x24volatile unsigned int BRR; // 0x28volatile unsigned int res;volatile unsigned int SECCFGR; // 0x30
}gpio_t;#define LED_ON _IOW('a',1,int) //封装灯亮命令码
#define LED_OFF _IOW('a',0,int) //封装灯灭命令码
#define GET_CMD_SIZE(cmd) (cmd >> 16 & 0x3fff) //封装命令码大小#endif
2.pdrv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>struct cdev* cdev;
#if 1
unsigned int major = 0;
#else
unsigned int major = 500;
#endif
unsigned int minor = 0;
unsigned int count = 3;
#define CNAME "myled"
struct class *cls;
struct device *device;unsigned int* rcc_virt = NULL;
gpio_t* gpioe_virt = NULL;
gpio_t* gpiof_virt = NULL;#define LED1_ON (gpioe_virt->ODR |= (0x1 << 10))
#define LED1_OFF (gpioe_virt->ODR &= (~(0x1 << 10)))#define LED2_ON (gpiof_virt->ODR |= (0x1 << 10))
#define LED2_OFF (gpiof_virt->ODR &= (~(0x1 << 10)))#define LED3_ON (gpioe_virt->ODR |= (0x1 << 8))
#define LED3_OFF (gpioe_virt->ODR &= (~(0x1 << 8)))
struct resource* res;#define GPIOE res[0].start
#define RCC_MP_AHB4ENSETR_PHY res[1].startint myled_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("美妙的时光总有尽头\n");return 0;
}long myled_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{int ret;int whitch;switch(cmd) //判断命令码{case LED_ON: //灯亮命令码ret = copy_from_user(&whitch,(void*)args,GET_CMD_SIZE(LED_ON));if(ret){printk("copy from user is error\n");return -EIO;}switch (whitch) //判断哪一盏灯点亮{case LED1:LED1_ON; //LED1点亮break; }break;case LED_OFF: //灯灭命令码ret = copy_from_user(&whitch,(void*)args,GET_CMD_SIZE(LED_OFF));if(ret){printk("copy from user is error\n");return -EIO;}switch (whitch) //判断哪一盏灯熄灭{case LED1:LED1_OFF; //LED1熄灭break; } break;}return 0;
}
int myled_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("还起床了\n");return 0;
}//操作方法结构体
const struct file_operations fops = {.open = myled_open,.unlocked_ioctl = myled_ioctl,.release = myled_close,
};//当设备信息端和设备驱动端匹配成功时,执行probe函数
int pdrv_probe(struct platform_device *pdev)
{int ret;int i;dev_t devno;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("name = %s id = %ld\n",pdev->id_entry->name,pdev->id_entry->driver_data);//获取设备信息端地址信息res = platform_get_resource(pdev,IORESOURCE_MEM,0);if(res == NULL){printk("platform get resource is error\n");return -EIO;}//打印获取到的地址信息 中断号printk("GPIOEaddress = %#x RCCaddress = %#x\n",res[0].start,res[1].start);//分配对象cdev = cdev_alloc(); if(cdev == NULL){printk("cdev alloc is error\n");ret = -ENOMEM;goto ERR1; }//对象初始化cdev_init(cdev,&fops);if(major > 0){ //静态指定设备号ret = register_chrdev_region(MKDEV(major,minor),count,CNAME);if(ret){printk("register chrdev region is error\n");ret = -EIO;goto ERR2; }}else{ //动态指定设备号ret = alloc_chrdev_region(&devno,minor,count,CNAME);if(ret){printk("alloc chrdev region is error\n");ret = -EIO;goto ERR2; }major = MAJOR(devno);//通过设备号,获取到主设备号的值minor = MINOR(devno);//通过设备号,获取到次设备号的值} //注册ret = cdev_add(cdev,MKDEV(major,minor),count); if(ret){printk("cdev add is error\n");ret = -EIO;goto ERR3; }//向上层提交目录信息cls = class_create(THIS_MODULE,CNAME);if(IS_ERR(cls)){ret = PTR_ERR(cls);goto ERR4;}for(i=0;i<count;i++){//向上层提交设备节点信息device = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(device)){ret = PTR_ERR(device);goto ERR5;} }//rcc物理地址映射rcc_virt = ioremap(RCC_MP_AHB4ENSETR_PHY,4);if(rcc_virt == NULL){printk("rcc ioremap is error\n");return -EIO;}//GPIOE组寄存器物理地址映射gpioe_virt = ioremap(GPIOE,sizeof(gpio_t));if(gpioe_virt == NULL){printk("gpioe ioremap is error\n");return -EIO;}//LED1灯初始化 PE10*rcc_virt |= (0x1 << 4); //使能GPIOE组控制器 gpioe_virt->MODER &= (~(0x3 << 20)); //设置PE10引脚为输出模式gpioe_virt->MODER |= (0x1 << 20);gpioe_virt->ODR &= (~(0x1 << 10)); //设置PE10引脚输出低电平return 0; ERR5://创建三个设备节点时,第一个设备节点和第二个设备节点创建成功,第三个设备节点创建失败//需要将第一个设备节点和第二个设备节点创建成功,需要进行释放for(--i;i>=0;i--){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:kfree(cdev);
ERR1:return ret;
}//当任意一方卸载,执行remove函数
int pdrv_remove(struct platform_device *pdev)
{int i = 0;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//取消地址映射iounmap(rcc_virt);iounmap(gpioe_virt);for(i=0;i<count;i++){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);cdev_del(cdev);unregister_chrdev_region(MKDEV(major,minor),count);kfree(cdev);return 0;
}const struct platform_device_id idtable[] = {{"hello1",1},{},/*防止数组越界*/
};//初始化设备驱动端结构体
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name = "hello DC23111", //通过名字进行匹配},.id_table = idtable,
};
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
3.pdev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>//描述设备信息结构体
struct resource res[2] = {[0] = {.start = 0x50006000, //起始地址.end = 0x50006000 + 31, //终止地址.flags = IORESOURCE_MEM, //资源类型},[1] = {.start = 0x50000A28, .end = 0x50000A28 + 31,.flags = IORESOURCE_MEM,},
};
void pdev_release(struct device *dev)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
}
//初始化设备信息端结构体
struct platform_device pdev = {.name = "hello1", //通过名字进行匹配.id = PLATFORM_DEVID_AUTO, //自动分配.dev = {.release = pdev_release,},.num_resources = ARRAY_SIZE(res),.resource = res,
};static int __init demo_init(void)
{//注册设备信息端return platform_device_register(&pdev);
}static void __exit demo_exit(void)
{//注销设备信息端platform_device_unregister(&pdev);
}module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
4.test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "myled.h"int main(int argc, const char *argv[])
{int fd = -1;int whitch;char buf[128] = "";fd = open("/dev/myled0",O_RDWR);if(fd == -1){perror("open is error");return -1;}while(1){whitch = LED1;ioctl(fd,LED_ON,&whitch);sleep(1);ioctl(fd,LED_OFF,&whitch);sleep(1);}close(fd);return 0;
}