Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Sep 8th, 2010 | Syntax: None | Size: 32.65 KB | Hits: 39 | Expires: Never
Copy text to clipboard
  1. cass@VMHP:~/htcleo-32/kernel/drivers/video$ cat msm/msm_fb.c
  2. /* drivers/video/msm/msm_fb.c
  3.  *
  4.  * Core MSM framebuffer driver.
  5.  *
  6.  * Copyright (C) 2007 Google Incorporated
  7.  *
  8.  * This software is licensed under the terms of the GNU General Public
  9.  * License version 2, as published by the Free Software Foundation, and
  10.  * may be copied, distributed, and modified under those terms.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  */
  17.  
  18. #include <linux/platform_device.h>
  19. #include <linux/module.h>
  20. #include <linux/fb.h>
  21. #include <linux/delay.h>
  22.  
  23. #include <linux/freezer.h>
  24. #include <linux/wait.h>
  25. #include <linux/wakelock.h>
  26. #include <linux/earlysuspend.h>
  27. #include <linux/msm_mdp.h>
  28. #include <linux/io.h>
  29. #include <linux/uaccess.h>
  30. #include <mach/msm_fb.h>
  31. #include <mach/board.h>
  32. #include <linux/workqueue.h>
  33. #include <linux/clk.h>
  34. #include <linux/debugfs.h>
  35. #include <linux/dma-mapping.h>
  36. #include <linux/android_pmem.h>
  37.  
  38. extern void start_drawing_late_resume(struct early_suspend *h);
  39. static void msmfb_resume_handler(struct early_suspend *h);
  40. static void msmfb_resume(struct work_struct *work);
  41.  
  42. #define MSMFB_DEBUG 1
  43. #ifdef CONFIG_FB_MSM_LOGO
  44. #define INIT_IMAGE_FILE "/logo.rle"
  45. extern int load_565rle_image(char *filename);
  46. #endif
  47.  
  48. #define PRINT_FPS 0
  49. #define PRINT_BLIT_TIME 0
  50.  
  51. #define SLEEPING 0x4
  52. #define UPDATING 0x3
  53. #define FULL_UPDATE_DONE 0x2
  54. #define WAKING 0x1
  55. #define AWAKE 0x0
  56.  
  57. #define NONE 0
  58. #define SUSPEND_RESUME 0x1
  59. #define FPS 0x2
  60. #define BLIT_TIME 0x4
  61. #define SHOW_UPDATES 0x8
  62.  
  63. #define DLOG(mask, fmt, args...) \
  64. do { \
  65.         if ((msmfb_debug_mask | SUSPEND_RESUME) & mask) \
  66.                 printk(KERN_INFO "msmfb: "fmt, ##args); \
  67. } while (0)
  68.  
  69. #define BITS_PER_PIXEL(info) (info->fb->var.bits_per_pixel)
  70. #define BYTES_PER_PIXEL(info) (info->fb->var.bits_per_pixel >> 3)
  71. static int msmfb_debug_mask;
  72. module_param_named(msmfb_debug_mask, msmfb_debug_mask, int,
  73.                    S_IRUGO | S_IWUSR | S_IWGRP);
  74.  
  75. struct mdp_device *mdp;
  76.  
  77. struct msmfb_info {
  78.         struct fb_info *fb;
  79.         struct msm_panel_data *panel;
  80.         int xres;
  81.         int yres;
  82.         unsigned output_format;
  83.         unsigned yoffset;
  84.         unsigned frame_requested;
  85.         unsigned frame_done;
  86.         int sleeping;
  87.         unsigned update_frame;
  88.         struct {
  89.                 int left;
  90.                 int top;
  91.                 int eright; /* exclusive */
  92.                 int ebottom; /* exclusive */
  93.         } update_info;
  94.         char *black;
  95.  
  96.         struct early_suspend earlier_suspend;
  97.         struct early_suspend early_suspend;
  98.         struct wake_lock idle_lock;
  99.         spinlock_t update_lock;
  100.         struct mutex panel_init_lock;
  101.         wait_queue_head_t frame_wq;
  102.         struct workqueue_struct *resume_workqueue;
  103.         struct work_struct resume_work;
  104.         struct work_struct msmfb_resume_work;
  105.         struct msmfb_callback dma_callback;
  106.         struct msmfb_callback vsync_callback;
  107.         struct hrtimer fake_vsync;
  108.         ktime_t vsync_request_time;
  109.         unsigned fb_resumed;
  110. };
  111.  
  112. #ifdef CONFIG_FB_MSM_OVERLAY
  113. #define USE_OVERLAY     1
  114. struct overlay_waitevent{
  115.         uint32_t waked_up;
  116.         wait_queue_head_t event_wait;
  117. };
  118. static struct overlay_waitevent overlay_event;
  119. DEFINE_MUTEX(overlay_event_lock);
  120. #endif
  121.  
  122. #if (defined(CONFIG_USB_FUNCTION_PROJECTOR) || defined(CONFIG_USB_ANDROID_PROJECTOR))
  123. static spinlock_t fb_data_lock = SPIN_LOCK_UNLOCKED;
  124. static struct msm_fb_info msm_fb_data;
  125. int msmfb_get_var(struct msm_fb_info *tmp)
  126. {
  127.         unsigned long flags;
  128.         spin_lock_irqsave(&fb_data_lock, flags);
  129.         memcpy(tmp, &msm_fb_data, sizeof(msm_fb_data));
  130.         spin_unlock_irqrestore(&fb_data_lock, flags);
  131.         return 0;
  132. }
  133.  
  134. /* projector need this, and very much */
  135. int msmfb_get_fb_area(void)
  136. {
  137.         int area;
  138.         unsigned long flags;
  139.         spin_lock_irqsave(&fb_data_lock, flags);
  140.         area = msm_fb_data.msmfb_area;
  141.         spin_unlock_irqrestore(&fb_data_lock, flags);
  142.         return area;
  143. }
  144.  
  145. static void msmfb_set_var(unsigned char *addr, int area)
  146. {
  147.         unsigned long flags;
  148.  
  149.         spin_lock_irqsave(&fb_data_lock, flags);
  150.         msm_fb_data.fb_addr = addr;
  151.         msm_fb_data.msmfb_area = area;
  152.         spin_unlock_irqrestore(&fb_data_lock, flags);
  153.  
  154. }
  155. #endif
  156.  
  157. static int msmfb_open(struct fb_info *info, int user)
  158. {
  159.         return 0;
  160. }
  161.  
  162. static int msmfb_release(struct fb_info *info, int user)
  163. {
  164.         return 0;
  165. }
  166.  
  167. /* Called from dma interrupt handler, must not sleep */
  168. static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback)
  169. {
  170.         unsigned long irq_flags;
  171.         struct msmfb_info *msmfb  = container_of(callback, struct msmfb_info,
  172.                                                dma_callback);
  173. #if PRINT_FPS
  174.         int64_t dt;
  175.         ktime_t now;
  176.         static int64_t frame_count;
  177.         static ktime_t last_sec;
  178. #endif
  179.  
  180.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  181.         msmfb->frame_done = msmfb->frame_requested;
  182.         if (msmfb->sleeping == UPDATING &&
  183.             msmfb->frame_done == msmfb->update_frame) {
  184.                 DLOG(SUSPEND_RESUME, "full update completed\n");
  185.                 queue_work(msmfb->resume_workqueue, &msmfb->resume_work);
  186.         }
  187. #if PRINT_FPS
  188.         now = ktime_get();
  189.         dt = ktime_to_ns(ktime_sub(now, last_sec));
  190.         frame_count++;
  191.         if (dt > NSEC_PER_SEC) {
  192.                 int64_t fps = frame_count * NSEC_PER_SEC * 100;
  193.                 frame_count = 0;
  194.                 last_sec = ktime_get();
  195.                 do_div(fps, dt);
  196.                 DLOG(FPS, "fps * 100: %llu\n", fps);
  197.         }
  198. #endif
  199.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  200.         wake_up(&msmfb->frame_wq);
  201. }
  202.  
  203. static int msmfb_start_dma(struct msmfb_info *msmfb)
  204. {
  205.         uint32_t x, y, w, h;
  206.         unsigned addr;
  207.         unsigned long irq_flags;
  208.         uint32_t yoffset;
  209.         s64 time_since_request;
  210.         struct msm_panel_data *panel = msmfb->panel;
  211.  
  212.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  213.         time_since_request = ktime_to_ns(ktime_sub(ktime_get(),
  214.                              msmfb->vsync_request_time));
  215.         if (time_since_request > 20 * NSEC_PER_MSEC) {
  216.                 uint32_t us;
  217.                 us = do_div(time_since_request, NSEC_PER_MSEC) / NSEC_PER_USEC;
  218.                 printk(KERN_WARNING "msmfb_start_dma %lld.%03u ms after vsync "
  219.                         "request\n", time_since_request, us);
  220.         }
  221.         if (msmfb->frame_done == msmfb->frame_requested) {
  222.                 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  223.                 return -1;
  224.         }
  225.         if (msmfb->sleeping == SLEEPING) {
  226.                 DLOG(SUSPEND_RESUME, "tried to start dma while asleep\n");
  227.                 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  228.                 return -1;
  229.         }
  230.         x = msmfb->update_info.left;
  231.         y = msmfb->update_info.top;
  232.         w = msmfb->update_info.eright - x;
  233.         h = msmfb->update_info.ebottom - y;
  234.        
  235. #if defined(CONFIG_MACH_HTCLEO)
  236.         // For some reason we need to force a full-screen update to prevent
  237.         // the screen from mixing up (top +-100px missing, garbled data
  238.         // at the bottom +-100px). Maybe it has to do with the vsync we
  239.         // had to disable in mdp_lcdc?
  240.         x = 0; y = 0; w = msmfb->xres; h = msmfb->yres;
  241. #endif
  242.  
  243.         yoffset = msmfb->yoffset;
  244.         msmfb->update_info.left = msmfb->xres + 1;
  245.         msmfb->update_info.top = msmfb->yres + 1;
  246.         msmfb->update_info.eright = 0;
  247.         msmfb->update_info.ebottom = 0;
  248.         if (unlikely(w > msmfb->xres || h > msmfb->yres ||
  249.                      w == 0 || h == 0)) {
  250.                 printk(KERN_INFO "invalid update: %d %d %d "
  251.                                 "%d\n", x, y, w, h);
  252.                 msmfb->frame_done = msmfb->frame_requested;
  253.                 goto error;
  254.         }
  255.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  256.  
  257.         addr = ((msmfb->xres * (yoffset + y) + x) * BYTES_PER_PIXEL(msmfb));
  258.         mdp->dma(mdp, addr + msmfb->fb->fix.smem_start,
  259.                  msmfb->xres * BYTES_PER_PIXEL(msmfb), w, h, x, y,
  260.                  &msmfb->dma_callback,
  261.                  panel->interface_type);
  262.         return 0;
  263. error:
  264.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  265.         /* some clients need to clear their vsync interrupt */
  266.         if (panel->clear_vsync)
  267.                 panel->clear_vsync(panel);
  268.         wake_up(&msmfb->frame_wq);
  269.         return 0;
  270. }
  271.  
  272. /* Called from esync interrupt handler, must not sleep */
  273. static void msmfb_handle_vsync_interrupt(struct msmfb_callback *callback)
  274. {
  275.         struct msmfb_info *msmfb = container_of(callback, struct msmfb_info,
  276.                                                vsync_callback);
  277.         wake_unlock(&msmfb->idle_lock);
  278.         msmfb_start_dma(msmfb);
  279. }
  280.  
  281. static enum hrtimer_restart msmfb_fake_vsync(struct hrtimer *timer)
  282. {
  283.         struct msmfb_info *msmfb  = container_of(timer, struct msmfb_info,
  284.                                                fake_vsync);
  285.         msmfb_start_dma(msmfb);
  286.         return HRTIMER_NORESTART;
  287. }
  288.  
  289. static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top,
  290.                              uint32_t eright, uint32_t ebottom,
  291.                              uint32_t yoffset, int pan_display)
  292. {
  293.         struct msmfb_info *msmfb = info->par;
  294.         struct msm_panel_data *panel = msmfb->panel;
  295.         unsigned long irq_flags;
  296.         int sleeping;
  297.         int retry = 1;
  298. #if PRINT_FPS
  299.         ktime_t t1, t2;
  300.         static uint64_t pans;
  301.         static uint64_t dt;
  302.         t1 = ktime_get();
  303. #endif
  304.  
  305.         DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n",
  306.                 left, top, eright, ebottom, yoffset, pan_display);
  307.  
  308. #if !defined(CONFIG_MACH_HTCLEO)
  309.         // For some reason we need to remove it here, state is 1, we have to look later to this problem
  310.         if (msmfb->sleeping != AWAKE)
  311.                 DLOG(SUSPEND_RESUME, "pan_update in state(%d)\n", msmfb->sleeping);
  312. #endif
  313.  
  314. #if (defined(CONFIG_USB_FUNCTION_PROJECTOR) || defined(CONFIG_USB_ANDROID_PROJECTOR))
  315.         /* Jay, 8/1/09' */
  316.         msmfb_set_var(msmfb->fb->screen_base, yoffset);
  317. #endif
  318.  
  319. restart:
  320.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  321.  
  322.         /* if we are sleeping, on a pan_display wait 10ms (to throttle back
  323.          * drawing otherwise return */
  324.         if (msmfb->sleeping == SLEEPING) {
  325.                 DLOG(SUSPEND_RESUME, "drawing while asleep\n");
  326.                 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  327.                 if (pan_display)
  328.                         wait_event_interruptible_timeout(msmfb->frame_wq,
  329.                                 msmfb->sleeping != SLEEPING, HZ/10);
  330.                 return;
  331.         }
  332.  
  333.         sleeping = msmfb->sleeping;
  334.         /* on a full update, if the last frame has not completed, wait for it */
  335.         if (pan_display && (msmfb->frame_requested != msmfb->frame_done ||
  336.                             sleeping == UPDATING)) {
  337.                 int ret;
  338.                 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  339.                 ret = wait_event_interruptible_timeout(msmfb->frame_wq,
  340.                         msmfb->frame_done == msmfb->frame_requested &&
  341.                         msmfb->sleeping != UPDATING, 5 * HZ);
  342.                 if (ret <= 0 && (msmfb->frame_requested != msmfb->frame_done ||
  343.                                  msmfb->sleeping == UPDATING)) {
  344.                         if (retry && panel->request_vsync &&
  345.                             (sleeping == AWAKE)) {
  346.                                 wake_lock_timeout(&msmfb->idle_lock, HZ/4);
  347.                                 panel->request_vsync(panel,
  348.                                         &msmfb->vsync_callback);
  349.                                 retry = 0;
  350.                                 printk(KERN_WARNING "msmfb_pan_display timeout "
  351.                                         "rerequest vsync\n");
  352.                         } else {
  353.                                 printk(KERN_WARNING "msmfb_pan_display timeout "
  354.                                         "waiting for frame start, %d %d\n",
  355.                                         msmfb->frame_requested,
  356.                                         msmfb->frame_done);
  357.                                 return;
  358.                         }
  359.                 }
  360.                 goto restart;
  361.         }
  362.  
  363. #if PRINT_FPS
  364.         t2 = ktime_get();
  365.         if (pan_display) {
  366.                 uint64_t temp = ktime_to_ns(ktime_sub(t2, t1));
  367.                 do_div(temp, 1000);
  368.                 dt += temp;
  369.                 pans++;
  370.                 if (pans > 1000) {
  371.                         do_div(dt, pans);
  372.                         DLOG(FPS, "ave_wait_time: %lld\n", dt);
  373.                         dt = 0;
  374.                         pans = 0;
  375.                 }
  376.         }
  377. #endif
  378.  
  379.         msmfb->frame_requested++;
  380.         /* if necessary, update the y offset, if this is the
  381.          * first full update on resume, set the sleeping state */
  382.         if (pan_display) {
  383.                 msmfb->yoffset = yoffset;
  384.                 if (left == 0 && top == 0 && eright == info->var.xres &&
  385.                     ebottom == info->var.yres) {
  386.                         if (sleeping == WAKING) {
  387.                                 msmfb->update_frame = msmfb->frame_requested;
  388.                                 DLOG(SUSPEND_RESUME, "full update starting\n");
  389.                                 msmfb->sleeping = UPDATING;
  390.                         }
  391.                 }
  392.         }
  393.  
  394.         /* set the update request */
  395.         if (left < msmfb->update_info.left)
  396.                 msmfb->update_info.left = left;
  397.         if (top < msmfb->update_info.top)
  398.                 msmfb->update_info.top = top;
  399.         if (eright > msmfb->update_info.eright)
  400.                 msmfb->update_info.eright = eright;
  401.         if (ebottom > msmfb->update_info.ebottom)
  402.                 msmfb->update_info.ebottom = ebottom;
  403.         DLOG(SHOW_UPDATES, "update queued %d %d %d %d %d\n",
  404.                 msmfb->update_info.left, msmfb->update_info.top,
  405.                 msmfb->update_info.eright, msmfb->update_info.ebottom,
  406.                 msmfb->yoffset);
  407.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  408.  
  409.         /* if the panel is all the way on wait for vsync, otherwise sleep
  410.          * for 16 ms (long enough for the dma to panel) and then begin dma */
  411.         msmfb->vsync_request_time = ktime_get();
  412.         if (panel->request_vsync && (sleeping == AWAKE)) {
  413.                 wake_lock_timeout(&msmfb->idle_lock, HZ/4);
  414.                 panel->request_vsync(panel, &msmfb->vsync_callback);
  415.         } else {
  416.                 if (!hrtimer_active(&msmfb->fake_vsync)) {
  417.                         hrtimer_start(&msmfb->fake_vsync,
  418.                                       ktime_set(0, NSEC_PER_SEC/60),
  419.                                       HRTIMER_MODE_REL);
  420.                 }
  421.         }
  422. }
  423.  
  424. static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top,
  425.                          uint32_t eright, uint32_t ebottom)
  426. {
  427.         msmfb_pan_update(info, left, top, eright, ebottom, 0, 0);
  428. }
  429.  
  430. static void power_on_panel(struct work_struct *work)
  431. {
  432.         struct msmfb_info *msmfb =
  433.                 container_of(work, struct msmfb_info, resume_work);
  434.         struct msm_panel_data *panel = msmfb->panel;
  435.         unsigned long irq_flags;
  436.         mutex_lock(&msmfb->panel_init_lock);
  437.         DLOG(SUSPEND_RESUME, "turning on panel\n");
  438.         if (msmfb->sleeping == UPDATING) {
  439.                 wake_lock_timeout(&msmfb->idle_lock, HZ);
  440.                 if (panel->unblank(panel)) {
  441.                         printk(KERN_INFO "msmfb: panel unblank failed,"
  442.                                "not starting drawing\n");
  443.                         goto error;
  444.                 }
  445.                 wake_unlock(&msmfb->idle_lock);
  446.                 spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  447.                 msmfb->sleeping = AWAKE;
  448.                 wake_up(&msmfb->frame_wq);
  449.                 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  450.         }
  451. error:
  452.         mutex_unlock(&msmfb->panel_init_lock);
  453. }
  454.  
  455. static BLOCKING_NOTIFIER_HEAD(display_chain_head);                              
  456. int register_display_notifier(struct notifier_block *nb)                  
  457. {                                                                                
  458.         return blocking_notifier_chain_register(&display_chain_head, nb);        
  459. }                                                                                
  460. static int display_notifier_callback(struct notifier_block *nfb,                
  461.                 unsigned long action,                      
  462.                 void *ignored)                              
  463. {                                                                                
  464.         struct msmfb_info *msm_fb = (struct msmfb_info *)ignored;
  465.        
  466.         switch (action) {
  467.         case NOTIFY_MSM_FB:
  468.                 printk(KERN_DEBUG "NOTIFY_MSM_FB\n");
  469.                 //msmfb_resume(&msm_fb->early_suspend);
  470.                 break;
  471.         case NOTIFY_POWER:
  472.                 /* nothing to do */
  473.                 break;
  474.         default:
  475.                 printk(KERN_ERR "%s: unknown action in 0x%lx\n",
  476.                                 __func__, action);
  477.                 return NOTIFY_BAD;
  478.         }
  479.         return NOTIFY_OK;
  480. }                                                                                
  481.  
  482. /* -------------------------------------------------------------------------- */
  483. #ifdef CONFIG_HAS_EARLYSUSPEND
  484. /* turn off the panel */
  485. static void msmfb_earlier_suspend(struct early_suspend *h)
  486. {
  487.         struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
  488.                                                 earlier_suspend);
  489.         struct msm_panel_data *panel = msmfb->panel;
  490.         unsigned long irq_flags;
  491.  
  492.         mutex_lock(&msmfb->panel_init_lock);
  493.         msmfb->sleeping = SLEEPING;
  494.         wake_up(&msmfb->frame_wq);
  495.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  496.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  497.         wait_event_timeout(msmfb->frame_wq,
  498.                            msmfb->frame_requested == msmfb->frame_done, HZ/10);
  499. #ifndef CONFIG_MSM_MDP40
  500.         mdp->dma(mdp, virt_to_phys(msmfb->black), 0,
  501.                  msmfb->fb->var.xres, msmfb->fb->var.yres, 0, 0,
  502.                  NULL, panel->interface_type);
  503.         mdp->dma_wait(mdp, panel->interface_type);
  504. #endif
  505.         /* turn off the panel */
  506.         panel->blank(panel);
  507. }
  508.  
  509. static void msmfb_suspend(struct early_suspend *h)
  510. {
  511.         struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
  512.                                                 early_suspend);
  513.         struct msm_panel_data *panel = msmfb->panel;
  514.         /* suspend the panel */
  515. #ifdef CONFIG_FB_MSM_OVERLAY
  516.         /*check whether overlay done*/
  517.         wait_event_interruptible_timeout(
  518.                 overlay_event.event_wait,
  519.                 (overlay_event.waked_up == ~USE_OVERLAY),
  520.                 10*HZ);
  521.         pr_info("wait event : %X\n", overlay_event.waked_up);
  522. #endif
  523.         panel->suspend(panel);
  524.         msmfb->fb_resumed = 0;
  525.         mutex_unlock(&msmfb->panel_init_lock);
  526. }
  527.  
  528. static void msmfb_resume_handler(struct early_suspend *h)
  529. {
  530.         struct msmfb_info *msmfb = container_of(h, struct msmfb_info,
  531.                                         early_suspend);
  532.         queue_work(msmfb->resume_workqueue, &msmfb->msmfb_resume_work);
  533.         wait_event_interruptible_timeout(msmfb->frame_wq, msmfb->fb_resumed==1,HZ/2);
  534. }
  535.  
  536. static void msmfb_resume(struct work_struct *work)
  537. {
  538.         struct msmfb_info *msmfb =
  539.                 container_of(work, struct msmfb_info, msmfb_resume_work);
  540.         struct msm_panel_data *panel = msmfb->panel;
  541.         unsigned long irq_flags;
  542.  
  543.         if (panel->resume(panel)) {
  544.                 printk(KERN_INFO "msmfb: panel resume failed, not resuming "
  545.                        "fb\n");
  546.                 return;
  547.         }
  548.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  549.         msmfb->frame_requested = msmfb->frame_done = msmfb->update_frame = 0;
  550.         msmfb->sleeping = WAKING;
  551.         DLOG(SUSPEND_RESUME, "ready, waiting for full update\n");
  552.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  553.         start_drawing_late_resume(NULL);
  554.         msmfb->fb_resumed = 1;
  555.         wake_up(&msmfb->frame_wq);
  556. }
  557. #endif
  558.  
  559. static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  560. {
  561.         u32 size;
  562.  
  563.         if ((var->xres != info->var.xres) ||
  564.             (var->yres != info->var.yres) ||
  565.             (var->xoffset != info->var.xoffset) ||
  566.             (mdp->check_output_format(mdp, var->bits_per_pixel)) ||
  567.             (var->grayscale != info->var.grayscale))
  568.                  return -EINVAL;
  569.  
  570.         size = var->xres_virtual * var->yres_virtual *
  571.                 (var->bits_per_pixel >> 3);
  572.         if (size > info->fix.smem_len)
  573.                 return -EINVAL;
  574.         return 0;
  575. }
  576.  
  577. static int msmfb_set_par(struct fb_info *info)
  578. {
  579.         struct fb_var_screeninfo *var = &info->var;
  580.         struct fb_fix_screeninfo *fix = &info->fix;
  581.  
  582.         /* we only support RGB ordering for now */
  583.         if (var->bits_per_pixel == 32 || var->bits_per_pixel == 24) {
  584.                 var->red.offset = 0;
  585.                 var->red.length = 8;
  586.                 var->green.offset = 8;
  587.                 var->green.length = 8;
  588.                 var->blue.offset = 16;
  589.                 var->blue.length = 8;
  590.         } else if (var->bits_per_pixel == 16) {
  591.                 var->red.offset = 11;
  592.                 var->red.length = 5;
  593.                 var->green.offset = 5;
  594.                 var->green.length = 6;
  595.                 var->blue.offset = 0;
  596.                 var->blue.length = 5;
  597.         } else
  598.                 return -1;
  599.         mdp->set_output_format(mdp, var->bits_per_pixel);
  600.         fix->line_length = var->xres * var->bits_per_pixel / 8;
  601.         return 0;
  602. }
  603.  
  604. int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
  605. {
  606.         struct msmfb_info *msmfb = info->par;
  607.         struct msm_panel_data *panel = msmfb->panel;
  608.  
  609.         /* "UPDT" */
  610.         if ((panel->caps & MSMFB_CAP_PARTIAL_UPDATES) &&
  611.             (var->reserved[0] == 0x54445055)) {
  612. #if 0
  613.                 printk(KERN_INFO "pan frame %d-%d, rect %d %d %d %d\n",
  614.                        msmfb->frame_requested, msmfb->frame_done,
  615.                        var->reserved[1] & 0xffff,
  616.                        var->reserved[1] >> 16, var->reserved[2] & 0xffff,
  617.                        var->reserved[2] >> 16);
  618. #endif
  619.                 msmfb_pan_update(info, var->reserved[1] & 0xffff,
  620.                                  var->reserved[1] >> 16,
  621.                                  var->reserved[2] & 0xffff,
  622.                                  var->reserved[2] >> 16, var->yoffset, 1);
  623.         } else {
  624.                 msmfb_pan_update(info, 0, 0, info->var.xres, info->var.yres,
  625.                                  var->yoffset, 1);
  626.         }
  627.         return 0;
  628. }
  629.  
  630. static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
  631. {
  632.         cfb_fillrect(p, rect);
  633. #if !defined(CONFIG_MACH_HTCLEO)       
  634.         msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width,
  635.                      rect->dy + rect->height);
  636. #endif
  637. }
  638.  
  639. static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
  640. {
  641.         cfb_copyarea(p, area);
  642. #if !defined(CONFIG_MACH_HTCLEO)       
  643.         msmfb_update(p, area->dx, area->dy, area->dx + area->width,
  644.                      area->dy + area->height);
  645. #endif
  646. }
  647.  
  648. static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image)
  649. {
  650.         cfb_imageblit(p, image);
  651. #if !defined(CONFIG_MACH_HTCLEO)       
  652.         msmfb_update(p, image->dx, image->dy, image->dx + image->width,
  653.                      image->dy + image->height);
  654. #endif
  655. }
  656.  
  657.  
  658. static int msmfb_blit(struct fb_info *info,
  659.                       void __user *p)
  660. {
  661.         struct mdp_blit_req req;
  662.         struct mdp_blit_req_list req_list;
  663.         int i;
  664.         int ret;
  665.  
  666.         if (copy_from_user(&req_list, p, sizeof(req_list)))
  667.                 return -EFAULT;
  668.  
  669.         for (i = 0; i < req_list.count; i++) {
  670.                 struct mdp_blit_req_list *list =
  671.                         (struct mdp_blit_req_list *)p;
  672.                 if (copy_from_user(&req, &list->req[i], sizeof(req)))
  673.                         return -EFAULT;
  674.                 ret = mdp->blit(mdp, info, &req);
  675.                 if (ret)
  676.                         return ret;
  677.         }
  678.         return 0;
  679. }
  680. #ifdef CONFIG_FB_MSM_OVERLAY
  681. static int msmfb_overlay_get(struct fb_info *info, void __user *p)
  682. {
  683.         struct mdp_overlay req;
  684.         int ret;
  685.  
  686.         if (copy_from_user(&req, p, sizeof(req)))
  687.                 return -EFAULT;
  688.  
  689.         ret = mdp->overlay_get(mdp, info, &req);
  690.  
  691.         if (ret) {
  692.                 printk(KERN_ERR "%s: ioctl failed \n",
  693.                         __func__);
  694.                 return ret;
  695.         }
  696.         if (copy_to_user(p, &req, sizeof(req))) {
  697.                 printk(KERN_ERR "%s: copy2user failed \n",
  698.                         __func__);
  699.                 return -EFAULT;
  700.         }
  701.  
  702.         return 0;
  703. }
  704.  
  705. static int msmfb_overlay_set(struct fb_info *info, void __user *p)
  706. {
  707.         struct mdp_overlay req;
  708.         int ret;
  709.  
  710.         if (copy_from_user(&req, p, sizeof(req)))
  711.                 return -EFAULT;
  712.  
  713.         ret = mdp->overlay_set(mdp, info, &req);
  714.         if (ret) {
  715.                 printk(KERN_ERR "%s:ioctl failed \n",
  716.                         __func__);
  717.                 return ret;
  718.         }
  719.  
  720.         if (copy_to_user(p, &req, sizeof(req))) {
  721.                 printk(KERN_ERR "%s: copy2user failed \n",
  722.                         __func__);
  723.                 return -EFAULT;
  724.         }
  725.  
  726.         return 0;
  727. }
  728.  
  729. static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp)
  730. {
  731.         int     ret, ndx;
  732.  
  733.         ret = copy_from_user(&ndx, argp, sizeof(ndx));
  734.         if (ret) {
  735.                 printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n",
  736.                         __func__);
  737.                 return ret;
  738.         }
  739.  
  740.         return mdp->overlay_unset(mdp, info, ndx);
  741. }
  742.  
  743. static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
  744. {
  745.         int     ret;
  746.         struct msmfb_overlay_data req;
  747.         struct file *p_src_file = 0;
  748.  
  749.         ret = copy_from_user(&req, argp, sizeof(req));
  750.         if (ret) {
  751.                 printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n",
  752.                         __func__);
  753.                 return ret;
  754.         }
  755.  
  756.         ret = mdp->overlay_play(mdp, info, &req, &p_src_file);
  757.  
  758.         if (p_src_file)
  759.                 put_pmem_file(p_src_file);
  760.  
  761.         return ret;
  762. }
  763.  
  764. #endif
  765.  
  766.  
  767. DEFINE_MUTEX(mdp_ppp_lock);
  768.  
  769. static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg)
  770. {
  771.         void __user *argp = (void __user *)arg;
  772.         int ret;
  773. #if PRINT_BLIT_TIME
  774.         ktime_t t1, t2;
  775. #endif
  776.  
  777.         switch (cmd) {
  778.         case MSMFB_GRP_DISP:
  779.                 mdp->set_grp_disp(mdp, arg);
  780.                 break;
  781.         case MSMFB_BLIT:
  782. #if PRINT_BLIT_TIME
  783.                 t1 = ktime_get();
  784. #endif
  785.                 ret = msmfb_blit(p, argp);
  786.                 if (ret)
  787.                         return ret;
  788. #if PRINT_BLIT_TIME
  789.                 t2 = ktime_get();
  790.                 DLOG(BLIT_TIME, "total %lld\n",
  791.                        ktime_to_ns(t2) - ktime_to_ns(t1));
  792. #endif
  793.                 break;
  794. #ifdef CONFIG_FB_MSM_OVERLAY
  795.         case MSMFB_OVERLAY_GET:
  796.                 printk("CONFIG_FB_MSM_OVERLAY\n");
  797.                 //down(&mdp_ppp_lock);
  798.                 ret = msmfb_overlay_get(p, argp);
  799.                 //up(&mdp_ppp_lock);
  800.                 break;
  801.         case MSMFB_OVERLAY_SET:
  802.                 printk("MSMFB_OVERLAY_SET\n");
  803.                 //down(&mdp_ppp_lock);
  804.                 ret = msmfb_overlay_set(p, argp);
  805.                 mutex_lock(&overlay_event_lock);
  806.                 overlay_event.waked_up = USE_OVERLAY;
  807.                 mutex_unlock(&overlay_event_lock);
  808.                 //up(&mdp_ppp_lock);
  809.                 break;
  810.         case MSMFB_OVERLAY_UNSET:
  811.                 printk("MSMFB_OVERLAY_UNSET\n");
  812.                 //down(&mdp_ppp_lock);
  813.                 ret = msmfb_overlay_unset(p, argp);
  814.                 mutex_lock(&overlay_event_lock);
  815.                 overlay_event.waked_up = ~USE_OVERLAY;
  816.                 wake_up(&overlay_event.event_wait);
  817.                 mutex_unlock(&overlay_event_lock);
  818.                 //up(&mdp_ppp_lock);
  819.                 break;
  820.         case MSMFB_OVERLAY_PLAY:
  821.                 //down(&mdp_ppp_lock);
  822.                 ret = msmfb_overlay_play(p, argp);
  823.                 //up(&mdp_ppp_lock);
  824.                 break;
  825. #endif
  826.         default:
  827.                         printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd);
  828.                         return -EINVAL;
  829.         }
  830.         return 0;
  831. }
  832.  
  833. static struct fb_ops msmfb_ops = {
  834.         .owner = THIS_MODULE,
  835.         .fb_open = msmfb_open,
  836.         .fb_release = msmfb_release,
  837.         .fb_check_var = msmfb_check_var,
  838.         .fb_set_par = msmfb_set_par,
  839.         .fb_pan_display = msmfb_pan_display,
  840.         .fb_fillrect = msmfb_fillrect,
  841.         .fb_copyarea = msmfb_copyarea,
  842.         .fb_imageblit = msmfb_imageblit,
  843.         .fb_ioctl = msmfb_ioctl,
  844. };
  845.  
  846. static unsigned PP[16];
  847.  
  848.  
  849. #if MSMFB_DEBUG
  850. static ssize_t debug_open(struct inode *inode, struct file *file)
  851. {
  852.         file->private_data = inode->i_private;
  853.         return 0;
  854. }
  855.  
  856.  
  857. static ssize_t debug_read(struct file *file, char __user *buf, size_t count,
  858.                           loff_t *ppos)
  859. {
  860.         const int debug_bufmax = 4096;
  861.         static char buffer[4096];
  862.         int n = 0;
  863.         struct msmfb_info *msmfb = (struct msmfb_info *)file->private_data;
  864.         unsigned long irq_flags;
  865.  
  866.         spin_lock_irqsave(&msmfb->update_lock, irq_flags);
  867.         n = scnprintf(buffer, debug_bufmax, "yoffset %d\n", msmfb->yoffset);
  868.         n += scnprintf(buffer + n, debug_bufmax, "frame_requested %d\n",
  869.                        msmfb->frame_requested);
  870.         n += scnprintf(buffer + n, debug_bufmax, "frame_done %d\n",
  871.                        msmfb->frame_done);
  872.         n += scnprintf(buffer + n, debug_bufmax, "sleeping %d\n",
  873.                        msmfb->sleeping);
  874.         n += scnprintf(buffer + n, debug_bufmax, "update_frame %d\n",
  875.                        msmfb->update_frame);
  876.         spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
  877.         n++;
  878.         buffer[n] = 0;
  879.         return simple_read_from_buffer(buf, count, ppos, buffer, n);
  880. }
  881.  
  882. static struct file_operations debug_fops = {
  883.         .read = debug_read,
  884.         .open = debug_open,
  885. };
  886. #endif
  887.  
  888. #define BITS_PER_PIXEL 16
  889.  
  890. static void setup_fb_info(struct msmfb_info *msmfb)
  891. {
  892.         struct fb_info *fb_info = msmfb->fb;
  893.         int r;
  894.  
  895.         /* finish setting up the fb_info struct */
  896.         strncpy(fb_info->fix.id, "msmfb", 16);
  897.         fb_info->fix.ypanstep = 1;
  898.  
  899.         fb_info->fbops = &msmfb_ops;
  900.         fb_info->flags = FBINFO_DEFAULT;
  901.  
  902.         fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
  903.         fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
  904.         fb_info->fix.line_length = msmfb->xres * 2;
  905.  
  906.         fb_info->var.xres = msmfb->xres;
  907.         fb_info->var.yres = msmfb->yres;
  908.         fb_info->var.width = msmfb->panel->fb_data->width;
  909.         fb_info->var.height = msmfb->panel->fb_data->height;
  910.         fb_info->var.xres_virtual = msmfb->xres;
  911.         fb_info->var.yres_virtual = msmfb->yres * 2;
  912.         fb_info->var.bits_per_pixel = BITS_PER_PIXEL;
  913.         fb_info->var.accel_flags = 0;
  914.  
  915.         fb_info->var.yoffset = 0;
  916.  
  917.         if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) {
  918.                 /* set the param in the fixed screen, so userspace can't
  919.                  * change it. This will be used to check for the
  920.                  * capability. */
  921.  
  922.                 /* FIX ME: every panel support partial update?
  923.                 fb_info->fix.reserved[0] = 0x5444;
  924.                 fb_info->fix.reserved[1] = 0x5055;
  925.                 */
  926.  
  927.                 /* This preloads the value so that if userspace doesn't
  928.                  * change it, it will be a full update */
  929.                 fb_info->var.reserved[0] = 0x54445055;
  930.                 fb_info->var.reserved[1] = 0;
  931.                 fb_info->var.reserved[2] = (uint16_t)msmfb->xres |
  932.                                            ((uint32_t)msmfb->yres << 16);
  933.         }
  934.  
  935.         fb_info->var.red.offset = 11;
  936.         fb_info->var.red.length = 5;
  937.         fb_info->var.red.msb_right = 0;
  938.         fb_info->var.green.offset = 5;
  939.         fb_info->var.green.length = 6;
  940.         fb_info->var.green.msb_right = 0;
  941.         fb_info->var.blue.offset = 0;
  942.         fb_info->var.blue.length = 5;
  943.         fb_info->var.blue.msb_right = 0;
  944.  
  945.         mdp->set_output_format(mdp, fb_info->var.bits_per_pixel);
  946.  
  947.         r = fb_alloc_cmap(&fb_info->cmap, 16, 0);
  948.         fb_info->pseudo_palette = PP;
  949.  
  950.         PP[0] = 0;
  951.         for (r = 1; r < 16; r++)
  952.                 PP[r] = 0xffffffff;
  953.  
  954.         /* Jay add, 7/1/09' */
  955. #if (defined(CONFIG_USB_FUNCTION_PROJECTOR) || defined(CONFIG_USB_ANDROID_PROJECTOR))
  956.         msm_fb_data.xres = msmfb->xres;
  957.         msm_fb_data.yres = msmfb->yres;
  958.         printk(KERN_INFO "setup_fb_info msmfb->xres %d, msmfb->yres %d\n",
  959.                                 msmfb->xres,msmfb->yres);
  960. #endif
  961. }
  962.  
  963. static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev)
  964. {
  965.         struct fb_info *fb = msmfb->fb;
  966.         struct resource *resource;
  967.         unsigned long size = msmfb->xres * msmfb->yres *
  968.                 BYTES_PER_PIXEL(msmfb) * 2;
  969.         unsigned long resource_size;
  970.         unsigned char *fbram;
  971.  
  972.         /* board file might have attached a resource describing an fb */
  973.         resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  974.         if (!resource)
  975.                 return -EINVAL;
  976.         resource_size = resource->end - resource->start + 1;
  977.  
  978.         /* check the resource is large enough to fit the fb */
  979.         if (resource_size < size) {
  980.                 printk(KERN_ERR "msmfb: allocated resource is too small for "
  981.                                 "fb\n");
  982.                 return -ENOMEM;
  983.         }
  984.         fb->fix.smem_start = resource->start;
  985.         fb->fix.smem_len = resource_size;
  986.         fbram = ioremap(resource->start, resource_size);
  987.         if (fbram == 0) {
  988.                 printk(KERN_ERR "msmfb: cannot allocate fbram!\n");
  989.                 return -ENOMEM;
  990.         }
  991.  
  992.         fb->screen_base = fbram;
  993.         return 0;
  994. }
  995.  
  996. static int msmfb_probe(struct platform_device *pdev)
  997. {
  998.         struct fb_info *fb;
  999.         struct msmfb_info *msmfb;
  1000.         struct msm_panel_data *panel = pdev->dev.platform_data;
  1001.         int ret;
  1002.  
  1003.         if (!panel) {
  1004.                 pr_err("msmfb_probe: no platform data\n");
  1005.                 return -EINVAL;
  1006.         }
  1007.         if (!panel->fb_data) {
  1008.                 pr_err("msmfb_probe: no fb_data\n");
  1009.                 return -EINVAL;
  1010.         }
  1011.  
  1012.         fb = framebuffer_alloc(sizeof(struct msmfb_info), &pdev->dev);
  1013.         if (!fb)
  1014.                 return -ENOMEM;
  1015.         msmfb = fb->par;
  1016.         msmfb->fb = fb;
  1017.         msmfb->panel = panel;
  1018.         msmfb->xres = panel->fb_data->xres;
  1019.         msmfb->yres = panel->fb_data->yres;
  1020.  
  1021.         ret = setup_fbmem(msmfb, pdev);
  1022.         if (ret)
  1023.                 goto error_setup_fbmem;
  1024.  
  1025. #if (defined(CONFIG_USB_FUNCTION_PROJECTOR) || defined(CONFIG_USB_ANDROID_PROJECTOR))
  1026.         /* Jay, 8/1/09' */
  1027.         msmfb_set_var(msmfb->fb->screen_base, 0);
  1028. #endif
  1029.  
  1030.         setup_fb_info(msmfb);
  1031.  
  1032.         spin_lock_init(&msmfb->update_lock);
  1033.         mutex_init(&msmfb->panel_init_lock);
  1034.         init_waitqueue_head(&msmfb->frame_wq);
  1035.         msmfb->resume_workqueue = create_rt_workqueue("panel_on");
  1036.         if (msmfb->resume_workqueue == NULL) {
  1037.                 printk(KERN_ERR "failed to create panel_on workqueue\n");
  1038.                 ret = -ENOMEM;
  1039.                 goto error_create_workqueue;
  1040.         }
  1041.         INIT_WORK(&msmfb->resume_work, power_on_panel);
  1042.         msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres,
  1043.                                GFP_KERNEL);
  1044.  
  1045.         wake_lock_init(&msmfb->idle_lock, WAKE_LOCK_IDLE, "msmfb_idle_lock");
  1046.  
  1047. #ifdef CONFIG_HAS_EARLYSUSPEND
  1048.         INIT_WORK(&msmfb->msmfb_resume_work, msmfb_resume);
  1049.         msmfb->early_suspend.suspend = msmfb_suspend;
  1050.         msmfb->early_suspend.resume = msmfb_resume_handler;
  1051.         msmfb->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
  1052.         register_early_suspend(&msmfb->early_suspend);
  1053.  
  1054.         msmfb->earlier_suspend.suspend = msmfb_earlier_suspend;
  1055.         msmfb->earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
  1056.         register_early_suspend(&msmfb->earlier_suspend);
  1057. #endif
  1058.  
  1059. #if MSMFB_DEBUG
  1060.         debugfs_create_file("msm_fb", S_IFREG | S_IRUGO, NULL,
  1061.                             (void *)fb->par, &debug_fops);
  1062. #endif
  1063.  
  1064.         printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n",
  1065.                msmfb->xres, msmfb->yres);
  1066.  
  1067.         msmfb->dma_callback.func = msmfb_handle_dma_interrupt;
  1068.         msmfb->vsync_callback.func = msmfb_handle_vsync_interrupt;
  1069.         hrtimer_init(&msmfb->fake_vsync, CLOCK_MONOTONIC,
  1070.                      HRTIMER_MODE_REL);
  1071.  
  1072.         msmfb->fake_vsync.function = msmfb_fake_vsync;
  1073.  
  1074.         ret = register_framebuffer(fb);
  1075.         if (ret)
  1076.                 goto error_register_framebuffer;
  1077.  
  1078.         msmfb->sleeping = WAKING;
  1079.  
  1080. #ifdef CONFIG_FB_MSM_OVERLAY
  1081.         /*init wait event*/
  1082.         init_waitqueue_head(&overlay_event.event_wait);
  1083.         /*init waked_up value*/
  1084.         overlay_event.waked_up = ~USE_OVERLAY;
  1085. #endif
  1086.  
  1087. #ifdef CONFIG_FB_MSM_LOGO
  1088.         if (!load_565rle_image(INIT_IMAGE_FILE)) {
  1089.                 /* Flip buffer */
  1090.                 msmfb->update_info.left = 0;
  1091.                 msmfb->update_info.top = 0;
  1092.                 msmfb->update_info.eright = info->var.xres;
  1093.                 msmfb->update_info.ebottom = info->var.yres;
  1094.                 msmfb_pan_update(info, 0, 0, fb->var.xres,
  1095.                                  fb->var.yres, 0, 1);
  1096.         }
  1097. #endif
  1098.         /* Jay, 29/12/08' */
  1099.         display_notifier(display_notifier_callback, NOTIFY_MSM_FB);
  1100.         return 0;
  1101.  
  1102. error_register_framebuffer:
  1103.         wake_lock_destroy(&msmfb->idle_lock);
  1104.         destroy_workqueue(msmfb->resume_workqueue);
  1105. error_create_workqueue:
  1106.         iounmap(fb->screen_base);
  1107. error_setup_fbmem:
  1108.         framebuffer_release(msmfb->fb);
  1109.         return ret;
  1110. }
  1111.  
  1112. static void msmfb_shutdown(struct platform_device *pdev)
  1113. {
  1114.         struct msm_panel_data *panel = pdev->dev.platform_data;
  1115.         struct fb_info *fb;
  1116.         struct msmfb_info *msmfb;
  1117.  
  1118.         printk(KERN_INFO "%s\n", __func__);
  1119.         fb = registered_fb[0];
  1120.         if (!fb) {
  1121.                 printk(KERN_ERR "fb0 unavailable.\n");
  1122.                 return;
  1123.         }
  1124.         msmfb = fb->par;
  1125.  
  1126.         mdp->dma(mdp, virt_to_phys(msmfb->black), 0,
  1127.                         msmfb->fb->var.xres, msmfb->fb->var.yres, 0, 0,
  1128.                         NULL, panel->interface_type);
  1129.  
  1130.         if (panel->blank)
  1131.                 panel->blank(panel);
  1132.  
  1133.         if (panel->shutdown)
  1134.                 panel->shutdown(panel);
  1135. }
  1136.  
  1137. static struct platform_driver msm_panel_driver = {
  1138.         /* need to write remove */
  1139.         .probe = msmfb_probe,
  1140.         .shutdown = msmfb_shutdown,
  1141.         .driver = {.name = "msm_panel"},
  1142. };
  1143.  
  1144.  
  1145. static int msmfb_add_mdp_device(struct device *dev,
  1146.                                 struct class_interface *class_intf)
  1147. {
  1148.         /* might need locking if mulitple mdp devices */
  1149.         if (mdp)
  1150.                 return 0;
  1151.         mdp = container_of(dev, struct mdp_device, dev);
  1152.         return platform_driver_register(&msm_panel_driver);
  1153. }
  1154.  
  1155. static void msmfb_remove_mdp_device(struct device *dev,
  1156.                                 struct class_interface *class_intf)
  1157. {
  1158.         /* might need locking if mulitple mdp devices */
  1159.         if (dev != &mdp->dev)
  1160.                 return;
  1161.         platform_driver_unregister(&msm_panel_driver);
  1162.         mdp = NULL;
  1163. }
  1164.  
  1165. static struct class_interface msm_fb_interface = {
  1166.         .add_dev = &msmfb_add_mdp_device,
  1167.         .remove_dev = &msmfb_remove_mdp_device,
  1168. };
  1169.  
  1170. static int __init msmfb_init(void)
  1171. {
  1172.         return register_mdp_client(&msm_fb_interface);
  1173. }
  1174.  
  1175. module_init(msmfb_init);