六亲不认八字分析实例:LED驱动学习

来源:百度文库 编辑:中财网 时间:2024/04/29 08:53:11

是一个char字符类型的驱动

//配置模式为输出端口

static unsigned int led_cfg_table [] = {

S3C2410_GPB5_OUTP,

S3C2410_GPB6_OUTP,

S3C2410_GPB7_OUTP,

S3C2410_GPB8_OUTP,

};

s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);

s3c2410_gpio_cfgpin(37, 0x01 << 10);

这个在\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中定义

#define S3C2410_GPB5 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

#define S3C2410_GPB5_INP (0x00 << 10)

#define S3C2410_GPB5_OUTP (0x01 << 10)

#define S3C2410_GPB5_nXBACK (0x02 << 10)

S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))

#define S3C2410_GPIO_BANKA (32*0)

#define S3C2410_GPIO_BANKB (32*1)

static int __init dev_init(void)

{

int ret;

int i;

for (i = 0; i < 4; i++) {

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

s3c2410_gpio_setpin(led_table[i], 0);

}

在驱动的初始化函数中经常看到,__init 前缀, 这个在下面文件中定义

file:/include/linux/init.h

· /* These macros are used to mark some functions or  

·  * initialized data (doesn't apply to uninitialized data)  

·  * as `initialization' functions. The kernel can take this

·  * as hint that the function is used only during the initialization  

·  * phase and free up used memory resources after  

·  *  

·  * Usage:  

·  * For functions:  

·  *  

·  * You should add __init immediately before the function name, like:  

·  *  

·  * static void __init initme(int x, int y)  

·  * {  

·  *    extern int z; z = x * y;  

·  * } 

主要是将这个函数放在init段section中,这样可以在执行完成后,释放内存。

void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

{

void __iomem *base = S3C24XX_GPIO_BASE(pin);

unsigned long mask;

unsigned long con;

unsigned long flags;

if (pin < S3C2410_GPIO_BANKB) {

mask = 1 << S3C2410_GPIO_OFFSET(pin);

} else {

mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; //3<<(37*2)

}

switch (function) {

case S3C2410_GPIO_LEAVE:

mask = 0;

function = 0;

break;

case S3C2410_GPIO_INPUT:

case S3C2410_GPIO_OUTPUT:

case S3C2410_GPIO_SFN2:

case S3C2410_GPIO_SFN3:

if (pin < S3C2410_GPIO_BANKB) {

function -= 1;

function &= 1;

function <<= S3C2410_GPIO_OFFSET(pin);

} else {

function &= 3;

function <<= S3C2410_GPIO_OFFSET(pin)*2;

}

}

/* modify the specified register wwith IRQs off */

local_irq_save(flags);

con = __raw_readl(base + 0x00);

con &= ~mask;

con |= function;

__raw_writel(con, base + 0x00);

local_irq_restore(flags);

}

#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)

#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

S3C24XX_VA_GPIO这个在\arch\arm\plat-s3c24xx\include\plat\map.h中定义,这个是Memory Map的定义:

#define S3C2410_PA_GPIO (0x56000000)

#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)

#define S3C24XX_SZ_GPIO SZ_1M

其中PA表示Physical Address,VA表示Virtual Address

由pdf中的GPIO的定义可以看出是一致的。

/* UARTs */

#define S3C24XX_VA_UART S3C_VA_UART

#define S3C2410_PA_UART (0x50000000)

#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */

#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))

#define S3C_ADDR_BASE (0xF4000000)

__iomem是2.6.9中加入的特性。是用来个表示指会指向一个I/O的内存空间。主要是为了driver的通用性考虑。由于不同的CPU体系结构对 I/O空间的表示可能不同。当使用__iomem时,compiler会忽略对变量的检查(因为用的是void __iomem)。但sparse会对它进行检查,当__iomem的指针和正常的指针混用时,就会发出一些warnings

有个地方讲不通:(这个地方应该是都不满足switch的条件,所以,function不改变)

#define S3C2410_GPIO_LEAVE (0xFFFFFFFF)

#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */

#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)

#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */

#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */

#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */

#define S3C2410_GPB5_OUTP (0x01 << 10)

所以,

s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);

switch (function)

根本对不上号?

#define __raw_readl(p) (*(unsigned long *)(p))

#define __raw_writel(v,p) (*(unsigned long *)(p) = (v))

*******************************

static struct miscdevice misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_fops,

};

驱动注册时,如果次号指定MISC_DYNAMIC_MINOR则进行动态分配。

#define DEVICE_NAME "leds"

include\linux

在这个头文件中主要是misc(混合)设备注册和注销:
其它类型---不能严格划分的设备类型,也叫混合类型
有:
1.
结构体:
struct miscdevice {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
};
2.
misc设备注册:
extern int misc_register(struct miscdevice * misc);
misc设备注销:
extern int misc_deregister(struct miscdevice * misc);
说明:上面的结构体是注册混合设备所需要的参数。主要有:
minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。利用次设备号来区分设备的。
name:misc设备名。
*fops:misc设备文件操作结构体。
其它三个参数很少用。

杂项设备(misc device)

杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。

也就是说,misc设备其实也就是特殊的字符设备,可自动生成设备节点。

module_init(dev_init);

module_exit(dev_exit);

参考:http://blog.csdn.net/zhandoushi1982/archive/2009/12/02/4927579.aspx