分析内核自带LCD驱动程序drivers\video\fbmem.c
内核自带的LCD驱动程序,在drivers\video\fbmem.c
中,fbmem.c
提供的都是抽象的,具体的实现依赖里边的数组registered_fb[iminor(inode)]
,fb帧缓冲区(Frame Buffer),可以看到以下步骤:
major
fops
register_chrdev
class_create
没有 class_device_create
...
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
...
static int __init
fbmem_init(void)
{
create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
// major register_chrdev fops
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
// class_create
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;
}
查看open函数,和read函数,
static int
fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode); // 获取次设备号
if (!(info = registered_fb[fbidx])) // 以此设备号为数组下标赋值给fb_info
res = info->fbops->fb_open(info,1); // 调用open
return res;
}
static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int fbidx = iminor(inode); // 获取次设备号
struct fb_info *info = registered_fb[fbidx]; // 以次设备号为数组下标赋值给struct fb_info
if (info->fbops->fb_read) // 有read就read
return info->fbops->fb_read(info, buf, count, ppos);
src = (u32 __iomem *) (info->screen_base + p); // 无read读取显存的缓存
*dst++ = fb_readl(src++);
if (copy_to_user(buf, buffer, c)) { // 将读取的内容拷贝到用户空间
为fbmem.c提供硬件设备的数组registered_fb,register_framebuffer为fbmem.c和硬之间桥梁
fbmem.c提供的都是抽象的,具体的实现依赖里边的数组registered_fb[iminor(inode)]
,也在里边定义,修改也是,
struct fb_info *registered_fb[FB_MAX] __read_mostly; // 定义
// fbmem.c依赖register_framebuffer,register_framebuffer会把底层设备向上注册
int
register_framebuffer(struct fb_info *fb_info)
{
// device_create对应于前面fb_class = class_create(THIS_MODULE, "graphics");
// 创建设备节点
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), "fb%d", i);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info; // 修改
event.info = fb_info;
硬件相关以drivers\video\s3c2410fb.c为例
有很多驱动程序都会调用register_framebuffer函数,如我们的drivers\video\s3c2410fb.c
,进去简单看看,
// 入口函数
int __devinit s3c2410fb_init(void)
{
return platform_driver_register(&s3c2410fb_driver); // platform_driver_register --> add
}
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd", // 会根据name寻找同名dev
.owner = THIS_MODULE,
},
};
// 首先根据platform_device获取硬件信息,然后分配struct fb_info,设置,注册framebuffer
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
// 获取硬件信息,
mach_info = pdev->dev.platform_data;
// 然后分配struct fb_info
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
// 设置
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = 0;
// 注册framebuffer
ret = register_framebuffer(fbinfo);
fbmem.c找到硬件信息的例子,如获取分辨率
如果在用户空间想获得屏幕的分辨率,通过fops中的fb_ioctl
可以获得可变的屏幕信息FBIOGET_VSCREENINFO
V(var)
drivers\video\fbmem.c
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_info registered_fb数组很重要
struct fb_ops *fb = info->fbops;
case FBIOGET_VSCREENINFO:
return copy_to_user(argp, &info->var, // 通过struct fb_info找到var把结果拷贝到用户空间
sizeof(var)) ? -EFAULT : 0;
include\linux\fb.h
struct fb_info {
int node;
int flags;
struct fb_var_screeninfo var; /* Current var */ // struct fb_info包含var结构
struct fb_fix_screeninfo fix; /* Current fix */
include\linux\fb.h
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */ // x y 方向的分辨率
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
*** 小结fbmem.c <---- register_framebuffer ----> 硬件
fbmem.c
提供抽象的代码,主要依赖数组registered_fb[iminor(inode)]
的项获取硬件相关代码,而这个数组由register_framebuffer
函数设置,register_framebuffer
函数还完成自动创建设备节点的任务device_create
,完成向上注册设备,而硬件部分就跟fbmem.c
分离,由各自的芯片什么去完成如drivers\video\s3c2410fb.c
然后调用register_framebuffer
完成向上注册设备,