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