您的位置:首页 > Web前端

FrameBuffer(LCD设备层编程)

2016-03-26 21:49 260 查看
大部分驱动程序都是内核自带的,主要是为了进行驱动移植。驱动模型分为驱动层和设备层。现在内核已经带有驱动层带代码,还缺少设备层代码。我们可以根据内核提供的LCD驱动程序,分析出设备层代码。

在“平台设备驱动之平台设备”中,可以知道设备层步骤:

1.设备占用的资源;2.设备的平台数据结构struct platform_data(可以从设备相应的驱动程序中获得);3.定义并填充struct platform_device结构;4.注册;5.注销

而1,2中的问题可以从两个方面得到:(1)设备硬件原理图;(2)驱动层的探测函数(probe)

s3c2410fb_probe (drivers\video\s3c2410fb.c)

static int __init s3c24xxfb_probe(struct platform_device *pdev,
enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
struct s3c2410fb_display *display;
struct fb_info *fbinfo;
struct s3c2410fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
int i;
int size;
u32 lcdcon1;

mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
dev_err(&pdev->dev,
"no platform data for lcd, cannot attach\n");
return -EINVAL;
}


platform_data是平台数据结构,其对应的是mach_info,struct s3c2410fb_mach_info(); (include\mach\fb.h)

struct s3c2410fb_mach_info {

struct s3c2410fb_display *displays;    /* attached diplays info */
unsigned num_displays;            /* number of defined displays */
unsigned default_display;

/* GPIOs */

unsigned long    gpcup;
unsigned long    gpcup_mask;
unsigned long    gpccon;
unsigned long    gpccon_mask;
unsigned long    gpdup;
unsigned long    gpdup_mask;
unsigned long    gpdcon;
unsigned long    gpdcon_mask;

/* lpc3600 control register */
unsigned long    lpcsel;
};


struct s3c2410fb_mach_info()中的struct s3c2410fb_display()

struct s3c2410fb_display {
/* LCD type */
unsigned type;

/* Screen size */
unsigned short width;
unsigned short height;

/* Screen info */
unsigned short xres;
unsigned short yres;
unsigned short bpp;

unsigned pixclock;        /* pixclock in picoseconds */
unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */
unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */
unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */
unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */
unsigned short vsync_len;    /* value in lines (TFT) or 0 (STN) */

/* lcd configuration registers */
unsigned long    lcdcon5;
};


平台数据已经找到,接下来是平台数据的初始化和struct platform_device的定义 (arch\arm\mach-s3c2440\mach-mini2440.c)

//(arch\arm\mach-s3c2440\mach-mini2440.c)
static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {

#if !defined (LCD_CON5)
.lcdcon5    = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
#else
.lcdcon5    = LCD_CON5,
#endif

.type        = S3C2410_LCDCON1_TFT,

.width        = LCD_WIDTH,
.height        = LCD_HEIGHT,

.pixclock    = LCD_PIXCLOCK,
.xres        = LCD_WIDTH,
.yres        = LCD_HEIGHT,
.bpp        = 16,
.left_margin    = LCD_LEFT_MARGIN + 1,
.right_margin    = LCD_RIGHT_MARGIN + 1,
.hsync_len    = LCD_HSYNC_LEN + 1,
.upper_margin    = LCD_UPPER_MARGIN + 1,
.lower_margin    = LCD_LOWER_MARGIN + 1,
.vsync_len    = LCD_VSYNC_LEN + 1,
};

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
.displays    = &mini2440_lcd_cfg,
.num_displays    = 1,
.default_display = 0,

.gpccon =       0xaa955699,
.gpccon_mask =  0xffc003cc,
.gpcup =        0x0000ffff,
.gpcup_mask =   0xffffffff,

.gpdcon =       0xaa95aaa1,
.gpdcon_mask =  0xffc0fff0,
.gpdup =        0x0000faff,
.gpdup_mask =   0xffffffff,

.lpcsel        = 0xf82,
};

#endif

/* (arch\arm\plat-s3c24xx\dev.c)*/

static struct resource s3c_lcd_resource[] = {
[0] = {
.start = S3C24XX_PA_LCD,
.end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end   = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}

};

//struct platform_device的定义  (arch\arm\plat-s3c24xx\dev.c)

struct platform_device s3c_device_lcd = {
.name          = "s3c2410-lcd",
.id          = -1,
.num_resources      = ARRAY_SIZE(s3c_lcd_resource),
.resource      = s3c_lcd_resource,
.dev              = {
.dma_mask        = &s3c_device_lcd_dmamask,
.coherent_dma_mask    = 0xffffffffUL
}
};


我在看struct platform_device时,发现里面少了struct platform_data的定义,于是便有了在probe函数中,为什么struct s3c2410fb_mach_info *mach_info=pdev->dev.platform_data?

也就是说为什么pdev->dev.platform_data结构类型会是struct s3c2410fb_mach_info, 比如在LED驱动时,dev.platform_data的结构类型就会是s3c2410_leds_drv_data.led_pdata, 就是说platform_data是怎么实现不同数据结构之间的赋值的?

经查找资料知道,在dev.c ( arch\arm\plat-s3c24xx\dev.c)中,会调用函数void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd), 代码如下

void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
{
struct s3c2410fb_mach_info *npd;

npd = kmalloc(sizeof(*npd), GFP_KERNEL);
if (npd) {
memcpy(npd, pd, sizeof(*npd));
s3c_device_lcd.dev.platform_data = npd;
} else {
printk(KERN_ERR "no memory for LCD platform data\n");
}
}


在这个程序完成了对dev.platformdata的定义,对函数void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)的理解,可以参考http://www.cnblogs.com/armlinux/archive/2010/07/28/2396954.html

p.s. void __init s3c24xx_...注意(初始化函数)init前面的__ , 而不是_ ;之前在调程序时,遇到了这种提示,找了大半天才发现,是这错了_^_

参考资料:

《嵌入式Linux高级驱动教程》 电子工业出版社 深圳信盈达电子有限公司 陈志发 周中孝 李志超 编著
http://www.cnblogs.com/armlinux/archive/2010/07/28/2396954.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: