staging: udlfb: add module options for console and fb_defio

Add module options for console and fb_defio

Convert fb_defio on/off switch to module option and add console option.

>From the command line, pass options to modprobe
modprobe udlfb defio=1 console=1

Or for permanent option, create file like /etc/modprobe.d/options with text
options udlfb defio=1 console=1

Accepted options:

fb_defio	Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel
		module to track changed areas of the framebuffer by page faults.
        	Standard fbdev applications that use mmap but that do not
		report damage, may be able to work with this enabled.
		Disabled by default because of overhead and other issues.

console		Allow fbcon to attach to udlfb provided framebuffers. This
		is disabled by default because fbcon will aggressively consume
		the first framebuffer it finds, which isn't usually what the
		user wants in the case of USB displays.

Signed-off-by: Bernie Thompson <bernie@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Bernie Thompson 2010-09-05 16:35:39 -07:00 committed by Greg Kroah-Hartman
parent 8ef8cc4fca
commit d5ed54322e
2 changed files with 81 additions and 98 deletions

View File

@ -59,19 +59,9 @@ static struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
#ifndef CONFIG_FB_DEFERRED_IO
#warning Please set CONFIG_FB_DEFFERRED_IO option to support generic fbdev apps
#endif
#ifndef CONFIG_FB_SYS_IMAGEBLIT
#ifndef CONFIG_FB_SYS_IMAGEBLIT_MODULE
#warning Please set CONFIG_FB_SYS_IMAGEBLIT option to support fb console
#endif
#endif
#ifndef CONFIG_FB_MODE_HELPERS
#warning CONFIG_FB_MODE_HELPERS required. Expect build break
#endif
/* module options */
static int console; /* Optionally allow fbcon to consume first framebuffer */
static int fb_defio; /* Optionally enable experimental fb_defio mmap support */
/* dlfb keeps a list of urbs for efficient bulk transfers */
static void dlfb_urb_completion(struct urb *urb);
@ -695,6 +685,68 @@ static void dlfb_ops_fillrect(struct fb_info *info,
}
#ifdef CONFIG_FB_DEFERRED_IO
/*
* NOTE: fb_defio.c is holding info->fbdefio.mutex
* Touching ANY framebuffer memory that triggers a page fault
* in fb_defio will cause a deadlock, when it also tries to
* grab the same mutex.
*/
static void dlfb_dpy_deferred_io(struct fb_info *info,
struct list_head *pagelist)
{
struct page *cur;
struct fb_deferred_io *fbdefio = info->fbdefio;
struct dlfb_data *dev = info->par;
struct urb *urb;
char *cmd;
cycles_t start_cycles, end_cycles;
int bytes_sent = 0;
int bytes_identical = 0;
int bytes_rendered = 0;
if (!fb_defio)
return;
if (!atomic_read(&dev->usb_active))
return;
start_cycles = get_cycles();
urb = dlfb_get_urb(dev);
if (!urb)
return;
cmd = urb->transfer_buffer;
/* walk the written page list and render each to device */
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
&cmd, cur->index << PAGE_SHIFT,
PAGE_SIZE, &bytes_identical, &bytes_sent);
bytes_rendered += PAGE_SIZE;
}
if (cmd > (char *) urb->transfer_buffer) {
/* Send partial buffer remaining before exiting */
int len = cmd - (char *) urb->transfer_buffer;
dlfb_submit_urb(dev, urb, len);
bytes_sent += len;
} else
dlfb_urb_completion(urb);
atomic_add(bytes_sent, &dev->bytes_sent);
atomic_add(bytes_identical, &dev->bytes_identical);
atomic_add(bytes_rendered, &dev->bytes_rendered);
end_cycles = get_cycles();
atomic_add(((unsigned int) ((end_cycles - start_cycles)
>> 10)), /* Kcycles */
&dev->cpu_kcycles_used);
}
#endif
static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
{
int i;
@ -758,8 +810,6 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
if (area->y > info->var.yres)
area->y = info->var.yres;
atomic_set(&dev->use_defio, 0);
dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
info->screen_base);
}
@ -803,9 +853,13 @@ static int dlfb_ops_open(struct fb_info *info, int user)
{
struct dlfb_data *dev = info->par;
/* if (user == 0)
* We could special case kernel mode clients (fbcon) here
/*
* fbcon aggressively connects to first framebuffer it finds,
* preventing other clients (X) from working properly. Usually
* not what the user wants. Fail by default with option to enable.
*/
if ((user == 0) & (!console))
return -EBUSY;
/* If the USB device is gone, we don't accept new opens */
if (dev->virtualized)
@ -816,7 +870,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
kref_get(&dev->kref);
#ifdef CONFIG_FB_DEFERRED_IO
if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
if (fb_defio && (info->fbdefio == NULL)) {
/* enable defio */
info->fbdefio = &dlfb_defio;
fb_deferred_io_init(info);
@ -1345,30 +1399,6 @@ static ssize_t metrics_reset_store(struct device *fbdev,
return count;
}
static ssize_t use_defio_show(struct device *fbdev,
struct device_attribute *a, char *buf) {
struct fb_info *fb_info = dev_get_drvdata(fbdev);
struct dlfb_data *dev = fb_info->par;
return snprintf(buf, PAGE_SIZE, "%d\n",
atomic_read(&dev->use_defio));
}
static ssize_t use_defio_store(struct device *fbdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct fb_info *fb_info = dev_get_drvdata(fbdev);
struct dlfb_data *dev = fb_info->par;
if (count > 0) {
if (buf[0] == '0')
atomic_set(&dev->use_defio, 0);
if (buf[0] == '1')
atomic_set(&dev->use_defio, 1);
}
return count;
}
static struct bin_attribute edid_attr = {
.attr.name = "edid",
.attr.mode = 0666,
@ -1383,60 +1413,9 @@ static struct device_attribute fb_device_attrs[] = {
__ATTR_RO(metrics_bytes_sent),
__ATTR_RO(metrics_cpu_kcycles_used),
__ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
__ATTR_RW(use_defio),
};
#ifdef CONFIG_FB_DEFERRED_IO
static void dlfb_dpy_deferred_io(struct fb_info *info,
struct list_head *pagelist)
{
struct page *cur;
struct fb_deferred_io *fbdefio = info->fbdefio;
struct dlfb_data *dev = info->par;
struct urb *urb;
char *cmd;
cycles_t start_cycles, end_cycles;
int bytes_sent = 0;
int bytes_identical = 0;
int bytes_rendered = 0;
if (!atomic_read(&dev->use_defio))
return;
if (!atomic_read(&dev->usb_active))
return;
start_cycles = get_cycles();
urb = dlfb_get_urb(dev);
if (!urb)
return;
cmd = urb->transfer_buffer;
/* walk the written page list and render each to device */
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
&cmd, cur->index << PAGE_SHIFT,
PAGE_SIZE, &bytes_identical, &bytes_sent);
bytes_rendered += PAGE_SIZE;
}
if (cmd > (char *) urb->transfer_buffer) {
/* Send partial buffer remaining before exiting */
int len = cmd - (char *) urb->transfer_buffer;
dlfb_submit_urb(dev, urb, len);
bytes_sent += len;
} else
dlfb_urb_completion(urb);
atomic_add(bytes_sent, &dev->bytes_sent);
atomic_add(bytes_identical, &dev->bytes_identical);
atomic_add(bytes_rendered, &dev->bytes_rendered);
end_cycles = get_cycles();
atomic_add(((unsigned int) ((end_cycles - start_cycles)
>> 10)), /* Kcycles */
&dev->cpu_kcycles_used);
}
static struct fb_deferred_io dlfb_defio = {
.delay = 5,
@ -1563,6 +1542,8 @@ static int dlfb_usb_probe(struct usb_interface *interface,
dl_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n",
usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
usbdev->descriptor.bcdDevice, dev);
dl_info("console enable=%d\n", console);
dl_info("fb_defio enable=%d\n", fb_defio);
dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
@ -1611,9 +1592,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
/* ready to begin using device */
#ifdef CONFIG_FB_DEFERRED_IO
atomic_set(&dev->use_defio, 1);
#endif
atomic_set(&dev->usb_active, 1);
dlfb_select_std_channel(dev);
@ -1893,6 +1871,12 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
return ret;
}
module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found");
module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support. *Experimental*");
MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
"Jaya Kumar <jayakumar.lkml@gmail.com>, "
"Bernie Thompson <bernie@plugable.com>");

View File

@ -43,7 +43,6 @@ struct dlfb_data {
struct delayed_work free_framebuffer_work;
atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
char *edid; /* null until we read edid from hw or get from sysfs */
size_t edid_size;
int sku_pixel_limit;