Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c0fad8e authored by Florian Tobias Schandinat's avatar Florian Tobias Schandinat
Browse files

Merge pull request #1 from bernieplug/fbdev-next

udlfb patches for fbdev-next
parents 0d04c58a 664c5f18
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -2231,6 +2231,15 @@ F: Documentation/filesystems/quota.txt
F:	fs/quota/
F:	fs/quota/
F:	include/linux/quota*.h
F:	include/linux/quota*.h


DISPLAYLINK USB 2.0 FRAMEBUFFER DRIVER (UDLFB)
M:	Bernie Thompson <bernie@plugable.com>
L:	linux-fbdev@vger.kernel.org
S:	Maintained
W:	http://plugable.com/category/projects/udlfb/
F:	drivers/video/udlfb.c
F:	include/video/udlfb.h
F:	Documentation/fb/udlfb.txt

DISTRIBUTED LOCK MANAGER (DLM)
DISTRIBUTED LOCK MANAGER (DLM)
M:	Christine Caulfield <ccaulfie@redhat.com>
M:	Christine Caulfield <ccaulfie@redhat.com>
M:	David Teigland <teigland@redhat.com>
M:	David Teigland <teigland@redhat.com>
+95 −68
Original line number Original line Diff line number Diff line
@@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
static bool console = 1; /* Allow fbcon to open framebuffer */
static bool console = 1; /* Allow fbcon to open framebuffer */
static bool fb_defio = 1;  /* Detect mmap writes using page faults */
static bool fb_defio = 1;  /* Detect mmap writes using page faults */
static bool shadow = 1; /* Optionally disable shadow framebuffer */
static bool shadow = 1; /* Optionally disable shadow framebuffer */
static int pixel_limit; /* Optionally force a pixel resolution limit */


/* dlfb keeps a list of urbs for efficient bulk transfers */
/* dlfb keeps a list of urbs for efficient bulk transfers */
static void dlfb_urb_completion(struct urb *urb);
static void dlfb_urb_completion(struct urb *urb);
@@ -918,10 +919,6 @@ static void dlfb_free(struct kref *kref)
{
{
	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);


	/* this function will wait for all in-flight urbs to complete */
	if (dev->urbs.count > 0)
		dlfb_free_urb_list(dev);

	if (dev->backing_buffer)
	if (dev->backing_buffer)
		vfree(dev->backing_buffer);
		vfree(dev->backing_buffer);


@@ -940,11 +937,11 @@ static void dlfb_release_urb_work(struct work_struct *work)
	up(&unode->dev->urbs.limit_sem);
	up(&unode->dev->urbs.limit_sem);
}
}


static void dlfb_free_framebuffer_work(struct work_struct *work)
static void dlfb_free_framebuffer(struct dlfb_data *dev)
{
{
	struct dlfb_data *dev = container_of(work, struct dlfb_data,
					     free_framebuffer_work.work);
	struct fb_info *info = dev->info;
	struct fb_info *info = dev->info;

	if (info) {
		int node = info->node;
		int node = info->node;


		unregister_framebuffer(info);
		unregister_framebuffer(info);
@@ -958,17 +955,24 @@ static void dlfb_free_framebuffer_work(struct work_struct *work)


		fb_destroy_modelist(&info->modelist);
		fb_destroy_modelist(&info->modelist);


	dev->info = 0;
		dev->info = NULL;


		/* Assume info structure is freed after this point */
		/* Assume info structure is freed after this point */
		framebuffer_release(info);
		framebuffer_release(info);


		pr_warn("fb_info for /dev/fb%d has been freed\n", node);
		pr_warn("fb_info for /dev/fb%d has been freed\n", node);
	}


	/* ref taken in probe() as part of registering framebfufer */
	/* ref taken in probe() as part of registering framebfufer */
	kref_put(&dev->kref, dlfb_free);
	kref_put(&dev->kref, dlfb_free);
}
}


static void dlfb_free_framebuffer_work(struct work_struct *work)
{
	struct dlfb_data *dev = container_of(work, struct dlfb_data,
					     free_framebuffer_work.work);
	dlfb_free_framebuffer(dev);
}
/*
/*
 * Assumes caller is holding info->lock mutex (for open and release at least)
 * Assumes caller is holding info->lock mutex (for open and release at least)
 */
 */
@@ -1012,7 +1016,8 @@ static int dlfb_is_valid_mode(struct fb_videomode *mode,
		return 0;
		return 0;
	}
	}


	pr_info("%dx%d valid mode\n", mode->xres, mode->yres);
	pr_info("%dx%d @ %d Hz valid mode\n", mode->xres, mode->yres,
		mode->refresh);


	return 1;
	return 1;
}
}
@@ -1537,7 +1542,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
			u8 length;
			u8 length;
			u16 key;
			u16 key;


			key = *((u16 *) desc);
			key = le16_to_cpu(*((u16 *) desc));
			desc += sizeof(u16);
			desc += sizeof(u16);
			length = *desc;
			length = *desc;
			desc++;
			desc++;
@@ -1570,14 +1575,15 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
	kfree(buf);
	kfree(buf);
	return true;
	return true;
}
}

static void dlfb_init_framebuffer_work(struct work_struct *work);

static int dlfb_usb_probe(struct usb_interface *interface,
static int dlfb_usb_probe(struct usb_interface *interface,
			const struct usb_device_id *id)
			const struct usb_device_id *id)
{
{
	struct usb_device *usbdev;
	struct usb_device *usbdev;
	struct dlfb_data *dev = 0;
	struct dlfb_data *dev = 0;
	struct fb_info *info = 0;
	int retval = -ENOMEM;
	int retval = -ENOMEM;
	int i;


	/* usb initialization */
	/* usb initialization */


@@ -1589,9 +1595,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
		goto error;
		goto error;
	}
	}


	/* we need to wait for both usb and fbdev to spin down on disconnect */
	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */


	dev->udev = usbdev;
	dev->udev = usbdev;
	dev->gdev = &usbdev->dev; /* our generic struct device * */
	dev->gdev = &usbdev->dev; /* our generic struct device * */
@@ -1613,16 +1617,53 @@ static int dlfb_usb_probe(struct usb_interface *interface,
		goto error;
		goto error;
	}
	}


	if (pixel_limit) {
		pr_warn("DL chip limit of %d overriden"
			" by module param to %d\n",
			dev->sku_pixel_limit, pixel_limit);
		dev->sku_pixel_limit = pixel_limit;
	}


	if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
	if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
		retval = -ENOMEM;
		retval = -ENOMEM;
		pr_err("dlfb_alloc_urb_list failed\n");
		pr_err("dlfb_alloc_urb_list failed\n");
		goto error;
		goto error;
	}
	}


	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */

	/* We don't register a new USB class. Our client interface is fbdev */
	/* We don't register a new USB class. Our client interface is fbdev */


	/* Workitem keep things fast & simple during USB enumeration */
	INIT_DELAYED_WORK(&dev->init_framebuffer_work,
			  dlfb_init_framebuffer_work);
	schedule_delayed_work(&dev->init_framebuffer_work, 0);

	return 0;

error:
	if (dev) {

		kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
		kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */

		/* dev has been deallocated. Do not dereference */
	}

	return retval;
}

static void dlfb_init_framebuffer_work(struct work_struct *work)
{
	struct dlfb_data *dev = container_of(work, struct dlfb_data,
					     init_framebuffer_work.work);
	struct fb_info *info;
	int retval;
	int i;

	/* allocates framebuffer driver structure, not framebuffer memory */
	/* allocates framebuffer driver structure, not framebuffer memory */
	info = framebuffer_alloc(0, &interface->dev);
	info = framebuffer_alloc(0, dev->gdev);
	if (!info) {
	if (!info) {
		retval = -ENOMEM;
		retval = -ENOMEM;
		pr_err("framebuffer_alloc failed\n");
		pr_err("framebuffer_alloc failed\n");
@@ -1668,15 +1709,13 @@ static int dlfb_usb_probe(struct usb_interface *interface,
	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
		retval = device_create_file(info->dev, &fb_device_attrs[i]);
		retval = device_create_file(info->dev, &fb_device_attrs[i]);
		if (retval) {
		if (retval) {
			pr_err("device_create_file failed %d\n", retval);
			pr_warn("device_create_file failed %d\n", retval);
			goto err_del_attrs;
		}
		}
	}
	}


	retval = device_create_bin_file(info->dev, &edid_attr);
	retval = device_create_bin_file(info->dev, &edid_attr);
	if (retval) {
	if (retval) {
		pr_err("device_create_bin_file failed %d\n", retval);
		pr_warn("device_create_bin_file failed %d\n", retval);
		goto err_del_attrs;
	}
	}


	pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
	pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
@@ -1684,38 +1723,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
			info->var.xres, info->var.yres,
			info->var.xres, info->var.yres,
			((dev->backing_buffer) ?
			((dev->backing_buffer) ?
			info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
			info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
	return 0;
	return;

err_del_attrs:
	for (i -= 1; i >= 0; i--)
		device_remove_file(info->dev, &fb_device_attrs[i]);


error:
error:
	if (dev) {
	dlfb_free_framebuffer(dev);

		if (info) {
			if (info->cmap.len != 0)
				fb_dealloc_cmap(&info->cmap);
			if (info->monspecs.modedb)
				fb_destroy_modedb(info->monspecs.modedb);
			if (info->screen_base)
				vfree(info->screen_base);

			fb_destroy_modelist(&info->modelist);

			framebuffer_release(info);
		}

		if (dev->backing_buffer)
			vfree(dev->backing_buffer);

		kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
		kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */

		/* dev has been deallocated. Do not dereference */
	}

	return retval;
}
}


static void dlfb_usb_disconnect(struct usb_interface *interface)
static void dlfb_usb_disconnect(struct usb_interface *interface)
@@ -1735,12 +1746,24 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
	/* When non-active we'll update virtual framebuffer, but no new urbs */
	/* When non-active we'll update virtual framebuffer, but no new urbs */
	atomic_set(&dev->usb_active, 0);
	atomic_set(&dev->usb_active, 0);


	/* this function will wait for all in-flight urbs to complete */
	dlfb_free_urb_list(dev);

	if (info) {

		/* remove udlfb's sysfs interfaces */
		/* remove udlfb's sysfs interfaces */
		for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
		for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
			device_remove_file(info->dev, &fb_device_attrs[i]);
			device_remove_file(info->dev, &fb_device_attrs[i]);
		device_remove_bin_file(info->dev, &edid_attr);
		device_remove_bin_file(info->dev, &edid_attr);

		/* it's safe to uncomment next line if your kernel
		   doesn't yet have this function exported */
		unlink_framebuffer(info);
		unlink_framebuffer(info);
	}

	usb_set_intfdata(interface, NULL);
	usb_set_intfdata(interface, NULL);
	dev->udev = NULL;
	dev->gdev = NULL;


	/* if clients still have us open, will be freed on last close */
	/* if clients still have us open, will be freed on last close */
	if (dev->fb_count == 0)
	if (dev->fb_count == 0)
@@ -1806,12 +1829,12 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
	int ret;
	int ret;
	unsigned long flags;
	unsigned long flags;


	pr_notice("Waiting for completes and freeing all render urbs\n");
	pr_notice("Freeing all render urbs\n");


	/* keep waiting and freeing, until we've got 'em all */
	/* keep waiting and freeing, until we've got 'em all */
	while (count--) {
	while (count--) {


		/* Getting interrupted means a leak, but ok at shutdown*/
		/* Getting interrupted means a leak, but ok at disconnect */
		ret = down_interruptible(&dev->urbs.limit_sem);
		ret = down_interruptible(&dev->urbs.limit_sem);
		if (ret)
		if (ret)
			break;
			break;
@@ -1833,6 +1856,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
		kfree(node);
		kfree(node);
	}
	}


	dev->urbs.count = 0;
}
}


static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
@@ -1948,6 +1972,9 @@ MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes");
module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");
MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");


module_param(pixel_limit, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
MODULE_PARM_DESC(pixel_limit, "Force limit on max mode (in x*y pixels)");

MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
	      "Jaya Kumar <jayakumar.lkml@gmail.com>, "
	      "Jaya Kumar <jayakumar.lkml@gmail.com>, "
	      "Bernie Thompson <bernie@plugable.com>");
	      "Bernie Thompson <bernie@plugable.com>");
+1 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ struct dlfb_data {
	char *backing_buffer;
	char *backing_buffer;
	int fb_count;
	int fb_count;
	bool virtualized; /* true when physical usb device not present */
	bool virtualized; /* true when physical usb device not present */
	struct delayed_work init_framebuffer_work;
	struct delayed_work free_framebuffer_work;
	struct delayed_work free_framebuffer_work;
	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
	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 lost_pixels; /* 1 = a render op failed. Need screen refresh */