嵌入式 linux中的 lcd驱动分析
作者:杰洲村的木棉 学校:广东工业大学 QQ:568109894
在嵌入式 linux中,lcd和触摸屏驱动都是字符驱动,采用“文件层-驱动层”的接口方式,本文档中分析的 lcd驱动是针对
linux2.6.13内核的,本人用的开发板是 qq2440,lcd是三星的 LTV3500V(带触摸屏的),具体分析的文件:
是
"include/linux/fb.h","drivers/video/s3c2410fb.h","drivers/video/s3c2410fb.c","drivers/video/fbmem.c","/include/asm/arch-
s3c2410.fb.h(些头文件是针对 s3c2440或 s3c2410芯片的)",“/home/linux/5/kernel-2.6.13/arch/arm/mach-s3c2410/mach-
smdk2410.c"(驱动移植主要就是要修改这个文件,配置一些参数)。详细看一下 LCD的驱动,实际上,几乎 lcd设备驱动所要做的所有事情
就是填充 fb_info结构然后向系统注册或注销它
(1)fb.h包含了 framebuffer所用到的结构
(2)fbmem.c处于 Framebuffer设备驱动技术的中心位置.它为上层应用程序提供系统调用也为下一层的特定硬件驱动提供接口;那些底层
硬件驱动需要用到这儿的接口来向系统内核注册它们自己. fbmem.c 为所有支持 FrameBuffer的设备驱动提供了通用的接口,避免重复工
作.
(3)s3c2410fb.c就是特定硬件驱动(针对 s3c2410芯片的),fbmem.c就是沟通应用层跟 s3c2410fb.c的桥梁
FrameBuffer设备驱动基于如下几个文件:
1)include/linux/fb.h
2)drivers/video/fbmem.c
3)drivers/video/s3c2410fb.c
4)drivers/video/s3c2410fb.h
5)include/asm/arch-s3c2410/fb.h
现在先来分析这两个文件:
1.fb.h包含了 framebuffer所用到的结构
1)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 */
};
2)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 */
__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 */
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
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 */
};
3)fb_cmap
描述设备无关的颜色映射信息。可以通过 FBIOGETCMAP 和 FBIOPUTCMAP 对应的 ioctl操作设定或获取颜色映射信息
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};
4)fb_info
(1)定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个 fb_ops指针, 指向驱动设备工作所需的函数集。
struct fb_info {
int node;
int flags;
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
struct fb_ops *fbops; //(注意这个结构)
struct device *device;
struct class_device *class_device; /* sysfs per device attrs */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
};
(2)fb_info中纪录了帧缓冲设备的全部信息,包括设备的设置参数,状态以及操作函数指针。每一个帧缓冲设备都必须对
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
应一个 fb_info结构。其中成员 变量Modename为设备名称,fontname为显示字体,fbops为指向底层操作的函数的指针,
这些函数是需要驱动程序开发人员编写的。成员 fb_var_screeninfo和 fb_fix_screeninfo也是结构体。其中 fb_var_screeninfo
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
用户可修改的显示控制器参数,包括屏幕分辨率和每个像素点的 比特数。fb_var_screeninfo中的 xres定义屏幕一行有
多少个点, yres定义屏幕一列有多少个点, bits_per_pixel定义每个点用多少个字节
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示。而 fb_fix_screeninfo中记录用户不能
修改的显示控制器的参数,如屏幕缓冲区的 物理地址,长度。当对帧缓冲设备进行映射操作的时候,就是从
fb_fix_screeninfo中取得缓冲区物理地址的。重要:::(上面所说的数据成员都是需要在驱 动程序中设置的)。
5)fb_fops
(1)结构包含在 fb_info结构中,指向驱动设备工作所需的函数集。fb_ops结构中包含了很多涵数指针(在 drivers/video/fbmem.c文件中
定义)
(2)用户应用程序通过 ioctl()系统调用操作硬件,fb_ops 中的函数就用于支持这些操作。(注: fb_ops结构与 file_operations 结构
不同,fb_ops是底层操作的抽象,而 file_operations是提供给上层系统调用的接口,可以直接调用.
ioctl()系统调用在文件 fbmem.c中实现,通过观察可以发现 ioctl()命令与 fb_ops’s 中函数的关系:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display
如果我们定义了 fb_XXX_XXX
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
,用户程序就可以使用 FBIOXXXX宏的 ioctl()操作来操作硬件。
当应用程序对设备文件进行 ioctl操作时候会调用它们。对于 fb_get_fix(),应用程序传入的是 fb_fix_screeninfo结构,在
函数中对其成员变量赋值,主要是 smem_start(缓冲区起始地址)和 smem_len(缓冲区长度),最终返回给应用程序。
static struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap, //这个在哪定义呢???(在 fbmem.c中定义,这个函数比较重要,是 framebuffer的映射函数)
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
};
*/
/*
* Frame buffer operations
*
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mecanism we have
* in 2.6. Some may be called at interrupt time at this point though.
*/
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 file *file, char __user *buf, size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
/* checks var and eventually tweaks it to something supported,
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
* 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 inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, struct fb_info *info);
/* Handle 32bit compat ioctl (optional) */
long (*fb_compat_ioctl)(struct file *f, unsigned cmd, unsigned long arg,
struct fb_info *info);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
};
3)我们来研究一下 fb_ioctl接口函数:
当应用程序对设备文件进行 ioctl操作时候会调用它们。对于 fb_get_fix(),应用程序传入的是 fb_fix_screeninfo结构,在
函数中对其成员变量赋值,主要是 smem_start(缓冲区起始地址)和 smem_len(缓冲区长度),最终返回给应用程序。
static int
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_con2fbmap con2fb;
struct fb_cmap_user cmap;
struct fb_event event;
void __user *argp = (void __user *)arg;
int i;
if (!fb)
return -ENODEV;
switch (cmd) {
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
case FBIOGET_VSCREENINFO://获取屏的可变参数(fb_get_var)
return copy_to_user(argp, &info->var,
sizeof(var)) ? -EFAULT : 0;
case FBIOPUT_VSCREENINFO://设置屏的可变参数(fb_set_var)
if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT;
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
i = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
if (i) return i;
if (copy_to_user(argp, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIOGET_FSCREENINFO://获取屏的固定参数(fb_get_fix)
return copy_to_user(argp, &info->fix,
sizeof(fix)) ? -EFAULT : 0;
case FBIOPUTCMAP://设置调色板(fb_get_cmap)
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
return (fb_set_user_cmap(&cmap, info));
case FBIOGETCMAP://获取调色板信息(fb_get_cmap)
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
return fb_cmap_to_user(&info->cmap, &cmap);
case FBIOPAN_DISPLAY:(fb_pan_display)
if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT;
acquire_console_sem();
i = fb_pan_display(info, &var);
release_console_sem();
if (i)
return i;
if (copy_to_user(argp, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIO_CURSOR:
return -EINVAL;
case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
con2fb.framebuffer = -1;
event.info = info;
event.data = &con2fb;
notifier_call_chain(&fb_notifier_list,
FB_EVENT_GET_CONSOLE_MAP, &event);
return copy_to_user(argp, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
case FBIOPUT_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
return - EFAULT;
if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
return -EINVAL;
#ifdef CONFIG_KMOD
if (!registered_fb[con2fb.framebuffer])
try_to_load(con2fb.framebuffer);
#endif /* CONFIG_KMOD */
if (!registered_fb[con2fb.framebuffer])
return -EINVAL;
event.info = info;
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
event.data = &con2fb;
return notifier_call_chain(&fb_notifier_list,
FB_EVENT_SET_CONSOLE_MAP,
&event);
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
i = fb_blank(info, arg); //开关显示用
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
return i;
default:
if (fb->fb_ioctl == NULL)
return -EINVAL;
return fb->fb_ioctl(inode, file, cmd, arg, info);
}
}
2.fbmem.c(.mmap =fb_mmap函数比较重要,是 framebuffer的映射函数,如我的程序就用到
vd->map = ( unsigned char * )mmap( 0, vd->mbuf.size, PROT_READ | PROT_WRITE,
MAP_SHARED, vd->fd, 0 ),请自己阅读我的一分关于视频采集系统的文档(已经付上源程
序))
linux内核启动时将自动加载定义在 linux/drivers/video/fbmem.c文件中的 framebuffer
1)全局变量
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
这两变量记录了所有 fb_info 结构的实例,fb_info 结构描述显卡的当前状态,所有设备对应的 fb_info 结构都保存在这个数组中,当
一个 FrameBuffer设备驱动向系统注册自己时,其对应的 fb_info 结构就会添加到这个结构中,同时 num_registered_fb 为自动加 1.
2)fbmem.c 实现了如下函数.
register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);
这两个是提供给下层 FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情
就是填充 fb_info结构然后向系统注册或注销它。
3)fb_set_var()
在所有的这些函数中 fb_set_var()是最重要的,它用于设定显示卡的模式和其它属性,下面是函数 fb_set_var()的执行步骤:
(1)检测是否必须设定模式
(2)设定模式
(3)设定颜色映射
(4) 根据以前的设定重新设置 LCD控制器的各寄存器。
第四步表明了底层操作到底放置在何处。在系统内存中分配显存后,显存的起始地址及长度将被设定到 LCD控制器的各寄存器中(一般通
过 fb_set_var()函数),显存中的
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
将自动被 LCD控制器输出到屏幕上。另一方面,用户程序通过函数 mmap()将显存映射到用户进程
地址空间中,然后用户进程向映射空间发送的所有数据都将会被显示到 LCD显示器上。
流程图:
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
s3c2410fb.c中 var->activate设置为 FB_ACTIVATE_NOW,所以这里只考虑条件 2。
/*这是 linux2.6.13的 fb_set_var
int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
int err, flags = info->flags;
1:
if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2;
int ret = 0;
fb_var_to_videomode(&mode1, var);
fb_var_to_videomode(&mode2, &info->var);
/* make sure we don't delete the videomode of current var */
ret = fb_mode_is_equal(&mode1, &mode2);
if (!ret) {
struct fb_event event;
event.info = info;
event.data = &mode1;
ret = notifier_call_chain(&fb_notifier_list,
FB_EVENT_MODE_DELETE, &event);
}
if (!ret)
fb_delete_videomode(&mode1, &info->modelist);
return ret;
}
2:
if ((var->activate & FB_ACTIVATE_FORCE) ||
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
if (!info->fbops->fb_check_var) {
*var = info->var;
return 0;
}
if ((err = info->fbops->fb_check_var(var, info)))//先检查一下设置是否符合要求
return err;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {//条件符合
struct fb_videomode mode;
int err = 0;
info->var = *var;
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);//设置可变参数
fb_pan_display(info, &info->var);//s3c2410不支持硬件虚拟显示,在 s3c2410fb.c
上没有实现该接口
/*什么功能都没有实现
static int s3c2410fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
gprintk("pan_display(var=%p, info=%p)\n", var, info);
gprintk("pan_display: xoffset=%d\n", var->xoffset);
gprintk("pan_display: yoffset=%d\n", var->yoffset);
return 0;
}
*/
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
fb_set_cmap(&info->cmap, info);//调色板设置
fb_var_to_videomode(&mode, &info->var);
if (info->modelist.prev && info->modelist.next &&
!list_empty(&info->modelist))
err = fb_add_videomode(&mode, &info->modelist);
if (!err && (flags & FBINFO_MISC_USEREVENT)) {
struct fb_event event;
info->flags &= ~FBINFO_MISC_USEREVENT;
event.info = info;
notifier_call_chain(&fb_notifier_list,
FB_EVENT_MODE_CHANGE,
&event);
}
}
}
return 0;
}
*/
/*这是网上的一个参考函数:
static int s3c2440fb_set_var(struct fb_var_screeninfo *var,int con,struct fb_info *info){
struct s3c2440fb_info *fbi= (struct s3c2440fb_info *)info; /* 将显示模式读入结构体 s3c2440fb_info*/
struct fb_var_screeninfo *dvar= get_con_var(&fbi->fb,con);
int err;
err= s3c2440fb_validate_var(var,fbi); /* 显示模式是否有效 */
if(err) /* 无效返回 */
return err;
dvar->red=fbi->rgb[rgbidx]->red; /* 将显示参数写入结构体 fb_var_screeninfo */
dvar->green=fbi->rgb[rgbidx]->green;
dvar->blue=fbi->rgb[rgbidx]->bIue;
dvar->transp=fbi->rgb[rgbidx]->transp;
display->var= *dvar;
……
s3c2440fb_hw_set_var (dvar,fbi); /* 设置
RGB颜色信息,设置 S3C2440A的 LCD控制寄存器 */
return 0;
}
*/
3.s3c2410fb.c
qq2440开发板的 framdbuffer驱动程序在 linux/drivers/video/s3c2410fb.c中实现,由内核调用 int __devinit
s3c2410fb_init(void)开始
1)驱动初始化
int __devinit s3c2410fb_init(void)
{
return platform_driver_register(&s3c2410fb_driver); /*注册 LCD驱动进系统*/
}
很简单就是把这个驱动注册进系统, 系统会找到 LCD设备并调用这个驱动的 probe函数。
2)初始化 lcd 控制器的地址指针(LCDSADDR1:高位帧缓存地址寄存器 1;LCDSADDR2:高位帧缓存地址寄存器 2;LCDSADDR3:虚拟屏地址寄存器)
/* s3c2410fb_set_lcdaddr
*
* initialise lcd controller address pointers
*/
static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
{
struct fb_var_screeninfo *var = &fbi->fb.var;
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn
unsigned long saddr1, saddr2, saddr3;
saddr1 = fbi->fb.fix.smem_start >> 1;
saddr2 = fbi->fb.fix.smem_start;
saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
saddr2>>= 1;
saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres);
gprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
gprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
gprintk("LCDSADDR3 = 0x%08lx\n", saddr3);
writel(saddr1, S3C2410_LCDSADDR1);
writel(saddr2, S3C2410_LCDSADDR2);
writel(saddr3, S3C2410_LCDSADDR3);
}
3)
static inline struct s3c2410fb_info *fb_to_s3cfb(struct fb_info *info)
{
return container_of(info, struct s3c2410fb_info, fb);
}
//解析
container_of()宏
指针 ptr指向结构体 type中的成员 member;通过指针 ptr,返回结构体 type的起始地址
type
|----------|
| |
| |
|----------|
ptr-->| member --|
|----------|
| |
| |
|----------|
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
* */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); -\
(type *)( (char *)__mptr - offsetof(type,member) );})
--------------------------------------------------
d = usb_device->dev.driver
container_of(d, struct usb_device_driver, drvwrap.driver)
struct usb_device
|----------------------------|
| |
| |
|----------------------------|
| | struct device
|struct device_driver *driver|--+
| | -|
|----------------------------| -|
| | -|
| | -|
|----------------------------| -|
|
+-------------------------------+
P