<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); 【总结】总线-设备-驱动,这是写驱动程序的一种机制,总线,设备,驱动,在实现上模式很固定,都是先描述 一个相对应的结构,把这个结构实现了,然后在实现相对应的属性,结构实现完了,在就是告诉内核, 你定义和实现的这个结构是做什么的,是总线或者设备或者驱动或者其他的东西,这个就是注册。注 册完成了以后,就可以把这个代码编译成相应的模块,编译,测试了。具体的设备驱动,在实现方法 和手段都不一样,但是是总体的结构是不会变的。 |
|