linux定义数据结构压缩,Linux内核中一些重要的数据结构(一)

本文中分析linux kernel 中的比较重要的,在开发驱动过程中会碰到,万丈高楼平地起嘛。

文中内容条目清单:

1、数据类型相关

2、module_init和module_exit

3、EXPORT_SYMBOL和EXPORT_SYMBOLGPL

具体内容:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、数据类型相关

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LCD控制器初始化过程中有个数据转换

#define PICOS2KHZ(a) (1000000000UL/(a))

#define KHZ2PICOS(a) (1000000000UL/(a))其中“UL”代表含义:

1不加UL的话, 默认地它的类型是int, 这是一个有符号类型,而内核中为了限制说这个值是个无符号的值,就明确地标出UL,表示C标准中关于一个整数是如何决定它类型的优先级表:

后缀             类型

无               int

long int

long long int

u or U        unsigned int

unsigned long int

unsigned long long int

l or L           long int

long long int

ul or UL      unsigned long int

unsigned long long int

ll or LL        long long int

ull or ULL

unsigned long long int

注意, 在上表中,比如对u, 则编译器依次判断常量值是否在unsigned int表示范围内, 是类型就是unsigned int,

否则, 是否在unsigned long int表示范围内, 是类型就是unsigned long int,否则, 是否在unsigned long long int表示范围内, 是类型就是unsigned long long int.其余一样道理.

更详细请参考C99标准:

ISO/IEC 9899:1999(草案) 6.4.4.1 Integer constants

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

module_init

module_exit

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 装载时(insmod),调用module_init(...)中说明的函数。

卸载时(rmmod),调用module_exit(...)中说明的函数。

lsmod 查看被加载的驱动列表

数据声明@kernel\include\linux\init.h

#define __init __section(.init.text) __cold notrace

#define __initdata __section(.init.data)

#define __initconst __section(.init.rodata)

#define __exitdata __section(.exit.data)

#define __exit_call __used __section(.exitcall.exit)

#define __exit __section(.exit.text) __exitused __cold分析module_init,

如果某驱动想以func作为该驱动的入口,则可以如下声明:module_init(func);被上面的宏处理过后,变成__initcall_func6 __used加入到内核映像的".initcall"区。内核的加载的时候,会搜索".initcall"中的所有条目,并按优先级加载它们,他的执行优先级为普通的6。值越小越优先被加载,被声明为pure_initcall的最先加载。

#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

#define pure_initcall(fn) __define_initcall("0",fn,0)

#define core_initcall(fn) __define_initcall("1",fn,1)

#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)

#define postcore_initcall(fn) __define_initcall("2",fn,2)

#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)

#define arch_initcall(fn) __define_initcall("3",fn,3)

#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)

#define subsys_initcall(fn) __define_initcall("4",fn,4)

#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)

#define fs_initcall(fn) __define_initcall("5",fn,5)

#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)

#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)

#define device_initcall(fn) __define_initcall("6",fn,6)

#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)

#define late_initcall(fn) __define_initcall("7",fn,7)

#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

如果某驱动想以func作为该驱动的入口,则可以如下声明:module_init(func);被上面的宏处理过后,变成__initcall_func6 __used加入到内核映像的".initcall"区。内核的加载的时候,会搜索".initcall"中的所有条目,并按优先级加载它们,普通驱动程序的优先级是6。其它模块优先级列出如下:值越小,越先加载。

#define module_exit(x) __exitcall(x);

#define early_initcall(fn) module_init(fn)

#define core_initcall(fn) module_init(fn)

#define postcore_initcall(fn) module_init(fn)

#define arch_initcall(fn) module_init(fn)

#define subsys_initcall(fn) module_init(fn)

#define fs_initcall(fn) module_init(fn)

#define device_initcall(fn) module_init(fn)

#define late_initcall(fn) module_init(fn)

linux kernel中有很大一部分代码是设备驱动代码,这些驱动代码都有初始化和反初始化函数,这些代码一般都只执行一次,为了有更有效的利用内存,这些代码所占用的内存可以释放出来。

linux就是这样做的,对只需要初始化运行一次的函数都加上__init属性。在kernel初始化后期,释放所有这些函数代码所占的内存空间

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EXPORT_SYMBOL

EXPORT_SYMBOL_GPL

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EXPORT_SYMBOL(符号名);

EXPORT_SYMBOL_GPL(符号名) 导出的符号可以被其他模块使用,不过使用之前一定要声明一下。EXPORT_SYMBOL_GPL()只适用于包含GPL许可权的模块。

用法:就是在一个文件中定义符号,这个用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL声明,可以其他函数中通过extern 声明调用的对应符号名,那么在此函数中即可被调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值