读书笔记(7)

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 int type, 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;
1217
1218        unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
1219
1220        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)];
1229
1230        unsigned int hint_events_per_packet;
1231
1232        unsigned int keycodemax;
1233        unsigned int keycodesize;
1234        void *keycode;
1235
1236        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);
1245
1246        struct ff_device *ff;
1247
1248        unsigned int repeat_key;
1249        struct timer_list timer;
1250
1251        int rep[REP_CNT];
1252
1253        struct input_mt_slot *mt;
1254        int mtsize;
1255        int slot;
1256        int trkid;
1257
1258        struct input_absinfo *absinfo;
1259
1260        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)];
1264
1265        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);
1269
1270        struct input_handle __rcu *grab;
1271
1272        spinlock_t event_lock;
1273        struct mutex mutex;
1274
1275        unsigned int users;
1276        bool going_away;
1277
1278        bool sync;
1279
1280        struct device dev;
1281
1282        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()。

你可能感兴趣的:(arm-linux驱动研究)