本文共 3541 字,大约阅读时间需要 11 分钟。
本人的项目是一个用oled来显示的android项目;需要在系统睡眠关闭主屏幕的时候,一起把oled屏幕关掉。但这是并没有进入系统睡眠。因此不能使用kernel里的suspend 与resume机制来控制oled的显示和背光。 可以使用framebuffer的功能来从用户态到kernel态来传递命令。
在用户层,可以使用消息的机制,来获得用户关屏的动作,无论是短按电源键还是时间到关屏,都会有一个消息发布;这是上层hardware从可以获得这个消息,然后通过framebuffer来告知kernel层;本文主要说明这个用户层和kernel之间的通信机制。
一. kernel对framebuffer的注册和使用
1. probe函数里的变量定义:
struct fb_info *info; u32 vmem_size; struct ssd1307fb_par *par; u8 *vmem;2. 主要变量的初始化:(只有部分)
info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev); if (!info) { dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); return -ENOMEM; }
vmem_size = par->width * par->height / 8; vmem = vmalloc(vmem_size); if (!vmem) { dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); ret = -ENOMEM; goto fb_alloc_error; } info->fbops = &ssd1307fb_ops; info->fix = ssd1307fb_fix; info->fix.line_length = par->width / 8; info->fbdefio = &ssd1307fb_defio; dev_info(&client->dev, "%s info->fix.line_length=%d\n", __func__, info->fix.line_length); info->var = ssd1307fb_var; info->var.xres = par->width; info->var.xres_virtual = par->width; info->var.yres = par->height; info->var.yres_virtual = par->height; info->var.red.length = 1; info->var.red.offset = 0; info->var.green.length = 1; info->var.green.offset = 0; info->var.blue.length = 1; info->var.blue.offset = 0; info->screen_base = (char *)vmem; info->fix.smem_start = (unsigned long)vmem; info->fix.smem_len = vmem_size; fb_deferred_io_init(info);3. 注册
ret = register_framebuffer(info); if (ret) { dev_err(&client->dev, "Couldn't register the framebuffer\n"); goto panel_init_error; }4. 在上面的注册中,还有一些文件节点需要定义:
static struct fb_fix_screeninfo ssd1307fb_fix = { .id = "Solomon SSD1307", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_MONO10, .xpanstep = 0, .ypanstep = 0, .ywrapstep = 0, .accel = FB_ACCEL_NONE,};static struct fb_var_screeninfo ssd1307fb_var = { .bits_per_pixel = 1,};
static struct fb_ops ssd1307fb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, .fb_write = ssd1307fb_write, .fb_fillrect = ssd1307fb_fillrect, .fb_copyarea = ssd1307fb_copyarea, .fb_imageblit = ssd1307fb_imageblit, .fb_blank = ssd1305fb_blank,};
static void ssd1307fb_deferred_io(struct fb_info *info, struct list_head *pagelist){ ssd1305fb_update_display(info->par);}static struct fb_deferred_io ssd1307fb_defio = { .delay = HZ, .deferred_io = ssd1307fb_deferred_io,};在上面的注册中, .fb_blank = ssd1305fb_blank, 就是对关屏动作的回调函数的调用。
二、 上层对framebuffer的调用
int fbfd = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; long int screensize = 0; char *fbp = 0; // Open the file for reading and writing fbfd = open("/dev/graphics/fb3", O_RDWR); if (fbfd < 0) { printf("Error: cannot open framebuffer device.\n"); exit(1); } printf("The framebuffer device was opened successfully. fbfd=%x\n", fbfd); screensize = 128 * 8; printf("the screensize is %d\n", screensize ); // Map the device to memory fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int)fbp == -1) { printf("Error: failed to map framebuffer device to memory.\n"); exit(4); } printf("The framebuffer device was mapped to memory successfully.\n"); memcpy(fbp, picture5, screensize); munmap(fbp, screensize); sleep(10); printf("start blank OLED\n"); ioctl(fbfd, FBIOBLANK, 0); // enable bklight ioctl(fbfd, FBIOBLANK, 1); // disable bkilght close(fbfd);在上面中,ioctl(fbfd, FBIOBLANK, 0) ; 函数就是对底层函数ssd1305fb_blank()的调用。
转载地址:http://spngi.baihongyu.com/