aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/udlfb.c146
-rw-r--r--include/video/udlfb.h1
2 files changed, 81 insertions, 66 deletions
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 04aea205f021..cbf030d0dfc4 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -918,10 +918,6 @@ static void dlfb_free(struct kref *kref)
918{ 918{
919 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); 919 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
920 920
921 /* this function will wait for all in-flight urbs to complete */
922 if (dev->urbs.count > 0)
923 dlfb_free_urb_list(dev);
924
925 if (dev->backing_buffer) 921 if (dev->backing_buffer)
926 vfree(dev->backing_buffer); 922 vfree(dev->backing_buffer);
927 923
@@ -940,35 +936,42 @@ static void dlfb_release_urb_work(struct work_struct *work)
940 up(&unode->dev->urbs.limit_sem); 936 up(&unode->dev->urbs.limit_sem);
941} 937}
942 938
943static void dlfb_free_framebuffer_work(struct work_struct *work) 939static void dlfb_free_framebuffer(struct dlfb_data *dev)
944{ 940{
945 struct dlfb_data *dev = container_of(work, struct dlfb_data,
946 free_framebuffer_work.work);
947 struct fb_info *info = dev->info; 941 struct fb_info *info = dev->info;
948 int node = info->node;
949 942
950 unregister_framebuffer(info); 943 if (info) {
944 int node = info->node;
951 945
952 if (info->cmap.len != 0) 946 unregister_framebuffer(info);
953 fb_dealloc_cmap(&info->cmap);
954 if (info->monspecs.modedb)
955 fb_destroy_modedb(info->monspecs.modedb);
956 if (info->screen_base)
957 vfree(info->screen_base);
958 947
959 fb_destroy_modelist(&info->modelist); 948 if (info->cmap.len != 0)
949 fb_dealloc_cmap(&info->cmap);
950 if (info->monspecs.modedb)
951 fb_destroy_modedb(info->monspecs.modedb);
952 if (info->screen_base)
953 vfree(info->screen_base);
954
955 fb_destroy_modelist(&info->modelist);
960 956
961 dev->info = 0; 957 dev->info = NULL;
962 958
963 /* Assume info structure is freed after this point */ 959 /* Assume info structure is freed after this point */
964 framebuffer_release(info); 960 framebuffer_release(info);
965 961
966 pr_warn("fb_info for /dev/fb%d has been freed\n", node); 962 pr_warn("fb_info for /dev/fb%d has been freed\n", node);
963 }
967 964
968 /* ref taken in probe() as part of registering framebfufer */ 965 /* ref taken in probe() as part of registering framebfufer */
969 kref_put(&dev->kref, dlfb_free); 966 kref_put(&dev->kref, dlfb_free);
970} 967}
971 968
969static void dlfb_free_framebuffer_work(struct work_struct *work)
970{
971 struct dlfb_data *dev = container_of(work, struct dlfb_data,
972 free_framebuffer_work.work);
973 dlfb_free_framebuffer(dev);
974}
972/* 975/*
973 * Assumes caller is holding info->lock mutex (for open and release at least) 976 * Assumes caller is holding info->lock mutex (for open and release at least)
974 */ 977 */
@@ -1571,14 +1574,15 @@ success:
1571 kfree(buf); 1574 kfree(buf);
1572 return true; 1575 return true;
1573} 1576}
1577
1578static void dlfb_init_framebuffer_work(struct work_struct *work);
1579
1574static int dlfb_usb_probe(struct usb_interface *interface, 1580static int dlfb_usb_probe(struct usb_interface *interface,
1575 const struct usb_device_id *id) 1581 const struct usb_device_id *id)
1576{ 1582{
1577 struct usb_device *usbdev; 1583 struct usb_device *usbdev;
1578 struct dlfb_data *dev = 0; 1584 struct dlfb_data *dev = 0;
1579 struct fb_info *info = 0;
1580 int retval = -ENOMEM; 1585 int retval = -ENOMEM;
1581 int i;
1582 1586
1583 /* usb initialization */ 1587 /* usb initialization */
1584 1588
@@ -1590,9 +1594,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
1590 goto error; 1594 goto error;
1591 } 1595 }
1592 1596
1593 /* we need to wait for both usb and fbdev to spin down on disconnect */
1594 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ 1597 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
1595 kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
1596 1598
1597 dev->udev = usbdev; 1599 dev->udev = usbdev;
1598 dev->gdev = &usbdev->dev; /* our generic struct device * */ 1600 dev->gdev = &usbdev->dev; /* our generic struct device * */
@@ -1620,10 +1622,39 @@ static int dlfb_usb_probe(struct usb_interface *interface,
1620 goto error; 1622 goto error;
1621 } 1623 }
1622 1624
1625 kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
1626
1623 /* We don't register a new USB class. Our client interface is fbdev */ 1627 /* We don't register a new USB class. Our client interface is fbdev */
1624 1628
1629 /* Workitem keep things fast & simple during USB enumeration */
1630 INIT_DELAYED_WORK(&dev->init_framebuffer_work,
1631 dlfb_init_framebuffer_work);
1632 schedule_delayed_work(&dev->init_framebuffer_work, 0);
1633
1634 return 0;
1635
1636error:
1637 if (dev) {
1638
1639 kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
1640 kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */
1641
1642 /* dev has been deallocated. Do not dereference */
1643 }
1644
1645 return retval;
1646}
1647
1648static void dlfb_init_framebuffer_work(struct work_struct *work)
1649{
1650 struct dlfb_data *dev = container_of(work, struct dlfb_data,
1651 init_framebuffer_work.work);
1652 struct fb_info *info;
1653 int retval;
1654 int i;
1655
1625 /* allocates framebuffer driver structure, not framebuffer memory */ 1656 /* allocates framebuffer driver structure, not framebuffer memory */
1626 info = framebuffer_alloc(0, &interface->dev); 1657 info = framebuffer_alloc(0, dev->gdev);
1627 if (!info) { 1658 if (!info) {
1628 retval = -ENOMEM; 1659 retval = -ENOMEM;
1629 pr_err("framebuffer_alloc failed\n"); 1660 pr_err("framebuffer_alloc failed\n");
@@ -1669,15 +1700,13 @@ static int dlfb_usb_probe(struct usb_interface *interface,
1669 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) { 1700 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
1670 retval = device_create_file(info->dev, &fb_device_attrs[i]); 1701 retval = device_create_file(info->dev, &fb_device_attrs[i]);
1671 if (retval) { 1702 if (retval) {
1672 pr_err("device_create_file failed %d\n", retval); 1703 pr_warn("device_create_file failed %d\n", retval);
1673 goto err_del_attrs;
1674 } 1704 }
1675 } 1705 }
1676 1706
1677 retval = device_create_bin_file(info->dev, &edid_attr); 1707 retval = device_create_bin_file(info->dev, &edid_attr);
1678 if (retval) { 1708 if (retval) {
1679 pr_err("device_create_bin_file failed %d\n", retval); 1709 pr_warn("device_create_bin_file failed %d\n", retval);
1680 goto err_del_attrs;
1681 } 1710 }
1682 1711
1683 pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." 1712 pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
@@ -1685,38 +1714,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
1685 info->var.xres, info->var.yres, 1714 info->var.xres, info->var.yres,
1686 ((dev->backing_buffer) ? 1715 ((dev->backing_buffer) ?
1687 info->fix.smem_len * 2 : info->fix.smem_len) >> 10); 1716 info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
1688 return 0; 1717 return;
1689
1690err_del_attrs:
1691 for (i -= 1; i >= 0; i--)
1692 device_remove_file(info->dev, &fb_device_attrs[i]);
1693 1718
1694error: 1719error:
1695 if (dev) { 1720 dlfb_free_framebuffer(dev);
1696
1697 if (info) {
1698 if (info->cmap.len != 0)
1699 fb_dealloc_cmap(&info->cmap);
1700 if (info->monspecs.modedb)
1701 fb_destroy_modedb(info->monspecs.modedb);
1702 if (info->screen_base)
1703 vfree(info->screen_base);
1704
1705 fb_destroy_modelist(&info->modelist);
1706
1707 framebuffer_release(info);
1708 }
1709
1710 if (dev->backing_buffer)
1711 vfree(dev->backing_buffer);
1712
1713 kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
1714 kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */
1715
1716 /* dev has been deallocated. Do not dereference */
1717 }
1718
1719 return retval;
1720} 1721}
1721 1722
1722static void dlfb_usb_disconnect(struct usb_interface *interface) 1723static void dlfb_usb_disconnect(struct usb_interface *interface)
@@ -1736,12 +1737,24 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
1736 /* When non-active we'll update virtual framebuffer, but no new urbs */ 1737 /* When non-active we'll update virtual framebuffer, but no new urbs */
1737 atomic_set(&dev->usb_active, 0); 1738 atomic_set(&dev->usb_active, 0);
1738 1739
1739 /* remove udlfb's sysfs interfaces */ 1740 /* this function will wait for all in-flight urbs to complete */
1740 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) 1741 dlfb_free_urb_list(dev);
1741 device_remove_file(info->dev, &fb_device_attrs[i]); 1742
1742 device_remove_bin_file(info->dev, &edid_attr); 1743 if (info) {
1743 unlink_framebuffer(info); 1744
1745 /* remove udlfb's sysfs interfaces */
1746 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1747 device_remove_file(info->dev, &fb_device_attrs[i]);
1748 device_remove_bin_file(info->dev, &edid_attr);
1749
1750 /* it's safe to uncomment next line if your kernel
1751 doesn't yet have this function exported */
1752 unlink_framebuffer(info);
1753 }
1754
1744 usb_set_intfdata(interface, NULL); 1755 usb_set_intfdata(interface, NULL);
1756 dev->udev = NULL;
1757 dev->gdev = NULL;
1745 1758
1746 /* if clients still have us open, will be freed on last close */ 1759 /* if clients still have us open, will be freed on last close */
1747 if (dev->fb_count == 0) 1760 if (dev->fb_count == 0)
@@ -1807,12 +1820,12 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
1807 int ret; 1820 int ret;
1808 unsigned long flags; 1821 unsigned long flags;
1809 1822
1810 pr_notice("Waiting for completes and freeing all render urbs\n"); 1823 pr_notice("Freeing all render urbs\n");
1811 1824
1812 /* keep waiting and freeing, until we've got 'em all */ 1825 /* keep waiting and freeing, until we've got 'em all */
1813 while (count--) { 1826 while (count--) {
1814 1827
1815 /* Getting interrupted means a leak, but ok at shutdown*/ 1828 /* Getting interrupted means a leak, but ok at disconnect */
1816 ret = down_interruptible(&dev->urbs.limit_sem); 1829 ret = down_interruptible(&dev->urbs.limit_sem);
1817 if (ret) 1830 if (ret)
1818 break; 1831 break;
@@ -1834,6 +1847,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
1834 kfree(node); 1847 kfree(node);
1835 } 1848 }
1836 1849
1850 dev->urbs.count = 0;
1837} 1851}
1838 1852
1839static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) 1853static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
diff --git a/include/video/udlfb.h b/include/video/udlfb.h
index c41f308c9636..f9466fa54ba4 100644
--- a/include/video/udlfb.h
+++ b/include/video/udlfb.h
@@ -41,6 +41,7 @@ struct dlfb_data {
41 char *backing_buffer; 41 char *backing_buffer;
42 int fb_count; 42 int fb_count;
43 bool virtualized; /* true when physical usb device not present */ 43 bool virtualized; /* true when physical usb device not present */
44 struct delayed_work init_framebuffer_work;
44 struct delayed_work free_framebuffer_work; 45 struct delayed_work free_framebuffer_work;
45 atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */ 46 atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
46 atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */ 47 atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */