专题**-Linux驱动开发前奏

学前理论


驱动分类-常规分类法

驱动分类-常规分类法:字符设备,块设备,网络设备。
驱动分类-总线分类法:USB设备,PCI设备,平台总线设备。

字符设备:字符设备是一种按字节来访问的设备,字符驱动则负责驱动字符设备,这样的驱动通常支持open,close,read,write系统调用。例如:串口,LED,按键。

块设备:在大部分UNIX系统中,块设备定义为以块(通常为512字节)为最小传输单位的设备,块设备不能按字节处理数据。而Linux则允许块设备传送任意数目的字节。因此,块设备和字符设备的区别仅仅是驱动的与内核的接口不同。常见的块设备包括硬盘,flash,SD卡等。

网络接口设备:网络接口可以是一个硬件设备,如网卡;但也可以是一个纯粹的软件设备,比如回环接口。一个网络接口负责发送和接收数据报文。


驱动学习方法和学习禁忌

驱动学习方法:驱动模型,硬件操作。
驱动学习切忌:驱动学习初期(前半年)请不要过多的去阅读内核代码!

硬件访问技术


硬件访问流程

硬件访问实质:
驱动程序控制设备,主要是通过访问设备内的寄存器来达到控制的目的,因此我们讨论如何访问硬件,就成了如何访问这些寄存器了。

硬件访问流程:
地址映射,读写寄存器。


地址映射


静态映射

静态映射:所谓静态映射,是指Linux系统根据用户事先指定的映射关系,在内核启动时,自动将物理地址映射为虚拟地址。

如何事先指定映射关系?
内核启动时,在什么地方完成自动映射?

将映射植入内核代码:
将映射代码写入内核文件(cpu关联文件)中,
在静态映射中,用户是通过map_desc结构来指明物理地址与虚拟地址的映射关系。
第一是填充如下结构(以下结构)

struct map_desc {
    unsigned long virtual;//映射后的虚拟地址
    unsigned long pfn;//物理地址所在的页帧号
    unsigned long length;//映射长度
    unsigned int type;//映射的设备类型
};

Pfn:利用__phys_to_pfn(paddr)可以计算出物理地址所在的物理页帧号。
第二是填充好结构后还得告诉Linux内核(将填充好的结构添加到对应数组中的尾部)

(例如arch/arm/mach-s3c2440/mach-smdk2440.c)
(例如arch/arm/mach-s5p64x0/cpu.c)

static struct map_desc smdk2440_iodesc[] __initdata = {
    /* ISA IO Space map (memory space selected by A24) */
    {
        .virtual    = (u32)S3C24XX_VA_ISA_WORD,
        .pfn        = __phys_to_pfn(S3C2410_CS2),
        .length     = 0x10000,
        .type       = MT_DEVICE,
    }, {
        .virtual    = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
        .pfn        = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
        .length     = SZ_4M,
        .type       = MT_DEVICE,
    }, {
        .virtual    = (u32)S3C24XX_VA_ISA_BYTE,
        .pfn        = __phys_to_pfn(S3C2410_CS2),
        .length     = 0x10000,
        .type       = MT_DEVICE,
    }, {
        .virtual    = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
        .pfn        = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
        .length     = SZ_4M,
        .type       = MT_DEVICE,
    }
};

第三就交给内核在启动时去初始化地址映射了:

static void __init mini2440_map_io(void)
{
    s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
    s3c24xx_init_clocks(12000000);
    s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
}
static void __init smdk2440_map_io(void)
{
    s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
    s3c24xx_init_clocks(16934400);
    s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}

动态映射

动态映射:ioremap()
动态映射:所谓动态映射,是指在驱动程序中采用ioremap函数将物理地址映射为虚拟地址。
原型:void * ioremap (physaddr, size);
返回值:映射后的虚拟地址。


寄存器读写

寄存器读写函数集:
在完成地址映射(通常为静态映射)后,就可以读写寄存器了,Linux内核提供了一系列函数,来读写寄存器。

unsigned ioread8(void *addr);
unsigned ioread16(void *addr);
unsigned ioread32(void *addr);
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);
unsigned iowrite8(u8 value, void *addr);
unsigned iowrite16(u16 value, void *addr);
unsigned iowrite32(u32 value, void *addr);
unsigned writeb(unsigned value, address);
unsigned writew(unsigned value, address);
unsigned writel(unsigned value, address);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值