LCD驱动程序——框架分析(一)

转自http://liu1227787871.blog.163.com/blog/static/205363197201242254810976/

在写lcd驱动程序之前,我们必须先要明白lcd驱动程序编写的框架,这点韦东山老师分析的相当详细,让我们来学习一下吧!首先从fbmem.c文件开始。

(1)我们先找到入口函数:
static int __init fbmem_init(void)
{
proc_create("fb", 0, NULL, &fb_proc_fops);

if (register_chrdev(FB_MAJOR,"fb",&fb_fops))//注册字符设备,FB_MAJOR为主设备号,fb_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;
}
(2)接下来当然要看操作函数集fb_fops
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
..............................................................
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
..............................................................
};
我们选两个来分析:open和read
首先是open函数:
static int fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
int fbidx = iminor(inode);//根据次设备号得到fbidx
struct fb_info *info;
int res = 0;

if (fbidx >= FB_MAX)
return -ENODEV;
info = registered_fb[fbidx];//这个东西很重要,从下面的注释中我们可以看到,帧缓冲区操作函数集定义在这个结构体里,我们将在注释1里来                                                      //具体分析
if (!info)
request_module("fb%d", fbidx);
info = registered_fb[fbidx];
if (!info)
return -ENODEV;
mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info;
if (info->fbops->fb_open)//如果在在帧缓冲区操作函数集里定义了open函数,就会调用open函数,否则就算了
        {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
mutex_unlock(&info->lock);
return res;
}

接下来我们看看read函数
static ssize_t
fb_read(struct file *file, 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, *dst;
u32 __iomem *src;
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_read)//如果操作函数集里定义了read函数,就调用,否则就算了
return info->fbops->fb_read(info, buf, count, ppos);
total_size = info->screen_size;//跟那个数组有关

if (total_size == 0)
total_size = info->fix.smem_len;//跟那个数组有关

if (p >= total_size)
return 0;

if (count >= total_size)
count = total_size;

if (count + p > total_size)
count = total_size - p;

buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,//开辟一个buffer
 GFP_KERNEL);
if (!buffer)
return -ENOMEM;

src = (u32 __iomem *) (info->screen_base + p);//显存基地址也在里面

if (info->fbops->fb_sync)
info->fbops->fb_sync(info);

while (count) {
c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst = buffer;//目的指针指向一个buffer(我们在上面开辟的)
for (i = c >> 2; i--; )
*dst++ = fb_readl(src++);//从基地址读取数据放进buffer中
if (c & 3) {
u8 *dst8 = (u8 *) dst;
u8 __iomem *src8 = (u8 __iomem *) src;

for (i = c & 3; i--;)
*dst8++ = fb_readb(src8++);

src = (u32 __iomem *) src8;
}

if (copy_to_user(buf, buffer, c))//将buffer中的数据拷贝到用户空间,这样在用户空间调用read函数时就把显存内容读出来了
              {
err = -EFAULT;
break;
}
*ppos += c;
buf += c;
cnt += c;
count -= c;
}

kfree(buffer);

return (err) ? err : cnt;
}
注释1:registered_fb[]这个东东哪里来的呢?我们收索了一下,并在本文件的register_framebuffer函数中找到了对它的赋值
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
struct fb_videomode mode;

if (num_registered_fb == FB_MAX)
return -ENXIO;

if (fb_check_foreignness(fb_info))
return -ENOSYS;

num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])//寻找registered_fb数组中空的一项
break;
fb_info->node = i;
mutex_init(&fb_info->lock);

fb_info->dev = device_create(fb_class, fb_info->device,
     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);//在类下面创建设备
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);

if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;

if (!fb_info->pixmap.blit_x)
fb_info->pixmap.blit_x = ~(u32)0;

if (!fb_info->pixmap.blit_y)
fb_info->pixmap.blit_y = ~(u32)0;

if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);

fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;//我们在这里找到了它

event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
return 0;
}
结合之前的知识我们就可以将整个框架大致搭建起来了,我们在驱动程序中调用register_framebuffer(struct fb_info *fb_info)这个函数,并将帧缓冲设备描述结构体struct fb_info *fb_info传递了进来,在这个结构体里就定义了帧缓冲操作函数集,以及各种跟硬件相关的东西。现在我们就清楚了registered_fb[]这个数组只是起到了一个中间变量的作用,在注册函数中将struct fb_info结构体存进去,然后在操作函数中再取出来。
(3)现在框架就搭建起来了,不过为了进一步理解,我们在内核里查看一下有哪些文件调用了register_framebuffer(struct fb_info *fb_info),并适当分析其各种硬件相关设置。其实我们搜索到的这些文件就是我们编写驱动程序应当编写的东西,下面我们以/driver/video/arcfb.c来分析一下:
platform_driver_register(&arcfb_driver);
          int __init arcfb_probe(struct platform_device *dev)
                    register_framebuffer(info);//struct fb_info *info;这个结构体里有各种东东的,包括file_operations结构体,注册前已经设置了
这样一注册的话,fb_info 里设置的东东就都传过去了,内核就可以调用我们自己写的东东了。
我们稍微总结一下驱动程序的流程:
分配fb_info
设置
注册
硬件相关设置
关于驱动程序的编写我们在接下来程序中会涉及。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
240x160 LCD 驱动程序是一种用于控制和驱动 240x160 像素显示屏的软件程序。驱动程序的主要功能是将来自计算机或其他设备的图形或文本数据转换为可在显示屏上显示的像素点。 这种驱动程序通常由芯片制造商提供,并根据特定的硬件规范进行编写。驱动程序通常包括以下几个方面的功能: 1. 初始化:驱动程序需要在使用显示屏之前进行初始化设置。这包括设置传输协议、屏幕分辨率、像素格式以及其他初始配置参数。 2. 数据传输:驱动程序负责将计算机或其他设备发送的图形或文本数据转换为适合在显示屏上显示的格式,并将数据传输到显示屏的控制器芯片。通常,数据以像素行或像素列的形式进行传输。 3. 图像处理:在传输数据之前或之后,驱动程序可以对图像进行处理,例如插值、缩放、旋转或反转。这些处理可以改善图像的质量或适应特定的显示要求。 4. 功能设置:驱动程序还可以提供一些附加功能,例如调整对比度、亮度、色彩饱和度、背光等,以满足用户对显示效果的要求。 5. 异常处理:驱动程序还需要处理可能出现的异常情况,例如传输错误或通信中断。这些异常情况可能导致显示屏无法正常工作,因此驱动程序需要支持错误检测和故障处理机制。 总的来说,240x160 LCD 驱动程序是一种控制和驱动特定分辨率显示屏的软件程序,它负责将图形或文本数据转换为像素点,并在显示屏上显示出来。该驱动程序通常由芯片制造商提供,并包括初始化、数据传输、图像处理、功能设置和异常处理等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值