读书笔记(7)

来源:互联网 发布:怎么看淘宝实名认证 编辑:程序博客网 时间:2024/05/16 01:13

7.工程中的Linux设备驱动

platform设备驱动

http://lxr.oss.org.cn/source/drivers/input/input.c?v=2.6.34#L1529

   platform总线,会匹配相应的设备和驱动。

   现实的设备中都需要挂接一种总线,对于本身依附于PCI,USB,I2C,SPI设备而言,这不会是问题,但是,如果不依赖于此类总线,Linux发明了platform总线,相应的设备叫platform device,而驱动叫做platform driver,platform_device是一种附加手段,例如S3c6410处理器中,把内部集成的I2C,RTC,LCD等控制器都归纳为platform_device.,而他们本身为字符设备。

  platform device结构,platform_driver 结构见P243。而匹配驱动和设备的match()函数是通过两者的name字段是否相同的。

  而platform_device的定义通常在BSP的板文件中实现的,将platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册,它其实内部调用了platform_device_register来注册单个平台设备。

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

  其中如platform_data,如dm9000_plat_data传给struct platform_device ldd6410_dm9000中的dev的platform_data


 28 struct dm9000_plat_data { 29         unsigned int    flags; 30         unsigned char   dev_addr[6]; 31  32         /* allow replacement IO routines */ 33  34         void    (*inblk)(void __iomem *reg, void *data, int len); 35         void    (*outblk)(void __iomem *reg, void *data, int len); 36         void    (*dumpblk)(void __iomem *reg, int len); 37 };

      引入platform总线概念,首先可以使得设备挂接在一个总线上,配套的sysfs节点和设备电源管理都成为可能;隔离了BSP和驱动,在BSP中,定义了platform设备和设备使用的资源,设备的具体配置信息,而在驱动中,只需要获取资源和数据就可以了,做到板相关代码和驱动代码相分离。

设备驱动的分层思想:

     设备核心层实现该设备通用的一些功能,如果具体的设备不想用核心层的函数,它可以重载。它的好处是,具体的底层驱动不需要再实现,而仅仅只需要关心其底层的操作,见P249,图12.1。

    输入设备驱动:input_dev   分配释放一个输入设备:input_allocate_device(),input_free_device() 分配一个结构体

                             input_register_device()注册一个输入设备 input_unregister_device()注销输入设备

                             报告输入事件用的接口:报告指定的type,code输入事件 input_event() input_report_key()报告键值  input_report_rel()报告相对坐标。

                             input_report_abs()报告绝对坐标   input_sync()报告同步事件

void input_set_capability(struct input_dev *dev, unsigned inttype, unsigned int code)

{switch (type)

{ case EV_KEY:

__set_bit(code,dev->keybit);

break;

 case EV_REL:

__set_bit(code,dev->relbit);

break;

case EV_ABS:

__set_bit(code,dev->absbit);

break;

case EV_MSC:

__set_bit(code,dev->mscbit);

break;

 case EV_SW:

__set_bit(code,dev->swbit);

break;

case EV_LED:

__set_bit(code,dev->ledbit);

 break;

case EV_SND:

__set_bit(code,dev->sndbit);

 break;

case EV_FF:

__set_bit(code,dev->ffbit);

break;

case EV_PWR:

 /* do nothing */

break;

 default:

pr_err("input_set_capability: unknown type %u (code %u)\n",

 type,code);

 dump_stack();

 return;

}__set_bit(type,dev->evbit);

}

            struct input_dev {1213        const char *name;1214        const char *phys;1215        const char *uniq;1216        struct input_id id;12171218        unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];12191220        unsigned long evbit[BITS_TO_LONGS(EV_CNT)];1221        unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];1222        unsigned long relbit[BITS_TO_LONGS(REL_CNT)];1223        unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];1224        unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];1225        unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];1226        unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];1227        unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];1228        unsigned long swbit[BITS_TO_LONGS(SW_CNT)];12291230        unsigned int hint_events_per_packet;12311232        unsigned int keycodemax;1233        unsigned int keycodesize;1234        void *keycode;12351236        int (*setkeycode)(struct input_dev *dev,1237                          unsigned int scancode, unsigned int keycode);1238        int (*getkeycode)(struct input_dev *dev,1239                          unsigned int scancode, unsigned int *keycode);1240        int (*setkeycode_new)(struct input_dev *dev,1241                              const struct input_keymap_entry *ke,1242                              unsigned int *old_keycode);1243        int (*getkeycode_new)(struct input_dev *dev,1244                              struct input_keymap_entry *ke);12451246        struct ff_device *ff;12471248        unsigned int repeat_key;1249        struct timer_list timer;12501251        int rep[REP_CNT];12521253        struct input_mt_slot *mt;1254        int mtsize;1255        int slot;1256        int trkid;12571258        struct input_absinfo *absinfo;12591260        unsigned long key[BITS_TO_LONGS(KEY_CNT)];1261        unsigned long led[BITS_TO_LONGS(LED_CNT)];1262        unsigned long snd[BITS_TO_LONGS(SND_CNT)];1263        unsigned long sw[BITS_TO_LONGS(SW_CNT)];12641265        int (*open)(struct input_dev *dev);1266        void (*close)(struct input_dev *dev);1267        int (*flush)(struct input_dev *dev, struct file *file);1268        int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);12691270        struct input_handle __rcu *grab;12711272        spinlock_t event_lock;1273        struct mutex mutex;12741275        unsigned int users;1276        bool going_away;12771278        bool sync;12791280        struct device dev;12811282        struct list_head        h_list;1283        struct list_head        node;1284};
   4  struct gpio_keys_button {   5        /* Configuration parameters */   6        int code;               /* input event code (KEY_*, SW_*) */   7        int gpio;   8        int active_low;   9        char *desc;  10        int type;               /* input event type (EV_KEY, EV_SW) */  11        int wakeup;             /* configure the button as a wake-up source */  12        int debounce_interval;  /* debounce ticks interval in msecs */  13        bool can_disable;  14      };  15  16     struct gpio_keys_platform_data {  17        struct gpio_keys_button *buttons;  18        int nbuttons;  19        unsigned int poll_interval;     /* polling interval in msecs -  20                                           for polling driver only */  21        unsigned int rep:1;             /* enable input subsystem auto repeat */  22        int (*enable)(struct device *dev);  23        void (*disable)(struct device *dev);  24};
 29 struct gpio_button_data { 30         struct gpio_keys_button *button; 31         struct input_dev *input; 32         struct timer_list timer; 33         struct work_struct work; 34         bool disabled; 35 }; 36  37 struct gpio_keys_drvdata { 38         struct input_dev *input; 39         struct mutex disable_lock; 40         unsigned int n_buttons; 41         struct gpio_button_data data[0]; 42 };

主机驱动和外设驱动分离

如果不分离的话,针对不同的主机或者同一个主机上面的不同设备都需要相应的设备驱动。这样的话,3个主机3个不同驱动只要6个驱动(3个主机控制器驱动,3个外设驱动),否则要9个,
如Linux的SPI驱动分为SPI主控制器驱动和设备驱动,主控制器驱动,主要成员是主控制器序号,片选数量,SPI模式,时钟设置用到的函数,数据传输用到的函数。

见P259页,可以知道spi_master的分配注销和注册函数,比如struct spi_master * spi_alloc_master(struct device * host,unsigned size)等等

spi_driver结构体描述了一个spi外设驱动,可以认为是spi_master的client驱动。

struct spi_transfer{

}当透过spi总线进行数据传输的时候,它用于描述spi传输。见P258

但是最后,因为一次完整的SPI传输流程可能不止包含一次spi_transfer,它也是要通过spi_message组织在一起的。

P259介绍了spi_message()的初始化,添加spi_transfer()到spi_message队列的方法,还有spi同步异步操作函数。最后是利用spi_transfer()和spi_message()进行spi_write()和spi_read()两个API。同时spi_driver和platform_driver一样,存在着一个spi_device,而spi_device的板信息用spi_board_info()结构体描述。

设备驱动电源管理

CONFIG_PM,suspend()里面会停止设备,关闭给它提供的时钟。而resume()是一个相反的过程。

在BSP中为SoC各个PLL,分频器和时钟gate建立了一棵树,并提供了一组操作时钟的通用API。如clk_get(),clk_put() clk_enable() clk_disbale() clk_get_rate() clk_round_rate() clk_set_rate() clk_set_parent() clk_get_parent()设置获取父设备,等P262 还有一些关于suspend_late()工作与中断都被禁止的情况下。

misc混杂设备

共享一个主设备号MISC_MAJOR(10),不同的次设备号,miscdevice结构体表征miscdevice设备,它本质属于字符设备,因此其驱动的主体工作还是属于file_operation的成员函数。混杂设备的注册注销为misc_register() misc_deregister()两个函数完成。

基于sysfs的设备驱动

在P263

Linux设备驱动的固件加载

申请固件,释放请求——P265 request_firmware()三个参数分别为保存申请到的固件,固件名,申请的固件设备结构体。release_firmware()。

原创粉丝点击