分类: LINUX
2012-03-31 14:25:09
在linux2.6.38中提供了统一管理外部io的模块。本文的内容是跟踪这些模块,是如何关联起来的。
环境:龙芯1b开发板
一、重点关注的相关的结构体:
gpiolib.c文件,被移植到driver/gpio/目录下。
structgpio_desc {
structgpio_chip *chip;
unsignedlong flags;
/*flag symbols are bit numbers */
#defineFLAG_REQUESTED 0
#defineFLAG_IS_OUT 1
#defineFLAG_RESERVED 2
#defineFLAG_EXPORT 3 /* protected by sysfs_lock */
#defineFLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
#defineFLAG_TRIG_FALL 5 /* trigger on falling edge */
#defineFLAG_TRIG_RISE 6 /* trigger on rising edge */
#defineFLAG_ACTIVE_LOW 7 /* sysfs value has active low */
#defineID_SHIFT 16 /* add new flags before this one */
#defineGPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
#defineGPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
#ifdefCONFIG_DEBUG_FS
constchar *label;
#endif
};
对于上面这个结构体,现在只关心structgpio_chip *chip;
structgpio_chip {
constchar *label;
structdevice *dev;
structmodule *owner;
int (*request)(struct gpio_chip *chip,
unsignedoffset);
void (*free)(struct gpio_chip *chip,
unsignedoffset);
int (*direction_input)(struct gpio_chip *chip,
unsignedoffset);
int (*get)(struct gpio_chip *chip,
unsignedoffset);
int (*direction_output)(struct gpio_chip *chip,
unsignedoffset, int value);
int (*set_debounce)(struct gpio_chip *chip,
unsignedoffset, unsigned debounce);
void (*set)(struct gpio_chip *chip,
unsignedoffset, int value);
int (*to_irq)(struct gpio_chip *chip,
unsignedoffset);
void (*dbg_show)(struct seq_file *s,
structgpio_chip *chip);
int base;
u16 ngpio;
constchar *const *names;
unsigned can_sleep:1;
unsigned exported:1;
/****省略了一些内容********/
};
二、把目光转到龙芯自身的gpio文件。
在1b的内容是放在arch/mips/loongson/sb2f-board/gpio.c
staticstruct gpio_chip ls2f_chip = {
.label = "ls2f",
.direction_input = ls2f_gpio_direction_input,
.get = ls2f_gpio_get_value,
.direction_output = ls2f_gpio_direction_output,
.set = ls2f_gpio_set_value,
.base = 0,
.ngpio = STLS2F_N_GPIO,
};
staticint __init ls2f_gpio_setup(void)
{
returngpiochip_add(&ls2f_chip);
}
arch_initcall(ls2f_gpio_setup);
arch_initcall函数在内核启动的时候被初始化。(详细情况,以后再写)
跟着调用了ls2f_gpio_setup -> gpiochip_add
增加了ls2f_chip。
注意ls2f_chip里面的函数指针(我们姑且成为接口吧)已经在本文件(gpio.c里面实现。)
三、现在跳到gpiochip_add函数(在driver/gpio/gpiolib.c中)
intgpiochip_add(struct gpio_chip *chip)
{
……
for(id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip= chip;
……
}
……
}
上述的代码初始化了gpio_desc数组。在gpiolib.c中定义:
staticstruct gpio_desc gpio_desc[ARCH_NR_GPIOS];
直到这里,gpio_desc已经可以和龙芯下面的函数接口关联起来!
四、在驱动中利用这些接口
如在驱动中调用函数:gpio_direction_output(57,0);
函数定义位gpiolib.c文件中
intgpio_direction_output(unsigned gpio, int value)
{
……
status= chip->direction_output(chip, gpio, value);
……
}
第三点已经说明了是如何关联起来的。于是相当于调用龙芯芯片下的函数:
staticint ls2f_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,int level)
{
u32temp;
u32mask;
if(gpio >= STLS2F_N_GPIO)
return-EINVAL;
gpio_set_value(gpio,level);
if(gpio>= 32){
spin_lock(&gpio_lock);
mask= 1 << (gpio - 32);
temp= LOONGSON_GPIOCFG1;
temp|= mask;
LOONGSON_GPIOCFG1= temp;
temp= LOONGSON_GPIOIE1;
temp&= (~mask);
LOONGSON_GPIOIE1= temp;
spin_unlock(&gpio_lock);
}else{
spin_lock(&gpio_lock);
mask= 1 << gpio;
temp= LOONGSON_GPIOCFG0;
temp|= mask;
LOONGSON_GPIOCFG0= temp;
temp= LOONGSON_GPIOIE0;
temp&= (~mask);
LOONGSON_GPIOIE0= temp;
spin_unlock(&gpio_lock);
}
return0;
}
直到这里,gpio的调用过程已经完成了。
其余的函数:
ls2f_gpio_direction_input,
ls2f_gpio_get_value,
ls2f_gpio_direction_output,
ls2f_gpio_set_value,
的函数类似。
五、debugfs调试gpio端口
可以利用mount-t debugfs none /mnt
那么可以在/mnt下面看到gpio文件
通过echo57 w1 > gpio
就可以对gpio的第57个关键写入1
疑问:为什么这样可以调试呢?
查看文件 ~/driver/gpio/gpiolib.c
staticconst struct file_operations gpiolib_operations = {
.open = gpiolib_open,
.read = gpiolib_read,
.write = gpiolib_write,
.llseek = seq_lseek,
.release = single_release,
};
staticint __init gpiolib_debugfs_init(void)
{
(void)debugfs_create_file("gpio", S_IFREG | S_IRUGO,
NULL,NULL, &gpiolib_operations);
return0;
}
subsys_initcall(gpiolib_debugfs_init);
gpiolib_debugfs_init函数在内核启动的时候被调用。
于是创建了一个gpio文件,同时关联上了gpiolib_operations;
于是,echo57 w1 > gpio
相当于调用 gpiolib_write函数;
staticssize_t gpiolib_write(struct file *file, const char __user *buf,size_t size, loff_t *ppos)
{
charinfo[255];
int port=0,value=0;
memset(info,0, 255);
memcpy(info,buf, size);
printk("gpio:%s\n",info);
if((info[0]>= '0') && (info[0] <= '9')){
port= (info[0] - 48)*10;
if((info[1]>= '0') && (info[1] <= '9')){
port+= (info[1] - 48);
if(info[2]== ' '){
if(info[3] == 'w'){
value = (info[4] == '0')?0:1;
}
}
}
}
if(info[3]== 'r'){
gpio_direction_input(port);
printk("gpio%dstatus = %d\n", port, __gpio_get_value(port));
}elseif(info[3] == 'w'){
printk("write%d to gpio%d\n", value, port);
gpio_direction_output(port, value);
__gpio_set_value(port,value);
}
returnsize;
}
这就很明显了。