一、LCD驱动程序架构
1.裸机驱动代码分析
①LCD初始化:控制器初始化,端口初始化,指明帧缓冲
②LCD图形显示:将图形数据写入帧缓冲
-
void lcd_init()
-
{
-
lcd_port_init(); //初始化gpdcon和gpccon初始化
-
lcd_control_init(); //时序初始化和帧缓冲初始化
-
-
//打开LCD电源
-
GPGCON |= 0b11<<8;
-
LCDCON5 |= (1<<3);
-
LCDCON1 |= 1;
-
}
2.帧缓冲体验
帧缓冲:内存中的一段区域,通过对内存的修改。LCD控制器从内存中获取数据,自动的控制LCD的显示。
-
# cat tq2440.bin > /dev/fb0
将图片显示到lcd。
3.帧缓冲架构
/dev/fb0就是帧缓冲,字符设备
fbmem_init():
-
static int __init
-
fbmem_init(void)
-
{
-
proc_create("fb", 0, NULL, &fb_proc_fops);
-
-
if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) //注册设备文件,注册帧缓冲,fp_fops是操作函数集
-
printk("unable to get major %d for fb devs\n", FB_MAJOR);
-
-
fb_class = class_create(THIS_MODULE, "graphics");
-
if (IS_ERR(fb_class)) {
-
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
-
fb_class = NULL;
-
}
-
return 0;
-
}
fb_ops:
-
static const struct file_operations fb_fops = {
-
.owner = THIS_MODULE,
-
.read = fb_read, //写入
-
.write = fb_write,
-
.unlocked_ioctl = fb_ioctl,
-
#ifdef CONFIG_COMPAT
-
.compat_ioctl = fb_compat_ioctl,
-
#endif
-
.mmap = fb_mmap,
-
.open = fb_open,
-
.release = fb_release,
-
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
-
.get_unmapped_area = get_fb_unmapped_area,
-
#endif
-
#ifdef CONFIG_FB_DEFERRED_IO
-
.fsync = fb_deferred_io_fsync,
-
#endif
-
};
fb_write:
-
static ssize_t
-
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-
{
-
unsigned long p = *ppos;
-
struct inode *inode = file->f_path.dentry->d_inode;
-
int fbidx = iminor(inode);
-
struct fb_info *info = registered_fb[fbidx];
-
u32 *buffer, *src;
-
u32 __iomem *dst;
-
int c, i, cnt = 0, err = 0;
-
unsigned long total_size;
-
-
if (!info || !info->screen_base)
-
return -ENODEV;
-
-
if (info->state != FBINFO_STATE_RUNNING)
-
return -EPERM;
-
-
if (info->fbops->fb_write)
-
return info->fbops->fb_write(info, buf, count, ppos);
-
-
total_size = info->screen_size;
-
-
if (total_size == 0)
-
total_size = info->fix.smem_len;
-
-
if (p > total_size)
-
return -EFBIG;
-
-
if (count > total_size) {
-
err = -EFBIG;
-
count = total_size;
-
}
-
-
if (count + p > total_size) {
-
-
.........各种info
-
}
info结构:
-
struct fb_info {
-
int node;
-
int flags;
-
struct mutex lock; //控制io操作锁
-
struct fb_var_screeninfo var;/*LCD可变参数*/
-
struct fb_fix_screeninfo fix;/*LCD固定参数*/
-
struct fb_monspecs monspecs; /*LCD显示器标准*/
-
struct work_struct queue; /*帧缓冲事件队列*/
-
struct fb_pixmap pixmap; /*图像硬件mapper*/
-
struct fb_pixmap sprite; /*光标硬件mapper*/
-
struct fb_cmap cmap; /*当前的颜色表*/
-
struct fb_videomode *mode; /*当前的显示模式*/
-
-
#ifdef CONFIG_FB_BACKLIGHT
-
struct backlight_device *bl_dev;/*对应的背光设备*/
-
struct mutex bl_curve_mutex;
-
u8 bl_curve[FB_BACKLIGHT_LEVELS];/*背光调整*/
-
#endif
-
#ifdef CONFIG_FB_DEFERRED_IO
-
struct delayed_work deferred_work;
-
struct fb_deferred_io *fbdefio;
-
#endif
-
-
struct fb_ops *fbops; /*对底层硬件操作的函数指针*/
-
struct device *device;
-
struct device *dev; /*fb设备*/
-
int class_flag;
-
#ifdef CONFIG_FB_TILEBLITTING
-
struct fb_tile_ops *tileops; /*图块Blitting*/
-
#endif
-
char __iomem *screen_base; /*虚拟基地址*/
-
unsigned long screen_size; /*LCD IO映射的虚拟内存大小*/
-
void *pseudo_palette; /*伪16色颜色表*/
-
#define FBINFO_STATE_RUNNING 0
-
#define FBINFO_STATE_SUSPENDED 1
-
u32 state; /*LCD的挂起或恢复状态*/
-
void *fbcon_par;
-
void *par;
-
};
主要是fb_var_screeninfo、fb_fix_screeninfo、fb_ops三个结构体:
struct fb_var_screeninfo:主要记录用户可以修改的控制器的参数。
-
struct fb_var_screeninfo {
-
__u32 xres; /* visible resolution */
-
__u32 yres;
-
__u32 xres_virtual; /* virtual resolution */
-
__u32 yres_virtual;
-
__u32 xoffset; /* offset from virtual to visible */
-
__u32 yoffset; /* resolution */
-
-
__u32 bits_per_pixel; /* guess what */每个像素的位数即BPP
-
__u32 grayscale; /* != 0 Graylevels instead of colors */
-
-
struct fb_bitfield red; /* bitfield in fb mem if true color, */
-
struct fb_bitfield green; /* else only length is significant */
-
struct fb_bitfield blue;
-
struct fb_bitfield transp; /* transparency */
-
-
__u32 nonstd; /* != 0 Non standard pixel format */
-
-
__u32 activate; /* see FB_ACTIVATE_* */
-
-
__u32 height; /* height of picture in mm */
-
__u32 width; /* width of picture in mm */
-
-
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
-
-
/* Timing: All values in pixclocks, except pixclock (of course) */
-
__u32 pixclock; /* pixel clock in ps (pico seconds) */
-
__u32 left_margin; /* time from sync to picture */
-
__u32 right_margin; /* time from picture to sync */
-
__u32 upper_margin; /* time from sync to picture */
-
__u32 lower_margin;
-
__u32 hsync_len; /* length of horizontal sync */
-
__u32 vsync_len; /* length of vertical sync */
-
__u32 sync; /* see FB_SYNC_* */
-
__u32 vmode; /* see FB_VMODE_* */
-
__u32 rotate; /* angle we rotate counter clockwise */
-
__u32 reserved[5]; /* Reserved for future compatibility */
-
};
fb_fix_screeninfo:主要记录用户不可以修改的控制器的参数
-
struct fb_fix_screeninfo {
-
char id[16]; /* identification string eg "TT Builtin" */
-
unsigned long smem_start; /* Start of frame buffer mem */
-
/* (physical address) */
-
__u32 smem_len; /* Length of frame buffer mem */
-
__u32 type; /* see FB_TYPE_* */
-
__u32 type_aux; /* Interleave for interleaved Planes */
-
__u32 visual; /* see FB_VISUAL_* */
-
__u16 xpanstep; /* zero if no hardware panning */
-
__u16 ypanstep; /* zero if no hardware panning */
-
__u16 ywrapstep; /* zero if no hardware ywrap */
-
__u32 line_length; /* length of a line in bytes */
-
unsigned long mmio_start; /* Start of Memory Mapped I/O */
-
/* (physical address) */
-
__u32 mmio_len; /* Length of Memory Mapped I/O */
-
__u32 accel; /* Indicate to driver which */
-
/* specific chip/card we have */
-
__u16 reserved[3]; /* Reserved for future compatibility */
-
};
fb_ops:底层硬件操作的函数指针
-
struct fb_ops {
-
/* open/release and usage marking */
-
struct module *owner;
-
int (*fb_open)(struct fb_info *info, int user);
-
int (*fb_release)(struct fb_info *info, int user);
-
-
/* For framebuffers with strange non linear layouts or that do not
-
* work with normal memory mapped access
-
*/
-
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
-
size_t count, loff_t *ppos);
-
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
-
size_t count, loff_t *ppos);
-
-
/* checks var and eventually tweaks it to something supported,
-
* DO NOT MODIFY PAR */
-
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
-
-
/* set the video mode according to info->var */
-
int (*fb_set_par)(struct fb_info *info);
-
-
/* set color register */
-
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
-
unsigned blue, unsigned transp, struct fb_info *info);
-
-
/* set color registers in batch */
-
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
-
-
/* blank display */
-
int (*fb_blank)(int blank, struct fb_info *info);
-
-
/* pan display */
-
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
-
-
/* Draws a rectangle */
-
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
-
/* Copy data from area to another */
-
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
-
/* Draws a image to the display */
-
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
-
-
/* Draws cursor */
-
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
-
-
/* Rotates the display */
-
void (*fb_rotate)(struct fb_info *info, int angle);
-
-
/* wait for blit idle, optional */
-
int (*fb_sync)(struct fb_info *info);
-
-
/* perform fb specific ioctl (optional) */
-
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
-
unsigned long arg);
-
-
/* Handle 32bit compat ioctl (optional) */
-
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
-
unsigned long arg);
-
-
/* perform fb specific mmap */
-
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
-
-
/* save current hardware state */
-
void (*fb_save_state)(struct fb_info *info);
-
-
/* restore saved state */
-
void (*fb_restore_state)(struct fb_info *info);
-
-
/* get capability given var */
-
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
-
struct fb_var_screeninfo *var);
-
};
http://www.cnblogs.com/lishixian/articles/2999923.html
二、LCD驱动程序分析
s3c2410fb_init:
-
int __init s3c2410fb_init(void)
-
{
-
int ret = platform_driver_register(&s3c2410fb_driver); //注册平台驱动设备
-
-
if (ret == 0)
-
ret = platform_driver_register(&s3c2412fb_driver);;
-
-
return ret;
-
}
s3c2410fb_driver:
-
static struct platform_driver s3c2410fb_driver = {
-
.probe = s3c2410fb_probe, //probe函数,里面调用了s3c24xxfb_probe
-
.remove = s3c2410fb_remove,
-
.suspend = s3c2410fb_suspend,
-
.resume = s3c2410fb_resume,
-
.driver = {
-
.name = "s3c2410-lcd",
-
.owner = THIS_MODULE,
-
},
-
};
s3c24xxfb_probe:
-
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;
-
}
-
-
if (mach_info->default_display >= mach_info->num_displays) {
-
dev_err(&pdev->dev, "default is %d but only %d displays\n",
-
mach_info->default_display, mach_info->num_displays);
-
return -EINVAL;
-
}
-
-
display = mach_info->displays + mach_info->default_display;
-
-
irq = platform_get_irq(pdev, 0); //获取中断号
-
if (irq < 0) {
-
dev_err(&pdev->dev, "no irq for device\n");
-
return -ENOENT;
-
}
-
-
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); //分配fb_info结构
-
if (!fbinfo)
-
return -ENOMEM;
-
-
platform_set_drvdata(pdev, fbinfo);
-
-
info = fbinfo->par;
-
info->dev = &pdev->dev;
-
info->drv_type = drv_type;
-
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取寄存器地址
-
if (res == NULL) {
-
dev_err(&pdev->dev, "failed to get memory registers\n");
-
ret = -ENXIO;
-
goto dealloc_fb;
-
}
-
-
size = (res->end - res->start) + 1;
-
info->mem = request_mem_region(res->start, size, pdev->name);
-
if (info->mem == NULL) {
-
dev_err(&pdev->dev, "failed to get memory region\n");
-
ret = -ENOENT;
-
goto dealloc_fb;
-
}
-
-
info->io = ioremap(res->start, size); //转化成虚拟地址
-
if (info->io == NULL) {
-
dev_err(&pdev->dev, "ioremap() of registers failed\n");
-
ret = -ENXIO;
-
goto release_mem;
-
}
-
-
info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
-
-
dprintk("devinit\n");
-
-
strcpy(fbinfo->fix.id, driver_name);
-
-
/* Stop the video */ //初始化fbinfo结构
-
lcdcon1 = readl(info->io + S3C2410_LCDCON1);
-
writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
-
-
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
-
fbinfo->fix.type_aux = 0;
-
fbinfo->fix.xpanstep = 0;
-
fbinfo->fix.ypanstep = 0;
-
fbinfo->fix.ywrapstep = 0;
-
fbinfo->fix.accel = FB_ACCEL_NONE;
-
-
fbinfo->var.nonstd = 0;
-
fbinfo->var.activate = FB_ACTIVATE_NOW;
-
fbinfo->var.accel_flags = 0;
-
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
-
-
fbinfo->fbops = &s3c2410fb_ops;
-
fbinfo->flags = FBINFO_FLAG_DEFAULT;
-
fbinfo->pseudo_palette = &info->pseudo_pal;
-
-
for (i = 0; i < 256; i++)
-
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
-
-
ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info); //注册中断函数
-
if (ret) {
-
dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
-
ret = -EBUSY;
-
goto release_regs;
-
}
-
-
info->clk = clk_get(NULL, "lcd");
-
if (!info->clk || IS_ERR(info->clk)) {
-
printk(KERN_ERR "failed to get lcd clock source\n");
-
ret = -ENOENT;
-
goto release_irq;
-
}
-
-
clk_enable(info->clk);
-
dprintk("got and enabled clock\n");
-
-
msleep(1);
-
-
/* find maximum required memory size for display */
-
for (i = 0; i < mach_info->num_displays; i++) {
-
unsigned long smem_len = mach_info->displays[i].xres;
-
-
smem_len *= mach_info->displays[i].yres;
-
smem_len *= mach_info->displays[i].bpp;
-
smem_len >>= 3;
-
if (fbinfo->fix.smem_len < smem_len)
-
fbinfo->fix.smem_len = smem_len;
-
}
-
-
/* Initialize video memory */
-
ret = s3c2410fb_map_video_memory(fbinfo); //为帧缓冲分配内存空间。同时使用了dma
-
if (ret) {
-
printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
-
ret = -ENOMEM;
-
goto release_clock;
-
}
-
-
dprintk("got video memory\n");
-
-
fbinfo->var.xres = display->xres;
-
fbinfo->var.yres = display->yres;
-
fbinfo->var.bits_per_pixel = display->bpp;
-
-
s3c2410fb_init_registers(fbinfo); //GPIO初始化
-
-
s3c2410fb_check_var(&fbinfo->var, fbinfo); //设置fb_var_screeninfo
-
-
ret = register_framebuffer(fbinfo); //注册帧缓冲-register_framebuffer
-
if (ret < 0) {
-
printk(KERN_ERR "Failed to register framebuffer device: %d\n",
-
ret);
-
goto free_video_memory;
-
}
-
-
/* create device files */
-
ret = device_create_file(&pdev->dev, &dev_attr_debug);
-
if (ret) {
-
printk(KERN_ERR "failed to add debug attribute\n");
-
}
-
-
printk(KERN_INFO "fb%d: %s frame buffer device\n",
-
fbinfo->node, fbinfo->fix.id);
-
-
return 0;
-
-
free_video_memory:
-
s3c2410fb_unmap_video_memory(fbinfo);
-
release_clock:
-
clk_disable(info->clk);
-
clk_put(info->clk);
-
release_irq:
-
free_irq(irq, info);
-
release_regs:
-
iounmap(info->io);
-
release_mem:
-
release_resource(info->mem);
-
kfree(info->mem);
-
dealloc_fb:
-
platform_set_drvdata(pdev, NULL);
-
framebuffer_release(fbinfo);
-
return ret;
-
}
s3c2410fb_map_vedio_memory:
-
static int __init s3c2410fb_map_video_memory(struct fb_info *info)
-
{
-
struct s3c2410fb_info *fbi = info->par;
-
dma_addr_t map_dma;
-
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
-
-
dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
-
-
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
-
&map_dma, GFP_KERNEL); //为帧缓冲分配内存空间。同时使用了dma
-
-
if (info->screen_base) {
-
/* prevent initial garbage on screen */
-
dprintk("map_video_memory: clear %p:%08x\n",
-
info->screen_base, map_size);
-
memset(info->screen_base, 0x00, map_size);
-
-
info->fix.smem_start = map_dma;
-
-
dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n",
-
info->fix.smem_start, info->screen_base, map_size);
-
}
-
-
return info->screen_base ? 0 : -ENOMEM;
-
}
分析到这里发现并没有设置帧缓冲的地址:
于是可以通过搜索帧地址来辨别,在哪个函数中实现。
s3c2410fb_set_lcdaddr:
-
static void s3c2410fb_set_lcdaddr(struct fb_info *info)
-
{
-
unsigned long saddr1, saddr2, saddr3;
-
struct s3c2410fb_info *fbi = info->par;
-
void __iomem *regs = fbi->io;
-
-
saddr1 = info->fix.smem_start >> 1;
-
saddr2 = info->fix.smem_start;
-
saddr2 += info->fix.line_length * info->var.yres;
-
saddr2 >>= 1;
-
-
saddr3 = S3C2410_OFFSIZE(0) |
-
S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff);
-
-
dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
-
dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
-
dprintk("LCDSADDR3 = 0x%08lx\n", saddr3);
-
-
writel(saddr1, regs + S3C2410_LCDSADDR1); //这里设置了帧缓冲的地址
-
writel(saddr2, regs + S3C2410_LCDSADDR2);
-
writel(saddr3, regs + S3C2410_LCDSADDR3);
-
}
但是如何知道调用顺序呢,可以在函数中调用dump_stack():
-
Backtrace:
-
[<c0049048>] (dump_backtrace+0x0/0x10c) from [<c0373fac>] (dump_stack+0x18/0x1c)
-
r7:232f3302 r6:5bd42233 r5:00000000 r4:3a352944
-
[<c0373f94>] (dump_stack+0x0/0x1c) from [<c01718c8>] (s3c2410fb_set_par+0x150/0x78c)
-
[<c0171778>] (s3c2410fb_set_par+0x0/0x78c) from [<c016a578>] (fbcon_init+0x42c/0x4b8)
-
[<c016a14c>] (fbcon_init+0x0/0x4b8) from [<c0185800>] (visual_init+0xb8/0x100)
-
[<c0185748>] (visual_init+0x0/0x100) from [<c018a65c>] (take_over_console+0x1f4/0x3d8)
-
r7:00000000 r6:c03a6c90 r5:c05a75a0 r4:00000019
-
[<c018a468>] (take_over_console+0x0/0x3d8) from [<c0167050>] (fbcon_takeover+0x7c/0xd4)
-
[<c0166fd4>] (fbcon_takeover+0x0/0xd4) from [<c016b1b0>] (fbcon_event_notify+0x768/0x7b0)
-
r5:ffffffff r4:00000000
-
[<c016aa48>] (fbcon_event_notify+0x0/0x7b0) from [<c0070784>] (notifier_call_chain+0x54/0x94)
-
[<c0070730>] (notifier_call_chain+0x0/0x94) from [<c0070d08>] (__blocking_notifier_call_chain+0x54/0x6c)
-
r9:c04b5008 r8:00000005 r7:ffffffff r6:c381dd98 r5:c04c5470
-
r4:c04c547c
-
[<c0070cb4>] (__blocking_notifier_call_chain+0x0/0x6c) from [<c0070d40>] (blocking_notifier_call_chain+0x20/0x28)
-
r8:c3842a04 r7:00000000 r6:c0513120 r5:c3842800 r4:c381dd60
-
[<c0070d20>] (blocking_notifier_call_chain+0x0/0x28) from [<c015fc48>] (fb_notifier_call_chain+0x1c/0x24)
-
[<c015fc2c>] (fb_notifier_call_chain+0x0/0x24) from [<c0160cf0>] (register_framebuffer+0x154/0x1fc)
-
[<c0160b9c>] (register_framebuffer+0x0/0x1fc) from [<c0014bbc>] (s3c24xxfb_probe+0x4c4/0x6fc)
-
[<c00146f8>] (s3c24xxfb_probe+0x0/0x6fc) from [<c0014e20>] (s3c2410fb_probe+0x14/0x18)
-
[<c0014e0c>] (s3c2410fb_probe+0x0/0x18) from [<c019369c>] (platform_drv_probe+0x20/0x24)
-
[<c019367c>] (platform_drv_probe+0x0/0x24) from [<c0192694>] (driver_probe_device+0x8c/0x1a0)
-
[<c0192608>] (driver_probe_device+0x0/0x1a0) from [<c019283c>] (__driver_attach+0x94/0x98)
-
[<c01927a8>] (__driver_attach+0x0/0x98) from [<c0191f38>] (bus_for_each_dev+0x6c/0x98)
-
r7:c01927a8 r6:c04c56b8 r5:c381de98 r4:00000000
-
[<c0191ecc>] (bus_for_each_dev+0x0/0x98) from [<c0192514>] (driver_attach+0x20/0x28)
-
r7:c04c56b8 r6:00000000 r5:c04c56b8 r4:c001fc68
-
[<c01924f4>] (driver_attach+0x0/0x28) from [<c0191764>] (bus_add_driver+0xa4/0x244)
-
[<c01916c0>] (bus_add_driver+0x0/0x244) from [<c0192b00>] (driver_register+0x74/0x15c)
-
[<c0192a8c>] (driver_register+0x0/0x15c) from [<c0193a80>] (platform_driver_register+0x6c/0x88)
-
r7:c381c000 r6:00000000 r5:c001fa50 r4:c001fc68
-
[<c0193a14>] (platform_driver_register+0x0/0x88) from [<c0014e38>] (s3c2410fb_init+0x14/0x30)
-
[<c0014e24>] (s3c2410fb_init+0x0/0x30) from [<c0044284>] (do_one_initcall+0x3c/0x1bc)
-
[<c0044248>] (do_one_initcall+0x0/0x1bc) from [<c0008438>] (kernel_init+0x88/0xf4)
-
[<c00083b0>] (kernel_init+0x0/0xf4) from [<c005a2e8>] (do_exit+0x0/0x620)
阅读(808) | 评论(0) | 转发(0) |