diff options
Diffstat (limited to 'drivers/hid/hid-picolcd_fb.c')
| -rw-r--r-- | drivers/hid/hid-picolcd_fb.c | 130 |
1 files changed, 48 insertions, 82 deletions
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 591f6b22aa94..8c28e982e09d 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /*************************************************************************** * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * * * * Based on Logitech G13 driver (v0.4) * * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, version 2 of the License. * - * * - * This driver is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this software. If not see <http://www.gnu.org/licenses/>. * ***************************************************************************/ #include <linux/hid.h> @@ -231,7 +221,7 @@ int picolcd_fb_reset(struct picolcd_data *data, int clear) return 0; } -/* Update fb_vbitmap from the screen_base and send changed tiles to device */ +/* Update fb_vbitmap from the screen_buffer and send changed tiles to device */ static void picolcd_fb_update(struct fb_info *info) { int chip, tile, n; @@ -293,54 +283,6 @@ out: mutex_unlock(&info->lock); } -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - if (!info->par) - return; - sys_fillrect(info, rect); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - if (!info->par) - return; - sys_copyarea(info, area); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - if (!info->par) - return; - sys_imageblit(info, image); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it's inefficient to do anything less than a full screen draw - */ -static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - if (!info->par) - return -ENODEV; - ret = fb_sys_write(info, buf, count, ppos); - if (ret >= 0) - schedule_delayed_work(&info->deferred_work, 0); - return ret; -} - static int picolcd_fb_blank(int blank, struct fb_info *info) { /* We let fb notification do this for us via lcd/backlight device */ @@ -354,7 +296,7 @@ static void picolcd_fb_destroy(struct fb_info *info) /* make sure no work is deferred */ fb_deferred_io_cleanup(info); - /* No thridparty should ever unregister our framebuffer! */ + /* No thirdparty should ever unregister our framebuffer! */ WARN_ON(fbdata->picolcd != NULL); vfree((u8 *)info->fix.smem_start); @@ -394,7 +336,8 @@ static int picolcd_set_par(struct fb_info *info) return -EINVAL; o_fb = fbdata->bitmap; - tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); + tmp_fb = kmalloc_array(PICOLCDFB_SIZE, info->var.bits_per_pixel, + GFP_KERNEL); if (!tmp_fb) return -ENOMEM; @@ -426,23 +369,36 @@ static int picolcd_set_par(struct fb_info *info) return 0; } -/* Note this can't be const because of struct fb_info definition */ -static struct fb_ops picolcdfb_ops = { +static void picolcdfb_ops_damage_range(struct fb_info *info, off_t off, size_t len) +{ + if (!info->par) + return; + schedule_delayed_work(&info->deferred_work, 0); +} + +static void picolcdfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + if (!info->par) + return; + schedule_delayed_work(&info->deferred_work, 0); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(picolcdfb_ops, + picolcdfb_ops_damage_range, + picolcdfb_ops_damage_area) + +static const struct fb_ops picolcdfb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(picolcdfb_ops), .fb_destroy = picolcd_fb_destroy, - .fb_read = fb_sys_read, - .fb_write = picolcd_fb_write, .fb_blank = picolcd_fb_blank, - .fb_fillrect = picolcd_fb_fillrect, - .fb_copyarea = picolcd_fb_copyarea, - .fb_imageblit = picolcd_fb_imageblit, .fb_check_var = picolcd_fb_check_var, .fb_set_par = picolcd_set_par, }; /* Callback from deferred IO workqueue */ -static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) +static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagereflist) { picolcd_fb_update(info); } @@ -465,12 +421,10 @@ static ssize_t picolcd_fb_update_rate_show(struct device *dev, size_t ret = 0; for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) - if (ret >= PAGE_SIZE) - break; - else if (i == fb_update_rate) - ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); + if (i == fb_update_rate) + ret += sysfs_emit_at(buf, ret, "[%u] ", i); else - ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); + ret += sysfs_emit_at(buf, ret, "%u ", i); if (ret > 0) buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; return ret; @@ -501,7 +455,7 @@ static ssize_t picolcd_fb_update_rate_store(struct device *dev, return count; } -static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show, +static DEVICE_ATTR(fb_update_rate, 0664, picolcd_fb_update_rate_show, picolcd_fb_update_rate_store); /* initialize Framebuffer device */ @@ -521,10 +475,8 @@ int picolcd_init_framebuffer(struct picolcd_data *data) sizeof(struct fb_deferred_io) + sizeof(struct picolcd_fb_data) + PICOLCDFB_SIZE, dev); - if (info == NULL) { - dev_err(dev, "failed to allocate a framebuffer\n"); + if (!info) goto err_nomem; - } info->fbdefio = info->par; *info->fbdefio = picolcd_fb_defio; @@ -538,7 +490,16 @@ int picolcd_init_framebuffer(struct picolcd_data *data) info->var = picolcdfb_var; info->fix = picolcdfb_fix; info->fix.smem_len = PICOLCDFB_SIZE*8; - info->flags = FBINFO_FLAG_DEFAULT; + +#ifdef CONFIG_FB_BACKLIGHT +#ifdef CONFIG_HID_PICOLCD_BACKLIGHT + info->bl_dev = data->backlight; +#endif +#endif + +#ifdef CONFIG_HID_PICOLCD_LCD + info->lcd_dev = data->lcd; +#endif fbdata = info->par; spin_lock_init(&fbdata->lock); @@ -552,7 +513,8 @@ int picolcd_init_framebuffer(struct picolcd_data *data) dev_err(dev, "can't get a free page for framebuffer\n"); goto err_nomem; } - info->screen_base = (char __force __iomem *)fbdata->bitmap; + info->flags |= FBINFO_VIRTFB; + info->screen_buffer = fbdata->bitmap; info->fix.smem_start = (unsigned long)fbdata->bitmap; memset(fbdata->vbitmap, 0xff, PICOLCDFB_SIZE); data->fb_info = info; @@ -593,10 +555,14 @@ err_nomem: void picolcd_exit_framebuffer(struct picolcd_data *data) { struct fb_info *info = data->fb_info; - struct picolcd_fb_data *fbdata = info->par; + struct picolcd_fb_data *fbdata; unsigned long flags; + if (!info) + return; + device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); + fbdata = info->par; /* disconnect framebuffer from HID dev */ spin_lock_irqsave(&fbdata->lock, flags); |
