除了platform传地址,其他的跟指定入口地址和指定出口地址没区别
platform和指定入口地址不能同时存在,一直报错模块初始化重定义,半个小时搞完程序没问题,这个重复定义因为代码太多没看懂错误,删了又加没试出来怎么改错。
1.myled.h
cs
#ifndef __MYLED_H__
#define __MYLED_H__
enum{
LED1, //0
LED2, //1
LED3, //2
};
typedef struct {
volatile unsigned int MODER; // 0x00
volatile unsigned int OTYPER; // 0x04
volatile unsigned int OSPEEDR; // 0x08
volatile unsigned int PUPDR; // 0x0C
volatile unsigned int IDR; // 0x10
volatile unsigned int ODR; // 0x14
volatile unsigned int BSRR; // 0x18
volatile unsigned int LCKR; // 0x1C
volatile unsigned int AFRL; // 0x20
volatile unsigned int AFRH; // 0x24
volatile unsigned int BRR; // 0x28
volatile 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
cs
#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].start
int 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
cs
#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
cs
#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;
}