| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * udlfb.c -- Framebuffer driver for DisplayLink USB controller |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> |
|---|
| 5 | 6 | * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> |
|---|
| 6 | 7 | * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This file is subject to the terms and conditions of the GNU General Public |
|---|
| 9 | | - * License v2. See the file COPYING in the main directory of this archive for |
|---|
| 10 | | - * more details. |
|---|
| 11 | 8 | * |
|---|
| 12 | 9 | * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven, |
|---|
| 13 | 10 | * usb-skeleton by GregKH. |
|---|
| .. | .. |
|---|
| 29 | 26 | #include <asm/unaligned.h> |
|---|
| 30 | 27 | #include <video/udlfb.h> |
|---|
| 31 | 28 | #include "edid.h" |
|---|
| 29 | + |
|---|
| 30 | +#define OUT_EP_NUM 1 /* The endpoint number we will use */ |
|---|
| 32 | 31 | |
|---|
| 33 | 32 | static const struct fb_fix_screeninfo dlfb_fix = { |
|---|
| 34 | 33 | .id = "udlfb", |
|---|
| .. | .. |
|---|
| 67 | 66 | MODULE_DEVICE_TABLE(usb, id_table); |
|---|
| 68 | 67 | |
|---|
| 69 | 68 | /* module options */ |
|---|
| 70 | | -static bool console = 1; /* Allow fbcon to open framebuffer */ |
|---|
| 71 | | -static bool fb_defio = 1; /* Detect mmap writes using page faults */ |
|---|
| 72 | | -static bool shadow = 1; /* Optionally disable shadow framebuffer */ |
|---|
| 69 | +static bool console = true; /* Allow fbcon to open framebuffer */ |
|---|
| 70 | +static bool fb_defio = true; /* Detect mmap writes using page faults */ |
|---|
| 71 | +static bool shadow = true; /* Optionally disable shadow framebuffer */ |
|---|
| 73 | 72 | static int pixel_limit; /* Optionally force a pixel resolution limit */ |
|---|
| 74 | 73 | |
|---|
| 75 | 74 | struct dlfb_deferred_free { |
|---|
| .. | .. |
|---|
| 1041 | 1040 | fb_deferred_io_cleanup(info); |
|---|
| 1042 | 1041 | kfree(info->fbdefio); |
|---|
| 1043 | 1042 | info->fbdefio = NULL; |
|---|
| 1044 | | - info->fbops->fb_mmap = dlfb_ops_mmap; |
|---|
| 1045 | 1043 | } |
|---|
| 1046 | 1044 | |
|---|
| 1047 | 1045 | dev_dbg(info->dev, "release, user=%d count=%d\n", user, dlfb->fb_count); |
|---|
| .. | .. |
|---|
| 1187 | 1185 | return 0; |
|---|
| 1188 | 1186 | } |
|---|
| 1189 | 1187 | |
|---|
| 1190 | | -static struct fb_ops dlfb_ops = { |
|---|
| 1188 | +static const struct fb_ops dlfb_ops = { |
|---|
| 1191 | 1189 | .owner = THIS_MODULE, |
|---|
| 1192 | 1190 | .fb_read = fb_sys_read, |
|---|
| 1193 | 1191 | .fb_write = dlfb_ops_write, |
|---|
| .. | .. |
|---|
| 1430 | 1428 | struct device_attribute *a, char *buf) { |
|---|
| 1431 | 1429 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1432 | 1430 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1433 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 1431 | + return sysfs_emit(buf, "%u\n", |
|---|
| 1434 | 1432 | atomic_read(&dlfb->bytes_rendered)); |
|---|
| 1435 | 1433 | } |
|---|
| 1436 | 1434 | |
|---|
| .. | .. |
|---|
| 1438 | 1436 | struct device_attribute *a, char *buf) { |
|---|
| 1439 | 1437 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1440 | 1438 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1441 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 1439 | + return sysfs_emit(buf, "%u\n", |
|---|
| 1442 | 1440 | atomic_read(&dlfb->bytes_identical)); |
|---|
| 1443 | 1441 | } |
|---|
| 1444 | 1442 | |
|---|
| .. | .. |
|---|
| 1446 | 1444 | struct device_attribute *a, char *buf) { |
|---|
| 1447 | 1445 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1448 | 1446 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1449 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 1447 | + return sysfs_emit(buf, "%u\n", |
|---|
| 1450 | 1448 | atomic_read(&dlfb->bytes_sent)); |
|---|
| 1451 | 1449 | } |
|---|
| 1452 | 1450 | |
|---|
| .. | .. |
|---|
| 1454 | 1452 | struct device_attribute *a, char *buf) { |
|---|
| 1455 | 1453 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1456 | 1454 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1457 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 1455 | + return sysfs_emit(buf, "%u\n", |
|---|
| 1458 | 1456 | atomic_read(&dlfb->cpu_kcycles_used)); |
|---|
| 1459 | 1457 | } |
|---|
| 1460 | 1458 | |
|---|
| .. | .. |
|---|
| 1462 | 1460 | struct file *filp, |
|---|
| 1463 | 1461 | struct kobject *kobj, struct bin_attribute *a, |
|---|
| 1464 | 1462 | char *buf, loff_t off, size_t count) { |
|---|
| 1465 | | - struct device *fbdev = container_of(kobj, struct device, kobj); |
|---|
| 1463 | + struct device *fbdev = kobj_to_dev(kobj); |
|---|
| 1466 | 1464 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1467 | 1465 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1468 | 1466 | |
|---|
| .. | .. |
|---|
| 1484 | 1482 | struct file *filp, |
|---|
| 1485 | 1483 | struct kobject *kobj, struct bin_attribute *a, |
|---|
| 1486 | 1484 | char *src, loff_t src_off, size_t src_size) { |
|---|
| 1487 | | - struct device *fbdev = container_of(kobj, struct device, kobj); |
|---|
| 1485 | + struct device *fbdev = kobj_to_dev(kobj); |
|---|
| 1488 | 1486 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
|---|
| 1489 | 1487 | struct dlfb_data *dlfb = fb_info->par; |
|---|
| 1490 | 1488 | int ret; |
|---|
| .. | .. |
|---|
| 1653 | 1651 | const struct device_attribute *attr; |
|---|
| 1654 | 1652 | struct dlfb_data *dlfb; |
|---|
| 1655 | 1653 | struct fb_info *info; |
|---|
| 1656 | | - int retval = -ENOMEM; |
|---|
| 1654 | + int retval; |
|---|
| 1657 | 1655 | struct usb_device *usbdev = interface_to_usbdev(intf); |
|---|
| 1656 | + static u8 out_ep[] = {OUT_EP_NUM + USB_DIR_OUT, 0}; |
|---|
| 1658 | 1657 | |
|---|
| 1659 | 1658 | /* usb initialization */ |
|---|
| 1660 | 1659 | dlfb = kzalloc(sizeof(*dlfb), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1668 | 1667 | dlfb->udev = usb_get_dev(usbdev); |
|---|
| 1669 | 1668 | usb_set_intfdata(intf, dlfb); |
|---|
| 1670 | 1669 | |
|---|
| 1670 | + if (!usb_check_bulk_endpoints(intf, out_ep)) { |
|---|
| 1671 | + dev_err(&intf->dev, "Invalid DisplayLink device!\n"); |
|---|
| 1672 | + retval = -EINVAL; |
|---|
| 1673 | + goto error; |
|---|
| 1674 | + } |
|---|
| 1675 | + |
|---|
| 1671 | 1676 | dev_dbg(&intf->dev, "console enable=%d\n", console); |
|---|
| 1672 | 1677 | dev_dbg(&intf->dev, "fb_defio enable=%d\n", fb_defio); |
|---|
| 1673 | 1678 | dev_dbg(&intf->dev, "shadow enable=%d\n", shadow); |
|---|
| .. | .. |
|---|
| 1677 | 1682 | if (!dlfb_parse_vendor_descriptor(dlfb, intf)) { |
|---|
| 1678 | 1683 | dev_err(&intf->dev, |
|---|
| 1679 | 1684 | "firmware not recognized, incompatible device?\n"); |
|---|
| 1685 | + retval = -ENODEV; |
|---|
| 1680 | 1686 | goto error; |
|---|
| 1681 | 1687 | } |
|---|
| 1682 | 1688 | |
|---|
| .. | .. |
|---|
| 1691 | 1697 | /* allocates framebuffer driver structure, not framebuffer memory */ |
|---|
| 1692 | 1698 | info = framebuffer_alloc(0, &dlfb->udev->dev); |
|---|
| 1693 | 1699 | if (!info) { |
|---|
| 1694 | | - dev_err(&dlfb->udev->dev, "framebuffer_alloc failed\n"); |
|---|
| 1700 | + retval = -ENOMEM; |
|---|
| 1695 | 1701 | goto error; |
|---|
| 1696 | 1702 | } |
|---|
| 1697 | 1703 | |
|---|
| .. | .. |
|---|
| 1922 | 1928 | } |
|---|
| 1923 | 1929 | |
|---|
| 1924 | 1930 | /* urb->transfer_buffer_length set to actual before submit */ |
|---|
| 1925 | | - usb_fill_bulk_urb(urb, dlfb->udev, usb_sndbulkpipe(dlfb->udev, 1), |
|---|
| 1931 | + usb_fill_bulk_urb(urb, dlfb->udev, |
|---|
| 1932 | + usb_sndbulkpipe(dlfb->udev, OUT_EP_NUM), |
|---|
| 1926 | 1933 | buf, size, dlfb_urb_completion, unode); |
|---|
| 1927 | 1934 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
|---|
| 1928 | 1935 | |
|---|