Chinaunix首页 | 论坛 | 博客
  • 博客访问: 357666
  • 博文数量: 127
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 333
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-27 14:44
个人简介

兴趣是最好的学习契机!

文章分类

全部博文(127)

文章存档

2017年(1)

2016年(3)

2015年(54)

2014年(58)

2013年(11)

我的朋友

分类: 嵌入式

2014-10-12 00:21:34

1 platform 设备驱动

1.1 platform总线、设备与驱动

Linux 2.6的设备驱动模型中,关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCIUSBI2 CSPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设等却不依附于此类总线。基于这一背景,Linux发明了一种虚拟的称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver


struct platform_device {

    const char  * name;

    int     id;

    struct device   dev;

    u32     num_resources;

    struct resource * resource;

};

 

struct platform_driver {

    int (*probe)(struct platform_device *);

    int (*remove)(struct platform_device *);

    void (*shutdown)(struct platform_device *);

    int (*suspend)(struct platform_device *, pm_message_t state);

    int (*suspend_late)(struct platform_device *, pm_message_t state);

    int (*resume_early)(struct platform_device *);

    int (*resume)(struct platform_device *);

    struct pm_ext_ops *pm;

    struct device_driver driver;

};


platform_deviceplatform_driver如何进行匹配?通过platform_match来比较name字段是否相同!

 

struct bus_type {

    const char      *name;

    struct bus_attribute    *bus_attrs;

    struct device_attribute *dev_attrs;

    struct driver_attribute *drv_attrs;

 

    int (*match)(struct device *dev, struct device_driver *drv);

……

};

 

struct bus_type platform_bus_type = {

    .name       = "platform",

    .dev_attrs  = platform_dev_attrs,

    .match      = platform_match,

    .uevent     = platform_uevent,

    .pm     = PLATFORM_PM_OPS_PTR,

};

 

static int platform_match(struct device *dev, struct device_driver *drv)

{

    struct platform_device *pdev;

    pdev = container_of(dev, struct platform_device, dev);

    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);

}

1.2 实现platform设备的步骤

1.platform_device的编写

2.platform_driver的编写

3.设备资源和数据的定义

设备资源由resource结构体描述:

struct resource {

    resource_size_t start;

    resource_size_t end;

    const char *name;

    unsigned long flags;

    struct resource *parent, *sibling, *child;

};

我们通常关心startendflags3个字段,分别标明资源的开始值、结束值和类型,flags可以为IORESOURCE_IOIORESOURCE_MEMIORESOURCE_IRQIORESOURCE_DMA等。startend的含义会随着flags而变更,如当 flagsIORESOURCE_MEM时,startend分别表示该platform_device占据的内存的开始地址和结束地址;当 flagsIORESOURCE_IRQ时,startend分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。对于同种类型的资源而言,可以有多份,譬如说某设备占据了2个内存区域,则可以定义2IORESOURCE_MEM资源。

resource的定义通常在BSP的板文件中进行,而在具体的设备驱动中透过platform_get_resource()这样的API来获取,此API的原型为:

struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);

设备除了可以在BSP中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存、DMA通道以外,可能还会有一些配置信息,而这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,platform也提供了platform_data的支持。platform_data 的形式是自定义的。

 

2 input输入子系统框架

下图是input输入子系统框架,输入子系统由输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 input driver -> Input core -> Event handler -> userspace 到达用户空间传给应用程序。

注意:keyboard.c不会在/dev/input下产生节点,而是作为ttyn终端(不包括串口终端)的输入。

 

3. SPI通信

该总线通信基于主-从配置。它有以下4个信号:

MOSI:主出/从入
MISO:
主入/从出
SCK:
串行时钟
SS:
从属选择

SPI传输串行数据时首先传输最高位。波特率可以高达5Mbps,具体速度大小取决于SPI硬件。例如,Xicor公司的SPI串行器件传输速度能达到5MHz

S3C2440SPI驱动在这个文件里讲得很详细:Spi_s3c24xx.c (drivers\spi)

 

4. 设备驱动中的电源管理

这又是一个很大的话题,这里只说一点:

挂起:suspend();

恢复:resume();

并且这两个函数在platform_driver结构体中已经包含。

 

5. misc 设备驱动

设备结构体定义在include/linux/miscdevice.h中:

struct miscdevice  { 

    int minor;                  //次设备号,若为 MISC_DYNAMIC_MINOR 自动分配  

    const char *name;           //设备名  

    const struct file_operations *fops; //设备文件操作结构体  

    struct list_head list;          //misc_list链表头  

    struct device *parent; 

    struct device *this_device; 

    const char *nodename; 

    mode_t mode; 

};

这个主设备号是10,所有注册为misc的设备都有相同的主设备号在使用过程中我们主要是通过次设备号来区分各个设备。这一点不难理解,内核将所有注册为misc的设备都归为一大类。

结构体中的list_head结构体类型的list成员的作用是什么呢?

内核自己会维护一个misc_list链表,所有注册为misc的设备都必须挂在这个链表上,这个list就是该链表的链表头。

结构体中的两个device结构体类型指针作用是什么呢?

作用就是创建设备文件。

我们如何定义自己的misc类型的设备呢?

static struct miscdevice misc = { 

    .minor = MISC_DYNAMIC_MINOR, 

    .name = DEVICE_NAME, 

    .fops = &dev_fops, 

}; 

static struct miscdevice misc = {

    .minor = MISC_DYNAMIC_MINOR,

    .name = DEVICE_NAME,

    .fops = &dev_fops,

};

其中的设备文件操作结构体和字符设备类似,这里就不再细讲。

定义了自己的misc设备,那么我们如何向内核注册/注销设备呢?

使用如下两个函数:

int misc_register(struct miscdevice * misc);    //在加载模块时会自动创建设备文件,是主设备号为10的字符设备  

int misc_deregister(struct miscdevice *misc);   //在卸载模块时会自动删除设备文件

6.Androidlinux的区别是什么?

Android平台是基于Linxu内核搭建的,Linux内核的优势在于大内存管理、进程管理、基于权限的安全模型、统一的驱动模型、共享库支持、代码开源等。

Android平台在设计过程中,针对移动终端资源有限的特点,对Linux进行了一定程度的裁剪:砍掉了原生的窗口系统、去除了对GNU Libc的支持(引入了更高效、针对嵌入式优化过的Bionic)、裁剪掉了一些标准Linux工具的部分特性等。

另外Android针对移动终端的特点还对Linux内核在闹钟(Alarm)、Low Memory KillerAshmem、内核调试(Kernel Debugger)、进程间通信(Binder)、日志(Logger)、电源管理(Power Management)等方面做了大量的优化。

其中Low Memory Killer相对于Linux标准OOMOut Of Memory)机制更加灵活,它可以根据需要杀死进程来释放需要的内存。Low Memory Killer的实现主要位于aurora\msm\msm drivers/staging/android/lowmemorykiller.c文件中。

Ashmem为进程间提供大块共享内存,同时为内核提供和管理这个内存的机制。 Ashmem的实现位于system\core\libcutils\ashmem-dev.c文件中。

参考文献:

http://blog.csdn.net/changjiang654/article/details/6154622

http://blog.csdn.net/chenlong12580/article/details/7339127

http://www.eefocus.com/ayayayaya/blog/2012-05/228130_1d55e.html

阅读(484) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~