驱动篇:驱动的移植(一)(摘录)

驱动篇:驱动的移植(一)

在编写 Linux 设备驱动的时候,驱动程序所服务的硬件芯片可能会在公司的多个采用不同处理器的系统中用到,因此,在编写驱动时,应该尽量考虑其可移植性
编写可移植的设备驱动
C 语言中的标准数据类型 int、long 的长度直接与平台相关,在驱动中,关键部分代码直接使用这些类型时需要特别小心!
在这里插入图片描述
因此,在 Linux 系统中,针对不同的体系结构重新 typedef 出了 u8、u16、u32、u64、s8、s16、s32、s64 等类型。例如,在 i386/arm 下这些类型的定义如代码清单 23.1所示,而在 ppc64 下这些类型的定义则如代码清单 23.2 所示,可见影响 C 语言基本数据类型大小的主要因素是 CPU 字长。

i386/arm 平台下 u8、u16、u32、u64、s8、s16、s32、s64 的定义

typedef signed char s8;
typedef unsigned char u8;

 typedef signed short s16;
 typedef unsigned short u16;

 typedef signed int s32;
 typedef unsigned int u32;

 typedef signed long long s64;
 typedef unsigned long long u64;

ppc64 平台下 u8、u16、u32、u64、s8、s16、s32、s64 的定义

 typedef signed char s8;
 typedef unsigned char u8;

 typedef signed short s16;
 typedef unsigned short u16;

 typedef signed int s32;
 typedef unsigned int u32;

 typedef signed long s64;
 typedef unsigned long u64;

在这里插入图片描述

 void my_delay(uint32_t t)
{
uint32_t i;
i = t;
while (i--);
}

很有可能达不到延迟的目的,如果这样修改:

void my_delay(uint32_t t)
{
volatile uint32_t i;
i = t;
while (i - -) ;
}while()循环的代码不会被编译器优化掉

结构体对界
在 C 语言中使用结构体时有一个需要特别注意的事项,那就是结构体的对界。struct 是一种复合数据类型,其构成元素既可以是基本数据类型的变量,也可以是一些复合数据类型(如数据、结构体、联合体等)的数据单元。对于结构体,编译器很可能会自动进行成员变量的对齐,以提高存取效率。默认情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
自然对界指按结构体的成员中 sizeof 最大的成员对齐(如果 sizeof 大于 CPU 的字长,仍然按照 CPU 字长对齐),例如对于 32 位系统:

struct naturalalign
{
char a;
short b;
char c;
};

在上述结构体中,size 最大的是 short,其长度为两个字节,因而结构体中的 char
成员 a、c 都以 2 为单位对齐,sizeof(naturalalign)的结果等于 6

如果改为:

struct naturalalign
{
char a;
int b;
char c;
};

其结果为 12

在 Linux 内核编程中,为了防止编译器自动在结构体的数据间插入空隙,可以使用__attribute__((packed))定义结构体

struct
{
u16 id;
u64 lun;
u16 reserved1;
u32 reserved2;
} __attribute__((packed))scsi; //不要在数据间插入空隙

Little Endian 与 Big Endian
采用 Little Endian 模式的 CPU 对操作数的存放方式是从低字节到高字节,而 BigEndian 模式对操作数的存放方式是从高字节到低字节。例如,16bit 宽的数 0x1234 在Little Endian 模式 CPU 内存中的存放方式(假设从地址 0x4000 开始存放)为:
在这里插入图片描述32bit 宽的数 0x12345678 在 Little Endian 模式 CPU 内存中的存放方式(假设从地址 0x4000 开始存放)为:
在这里插入图片描述内核中定义如下多个宏来进行 Big Endian 模式与 Little Endian 模式的互换,包括cpu_to_le64、le64_to_cpu、cpu_to_le32、le32_to_cpu、cpu_to_le16、le16_to_cpu。
内核中定义如下多个宏来进行 Big Endian 模式与 Big Endian 模式的互换:

cpu_to_be64 、 be64_to_cpu 、 cpu_to_be32 、 be32_to_cpu 、 cpu_to_be16 、
be16_to_cpu。

在 Linux/drivers 目录的 ATM、IEEE1394、SCSI、NET、USB 等源码中,都大量存在对上述这些宏的使用。
内存页面大小
一般情况下,内存页面的大小是 4KB(即 PAGE_SIZE 定义为 4KB),但是这并非是一定的,实际上,页面大小在一个 4~64KB 的范围内是可变的,即使在相同的平台下也可以定义不同的 PAGE_SIZE 和 PAGE_SHIFT。

鉴于此,当在内核空间中通过 get_free_pages()函数申请内存时,如果它的第二个参数为 order,意味着申请 PAGE_SIZE * 2 order 的内存,同样是申请 64KB 内存,如果PAGE_SIZE 为 4KB,应该传入的 order 是 4,如果 PAGE_SIZE 是 16KB,应该传入的参数是 2。为了保证在申请 64KB 内存时,在任何 PAGE_SIZE 的情况下都成立,可以使用如代码:
通过 get_order()获得要申请内存的 order

#include <asm/page.h>
int order = get_order(16*1024);
buf = get_free_pages(GFP_KERNEL, order);/*get_order 的参数必须是 2 的幂*/

巧用类似芯片的驱动程序
任何驱动工程师都没有必要在面对新设备驱动编写需求的时候一切从头开始,因为内核源代码 drivers 目录(音频设备的驱动在 sound 目录)中已经包含了大量现成的类似芯片驱动的源代码,是极好的参考模板,我们不需要“re-invent the wheel”。实际上,在内核源代码许多后期编写的驱动程序中,就直接参考了之前的驱动源码,所以同类设备的驱动往往呈现出非常相似的架构和数据结构定义。我们来看看 sound/oss/au1550_ac97.c 文件最开始的一段注释:
在这里插入图片描述这段注释很清楚地说明其绝大多数代码都来自 au1000.c 驱动,还有一些来自PowerMac dbdma 驱动。

打开 sound/oss 目录下的 au1550_ac97.c(Alchemy Au1550 MIPS 处理器的音频驱动) 、es1370.c(Ensoniq ES1370/Asahi Kasei AK4531 声卡驱动) 、es1371.c(reativeEnsoniq ES1371 声卡驱动)、cs46xx.c(Crystal SoundFusion CS46xx 声卡驱动),发现如下相似之处。

l 它们全都自定义了全局的 xxx_state 结构体实例用于封装音频设备的锁、 信号量、缓冲区、ID 等信息,这几个结构体分别是:au1550_state、es1370_state、es1371_state、cs_state。
l 它 们 的 核 心 函 数 都 使 用 了 完 全 相 同 的 实 现 方 法 , au1550_ac97.c 的au1550_read()和 es1370.c 的 es1370_read()的处理流程是一致的,下面列表的左右两列对等地给出了 au1550_read()和 es1370_read()函数的源代码(为了进行横向比较,适当地增加了源代码的换行,以达到类似WinMerge 等源码比较软件的效果)。
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述可以看出,内核中看似神秘的、庞大的设备驱动源码也是互相学习、互相借鉴的结果。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
《Android底层开发技术实战详解:内核移植驱动》是一本涵盖Android底层开发技术的实战性书籍。Android系统的内核是整个系统的核心,它负责管理系统的资源、执行任务和提供与硬件交互的接口。在这本书中,作者详细介绍了如何进行Android内核的开发和调试。 内容涵盖了内核的编译和配置、移植以及设备驱动的开发。首先,该书讲解了如何编译和配置Android内核,包括各种编译选项以及内核配置的常见问题和解决方案。其次,书中介绍了Android系统的移植方法和流程,包括移植到新的硬件平台以及在不同处理器架构上进行移植的技术要点和指导。最后,该书还探讨了设备驱动的开发,包括设备驱动的概念、编写和调试方法。 通过学习《Android底层开发技术实战详解:内核移植驱动》,读者可以掌握Android底层开发的重要知识和技能。这对于那些希望深入了解Android系统,并且想要进行系统优化、调试和定制的开发者来说,是一本非常实用的参考书。无论是从事Android系统开发的工程师,还是对Android底层开发感兴趣的爱好者,都能够从中获益良多。 总而言之,《Android底层开发技术实战详解:内核移植驱动》是一本内容丰富、实用性强的Android底层开发指南。它覆盖了内核移植驱动的方方面面,并且提供了大量实例和案例,帮助读者更好地理解和应用所学知识。无论是对于初学者来说,还是对于有一定经验的开发者来说,都是一本值得阅读的好书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值