au1200fb.c
来自「Linux环境下视频显示卡设备的驱动程序源代码」· C语言 代码 · 共 1,922 行 · 第 1/4 页
C
1,922 行
pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22; pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1; pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1; /* Window control register 2 */ pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24; pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23; pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21; pdata->enable = (lcd->winenable >> plane) & 1; au_sync();}static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){ int plane; int val;#ifdef CONFIG_PM au1xxx_pm_access(LCD_pm_dev);#endif plane = fbinfo2index(info); print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); if (cmd == AU1200_LCD_FB_IOCTL) { struct au1200_lcd_iodata_t iodata; if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata))) return -EFAULT; print_dbg("FB IOCTL called\n"); switch (iodata.subcmd) { case AU1200_LCD_SET_SCREEN: print_dbg("AU1200_LCD_SET_SCREEN\n"); set_global(cmd, &iodata.global); break; case AU1200_LCD_GET_SCREEN: print_dbg("AU1200_LCD_GET_SCREEN\n"); get_global(cmd, &iodata.global); break; case AU1200_LCD_SET_WINDOW: print_dbg("AU1200_LCD_SET_WINDOW\n"); set_window(plane, &iodata.window); break; case AU1200_LCD_GET_WINDOW: print_dbg("AU1200_LCD_GET_WINDOW\n"); get_window(plane, &iodata.window); break; case AU1200_LCD_SET_PANEL: print_dbg("AU1200_LCD_SET_PANEL\n"); if ((iodata.global.panel_choice >= 0) && (iodata.global.panel_choice < NUM_PANELS)) { struct panel_settings *newpanel; panel_index = iodata.global.panel_choice; newpanel = &known_lcd_panels[panel_index]; au1200_setpanel(newpanel); } break; case AU1200_LCD_GET_PANEL: print_dbg("AU1200_LCD_GET_PANEL\n"); iodata.global.panel_choice = panel_index; break; default: return -EINVAL; } val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata)); if (val) { print_dbg("error: could not copy %d bytes\n", val); return -EFAULT; } } return 0;}static struct fb_ops au1200fb_fb_ops = { .owner = THIS_MODULE, .fb_check_var = au1200fb_fb_check_var, .fb_set_par = au1200fb_fb_set_par, .fb_setcolreg = au1200fb_fb_setcolreg, .fb_blank = au1200fb_fb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_sync = NULL, .fb_ioctl = au1200fb_ioctl, .fb_mmap = au1200fb_fb_mmap,};/*-------------------------------------------------------------------------*/static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id){ /* Nothing to do for now, just clear any pending interrupt */ lcd->intstatus = lcd->intstatus; au_sync(); return IRQ_HANDLED;}/*-------------------------------------------------------------------------*//* AU1200 LCD device probe helpers */static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev){ struct fb_info *fbi = &fbdev->fb_info; int bpp; memset(fbi, 0, sizeof(struct fb_info)); fbi->fbops = &au1200fb_fb_ops; bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); /* Copy monitor specs from panel data */ /* fixme: we're setting up LCD controller windows, so these dont give a damn as to what the monitor specs are (the panel itself does, but that isnt done here...so maybe need a generic catchall monitor setting??? */ memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs)); /* We first try the user mode passed in argument. If that failed, * or if no one has been specified, we default to the first mode of the * panel list. Note that after this call, var data will be set */ if (!fb_find_mode(&fbi->var, fbi, NULL, /* drv_info.opt_mode, */ fbi->monspecs.modedb, fbi->monspecs.modedb_len, fbi->monspecs.modedb, bpp)) { print_err("Cannot find valid mode for panel %s", panel->name); return -EFAULT; } fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL); if (!fbi->pseudo_palette) { return -ENOMEM; } if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { print_err("Fail to allocate colormap (%d entries)", AU1200_LCD_NBR_PALETTE_ENTRIES); kfree(fbi->pseudo_palette); return -EFAULT; } strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id)); fbi->fix.smem_start = fbdev->fb_phys; fbi->fix.smem_len = fbdev->fb_len; fbi->fix.type = FB_TYPE_PACKED_PIXELS; fbi->fix.xpanstep = 0; fbi->fix.ypanstep = 0; fbi->fix.mmio_start = 0; fbi->fix.mmio_len = 0; fbi->fix.accel = FB_ACCEL_NONE; fbi->screen_base = (char __iomem *) fbdev->fb_mem; au1200fb_update_fbinfo(fbi); return 0;}/*-------------------------------------------------------------------------*//* AU1200 LCD controller device driver */static int au1200fb_drv_probe(struct device *dev){ struct au1200fb_device *fbdev; unsigned long page; int bpp, plane, ret; if (!dev) return -EINVAL; for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) win->w[plane].xres = panel->Xres; if (win->w[plane].yres == 0) win->w[plane].yres = panel->Yres; fbdev = &_au1200fb_devices[plane]; memset(fbdev, 0, sizeof(struct au1200fb_device)); fbdev->plane = plane; /* Allocate the framebuffer to the maximum screen size */ fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; fbdev->fb_mem = dma_alloc_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), &fbdev->fb_phys, GFP_KERNEL); if (!fbdev->fb_mem) { print_err("fail to allocate frambuffer (size: %dK))", fbdev->fb_len / 1024); return -ENOMEM; } /* * Set page reserved so that mmap will work. This is necessary * since we'll be remapping normal memory. */ for (page = (unsigned long)fbdev->fb_phys; page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + fbdev->fb_len); page += PAGE_SIZE) { SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */ } print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); /* Init FB data */ if ((ret = au1200fb_init_fbinfo(fbdev)) < 0) goto failed; /* Register new framebuffer */ if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { print_err("cannot register new framebuffer"); goto failed; } au1200fb_fb_set_par(&fbdev->fb_info);#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) if (plane == 0) if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { /* Start display and show logo on boot */ fb_set_cmap(&fbdev->fb_info.cmap, &fbdev->fb_info); fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); }#endif } /* Now hook interrupt too */ if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) { print_err("fail to request interrupt line %d (err: %d)", AU1200_LCD_INT, ret); goto failed; } return 0;failed: /* NOTE: This only does the current plane/window that failed; others are still active */ if (fbdev->fb_mem) dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); if (fbdev->fb_info.cmap.len != 0) fb_dealloc_cmap(&fbdev->fb_info.cmap); if (fbdev->fb_info.pseudo_palette) kfree(fbdev->fb_info.pseudo_palette); if (plane == 0) free_irq(AU1200_LCD_INT, (void*)dev); return ret;}static int au1200fb_drv_remove(struct device *dev){ struct au1200fb_device *fbdev; int plane; if (!dev) return -ENODEV; /* Turn off the panel */ au1200_setpanel(NULL); for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { fbdev = &_au1200fb_devices[plane]; /* Clean up all probe data */ unregister_framebuffer(&fbdev->fb_info); if (fbdev->fb_mem) dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); if (fbdev->fb_info.cmap.len != 0) fb_dealloc_cmap(&fbdev->fb_info.cmap); if (fbdev->fb_info.pseudo_palette) kfree(fbdev->fb_info.pseudo_palette); } free_irq(AU1200_LCD_INT, (void *)dev); return 0;}#ifdef CONFIG_PMstatic int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level){ /* TODO */ return 0;}static int au1200fb_drv_resume(struct device *dev, u32 level){ /* TODO */ return 0;}#endif /* CONFIG_PM */static struct device_driver au1200fb_driver = { .name = "au1200-lcd", .bus = &platform_bus_type, .probe = au1200fb_drv_probe, .remove = au1200fb_drv_remove,#ifdef CONFIG_PM .suspend = au1200fb_drv_suspend, .resume = au1200fb_drv_resume,#endif};/*-------------------------------------------------------------------------*//* Kernel driver */static void au1200fb_setup(void){ char* options = NULL; char* this_opt; int num_panels = ARRAY_SIZE(known_lcd_panels); int panel_idx = -1; fb_get_options(DRIVER_NAME, &options); if (options) { while ((this_opt = strsep(&options,",")) != NULL) { /* Panel option - can be panel name, * "bs" for board-switch, or number/index */ if (!strncmp(this_opt, "panel:", 6)) { int i; long int li; char *endptr; this_opt += 6; /* First check for index, which allows * to short circuit this mess */ li = simple_strtol(this_opt, &endptr, 0); if (*endptr == '\0') { panel_idx = (int)li; } else if (strcmp(this_opt, "bs") == 0) { extern int board_au1200fb_panel(void); panel_idx = board_au1200fb_panel(); } else for (i = 0; i < num_panels; i++) { if (!strcmp(this_opt, known_lcd_panels[i].name)) { panel_idx = i; break; } } if ((panel_idx < 0) || (panel_idx >= num_panels)) { print_warn("Panel %s not supported!", this_opt); } else panel_index = panel_idx; } else if (strncmp(this_opt, "nohwcursor", 10) == 0) { nohwcursor = 1; } /* Unsupported option */ else { print_warn("Unsupported option \"%s\"", this_opt); } } }}#ifdef CONFIG_PMstatic int au1200fb_pm_callback(au1xxx_power_dev_t *dev, au1xxx_request_t request, void *data) { int retval = -1; unsigned int d = 0; unsigned int brightness = 0; if (request == AU1XXX_PM_SLEEP) { board_au1200fb_panel_shutdown(); } else if (request == AU1XXX_PM_WAKEUP) { if(dev->prev_state == SLEEP_STATE) { int plane; au1200_setpanel(panel); for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { struct au1200fb_device *fbdev; fbdev = &_au1200fb_devices[plane]; au1200fb_fb_set_par(&fbdev->fb_info); } } d = *((unsigned int*)data); if(d <=10) brightness = 26; else if(d<=20) brightness = 51; else if(d<=30) brightness = 77; else if(d<=40) brightness = 102; else if(d<=50) brightness = 128; else if(d<=60) brightness = 153; else if(d<=70) brightness = 179; else if(d<=80) brightness = 204; else if(d<=90) brightness = 230; else brightness = 255; set_brightness(brightness); } else if (request == AU1XXX_PM_GETSTATUS) { return dev->cur_state; } else if (request == AU1XXX_PM_ACCESS) { if (dev->cur_state != SLEEP_STATE) return retval; else { au1200_setpanel(panel); } } else if (request == AU1XXX_PM_IDLE) { } else if (request == AU1XXX_PM_CLEANUP) { } return retval;}#endifstatic int __init au1200fb_init(void){ print_info("" DRIVER_DESC ""); /* Setup driver with options */ au1200fb_setup(); /* Point to the panel selected */ panel = &known_lcd_panels[panel_index]; win = &windows[window_index]; printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); /* Kickstart the panel, the framebuffers/windows come soon enough */ au1200_setpanel(panel); #ifdef CONFIG_PM LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); if ( LCD_pm_dev == NULL) printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); else printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); #endif return driver_register(&au1200fb_driver);}static void __exit au1200fb_cleanup(void){ driver_unregister(&au1200fb_driver);}module_init(au1200fb_init);module_exit(au1200fb_cleanup);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?