linuxGPIO 的模型实现主要一个gpio-chip:(抽象一个GPIO控制器)
struct gpio_chip {
};
---------------------------------------------------------------------------------------
struct gpio_desc {
#define FLAG_REQUESTED
#define FLAG_IS_OUT
#define FLAG_RESERVED
#define FLAG_EXPORT
#define FLAG_SYSFS
#define FLAG_TRIG_FALL
#define FLAG_TRIG_RISE
#define PDESC_ID_SHIFT
#define GPIO_FLAGS_MASK
#define GPIO_TRIGGER_MASK
#ifdef CONFIG_DEBUG_FS
#endif
};
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];定义了一个全局变量ARCH_NR_GPIOS是芯片GPIO口个数。
---------------------------------------------------------------------------------------
对于s3c2440来说,它有个GPIO-CORE.H,在这个文件夹中实现了对gpio-chip的封装和注册函数等。
---------------------------------------------------------------------------------
struct s3c_gpio_chip {
#ifdef CONFIG_PM
#endif
};
-----------------------------------------------------------------------------------
下面先说看看这种模型是如何被加入系统中的,然后再看看在这个模型下,对外提供的API。
在plat-s3c24xx目录下的gpiolib.c中,我们看到了这么一个语句core_initcall(s3c24xx_gpiolib_init),
s3c24xx_gpiolib_init()函数就是在系统中注册GPIO的一个起始点。但是我们就会有疑问,这个函数是怎么被调用的,什么时候调用。这里就简单的说下,具体的以后分析。core_initcall().在linux\init.h中这么个定义
#define core_initcall(fn)
#define __define_initcall(level,fn,id) \
把core_initcall(s3c24xx_gpiolib_init)展开可以得到
—define_initcall("1",s3c24xx_gpiolib_init,1)--->
static initcall_t __initcall_ s3c24xx_gpiolib_init1 __used __attribute__((__section__(".initcall" 1 ".init")))=s3c24xx_gpiolib_init
__initcall_##fn##id ,这个是指针变量,所以整个意思就是把指向函数s3c24xx_gpiolib_init()的指针放入到.initcall1.init的输入段.系统中还有很多的其他输入端,那么这些段在哪里被调用呢。
start_kernel()-->rest_init()-->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND)-->
kernel_init()-->do_basic_setup()-->do_initcalls-->do_one_initcall-->ret.result = fn()
do_initcalls定义如下:
do_initcalls()
{
...
...
}
在__early_initcall_end和__initcall_end定义看arch/arm/kernel/vmlinux.lds
__initcall_start = .;
__initcall_end = .;
所以属于.initcall1.init段的s3c24xx_gpiolib_init()函数会被调用。
关于core_initcall()就先到这。下面是接着叫GPIO
s3c24xx_gpiolib_init()定义如下:
----------------------------------------------------------------------------------
static __init int s3c24xx_gpiolib_init(void)
{
}
-----------------------------------------------------------------------------------
在里面有个s3c24xx_gpios中的没一个元素被s3c_gpiolib_add()调用一次。在本文件内我们还看到
-----------------------------------------------------------------------------------------
struct s3c_gpio_chip s3c24xx_gpios[] = {
};
---------------------------------------------------------------------------------------------
s3c24xx_gpios有七个元素。每一个元素与GPIO口的A,B,C,D,E,F,H组一一对应。拿第一个元素来说就对应A组GPIO。它描述了这组口的一些性质。外面.base是GPACON寄存器的首地址,里面.chip结构体的.base代表该组的第一个引脚。因为A口没有输入功能所以s3c24xx_gpiolib_banka_input为空。s3c24xx_gpiolib_banka_output()设置某个引脚输出的电平值。offset是第几位,value是电平值。第5,6组因为可以设置中断引脚所以.to_irq被赋值。
s3c24xx_gpiolib_bankg_toirq是怎么设置中断呢。
{
}
-------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset)
{
}
-------------------------------------------------------------------------------------------
为什么这样编写呢。这就关心到中断号了。有主中断和次中断。
#define IRQ_EINT0
#define IRQ_EINT1
#define IRQ_EINT2
#define IRQ_EINT3
#define IRQ_EINT4t7
#define IRQ_EINT8t23
#define IRQ_RESERVED6
#define IRQ_CAM
#define IRQ_BATT_FLT
#define IRQ_TICK
#define IRQ_WDT
#define IRQ_TIMER0
#define IRQ_TIMER1
#define IRQ_TIMER2
#define IRQ_TIMER3
#define IRQ_TIMER4
#define IRQ_UART2
#define IRQ_LCD
#define IRQ_DMA0
#define IRQ_DMA1
#define IRQ_DMA2
#define IRQ_DMA3
#define IRQ_SDI
#define IRQ_SPI0
#define IRQ_UART1
#define IRQ_RESERVED24 S3C2410_IRQ(24)
#define IRQ_NFCON
#define IRQ_USBD
#define IRQ_USBH
#define IRQ_IIC
#define IRQ_UART0
#define IRQ_SPI1
#define IRQ_RTC
#define IRQ_ADCPARENT
#define IRQ_EINT4
#define IRQ_EINT5
#define IRQ_EINT6
#define IRQ_EINT7
#define IRQ_EINT8
#define IRQ_EINT9
#define IRQ_EINT10
#define IRQ_EINT11
#define IRQ_EINT12
#define IRQ_EINT13
#define IRQ_EINT14
#define IRQ_EINT15
#define IRQ_EINT16
#define IRQ_EINT17
#define IRQ_EINT18
#define IRQ_EINT19
#define IRQ_EINT20
#define IRQ_EINT21
#define IRQ_EINT22
#define IRQ_EINT23
.ngpio的该组多少个引脚。.label只是对该组的一个标记符。其他的初始化在后面。.pm可以通过如下知道他的值。
如果定义了PM,那么__gpio_pm(x)就为x。
#ifdef CONFIG_PM
extern struct s3c_gpio_pm s3c_gpio_pm_1bit;
extern struct s3c_gpio_pm s3c_gpio_pm_2bit;
extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
#define __gpio_pm(x) x
#else
#define s3c_gpio_pm_1bit NULL
#define s3c_gpio_pm_2bit NULL
#define s3c_gpio_pm_4bit NULL
#define __gpio_pm(x) NULL
#endif
那么这样的7个元素怎么加入的呢。看s3c_gpiolib_add()
-----------------------------------------------------------------------------------------------
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
#ifdef CONFIG_PM
#endif
}
-------------------------------------------------------------------------------------------------
#define BUG_ON(a) if((a)) printf("bug report at line %d from
所以,这里不难看懂了吧。然后进行相关chip的初始化。PM中save和resume分别是保存控制器的值和恢复控制器的值。它的值保存在pm_save[4]里。
gpiochip_add(gc)做什么,这里是真正的注册GPIO了。看源代码:
-----------------------------------------------------------------------------------------
int gpiochip_add(struct gpio_chip *chip)
{
unlock:
fail:
}
-----------------------------------------------------------------------------------------
这里通过base值和.ngpio来确定gpio_desc[],为这个全局变量赋值。如果gpio_desc[]已经注册过了就会退出。
在这里我们就可以知道。gpio_desc[]记录了每一个gpio的属性。注意这里面的一个元素就是一个GPIO引脚。而这个元素是gpio_desc类型,它包含一个指向gpio_chip的结构体,这个结构体是这个引脚所属的GPIO组(A,或者B...)。
到这里,我其实有个疑问,在另外的一个mach-s3c2440中clock.c文件中有实现GPIO控制的API,这里又有,为什么弄这么多呢?