fl2440 plat_button.c驱动学习

本文档详细介绍了fl2440平台的plat_button.c驱动代码,包括按钮硬件信息结构、驱动的平台数据、中断处理、定时器处理函数等关键部分,展示了如何为S3C24XX系列的按键建立中断驱动。
这次学习了fl2440驱动代码,本代码比较复杂,在此逐一分析,各函数实现功能作为回顾。
#include "s3c_driver.h"

#define DRV_AUTHOR                "Guo Wenxue <guowenxue@gmail.com>"
#define DRV_DESC                  "S3C24XX button driver"

/* Driver version*/
#define DRV_MAJOR_VER             1
#define DRV_MINOR_VER             0
#define DRV_REVER_VER             0

#define DEV_NAME                  DEV_BUTTON_NAME

//#define DEV_MAJOR               DEV_BUTTON_MAJOR
#ifndef DEV_MAJOR
#define DEV_MAJOR                 0 /* dynamic major by default */
#endif

#define BUTTON_UP                 0 /* Button status is up */
#define BUTTON_DOWN               1 /* Button status is pushed down */
#define BUTTON_UNCERTAIN          2 /* Button status uncerntain */

#define TIMER_DELAY_DOWN          (HZ/50)   /*Remove button push down dithering timer delay 20ms  */
#define TIMER_DELAY_UP            (HZ/10)   /*Remove button up dithering timer delay 100ms  */

static int debug = DISABLE;
static int dev_major = DEV_MAJOR;
static int dev_minor = 0;


/*============================ Platform Device part ===============================*/
/* Button hardware informtation structure*/
struct s3c_button_info
{
    unsigned char           num;       /*Button nubmer  */
    char *                  name;      /*Button nubmer  */
    int                     nIRQ;      /*Button IRQ number*/
    unsigned int            setting;   /*Button IRQ Pin Setting*/
    unsigned int            gpio;      /*Button GPIO port */
};

/* The button plaotform device private data structure */
struct s3c_button_platform_data
{
    struct s3c_button_info *buttons;
    int                     nbuttons;
};

/* Button hardware informtation data*/
static struct s3c_button_info  s3c_buttons[] = {
    [0] = {
        .num = 1,
        .name = "KEY1",
        .nIRQ = IRQ_EINT0,
        .gpio = S3C2410_GPF(0),
        .setting = S3C2410_GPF0_EINT0,
    },
    [1] = {
        .num = 2,
        .name = "KEY2",
        .nIRQ = IRQ_EINT2,
        .gpio = S3C2410_GPF(2),
        .setting = S3C2410_GPF2_EINT2,
    },
    [2] = {
        .num = 3,
        .name = "KEY3",
        .nIRQ = IRQ_EINT3,
        .gpio = S3C2410_GPF(3),
        .setting = S3C2410_GPF3_EINT3,
    },
    [3] = {
        .num = 4,
        .name = "KEY4",
        .nIRQ = IRQ_EINT4,
        .gpio = S3C2410_GPF(4),
        .setting = S3C2410_GPF4_EINT4,
    },
};

/* The button platform device private data */
static struct s3c_button_platform_data s3c_button_data = {
    .buttons = s3c_buttons,
    .nbuttons = ARRAY_SIZE(s3c_buttons), //ARRAY_SIZE是个宏,读取数组成员的个数
};

struct button_device
{
    unsigned char                      *status;      /* The buttons Push down or up status */
    struct s3c_button_platform_data    *data;        /* The buttons hardware information data */

    struct timer_list                  *timers;      /* The buttons remove dithering timers */
    wait_queue_head_t                  waitq;           /* Wait queue for poll()  */
    volatile int                       ev_press;     /* Button pressed event */

    struct cdev                        cdev;           
    struct class                       *dev_class; 
} button_device;

static void platform_button_release(struct device * dev)
{
    return; 
}

static struct platform_device s3c_button_device = {         //s3c_button_device最终设备的信息被保存在这个结构体。然后传递给register函数。
    .name    = "s3c_kbd",
    .id      = 1,
    .dev     = 
    {
        .platform_data = &s3c_button_data, 
        .release = platform_button_release,
    },
};

static irqreturn_t s3c_button_intterupt(int irq,void *de_id)  //配置中断
{
    int i;
    int found = 0;
    struct s3c_button_platform_data *pdata = button_device.data;

    for(i=0; i<pdata->nbuttons; i++)
    {
        if(irq == pdata->buttons[i].nIRQ)   //用一个for循环检查中断号是哪一个管脚
        {
            found = 1; 
            break;
        }
    }

    if(!found) /* An ERROR interrupt  */
        return IRQ_NONE; //没有发生中断,此时cpu执行别的进程,IPQ_NONE是内核定义的,表示执行别的进程
    /* Only when button is up then we will handle this event */
    if(BUTTON_UP  == button_device.status[i])  //当按键状态是抬起
    {
       button_device.status[i] = BUTTON_UNCERTAIN; //把按键状态设置为不确定的某种状态
       mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);  //把计时器往后设置一个TIMER_DELAY_DOWN
    }    //这一段是让按下的按键在程序上可以抬起,

    return IRQ_HANDLED;  //检测到中断发生时,cpu执行我们需要中断做的进程
}


static void button_timer_handler(unsigned long data)  
{
    struct s3c_button_platform_data *pdata = button_device.data;
    int num =(int)data;
    int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio );

    if(LOWLEVEL == status)    //按键按下
    {
        if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */
        {
            //dbg_print("Key pressed!\n");
            button_device.status[num] = BUTTON_DOWN;

            printk("%s pressed.\n", pdata->buttons[num].name);

            /* Wake up the wait queue for read()/poll() */
            button_device.ev_press = 1;
            wake_up_interruptible(&(button_device.waitq));    //唤醒等待队列,把等待的进程继续执行下去
        }

        /* Cancel the dithering  */
        mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);  消抖,用计时器的方式,隔一个TIMER_DELAY_UP检测电平
    }
    else
    {
        //dbg_print("Key Released!\n");
        button_device.status[num] = BUTTON_UP;
     //   enable_irq(pdata->buttons[num].nIRQ);
    }

    return ;
}


/*===================== Button device driver part ===========================*/

static int button_open(struct inode *inode, struct file *file)
{ 
    struct button_device *pdev ;
    struct s3c_button_platform_data *pdata;
    int i, result;

    pdev = container_of(inode->i_cdev,struct button_device, cdev);
    pdata = pdev->data;
    file->private_data = pdev;

    /* Malloc for all the buttons remove dithering timer */
    pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL);
    if(NULL == pdev->timers)
    {
        printk("Alloc %s driver for timers failure.\n", DEV_NAME);
        return -ENOMEM;
    }
    memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list));

    /* Malloc for all the buttons status buffer */
    pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL);
    if(NULL == pdev->status)
    {
        printk("Alloc %s driver for status failure.\n", DEV_NAME);
        result = -ENOMEM; 
        goto  ERROR;
    }
    memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char));

    init_waitqueue_head(&(pdev->waitq));

    for(i=0; i<pdata->nbuttons; i++) 
    {
        /* Initialize all the buttons status to UP  */
        pdev->status[i] = BUTTON_UP; 

        /* Initialize all the buttons' remove dithering timer */
        setup_timer(&(pdev->timers[i]), button_timer_handler, i);   //消抖,第二个参数上面有解释

        /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */
        s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);  //设置gpio管脚
        irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING); //设置中断类型,这里是下降沿中断

        /* Request for button GPIO pin interrupt  */
        result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);
        if( result )             //上面是注册中断函数,第一个参数中断号,第二个参数中断处理函数
    
        {
            result = -EBUSY;
            goto ERROR1;
        }
    }

    return 0;

ERROR1:
     kfree((unsigned char *)pdev->status);
     while(--i) 
     { 
         disable_irq(pdata->buttons[i].nIRQ); 
         free_irq(pdata->buttons[i].nIRQ, (void *)i); 
     }

ERROR:
     kfree(pdev->timers);

     return result;
}

static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{ 
    struct button_device *pdev = file->private_data;
    struct s3c_button_platform_data *pdata;
    int   i, ret;
    unsigned int status = 0;

    pdata = pdev->data;

    dbg_print("ev_press: %d\n", pdev->ev_press);
    if(!pdev->ev_press)
    {
         if(file->f_flags & O_NONBLOCK)
         {
             dbg_print("read() without block mode.\n");
             return -EAGAIN;
         }
         else
         {
             /* Read() will be blocked here */
             dbg_print("read() blocked here now.\n");
             wait_event_interruptible(pdev->waitq, pdev->ev_press);
         }
    }

    pdev->ev_press = 0;

    for(i=0; i<pdata->nbuttons; i++)  //pdata->nbuttons是4
    {
        dbg_print("button[%d] status=%d\n", i, pdev->status[i]);
        status |= (pdev->status[i]<<i); //这里是用某个按键的状态(o|1)pdev->status[i]来配置status的某一位,可以理解位status的4个低位分别代表按键状态
    }

    ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count));

    return ret ? -EFAULT : min(sizeof(status), count);
}

static unsigned int button_poll(struct file *file, poll_table * wait)  //poll函数为中断提供监听,检测事件是否发生,如果发生执行什么程序。
{ 
    struct button_device *pdev = file->private_data;
    unsigned int mask = 0;

    poll_wait(file, &(pdev->waitq), wait);
    if(pdev->ev_press)
    {
        mask |= POLLIN | POLLRDNORM; /* The data aviable */ 
    }

    return mask;
}

static int button_release(struct inode *inode, struct file *file)
{ 
    int i;
    struct button_device *pdev = file->private_data;
    struct s3c_button_platform_data *pdata;
    pdata = pdev->data;

    for(i=0; i<pdata->nbuttons; i++) 
    {
        disable_irq(pdata->buttons[i].nIRQ);
        free_irq(pdata->buttons[i].nIRQ, (void *)i);
        del_timer(&(pdev->timers[i]));
    }

    kfree(pdev->timers);
    kfree((unsigned char *)pdev->status);

    return 0;
}


static struct file_operations button_fops = {  //file operations集合了设备的操作方式
  
   .owner = THIS_MODULE,
    .open = button_open,       //系统调用open
    .read = button_read,             //系统调用read     
    .poll = button_poll,            
    .release = button_release,      //系统调用close


};


static int s3c_button_probe(struct platform_device *dev) //设备和驱动向内核注注册完成后(先注册设备再注册驱动),内核检索通过设备和驱动的.name域把设备
{                            //和驱动二者匹配起来。然后再由probe函数进行给设备分配主次设备号,完成设备初始化,把设备添加到内核
    int result = 0;
    dev_t devno;


    /* Alloc the device for driver  */ 
    if (0 != dev_major) 
    { 
        devno = MKDEV(dev_major, dev_minor); 
        result = register_chrdev_region(devno, 1, DEV_NAME); 
    } 
    else 
    { 
        result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME); 
        dev_major = MAJOR(devno); 
    }

    /* Alloc for device major failure */
    if (result < 0) 
    { 
        printk("%s driver can't get major %d\n", DEV_NAME, dev_major); 
        return result; 
    }

    /*  Initialize button_device structure and register cdev*/
     memset(&button_device, 0, sizeof(button_device));
     button_device.data = dev->dev.platform_data;
     cdev_init (&(button_device.cdev), &button_fops);
     button_device.cdev.owner  = THIS_MODULE;

     result = cdev_add (&(button_device.cdev), devno , 1); 
     if (result) 
     { 
         printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME); 
         goto ERROR; 
     }

     button_device.dev_class = class_create(THIS_MODULE, DEV_NAME); 
     if(IS_ERR(button_device.dev_class)) 
     { 
         printk("%s driver create class failture\n",DEV_NAME); 
         result =  -ENOMEM; 
         goto ERROR; 
     }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)     
     device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);
#else
     device_create (button_device.dev_class, NULL, devno, DEV_NAME);
#endif

     printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);

     return 0;

ERROR: 
     printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
     cdev_del(&(button_device.cdev)); 
     unregister_chrdev_region(devno, 1);
     return result;
}


static int s3c_button_remove(struct platform_device *dev)
{
    dev_t devno = MKDEV(dev_major, dev_minor);

    cdev_del(&(button_device.cdev));
    device_destroy(button_device.dev_class, devno);
    class_destroy(button_device.dev_class);

    unregister_chrdev_region(devno, 1); 
    printk("S3C %s driver removed\n", DEV_NAME);

    return 0;
}


/*===================== Platform Device and driver regist part ===========================*/

static struct platform_driver s3c_button_driver = { 
    .probe      = s3c_button_probe, 
    .remove     = s3c_button_remove, 
    .driver     = { 
        .name       = "s3c_kbd", 
        .owner      = THIS_MODULE, 
    },
};


static int __init s3c_button_init(void) //2.在进入module_init函数后,通过此函数分别进行设备注册和驱动注册。                        
{
   int       ret = 0;

   ret = platform_device_register(&s3c_button_device); //paltform_device_register函数是内核定义的函数,通过此函数向内核注册设备。同理驱动注册一样

   if(ret)
   {
        printk(KERN_ERR "%s: Can't register platform device %d\n", __FUNCTION__, ret); 
        goto fail_reg_plat_dev;
   }
   dbg_print("Regist S3C %s Device successfully.\n", DEV_NAME);

   ret = platform_driver_register(&s3c_button_driver);
   if(ret)
   {
        printk(KERN_ERR "%s: Can't register platform driver %d\n", __FUNCTION__, ret); 
        goto fail_reg_plat_drv;
   }
   dbg_print("Regist S3C %s Driver successfully.\n", DEV_NAME);

   return 0;

fail_reg_plat_drv:
   platform_driver_unregister(&s3c_button_driver);
fail_reg_plat_dev:
   return ret;
}


static void s3c_button_exit(void)
{
    platform_driver_unregister(&s3c_button_driver);
    dbg_print("S3C %s platform device removed.\n", DEV_NAME);

    platform_device_unregister(&s3c_button_device);
    dbg_print("S3C %s platform driver removed.\n", DEV_NAME);
}

module_init(s3c_button_init);   //1.此函数,驱动入口函数,在insmod驱动时,首先调用这个函数。
module_exit(s3c_button_exit);

module_param(debug, int, S_IRUGO);
module_param(dev_major, int, S_IRUGO);
module_param(dev_minor, int, S_IRUGO);

MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:S3C24XX_button");
以上是对驱动各函数功能的分析,但是部分函数只是自己的理解,不一定完全正确,作为一个初学者,很多内核定义的函数功能不懂,
因为对很多函数的功能不了解,因此仅仅作为参考使用。



                
【事件触发一致性】研究多智能体网络如何通过分布式事件驱动控制实现有限时间内的共识(Matlab代码实现)内容概要:本文围绕多智能体网络中的事件触发一致性问题,研究如何通过分布式事件驱动控制实现有限时间内的共识,并提供了相应的Matlab代码实现方案。文中探讨了事件触发机制在降低通信负担、提升系统效率方面的优势,重点分析了多智能体系统在有限时间收敛的一致性控制策略,涉及系统模型构建、触发条件设计、稳定性与收敛性分析等核心技术环节。此外,文档还展示了该技术在航空航天、电力系统、机器人协同、无人机编队等多个前沿领域的潜在应用,体现了其跨学科的研究价值和工程实用性。; 适合人群:具备一定控制理论基础和Matlab编程能力的研究生、科研人员及从事自动化、智能系统、多智能体协同控制等相关领域的工程技术人员。; 使用场景及目标:①用于理解和实现多智能体系统在有限时间内达成一致的分布式控制方法;②为事件触发控制、分布式优化、协同控制等课题提供算法设计与仿真验证的技术参考;③支撑科研项目开发、学术论文复现及工程原型系统搭建; 阅读建议:建议结合文中提供的Matlab代码进行实践操作,重点关注事件触发条件的设计逻辑与系统收敛性证明之间的关系,同时可延伸至其他应用场景进行二次开发与性能优化。
【四旋翼无人机】具备螺旋桨倾斜机构的全驱动四旋翼无人机:建模与控制研究(Matlab代码、Simulink仿真实现)内容概要:本文围绕具备螺旋桨倾斜机构的全驱动四旋翼无人机展开,重点研究其动力学建模与控制系统设计。通过Matlab代码与Simulink仿真实现,详细阐述了该类无人机的运动学与动力学模型构建过程,分析了螺旋桨倾斜机构如何提升无人机的全向机动能力与姿态控制性能,并设计相应的控制策略以实现稳定飞行与精确轨迹跟踪。文中涵盖了从系统建模、控制器设计到仿真验证的完整流程,突出了全驱动结构相较于传统四旋翼在欠驱动问题上的优势。; 适合人群:具备一定控制理论基础和Matlab/Simulink使用经验的自动化、航空航天及相关专业的研究生、科研人员或无人机开发工程师。; 使用场景及目标:①学习驱动四旋翼无人机的动力学建模方法;②掌握基于Matlab/Simulink的无人机控制系统设计与仿真技术;③深入理解螺旋桨倾斜机构对飞行性能的影响及其控制实现;④为相关课题研究或工程开发提供可复现的技术参考与代码支持。; 阅读建议:建议读者结合提供的Matlab代码与Simulink模型,逐步跟进文档中的建模与控制设计步骤,动手实践仿真过程,以加深对全驱动无人机控制原理的理解,并可根据实际需求对模型与控制器进行修改与优化。
<think>我们正在处理一个Android构建错误,具体是SELinux策略文件(base_plat_sepolicy.cil)在解析'token'时遇到了语法错误,错误信息指向了'typeattribute'。 根据错误信息,这通常是因为策略文件中的语法问题。在SELinux的CIL(Common Intermediate Language)策略中,'typeattribute'用于将属性与类型关联。 可能的原因和解决方法: 1. 检查策略文件中'typeattribute'的使用是否正确。正确的语法是:`(typeattribute 类型名 属性名)`。注意,在CIL中,每个语句都放在括号内,且关键字和参数之间用空格分隔。 2. 确保类型和属性已经定义。如果引用了未定义的属性或类型,也会导致错误。 3. 检查是否有拼写错误或格式错误(如缺少括号、多余的空格等)。 4. 检查策略文件是否在正确的位置,并且被正确包含。 根据引用[2]中的信息,有时错误可能是因为策略文件被放错了位置或者需要忽略某些版本的兼容性。在Android构建中,SELinux策略文件通常位于`system/sepolicy`目录下,并且需要针对不同的API级别(SDK版本)进行管理。 建议步骤: - 确认错误发生在哪个具体的策略文件和行号。构建错误通常会给出文件名和行号。 - 检查该行附近的'typeattribute'语句,确保语法正确。 - 如果是新增的策略,确保将文件放在正确的目录下(例如,对于API 28,应放在`system/sepolicy/prebuilts/api/28.0`下?或者根据引用[2]的提示,可能只需要放在28的目录下,并在.ignore.cli中声明其他版本忽略)。 - 如果问题仍然存在,可以尝试清理构建并重新生成(`make clean`或`m clean`,然后重新构建)。 如果用户没有提供具体的错误行,建议先查看构建日志,定位到具体的错误位置。 由于用户的问题是关于如何修复这个语法错误的,我们将提供具体的检查步骤和可能的修复方法。 注意:在Android构建中,SELinux策略的编译过程对语法要求非常严格,任何小的错误都可能导致构建失败。 下面是一个示例,展示如何编写一个包含typeattribute的CIL规则: 正确示例: ``` (typeattribute my_domain_type my_attribute) ``` 这里,`my_domain_type`是一个类型,`my_attribute`是一个属性。在定义这个语句之前,必须已经定义了`my_domain_type`(使用`type`声明)和`my_attribute`(使用`attribute`声明)。 错误示例: ``` (typeattribute my_domain_type) # 缺少属性参数 (typeattribute my_domain_type my_attribute extra) # 参数过多 typeattribute my_domain_type my_attribute # 缺少括号 ``` 因此,请根据错误提示的行号,检查该行的语句是否符合正确语法。 另外,引用[1]提到了API兼容性问题,但当前错误是语法错误,所以可能不直接相关。但需要注意的是,如果策略文件被放置在错误的API级别目录下,也可能导致构建工具使用错误的解析器版本?不过通常语法是向后兼容的。 综上所述,我们首先需要检查策略文件中的语法错误,特别是'typeattribute'语句的结构。 如果用户需要更具体的帮助,请提供错误发生的具体文件和行号。 现在,我们将生成相关问题,以帮助用户进一步排查或了解相关背景。</think>### Android构建错误:base_plat_sepolicy.cil语法错误修复指南 当Android构建过程中遇到`base_plat_sepolicy.cil syntax error at token 'typeattribute'`错误时,通常是由于SELinux策略文件的语法或位置问题导致的。以下是系统性的解决方法: #### 1. **检查策略文件语法(核心步骤)** - 确认`typeattribute`声明格式正确: ```cil (typeattribute 类型名称) ; 标准格式 ``` - 检查是否缺少括号或存在拼写错误 - 确保所有引用的类型和属性已预先定义 - **修复示例**: ```diff - typeattribute my_custom_type + (typeattribute my_custom_type) ; 正确格式 ``` #### 2. **验证文件位置(关键环节)** - 新增的`.cil`文件必须放在正确目录: ```bash system/sepolicy/private/ # 设备私有策略 system/sepolicy/public/ # 公共策略 ``` - 对于API级别兼容问题(常见错误): - 仅需将文件添加到当前SDK版本目录(如`api/28.0/`) - **无需**复制到所有历史API目录(26,27等)[^2] #### 3. **处理API兼容性(构建系统要求)** - 在`system/sepolicy/.ignore.cil`中添加忽略声明: ```txt my_custom_type my_custom_attribute ``` - 执行API检查命令: ```bash m checkapi && m update-api ``` #### 4. **清理和重建(确认修复)** ```bash make clean # 或 m clean make -j8 # 重新构建 ``` ### 根本原因分析 此错误通常发生在: 1. CIL文件语法不符合SELinux规范 2. 新增策略文件位置错误 3. 缺少API版本兼容声明 4. 策略类型/属性未正确定义 > 引用案例表明:当策略文件被错误复制到多个API目录时,会触发类似兼容性错误[^2]。实际只需针对当前SDK版本操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值