Chinaunix首页 | 论坛 | 博客
  • 博客访问: 146227
  • 博文数量: 26
  • 博客积分: 590
  • 博客等级: 中士
  • 技术积分: 430
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-19 15:26
文章存档

2012年(10)

2011年(16)

我的朋友

分类: LINUX

2011-11-02 17:02:06

<1>.内核模块编译开发
编译一个内核需要有makefile文件,然后还要借助于某一个内核源文件。编译一个内核的makefile文件的格式
比较固定。常用的Makefile文件:(Makefile的第一个字母要大写,否则编译提示说找不到Makefile文件)
 ① 编译一个只有一个源码文件的内核模块的Makefile如下:
 obj-m += hello.o   //根据具体需要修改,这个是编译好的内核模块名字
 KDIR := /lib/modules/2.6.18-53.el5/build   //需要修改
 all:
  make -C $(KDIR) M=$(PWD) modules
 clean:
  rm -f *.ko *.o *.mod.c *.smsvers
 ② 编译一个具有多个源码文件的内核模块的makefile如下:
 obj-m += hello.o    //根据具体需要修改,这个是编译好的内核模块名字
 hello-objs := main.o add.o  //编译模块需要的源文件
 KDIR := /lib/modules/2.6.18-53.el5/build   //依赖的内核源文件目录,主要是使用顶层的Makefile
 all:
  make -C $(KDIR) M=$(PWD) modules
 clean:
  rm -f *.ko *.o *.mod.c *.smsvers
<2>.怎么创建一条总线
 在linux系统中创建一条总线,在/sys/bus目录下有显示。具体的做法如下:
 ① 首先创建一个总线结构bus_type,里面包含了这条总线的一些信息。bus_type结构的成员很多,内核中该结构
 的代码中如下:
 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);
 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 int (*probe)(struct device *dev);
 int (*remove)(struct device *dev);
 void (*shutdown)(struct device *dev);
 int (*suspend)(struct device *dev, pm_message_t state);
 int (*resume)(struct device *dev);
 const struct dev_pm_ops *pm;
 struct bus_type_private *p;
 };
 这里实现一个比较简单的总线,包括总线的名字和match方法。
 struct bus_type {
  .name = "my_bus",
  .match = my_match,
 };
 ② 在先实现一个总线的属性结构bus_attribute。结构的原型如下:
 struct bus_attribute {
  struct attribute attr;
  ssize_t (*show)(struct bus_type *,char *buf);
  ssize_t (*store)(struct bus_type *,const char *buf,size_f count);
 }
 2.6的内核中,关于属性的定义有一个宏来实现,在内核中可以搜索出更详细的代码信息。
 BUS_ATTR(_name, _mode, _show, _store);
 在内核中的定义部分:
 #define BUS_ATTR(_name, _mode, _show, _store) \
 struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
 _show指针指向的函数在读这个总线的属性的时候被调用。
 _store指针指向的函数在写总线属性的时候被调用。
 例如:实现一条总线的属性结构,只实现_show函数具体代码如下所示:
 static  BUS_ATTR(version,S_IRUGO,show_bus_version,NULL);
 ③ 注册总线,卸载总线属性。
 注册一条总线使用一下函数: bus_register(struct bus_type *bus_name);
 卸载总线: bus_unregister(struct bus_type *bus_name);
 
 注册总线属性:bus_creat_file(struct bus_type *bus_name,struct attribute *attri_name);
 卸载总线属性:bus_remove_file(struct bus_type *bus_name,struct attribute *attri_name);
 ④ 创建总线设备
 总线在内核中也是一个设备,所以也得有设备结构的构建和注册。
 设备的结构定义如下:
 struct device {
  ……… ……… …………
  struct kobject kobj;
  char bus_id[BUS_ID_SIZE]; /*在总线上唯一标识该设备的字符串*/
  struct bus_type *bus;
  struct device_driver *driver;
  void *driver_data;
  struct klist_node knode_class;
  struct class *class;
  struct attribute_group **groups;
  void (*release)(struct device *dev);
 }
 实现一个简单的设备:
 struct device my_bus = {
  .bus = "my_bus_type",
  .release = my_release,
 };
 ⑤ 注册总线设备,卸载总线设备
 注册总线设备:device_register(struct device *device);
 卸载总线设备:device_unregister(struct device *device);
 这里不需要
 【实践】 bus.c Makefile
<3>.创建设备
 ① 和创建一条总线一样,首先要实现一个设备,设备的结构定义如下:
 struct device {
 struct device  *parent;     //父设备也就是总线设备,
 struct device_private *p;  
 struct kobject kobj;
 const char  *init_name; /* 设备的ID  bus_id */
 struct device_type *type;
 struct semaphore sem; /* semaphore to synchronize calls to
      * its driver.
      */
 struct bus_type *bus;  /* 设备所在的总线 */
 struct device_driver *driver; /* 操作这个设备的驱动,设备驱动*/
 void  *platform_data; /* Platform specific data, device core doesn't touch it */
 struct dev_pm_info power;
 #ifdef CONFIG_NUMA
 int  numa_node; /* NUMA node this device is close to */
 #endif
 u64  *dma_mask; /* dma mask (if dma'able device) */
 u64  coherent_dma_mask;/* Like dma_mask, but for
          alloc_coherent mappings as
          not all hardware supports
          64 bit addresses for consistent
          allocations such descriptors. */
 struct device_dma_parameters *dma_parms;
 struct list_head dma_pools; /* dma pools (if dma'ble) */
 struct dma_coherent_mem *dma_mem; /* internal for coherent mem
          override */
 /* arch specific additions */
 struct dev_archdata archdata;
 dev_t   devt; /* dev_t, creates the sysfs "dev" */
 spinlock_t  devres_lock;
 struct list_head devres_head;
 struct klist_node knode_class;
 struct class  *class;
 const struct attribute_group **groups; /* optional groups */
 void (*release)(struct device *dev);
 };
 设备的描述结构很复杂,在一般的使用过程中,需要的部分给实现了,不需要的不用管就可以。
 现在首先一个比较简单的设备:
 struct device my_dev = {
  .bus = "my_bus_type",
  .parent = my_bus,
  .release = my_release,
 };
 
 ② 实现设备属性结构
 设备属性的结构和总线属性的结构在结构成员上是一样的。
 struct device_attribute {
  struct attribute attr;
  ssize_t (*show)(struct bus_type *,char *buf);
  ssize_t (*store)(struct bus_type *,const char *buf,size_f count);
 }
 在现实方法上也和总线属性的实现方法类似
 DEVICE_ATTR(_name,_mode,_show,_store);
 #define DEVICE_ATTR(_name, _mode, _show, _store) \
 struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
 ③ 注册与卸载设备
 注册设备:device_register(struct device *device);
 卸载设备:device_unregister(struct device *device);
 ④ 注册与卸载设备属性
 注册设备属性:device_creat_file(struct device *device,struct device_attribute *attr);
 卸载设备属性:device_remove_file(struct device *device,struct device_attribute *attr);
 【实践】device.c Makefile
<4>.创建驱动
 ① 还是一样,首先实现一个驱动结构,内核中驱动结构的定义如下:
 struct device_driver {
 const char  *name;  //驱动的名字,这个是要和设备的ID进行匹配检查的
 struct bus_type  *bus; //驱动所在的总线
 struct module  *owner; //所属模块
 const char  *mod_name; /* used for built-in modules */
 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
 int (*probe) (struct device *dev);   //驱动的具体操作实现
 int (*remove) (struct device *dev);
 void (*shutdown) (struct device *dev);
 int (*suspend) (struct device *dev, pm_message_t state);
 int (*resume) (struct device *dev);
 const struct attribute_group **groups;
 const struct dev_pm_ops *pm;
 struct driver_private *p;
 };
 实现一个简单的驱动结构:
 struct device_driver = {
  .name = "my_dev",
  .bus = my_bus_type,
  .probe = my_probe,
  .remove = my_remove,
 };
 ② 实现驱动的属性结构
 驱动属性跟设备属性的结构,总线属性的结构在结构成员上是一样的。
 struct device_attribute {
  struct attribute attr;
  ssize_t (*show)(struct bus_type *,char *buf);
  ssize_t (*store)(struct bus_type *,const char *buf,size_f count);
 }
 现实方法也都是一样的:DRIVER_ATTR(_name, _mode, _show, _store)
 #define DRIVER_ATTR(_name, _mode, _show, _store) \
 struct driver_attribute driver_attr_##_name =  \
 __ATTR(_name, _mode, _show, _store)
 具体的一个简单的驱动属性的实现:DRIVER_ATTR(driver,O_SIRUGO ,mydrivers_show,NULL);
 ③ 注册和卸载驱动
 注册驱动:driver_register(struct device_driver *driver);
 卸载驱动:driver_unregister(struct device_driver *driver);
 ④ 注册和卸载驱动属性
 注册驱动属性:driver_creat_file(struct device_driver *driver,struct driver_attribute *attr);
 卸载驱动属性:driver_remove_file(struct device_driver *driver,struct driver_attribute *attr);
 
【总结】总线-设备-驱动,这是写驱动程序的一种机制,总线,设备,驱动,在实现上模式很固定,都是先描述
  一个相对应的结构,把这个结构实现了,然后在实现相对应的属性,结构实现完了,在就是告诉内核,
  你定义和实现的这个结构是做什么的,是总线或者设备或者驱动或者其他的东西,这个就是注册。注
  册完成了以后,就可以把这个代码编译成相应的模块,编译,测试了。具体的设备驱动,在实现方法
  和手段都不一样,但是是总体的结构是不会变的。
 
 
阅读(1937) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~