-/* Do refcounting on our FB and cleanup per worker if FB is
- * closed after unplug of our device
- * (fb_release holds info->lock and still touches info after
- * we return so we can't release it immediately.
- */
-struct picolcd_fb_cleanup_item {
- struct fb_info *info;
- struct picolcd_fb_cleanup_item *next;
-};
-static struct picolcd_fb_cleanup_item *fb_pending;
-static DEFINE_SPINLOCK(fb_pending_lock);
-
-static void picolcd_fb_do_cleanup(struct work_struct *data)
-{
- struct picolcd_fb_cleanup_item *item;
- unsigned long flags;
-
- do {
- spin_lock_irqsave(&fb_pending_lock, flags);
- item = fb_pending;
- fb_pending = item ? item->next : NULL;
- spin_unlock_irqrestore(&fb_pending_lock, flags);
-
- if (item) {
- u8 *fb = (u8 *)item->info->fix.smem_start;
- /* make sure we do not race against fb core when
- * releasing */
- mutex_lock(&item->info->lock);
- mutex_unlock(&item->info->lock);
- framebuffer_release(item->info);
- vfree(fb);
- }
- } while (item);
-}
-
-static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
-
-static int picolcd_fb_open(struct fb_info *info, int u)
-{
- u32 *ref_cnt = info->pseudo_palette;
- ref_cnt--;
-
- (*ref_cnt)++;
- return 0;
-}
-
-static int picolcd_fb_release(struct fb_info *info, int u)
-{
- u32 *ref_cnt = info->pseudo_palette;
- ref_cnt--;
-
- (*ref_cnt)++;
- if (!*ref_cnt) {
- unsigned long flags;
- struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
- item--;
- spin_lock_irqsave(&fb_pending_lock, flags);
- item->next = fb_pending;
- fb_pending = item;
- spin_unlock_irqrestore(&fb_pending_lock, flags);
- schedule_work(&picolcd_fb_cleanup);
- }
- return 0;
-}
-