#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/console.h>
+#include <linux/module.h>
/**
* framebuffer_alloc - creates a new frame buffer info structure
info->device = dev;
+#ifdef CONFIG_FB_BACKLIGHT
+ mutex_init(&info->bl_mutex);
+#endif
+
return info;
#undef PADDING
#undef BYTES_PER_LONG
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length);
}
-/* Format for cmap is "%02x%c%4x%4x%4x\n" */
-/* %02x entry %c transp %4x red %4x blue %4x green \n */
-/* 256 rows at 16 chars equals 4096, the normal page size */
-/* the code will automatically adjust for different page sizes */
-static ssize_t store_cmap(struct class_device *class_device, const char *buf,
- size_t count)
-{
- struct fb_info *fb_info = class_get_devdata(class_device);
- int rc, i, start, length, transp = 0;
-
- if ((count > PAGE_SIZE) || ((count % 16) != 0))
- return -EINVAL;
-
- if (!fb_info->fbops->fb_setcolreg && !fb_info->fbops->fb_setcmap)
- return -EINVAL;
-
- sscanf(buf, "%02x", &start);
- length = count / 16;
-
- for (i = 0; i < length; i++)
- if (buf[i * 16 + 2] != ' ')
- transp = 1;
-
- /* If we can batch, do it */
- if (fb_info->fbops->fb_setcmap && length > 1) {
- struct fb_cmap umap;
-
- memset(&umap, 0, sizeof(umap));
- if ((rc = fb_alloc_cmap(&umap, length, transp)))
- return rc;
-
- umap.start = start;
- for (i = 0; i < length; i++) {
- sscanf(&buf[i * 16 + 3], "%4hx", &umap.red[i]);
- sscanf(&buf[i * 16 + 7], "%4hx", &umap.blue[i]);
- sscanf(&buf[i * 16 + 11], "%4hx", &umap.green[i]);
- if (transp)
- umap.transp[i] = (buf[i * 16 + 2] != ' ');
- }
- rc = fb_info->fbops->fb_setcmap(&umap, fb_info);
- fb_copy_cmap(&umap, &fb_info->cmap);
- fb_dealloc_cmap(&umap);
-
- return rc ?: count;
- }
- for (i = 0; i < length; i++) {
- u16 red, blue, green, tsp;
-
- sscanf(&buf[i * 16 + 3], "%4hx", &red);
- sscanf(&buf[i * 16 + 7], "%4hx", &blue);
- sscanf(&buf[i * 16 + 11], "%4hx", &green);
- tsp = (buf[i * 16 + 2] != ' ');
- if ((rc = fb_info->fbops->fb_setcolreg(start++,
- red, green, blue, tsp, fb_info)))
- return rc;
-
- fb_info->cmap.red[i] = red;
- fb_info->cmap.blue[i] = blue;
- fb_info->cmap.green[i] = green;
- if (transp)
- fb_info->cmap.transp[i] = tsp;
- }
- return count;
-}
-
-static ssize_t show_cmap(struct class_device *class_device, char *buf)
-{
- struct fb_info *fb_info = class_get_devdata(class_device);
- unsigned int i;
-
- if (!fb_info->cmap.red || !fb_info->cmap.blue ||
- !fb_info->cmap.green)
- return -EINVAL;
-
- if (fb_info->cmap.len > PAGE_SIZE / 16)
- return -EINVAL;
-
- /* don't mess with the format, the buffer is PAGE_SIZE */
- /* 256 entries at 16 chars per line equals 4096 = PAGE_SIZE */
- for (i = 0; i < fb_info->cmap.len; i++) {
- snprintf(&buf[ i * 16], PAGE_SIZE - i * 16, "%02x%c%4x%4x%4x\n", i + fb_info->cmap.start,
- ((fb_info->cmap.transp && fb_info->cmap.transp[i]) ? '*' : ' '),
- fb_info->cmap.red[i], fb_info->cmap.blue[i],
- fb_info->cmap.green[i]);
- }
- return 16 * fb_info->cmap.len;
-}
-
static ssize_t store_blank(struct class_device *class_device, const char * buf,
size_t count)
{
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
}
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+ unsigned int i;
+
+ if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+ return -EINVAL;
+
+ for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+ if (sscanf(&buf[i * 24],
+ "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+ &tmp_curve[i * 8 + 0],
+ &tmp_curve[i * 8 + 1],
+ &tmp_curve[i * 8 + 2],
+ &tmp_curve[i * 8 + 3],
+ &tmp_curve[i * 8 + 4],
+ &tmp_curve[i * 8 + 5],
+ &tmp_curve[i * 8 + 6],
+ &tmp_curve[i * 8 + 7]) != 8)
+ return -EINVAL;
+
+ /* If there has been an error in the input data, we won't
+ * reach this loop.
+ */
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+ fb_info->bl_curve[i] = tmp_curve[i];
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return count;
+}
+
+static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ ssize_t len = 0;
+ unsigned int i;
+
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+ len += snprintf(&buf[len], PAGE_SIZE,
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ fb_info->bl_curve[i + 0],
+ fb_info->bl_curve[i + 1],
+ fb_info->bl_curve[i + 2],
+ fb_info->bl_curve[i + 3],
+ fb_info->bl_curve[i + 4],
+ fb_info->bl_curve[i + 5],
+ fb_info->bl_curve[i + 6],
+ fb_info->bl_curve[i + 7]);
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return len;
+}
+#endif
+
+/* When cmap is added back in it should be a binary attribute
+ * not a text one. Consideration should also be given to converting
+ * fbdev to use configfs instead of sysfs */
static struct class_device_attribute class_device_attrs[] = {
__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
- __ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
__ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
__ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+ __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
};
int fb_init_class_device(struct fb_info *fb_info)
&class_device_attrs[i]);
}
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ * 0: off
+ * 1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+ unsigned int i, flat, count, range = (max - min);
+ fb_info->bl_curve[0] = off;
+
+ for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+ fb_info->bl_curve[flat] = min;
+
+ count = FB_BACKLIGHT_LEVELS * 15 / 16;
+ for (i = 0; i < count; ++i)
+ fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif