diff options
Diffstat (limited to 'drivers/video/udlfb.c')
-rw-r--r-- | drivers/video/udlfb.c | 178 |
1 files changed, 102 insertions, 76 deletions
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index a40c05ebbdc2..a159b63e18b9 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c | |||
@@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE(usb, id_table); | |||
72 | static bool console = 1; /* Allow fbcon to open framebuffer */ | 72 | static bool console = 1; /* Allow fbcon to open framebuffer */ |
73 | static bool fb_defio = 1; /* Detect mmap writes using page faults */ | 73 | static bool fb_defio = 1; /* Detect mmap writes using page faults */ |
74 | static bool shadow = 1; /* Optionally disable shadow framebuffer */ | 74 | static bool shadow = 1; /* Optionally disable shadow framebuffer */ |
75 | static int pixel_limit; /* Optionally force a pixel resolution limit */ | ||
75 | 76 | ||
76 | /* dlfb keeps a list of urbs for efficient bulk transfers */ | 77 | /* dlfb keeps a list of urbs for efficient bulk transfers */ |
77 | static void dlfb_urb_completion(struct urb *urb); | 78 | static void dlfb_urb_completion(struct urb *urb); |
@@ -918,10 +919,6 @@ static void dlfb_free(struct kref *kref) | |||
918 | { | 919 | { |
919 | struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); | 920 | struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); |
920 | 921 | ||
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) | 922 | if (dev->backing_buffer) |
926 | vfree(dev->backing_buffer); | 923 | vfree(dev->backing_buffer); |
927 | 924 | ||
@@ -940,35 +937,42 @@ static void dlfb_release_urb_work(struct work_struct *work) | |||
940 | up(&unode->dev->urbs.limit_sem); | 937 | up(&unode->dev->urbs.limit_sem); |
941 | } | 938 | } |
942 | 939 | ||
943 | static void dlfb_free_framebuffer_work(struct work_struct *work) | 940 | static void dlfb_free_framebuffer(struct dlfb_data *dev) |
944 | { | 941 | { |
945 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
946 | free_framebuffer_work.work); | ||
947 | struct fb_info *info = dev->info; | 942 | struct fb_info *info = dev->info; |
948 | int node = info->node; | ||
949 | 943 | ||
950 | unregister_framebuffer(info); | 944 | if (info) { |
945 | int node = info->node; | ||
951 | 946 | ||
952 | if (info->cmap.len != 0) | 947 | 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 | 948 | ||
959 | fb_destroy_modelist(&info->modelist); | 949 | if (info->cmap.len != 0) |
950 | fb_dealloc_cmap(&info->cmap); | ||
951 | if (info->monspecs.modedb) | ||
952 | fb_destroy_modedb(info->monspecs.modedb); | ||
953 | if (info->screen_base) | ||
954 | vfree(info->screen_base); | ||
960 | 955 | ||
961 | dev->info = 0; | 956 | fb_destroy_modelist(&info->modelist); |
962 | 957 | ||
963 | /* Assume info structure is freed after this point */ | 958 | dev->info = NULL; |
964 | framebuffer_release(info); | ||
965 | 959 | ||
966 | pr_warn("fb_info for /dev/fb%d has been freed\n", node); | 960 | /* Assume info structure is freed after this point */ |
961 | framebuffer_release(info); | ||
962 | |||
963 | pr_warn("fb_info for /dev/fb%d has been freed\n", node); | ||
964 | } | ||
967 | 965 | ||
968 | /* ref taken in probe() as part of registering framebfufer */ | 966 | /* ref taken in probe() as part of registering framebfufer */ |
969 | kref_put(&dev->kref, dlfb_free); | 967 | kref_put(&dev->kref, dlfb_free); |
970 | } | 968 | } |
971 | 969 | ||
970 | static void dlfb_free_framebuffer_work(struct work_struct *work) | ||
971 | { | ||
972 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
973 | free_framebuffer_work.work); | ||
974 | dlfb_free_framebuffer(dev); | ||
975 | } | ||
972 | /* | 976 | /* |
973 | * Assumes caller is holding info->lock mutex (for open and release at least) | 977 | * Assumes caller is holding info->lock mutex (for open and release at least) |
974 | */ | 978 | */ |
@@ -1012,7 +1016,8 @@ static int dlfb_is_valid_mode(struct fb_videomode *mode, | |||
1012 | return 0; | 1016 | return 0; |
1013 | } | 1017 | } |
1014 | 1018 | ||
1015 | pr_info("%dx%d valid mode\n", mode->xres, mode->yres); | 1019 | pr_info("%dx%d @ %d Hz valid mode\n", mode->xres, mode->yres, |
1020 | mode->refresh); | ||
1016 | 1021 | ||
1017 | return 1; | 1022 | return 1; |
1018 | } | 1023 | } |
@@ -1427,19 +1432,22 @@ static ssize_t edid_store( | |||
1427 | struct device *fbdev = container_of(kobj, struct device, kobj); | 1432 | struct device *fbdev = container_of(kobj, struct device, kobj); |
1428 | struct fb_info *fb_info = dev_get_drvdata(fbdev); | 1433 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
1429 | struct dlfb_data *dev = fb_info->par; | 1434 | struct dlfb_data *dev = fb_info->par; |
1435 | int ret; | ||
1430 | 1436 | ||
1431 | /* We only support write of entire EDID at once, no offset*/ | 1437 | /* We only support write of entire EDID at once, no offset*/ |
1432 | if ((src_size != EDID_LENGTH) || (src_off != 0)) | 1438 | if ((src_size != EDID_LENGTH) || (src_off != 0)) |
1433 | return 0; | 1439 | return -EINVAL; |
1434 | 1440 | ||
1435 | dlfb_setup_modes(dev, fb_info, src, src_size); | 1441 | ret = dlfb_setup_modes(dev, fb_info, src, src_size); |
1442 | if (ret) | ||
1443 | return ret; | ||
1436 | 1444 | ||
1437 | if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) { | 1445 | if (!dev->edid || memcmp(src, dev->edid, src_size)) |
1438 | pr_info("sysfs written EDID is new default\n"); | 1446 | return -EINVAL; |
1439 | dlfb_ops_set_par(fb_info); | 1447 | |
1440 | return src_size; | 1448 | pr_info("sysfs written EDID is new default\n"); |
1441 | } else | 1449 | dlfb_ops_set_par(fb_info); |
1442 | return 0; | 1450 | return src_size; |
1443 | } | 1451 | } |
1444 | 1452 | ||
1445 | static ssize_t metrics_reset_store(struct device *fbdev, | 1453 | static ssize_t metrics_reset_store(struct device *fbdev, |
@@ -1537,7 +1545,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev, | |||
1537 | u8 length; | 1545 | u8 length; |
1538 | u16 key; | 1546 | u16 key; |
1539 | 1547 | ||
1540 | key = *((u16 *) desc); | 1548 | key = le16_to_cpu(*((u16 *) desc)); |
1541 | desc += sizeof(u16); | 1549 | desc += sizeof(u16); |
1542 | length = *desc; | 1550 | length = *desc; |
1543 | desc++; | 1551 | desc++; |
@@ -1570,14 +1578,15 @@ success: | |||
1570 | kfree(buf); | 1578 | kfree(buf); |
1571 | return true; | 1579 | return true; |
1572 | } | 1580 | } |
1581 | |||
1582 | static void dlfb_init_framebuffer_work(struct work_struct *work); | ||
1583 | |||
1573 | static int dlfb_usb_probe(struct usb_interface *interface, | 1584 | static int dlfb_usb_probe(struct usb_interface *interface, |
1574 | const struct usb_device_id *id) | 1585 | const struct usb_device_id *id) |
1575 | { | 1586 | { |
1576 | struct usb_device *usbdev; | 1587 | struct usb_device *usbdev; |
1577 | struct dlfb_data *dev = 0; | 1588 | struct dlfb_data *dev = 0; |
1578 | struct fb_info *info = 0; | ||
1579 | int retval = -ENOMEM; | 1589 | int retval = -ENOMEM; |
1580 | int i; | ||
1581 | 1590 | ||
1582 | /* usb initialization */ | 1591 | /* usb initialization */ |
1583 | 1592 | ||
@@ -1589,9 +1598,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1589 | goto error; | 1598 | goto error; |
1590 | } | 1599 | } |
1591 | 1600 | ||
1592 | /* we need to wait for both usb and fbdev to spin down on disconnect */ | ||
1593 | kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ | 1601 | kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ |
1594 | kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */ | ||
1595 | 1602 | ||
1596 | dev->udev = usbdev; | 1603 | dev->udev = usbdev; |
1597 | dev->gdev = &usbdev->dev; /* our generic struct device * */ | 1604 | dev->gdev = &usbdev->dev; /* our generic struct device * */ |
@@ -1613,16 +1620,53 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1613 | goto error; | 1620 | goto error; |
1614 | } | 1621 | } |
1615 | 1622 | ||
1623 | if (pixel_limit) { | ||
1624 | pr_warn("DL chip limit of %d overriden" | ||
1625 | " by module param to %d\n", | ||
1626 | dev->sku_pixel_limit, pixel_limit); | ||
1627 | dev->sku_pixel_limit = pixel_limit; | ||
1628 | } | ||
1629 | |||
1630 | |||
1616 | if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { | 1631 | if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { |
1617 | retval = -ENOMEM; | 1632 | retval = -ENOMEM; |
1618 | pr_err("dlfb_alloc_urb_list failed\n"); | 1633 | pr_err("dlfb_alloc_urb_list failed\n"); |
1619 | goto error; | 1634 | goto error; |
1620 | } | 1635 | } |
1621 | 1636 | ||
1637 | kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */ | ||
1638 | |||
1622 | /* We don't register a new USB class. Our client interface is fbdev */ | 1639 | /* We don't register a new USB class. Our client interface is fbdev */ |
1623 | 1640 | ||
1641 | /* Workitem keep things fast & simple during USB enumeration */ | ||
1642 | INIT_DELAYED_WORK(&dev->init_framebuffer_work, | ||
1643 | dlfb_init_framebuffer_work); | ||
1644 | schedule_delayed_work(&dev->init_framebuffer_work, 0); | ||
1645 | |||
1646 | return 0; | ||
1647 | |||
1648 | error: | ||
1649 | if (dev) { | ||
1650 | |||
1651 | kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */ | ||
1652 | kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */ | ||
1653 | |||
1654 | /* dev has been deallocated. Do not dereference */ | ||
1655 | } | ||
1656 | |||
1657 | return retval; | ||
1658 | } | ||
1659 | |||
1660 | static void dlfb_init_framebuffer_work(struct work_struct *work) | ||
1661 | { | ||
1662 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
1663 | init_framebuffer_work.work); | ||
1664 | struct fb_info *info; | ||
1665 | int retval; | ||
1666 | int i; | ||
1667 | |||
1624 | /* allocates framebuffer driver structure, not framebuffer memory */ | 1668 | /* allocates framebuffer driver structure, not framebuffer memory */ |
1625 | info = framebuffer_alloc(0, &interface->dev); | 1669 | info = framebuffer_alloc(0, dev->gdev); |
1626 | if (!info) { | 1670 | if (!info) { |
1627 | retval = -ENOMEM; | 1671 | retval = -ENOMEM; |
1628 | pr_err("framebuffer_alloc failed\n"); | 1672 | pr_err("framebuffer_alloc failed\n"); |
@@ -1668,15 +1712,13 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1668 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) { | 1712 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) { |
1669 | retval = device_create_file(info->dev, &fb_device_attrs[i]); | 1713 | retval = device_create_file(info->dev, &fb_device_attrs[i]); |
1670 | if (retval) { | 1714 | if (retval) { |
1671 | pr_err("device_create_file failed %d\n", retval); | 1715 | pr_warn("device_create_file failed %d\n", retval); |
1672 | goto err_del_attrs; | ||
1673 | } | 1716 | } |
1674 | } | 1717 | } |
1675 | 1718 | ||
1676 | retval = device_create_bin_file(info->dev, &edid_attr); | 1719 | retval = device_create_bin_file(info->dev, &edid_attr); |
1677 | if (retval) { | 1720 | if (retval) { |
1678 | pr_err("device_create_bin_file failed %d\n", retval); | 1721 | pr_warn("device_create_bin_file failed %d\n", retval); |
1679 | goto err_del_attrs; | ||
1680 | } | 1722 | } |
1681 | 1723 | ||
1682 | pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." | 1724 | pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." |
@@ -1684,38 +1726,10 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1684 | info->var.xres, info->var.yres, | 1726 | info->var.xres, info->var.yres, |
1685 | ((dev->backing_buffer) ? | 1727 | ((dev->backing_buffer) ? |
1686 | info->fix.smem_len * 2 : info->fix.smem_len) >> 10); | 1728 | info->fix.smem_len * 2 : info->fix.smem_len) >> 10); |
1687 | return 0; | 1729 | return; |
1688 | |||
1689 | err_del_attrs: | ||
1690 | for (i -= 1; i >= 0; i--) | ||
1691 | device_remove_file(info->dev, &fb_device_attrs[i]); | ||
1692 | 1730 | ||
1693 | error: | 1731 | error: |
1694 | if (dev) { | 1732 | dlfb_free_framebuffer(dev); |
1695 | |||
1696 | if (info) { | ||
1697 | if (info->cmap.len != 0) | ||
1698 | fb_dealloc_cmap(&info->cmap); | ||
1699 | if (info->monspecs.modedb) | ||
1700 | fb_destroy_modedb(info->monspecs.modedb); | ||
1701 | if (info->screen_base) | ||
1702 | vfree(info->screen_base); | ||
1703 | |||
1704 | fb_destroy_modelist(&info->modelist); | ||
1705 | |||
1706 | framebuffer_release(info); | ||
1707 | } | ||
1708 | |||
1709 | if (dev->backing_buffer) | ||
1710 | vfree(dev->backing_buffer); | ||
1711 | |||
1712 | kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */ | ||
1713 | kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */ | ||
1714 | |||
1715 | /* dev has been deallocated. Do not dereference */ | ||
1716 | } | ||
1717 | |||
1718 | return retval; | ||
1719 | } | 1733 | } |
1720 | 1734 | ||
1721 | static void dlfb_usb_disconnect(struct usb_interface *interface) | 1735 | static void dlfb_usb_disconnect(struct usb_interface *interface) |
@@ -1735,12 +1749,20 @@ static void dlfb_usb_disconnect(struct usb_interface *interface) | |||
1735 | /* When non-active we'll update virtual framebuffer, but no new urbs */ | 1749 | /* When non-active we'll update virtual framebuffer, but no new urbs */ |
1736 | atomic_set(&dev->usb_active, 0); | 1750 | atomic_set(&dev->usb_active, 0); |
1737 | 1751 | ||
1738 | /* remove udlfb's sysfs interfaces */ | 1752 | /* this function will wait for all in-flight urbs to complete */ |
1739 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) | 1753 | dlfb_free_urb_list(dev); |
1740 | device_remove_file(info->dev, &fb_device_attrs[i]); | 1754 | |
1741 | device_remove_bin_file(info->dev, &edid_attr); | 1755 | if (info) { |
1742 | unlink_framebuffer(info); | 1756 | /* remove udlfb's sysfs interfaces */ |
1757 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) | ||
1758 | device_remove_file(info->dev, &fb_device_attrs[i]); | ||
1759 | device_remove_bin_file(info->dev, &edid_attr); | ||
1760 | unlink_framebuffer(info); | ||
1761 | } | ||
1762 | |||
1743 | usb_set_intfdata(interface, NULL); | 1763 | usb_set_intfdata(interface, NULL); |
1764 | dev->udev = NULL; | ||
1765 | dev->gdev = NULL; | ||
1744 | 1766 | ||
1745 | /* if clients still have us open, will be freed on last close */ | 1767 | /* if clients still have us open, will be freed on last close */ |
1746 | if (dev->fb_count == 0) | 1768 | if (dev->fb_count == 0) |
@@ -1806,12 +1828,12 @@ static void dlfb_free_urb_list(struct dlfb_data *dev) | |||
1806 | int ret; | 1828 | int ret; |
1807 | unsigned long flags; | 1829 | unsigned long flags; |
1808 | 1830 | ||
1809 | pr_notice("Waiting for completes and freeing all render urbs\n"); | 1831 | pr_notice("Freeing all render urbs\n"); |
1810 | 1832 | ||
1811 | /* keep waiting and freeing, until we've got 'em all */ | 1833 | /* keep waiting and freeing, until we've got 'em all */ |
1812 | while (count--) { | 1834 | while (count--) { |
1813 | 1835 | ||
1814 | /* Getting interrupted means a leak, but ok at shutdown*/ | 1836 | /* Getting interrupted means a leak, but ok at disconnect */ |
1815 | ret = down_interruptible(&dev->urbs.limit_sem); | 1837 | ret = down_interruptible(&dev->urbs.limit_sem); |
1816 | if (ret) | 1838 | if (ret) |
1817 | break; | 1839 | break; |
@@ -1833,6 +1855,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev) | |||
1833 | kfree(node); | 1855 | kfree(node); |
1834 | } | 1856 | } |
1835 | 1857 | ||
1858 | dev->urbs.count = 0; | ||
1836 | } | 1859 | } |
1837 | 1860 | ||
1838 | static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) | 1861 | static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) |
@@ -1948,6 +1971,9 @@ MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes"); | |||
1948 | module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); | 1971 | module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); |
1949 | MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf"); | 1972 | MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf"); |
1950 | 1973 | ||
1974 | module_param(pixel_limit, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); | ||
1975 | MODULE_PARM_DESC(pixel_limit, "Force limit on max mode (in x*y pixels)"); | ||
1976 | |||
1951 | MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, " | 1977 | MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, " |
1952 | "Jaya Kumar <jayakumar.lkml@gmail.com>, " | 1978 | "Jaya Kumar <jayakumar.lkml@gmail.com>, " |
1953 | "Bernie Thompson <bernie@plugable.com>"); | 1979 | "Bernie Thompson <bernie@plugable.com>"); |