Commit 9966c37c authored by Bruno Prémont's avatar Bruno Prémont Committed by Jiri Kosina

HID: picoLCD: Replace own refcounting with fbdev's

Signed-off-by: default avatarBruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent fabdbf2f
...@@ -96,7 +96,6 @@ struct picolcd_data { ...@@ -96,7 +96,6 @@ struct picolcd_data {
u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */
u8 *fb_bitmap; /* framebuffer */ u8 *fb_bitmap; /* framebuffer */
struct fb_info *fb_info; struct fb_info *fb_info;
struct fb_deferred_io fb_defio;
#endif /* CONFIG_HID_PICOLCD_FB */ #endif /* CONFIG_HID_PICOLCD_FB */
#ifdef CONFIG_HID_PICOLCD_LCD #ifdef CONFIG_HID_PICOLCD_LCD
struct lcd_device *lcd; struct lcd_device *lcd;
...@@ -179,8 +178,6 @@ int picolcd_init_framebuffer(struct picolcd_data *data); ...@@ -179,8 +178,6 @@ int picolcd_init_framebuffer(struct picolcd_data *data);
void picolcd_exit_framebuffer(struct picolcd_data *data); void picolcd_exit_framebuffer(struct picolcd_data *data);
void picolcd_fb_unload(void);
void picolcd_fb_refresh(struct picolcd_data *data); void picolcd_fb_refresh(struct picolcd_data *data);
#define picolcd_fbinfo(d) ((d)->fb_info) #define picolcd_fbinfo(d) ((d)->fb_info)
#else #else
...@@ -195,9 +192,6 @@ static inline int picolcd_init_framebuffer(struct picolcd_data *data) ...@@ -195,9 +192,6 @@ static inline int picolcd_init_framebuffer(struct picolcd_data *data)
static inline void picolcd_exit_framebuffer(struct picolcd_data *data) static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
{ {
} }
static inline void picolcd_fb_unload(void)
{
}
static inline void picolcd_fb_refresh(struct picolcd_data *data) static inline void picolcd_fb_refresh(struct picolcd_data *data)
{ {
} }
......
...@@ -695,7 +695,6 @@ static int __init picolcd_init(void) ...@@ -695,7 +695,6 @@ static int __init picolcd_init(void)
static void __exit picolcd_exit(void) static void __exit picolcd_exit(void)
{ {
hid_unregister_driver(&picolcd_driver); hid_unregister_driver(&picolcd_driver);
picolcd_fb_unload();
} }
module_init(picolcd_init); module_init(picolcd_init);
......
...@@ -256,7 +256,7 @@ static void picolcd_fb_update(struct picolcd_data *data) ...@@ -256,7 +256,7 @@ static void picolcd_fb_update(struct picolcd_data *data)
data->fb_bitmap, data->fb_bpp, chip, tile) || data->fb_bitmap, data->fb_bpp, chip, tile) ||
data->fb_force) { data->fb_force) {
n += 2; n += 2;
if (!data->fb_info->par) if (data->status & PICOLCD_FAILED)
return; /* device lost! */ return; /* device lost! */
if (n >= HID_OUTPUT_FIFO_SIZE / 2) { if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
usbhid_wait_io(data->hdev); usbhid_wait_io(data->hdev);
...@@ -327,24 +327,17 @@ static int picolcd_fb_blank(int blank, struct fb_info *info) ...@@ -327,24 +327,17 @@ static int picolcd_fb_blank(int blank, struct fb_info *info)
static void picolcd_fb_destroy(struct fb_info *info) static void picolcd_fb_destroy(struct fb_info *info)
{ {
struct picolcd_data *data = info->par; struct picolcd_data *data;
u32 *ref_cnt = info->pseudo_palette;
int may_release;
/* make sure no work is deferred */
cancel_delayed_work_sync(&info->deferred_work);
data = info->par;
info->par = NULL; info->par = NULL;
if (data) if (data)
data->fb_info = NULL; data->fb_info = NULL;
fb_deferred_io_cleanup(info);
ref_cnt--;
mutex_lock(&info->lock);
(*ref_cnt)--;
may_release = !*ref_cnt;
mutex_unlock(&info->lock);
if (may_release) {
vfree((u8 *)info->fix.smem_start); vfree((u8 *)info->fix.smem_start);
framebuffer_release(info); framebuffer_release(info);
}
} }
static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
...@@ -414,77 +407,10 @@ static int picolcd_set_par(struct fb_info *info) ...@@ -414,77 +407,10 @@ static int picolcd_set_par(struct fb_info *info)
return 0; return 0;
} }
/* 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;
}
/* Note this can't be const because of struct fb_info definition */ /* Note this can't be const because of struct fb_info definition */
static struct fb_ops picolcdfb_ops = { static struct fb_ops picolcdfb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_destroy = picolcd_fb_destroy, .fb_destroy = picolcd_fb_destroy,
.fb_open = picolcd_fb_open,
.fb_release = picolcd_fb_release,
.fb_read = fb_sys_read, .fb_read = fb_sys_read,
.fb_write = picolcd_fb_write, .fb_write = picolcd_fb_write,
.fb_blank = picolcd_fb_blank, .fb_blank = picolcd_fb_blank,
...@@ -550,7 +476,7 @@ static ssize_t picolcd_fb_update_rate_store(struct device *dev, ...@@ -550,7 +476,7 @@ static ssize_t picolcd_fb_update_rate_store(struct device *dev,
u = PICOLCDFB_UPDATE_RATE_DEFAULT; u = PICOLCDFB_UPDATE_RATE_DEFAULT;
data->fb_update_rate = u; data->fb_update_rate = u;
data->fb_defio.delay = HZ / data->fb_update_rate; data->fb_info->fbdefio->delay = HZ / data->fb_update_rate;
return count; return count;
} }
...@@ -580,25 +506,23 @@ int picolcd_init_framebuffer(struct picolcd_data *data) ...@@ -580,25 +506,23 @@ int picolcd_init_framebuffer(struct picolcd_data *data)
} }
data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
data->fb_defio = picolcd_fb_defio;
/* The extra memory is: /* The extra memory is:
* - struct picolcd_fb_cleanup_item
* - u32 for ref_count
* - 256*u32 for pseudo_palette * - 256*u32 for pseudo_palette
* - struct fb_deferred_io
*/ */
info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev); info = framebuffer_alloc(256 * sizeof(u32) +
sizeof(struct fb_deferred_io), dev);
if (info == NULL) { if (info == NULL) {
dev_err(dev, "failed to allocate a framebuffer\n"); dev_err(dev, "failed to allocate a framebuffer\n");
goto err_nomem; goto err_nomem;
} }
palette = info->par + sizeof(struct picolcd_fb_cleanup_item); info->fbdefio = info->par;
*palette = 1; *info->fbdefio = picolcd_fb_defio;
palette++; palette = info->par + sizeof(struct fb_deferred_io);
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
palette[i] = i > 0 && i < 16 ? 0xff : 0; palette[i] = i > 0 && i < 16 ? 0xff : 0;
info->pseudo_palette = palette; info->pseudo_palette = palette;
info->fbdefio = &data->fb_defio;
info->screen_base = (char __force __iomem *)fb_bitmap; info->screen_base = (char __force __iomem *)fb_bitmap;
info->fbops = &picolcdfb_ops; info->fbops = &picolcdfb_ops;
info->var = picolcdfb_var; info->var = picolcdfb_var;
...@@ -658,6 +582,10 @@ void picolcd_exit_framebuffer(struct picolcd_data *data) ...@@ -658,6 +582,10 @@ void picolcd_exit_framebuffer(struct picolcd_data *data)
return; return;
device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
mutex_lock(&info->lock);
fb_deferred_io_cleanup(info);
info->par = NULL;
mutex_unlock(&info->lock);
unregister_framebuffer(info); unregister_framebuffer(info);
data->fb_vbitmap = NULL; data->fb_vbitmap = NULL;
data->fb_bitmap = NULL; data->fb_bitmap = NULL;
...@@ -665,9 +593,3 @@ void picolcd_exit_framebuffer(struct picolcd_data *data) ...@@ -665,9 +593,3 @@ void picolcd_exit_framebuffer(struct picolcd_data *data)
data->fb_info = NULL; data->fb_info = NULL;
kfree(fb_vbitmap); kfree(fb_vbitmap);
} }
void picolcd_fb_unload()
{
flush_work_sync(&picolcd_fb_cleanup);
WARN_ON(fb_pending);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment