diff options
Diffstat (limited to 'drivers/gpu/drm/udl')
-rw-r--r-- | drivers/gpu/drm/udl/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/Makefile | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_drv.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_drv.h | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_edid.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_edid.h | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_main.c | 191 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_modeset.c | 160 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_transfer.c | 8 |
9 files changed, 276 insertions, 252 deletions
diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig index c744175c6992..d7a6abef7d78 100644 --- a/drivers/gpu/drm/udl/Kconfig +++ b/drivers/gpu/drm/udl/Kconfig @@ -5,6 +5,7 @@ config DRM_UDL depends on USB depends on USB_ARCH_HAS_HCD depends on MMU + select DRM_CLIENT_SELECTION select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER help diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile index 3f6db179455d..43d69a16af18 100644 --- a/drivers/gpu/drm/udl/Makefile +++ b/drivers/gpu/drm/udl/Makefile @@ -1,4 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only -udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o + +udl-y := \ + udl_drv.o \ + udl_edid.o \ + udl_main.o \ + udl_modeset.o \ + udl_transfer.o obj-$(CONFIG_DRM_UDL) := udl.o diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 1506094a8009..1922988625eb 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -5,8 +5,9 @@ #include <linux/module.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_drv.h> -#include <drm/drm_fbdev_generic.h> +#include <drm/drm_fbdev_shmem.h> #include <drm/drm_file.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> @@ -21,13 +22,14 @@ static int udl_usb_suspend(struct usb_interface *interface, pm_message_t message) { struct drm_device *dev = usb_get_intfdata(interface); + struct udl_device *udl = to_udl(dev); int ret; ret = drm_mode_config_helper_suspend(dev); if (ret) return ret; - udl_sync_pending_urbs(dev); + udl_sync_pending_urbs(udl); return 0; } @@ -48,22 +50,6 @@ static int udl_usb_reset_resume(struct usb_interface *interface) return drm_mode_config_helper_resume(dev); } -/* - * FIXME: Dma-buf sharing requires DMA support by the importing device. - * This function is a workaround to make USB devices work as well. - * See todo.rst for how to fix the issue in the dma-buf framework. - */ -static struct drm_gem_object *udl_driver_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf) -{ - struct udl_device *udl = to_udl(dev); - - if (!udl->dmadev) - return ERR_PTR(-ENODEV); - - return drm_gem_prime_import_dev(dev, dma_buf, udl->dmadev); -} - DEFINE_DRM_GEM_FOPS(udl_driver_fops); static const struct drm_driver driver = { @@ -72,11 +58,10 @@ static const struct drm_driver driver = { /* GEM hooks */ .fops = &udl_driver_fops, DRM_GEM_SHMEM_DRIVER_OPS, - .gem_prime_import = udl_driver_gem_prime_import, + DRM_FBDEV_SHMEM_DRIVER_OPS, .name = DRIVER_NAME, .desc = DRIVER_DESC, - .date = DRIVER_DATE, .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, @@ -117,7 +102,7 @@ static int udl_usb_probe(struct usb_interface *interface, DRM_INFO("Initialized udl on minor %d\n", udl->drm.primary->index); - drm_fbdev_generic_setup(&udl->drm, 0); + drm_client_setup(&udl->drm, NULL); return 0; } @@ -125,10 +110,10 @@ static int udl_usb_probe(struct usb_interface *interface, static void udl_usb_disconnect(struct usb_interface *interface) { struct drm_device *dev = usb_get_intfdata(interface); + struct udl_device *udl = to_udl(dev); - drm_kms_helper_poll_fini(dev); - udl_drop_usb(dev); drm_dev_unplug(dev); + udl_drop_usb(udl); } /* @@ -160,4 +145,5 @@ static struct usb_driver udl_driver = { .id_table = id_table, }; module_usb_driver(udl_driver); +MODULE_DESCRIPTION("KMS driver for the USB displaylink video adapters"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 282ebd6c02fd..145bb95ccc48 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -26,7 +26,6 @@ struct drm_mode_create_dumb; #define DRIVER_NAME "udl" #define DRIVER_DESC "DisplayLink" -#define DRIVER_DATE "20120220" #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 @@ -49,29 +48,15 @@ struct urb_list { size_t size; }; -struct udl_connector { - struct drm_connector connector; - /* last udl_detect edid */ - struct edid *edid; -}; - -static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) -{ - return container_of(connector, struct udl_connector, connector); -} - struct udl_device { struct drm_device drm; - struct device *dev; - struct device *dmadev; + + unsigned long sku_pixel_limit; struct drm_plane primary_plane; struct drm_crtc crtc; struct drm_encoder encoder; - - struct mutex gem_lock; - - int sku_pixel_limit; + struct drm_connector connector; struct urb_list urbs; }; @@ -84,22 +69,22 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl) } /* modeset */ -int udl_modeset_init(struct drm_device *dev); +int udl_modeset_init(struct udl_device *udl); struct drm_connector *udl_connector_init(struct drm_device *dev); -struct urb *udl_get_urb(struct drm_device *dev); +struct urb *udl_get_urb(struct udl_device *udl); -int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len); -void udl_sync_pending_urbs(struct drm_device *dev); +int udl_submit_urb(struct udl_device *udl, struct urb *urb, size_t len); +void udl_sync_pending_urbs(struct udl_device *udl); void udl_urb_completion(struct urb *urb); int udl_init(struct udl_device *udl); -int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, +int udl_render_hline(struct udl_device *udl, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width); -int udl_drop_usb(struct drm_device *dev); +int udl_drop_usb(struct udl_device *udl); int udl_select_std_channel(struct udl_device *udl); #endif diff --git a/drivers/gpu/drm/udl/udl_edid.c b/drivers/gpu/drm/udl/udl_edid.c new file mode 100644 index 000000000000..12f48ae17073 --- /dev/null +++ b/drivers/gpu/drm/udl/udl_edid.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/string.h> + +#include <drm/drm_drv.h> +#include <drm/drm_edid.h> + +#include "udl_drv.h" +#include "udl_edid.h" + +static int udl_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct udl_device *udl = data; + struct drm_device *dev = &udl->drm; + struct usb_device *udev = udl_to_usb_device(udl); + u8 *read_buff; + int idx, ret; + size_t i; + + read_buff = kmalloc(2, GFP_KERNEL); + if (!read_buff) + return -ENOMEM; + + if (!drm_dev_enter(dev, &idx)) { + ret = -ENODEV; + goto err_kfree; + } + + for (i = 0; i < len; i++) { + int bval = (i + block * EDID_LENGTH) << 8; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x02, (0x80 | (0x02 << 5)), bval, + 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); + goto err_drm_dev_exit; + } else if (ret < 1) { + ret = -EIO; + drm_err(dev, "Read EDID byte %zu failed\n", i); + goto err_drm_dev_exit; + } + + buf[i] = read_buff[1]; + } + + drm_dev_exit(idx); + kfree(read_buff); + + return 0; + +err_drm_dev_exit: + drm_dev_exit(idx); +err_kfree: + kfree(read_buff); + return ret; +} + +bool udl_probe_edid(struct udl_device *udl) +{ + u8 hdr[8]; + int ret; + + ret = udl_read_edid_block(udl, hdr, 0, sizeof(hdr)); + if (ret) + return false; + + /* + * The adapter sends all-zeros if no monitor has been + * connected. We consider anything else a connection. + */ + return !mem_is_zero(hdr, sizeof(hdr)); +} + +const struct drm_edid *udl_edid_read(struct drm_connector *connector) +{ + struct udl_device *udl = to_udl(connector->dev); + + return drm_edid_read_custom(connector, udl_read_edid_block, udl); +} diff --git a/drivers/gpu/drm/udl/udl_edid.h b/drivers/gpu/drm/udl/udl_edid.h new file mode 100644 index 000000000000..fe15ff3752b7 --- /dev/null +++ b/drivers/gpu/drm/udl/udl_edid.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef UDL_EDID_H +#define UDL_EDID_H + +#include <linux/types.h> + +struct drm_connector; +struct drm_edid; +struct udl_device; + +bool udl_probe_edid(struct udl_device *udl); +const struct drm_edid *udl_edid_read(struct drm_connector *connector); + +#endif diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 3ebe2ce55dfd..bc58991a6f14 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -8,6 +8,8 @@ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> */ +#include <linux/unaligned.h> + #include <drm/drm.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -23,72 +25,99 @@ #define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 +#define UDL_SKU_PIXEL_LIMIT_DEFAULT 2080000 + static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout); +/* + * Try to make sense of whatever we parse. Therefore return @end on + * errors, but don't fail hard. + */ +static const u8 *udl_parse_key_value_pair(struct udl_device *udl, const u8 *pos, const u8 *end) +{ + u16 key; + u8 len; + + /* read key */ + if (pos >= end - 2) + return end; + key = get_unaligned_le16(pos); + pos += 2; + + /* read value length */ + if (pos >= end - 1) + return end; + len = *pos++; + + /* read value */ + if (pos >= end - len) + return end; + switch (key) { + case 0x0200: { /* maximum number of pixels */ + unsigned int sku_pixel_limit; + + if (len < sizeof(__le32)) + break; + sku_pixel_limit = get_unaligned_le32(pos); + if (sku_pixel_limit >= 16 * UDL_SKU_PIXEL_LIMIT_DEFAULT) + break; /* almost 100 MiB, so probably bogus */ + udl->sku_pixel_limit = sku_pixel_limit; + break; + } + default: + break; + } + pos += len; + + return pos; +} + static int udl_parse_vendor_descriptor(struct udl_device *udl) { + struct drm_device *dev = &udl->drm; struct usb_device *udev = udl_to_usb_device(udl); - char *desc; - char *buf; - char *desc_end; - - u8 total_len = 0; + bool detected = false; + void *buf; + int ret; + unsigned int len; + const u8 *desc; + const u8 *desc_end; buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL); if (!buf) - return false; + return -ENOMEM; + + ret = usb_get_descriptor(udev, 0x5f, /* vendor specific */ + 0, buf, MAX_VENDOR_DESCRIPTOR_SIZE); + if (ret < 0) + goto out; + len = ret; + + if (len < 5) + goto out; + desc = buf; + desc_end = desc + len; - total_len = usb_get_descriptor(udev, 0x5f, /* vendor specific */ - 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE); - if (total_len > 5) { - DRM_INFO("vendor descriptor length:%x data:%11ph\n", - total_len, desc); - - if ((desc[0] != total_len) || /* descriptor length */ - (desc[1] != 0x5f) || /* vendor descriptor type */ - (desc[2] != 0x01) || /* version (2 bytes) */ - (desc[3] != 0x00) || - (desc[4] != total_len - 2)) /* length after type */ - goto unrecognized; - - desc_end = desc + total_len; - desc += 5; /* the fixed header we've already parsed */ - - while (desc < desc_end) { - u8 length; - u16 key; - - key = le16_to_cpu(*((u16 *) desc)); - desc += sizeof(u16); - length = *desc; - desc++; - - switch (key) { - case 0x0200: { /* max_area */ - u32 max_area; - max_area = le32_to_cpu(*((u32 *)desc)); - DRM_DEBUG("DL chip limited to %d pixel modes\n", - max_area); - udl->sku_pixel_limit = max_area; - break; - } - default: - break; - } - desc += length; - } - } + if ((desc[0] != len) || /* descriptor length */ + (desc[1] != 0x5f) || /* vendor descriptor type */ + (desc[2] != 0x01) || /* version (2 bytes) */ + (desc[3] != 0x00) || + (desc[4] != len - 2)) /* length after type */ + goto out; + desc += 5; - goto success; + detected = true; -unrecognized: - /* allow udlfb to load for now even if firmware unrecognized */ - DRM_ERROR("Unrecognized vendor firmware descriptor\n"); + while (desc < desc_end) + desc = udl_parse_key_value_pair(udl, desc, desc_end); -success: +out: + if (!detected) + drm_warn(dev, "Unrecognized vendor firmware descriptor\n"); kfree(buf); - return true; + + return 0; } /* @@ -145,9 +174,8 @@ void udl_urb_completion(struct urb *urb) wake_up(&udl->urbs.sleep); } -static void udl_free_urb_list(struct drm_device *dev) +static void udl_free_urb_list(struct udl_device *udl) { - struct udl_device *udl = to_udl(dev); struct urb_node *unode; struct urb *urb; @@ -172,9 +200,8 @@ static void udl_free_urb_list(struct drm_device *dev) wake_up_all(&udl->urbs.sleep); } -static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) +static int udl_alloc_urb_list(struct udl_device *udl, int count, size_t size) { - struct udl_device *udl = to_udl(dev); struct urb *urb; struct urb_node *unode; char *buf; @@ -210,7 +237,7 @@ retry: usb_free_urb(urb); if (size > PAGE_SIZE) { size /= 2; - udl_free_urb_list(dev); + udl_free_urb_list(udl); goto retry; } break; @@ -259,9 +286,8 @@ static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout) } #define GET_URB_TIMEOUT HZ -struct urb *udl_get_urb(struct drm_device *dev) +struct urb *udl_get_urb(struct udl_device *udl) { - struct udl_device *udl = to_udl(dev); struct urb *urb; spin_lock_irq(&udl->urbs.lock); @@ -270,9 +296,8 @@ struct urb *udl_get_urb(struct drm_device *dev) return urb; } -int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) +int udl_submit_urb(struct udl_device *udl, struct urb *urb, size_t len) { - struct udl_device *udl = to_udl(dev); int ret; if (WARN_ON(len > udl->urbs.size)) { @@ -290,9 +315,9 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) } /* wait until all pending URBs have been processed */ -void udl_sync_pending_urbs(struct drm_device *dev) +void udl_sync_pending_urbs(struct udl_device *udl) { - struct udl_device *udl = to_udl(dev); + struct drm_device *dev = &udl->drm; spin_lock_irq(&udl->urbs.lock); /* 2 seconds as a sane timeout */ @@ -308,53 +333,55 @@ int udl_init(struct udl_device *udl) { struct drm_device *dev = &udl->drm; int ret = -ENOMEM; + struct device *dma_dev; DRM_DEBUG("\n"); - udl->dmadev = usb_intf_get_dma_device(to_usb_interface(dev->dev)); - if (!udl->dmadev) + dma_dev = usb_intf_get_dma_device(to_usb_interface(dev->dev)); + if (dma_dev) { + drm_dev_set_dma_dev(dev, dma_dev); + put_device(dma_dev); + } else { drm_warn(dev, "buffer sharing not supported"); /* not an error */ + } - mutex_init(&udl->gem_lock); + /* + * Not all devices provide vendor descriptors with device + * information. Initialize to default values of real-world + * devices. It is just enough memory for FullHD. + */ + udl->sku_pixel_limit = UDL_SKU_PIXEL_LIMIT_DEFAULT; - if (!udl_parse_vendor_descriptor(udl)) { - ret = -ENODEV; - DRM_ERROR("firmware not recognized. Assume incompatible device\n"); + ret = udl_parse_vendor_descriptor(udl); + if (ret) goto err; - } if (udl_select_std_channel(udl)) DRM_ERROR("Selecting channel failed\n"); - if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { + if (!udl_alloc_urb_list(udl, WRITES_IN_FLIGHT, MAX_TRANSFER)) { DRM_ERROR("udl_alloc_urb_list failed\n"); + ret = -ENOMEM; goto err; } DRM_DEBUG("\n"); - ret = udl_modeset_init(dev); + ret = udl_modeset_init(udl); if (ret) goto err; - drm_kms_helper_poll_init(dev); - return 0; err: if (udl->urbs.count) - udl_free_urb_list(dev); - put_device(udl->dmadev); + udl_free_urb_list(udl); DRM_ERROR("%d\n", ret); return ret; } -int udl_drop_usb(struct drm_device *dev) +int udl_drop_usb(struct udl_device *udl) { - struct udl_device *udl = to_udl(dev); - - udl_free_urb_list(dev); - put_device(udl->dmadev); - udl->dmadev = NULL; + udl_free_urb_list(udl); return 0; } diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 7702359c90c2..231e829bd709 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -25,6 +25,7 @@ #include <drm/drm_vblank.h> #include "udl_drv.h" +#include "udl_edid.h" #include "udl_proto.h" /* @@ -204,6 +205,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const struct drm_rect *clip) { struct drm_device *dev = fb->dev; + struct udl_device *udl = to_udl(dev); void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */ int i, ret; char *cmd; @@ -215,7 +217,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, return ret; log_bpp = ret; - urb = udl_get_urb(dev); + urb = udl_get_urb(udl); if (!urb) return -ENOMEM; cmd = urb->transfer_buffer; @@ -225,7 +227,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const int byte_offset = line_offset + (clip->x1 << log_bpp); const int dev_byte_offset = (fb->width * i + clip->x1) << log_bpp; const int byte_width = drm_rect_width(clip) << log_bpp; - ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr, + ret = udl_render_hline(udl, log_bpp, &urb, (char *)vaddr, &cmd, byte_offset, dev_byte_offset, byte_width); if (ret) @@ -238,7 +240,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length) *cmd++ = UDL_MSG_BULK; len = cmd - (char *)urb->transfer_buffer; - ret = udl_submit_urb(dev, urb, len); + ret = udl_submit_urb(udl, urb, len); } else { udl_urb_completion(urb); } @@ -329,6 +331,7 @@ static const struct drm_plane_funcs udl_primary_plane_funcs = { static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; + struct udl_device *udl = to_udl(dev); struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct drm_display_mode *mode = &crtc_state->mode; struct urb *urb; @@ -338,7 +341,7 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom if (!drm_dev_enter(dev, &idx)) return; - urb = udl_get_urb(dev); + urb = udl_get_urb(udl); if (!urb) goto out; @@ -354,7 +357,7 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom buf = udl_vidreg_unlock(buf); buf = udl_dummy_render(buf); - udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); + udl_submit_urb(udl, urb, buf - (char *)urb->transfer_buffer); out: drm_dev_exit(idx); @@ -363,6 +366,7 @@ out: static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; + struct udl_device *udl = to_udl(dev); struct urb *urb; char *buf; int idx; @@ -370,7 +374,7 @@ static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato if (!drm_dev_enter(dev, &idx)) return; - urb = udl_get_urb(dev); + urb = udl_get_urb(udl); if (!urb) goto out; @@ -380,7 +384,7 @@ static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato buf = udl_vidreg_unlock(buf); buf = udl_dummy_render(buf); - udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); + udl_submit_urb(udl, urb, buf - (char *)urb->transfer_buffer); out: drm_dev_exit(idx); @@ -415,129 +419,42 @@ static const struct drm_encoder_funcs udl_encoder_funcs = { static int udl_connector_helper_get_modes(struct drm_connector *connector) { - struct udl_connector *udl_connector = to_udl_connector(connector); + const struct drm_edid *drm_edid; + int count; - drm_connector_update_edid_property(connector, udl_connector->edid); - if (udl_connector->edid) - return drm_add_edid_modes(connector, udl_connector->edid); + drm_edid = udl_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); - return 0; + return count; } -static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { - .get_modes = udl_connector_helper_get_modes, -}; - -static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +static int udl_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { - struct udl_device *udl = data; - struct drm_device *dev = &udl->drm; - struct usb_device *udev = udl_to_usb_device(udl); - u8 *read_buff; - int ret; - size_t i; + struct udl_device *udl = to_udl(connector->dev); - read_buff = kmalloc(2, GFP_KERNEL); - if (!read_buff) - return -ENOMEM; + if (udl_probe_edid(udl)) + return connector_status_connected; - for (i = 0; i < len; i++) { - int bval = (i + block * EDID_LENGTH) << 8; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x02, (0x80 | (0x02 << 5)), bval, - 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); - if (ret < 0) { - drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); - goto err_kfree; - } else if (ret < 1) { - ret = -EIO; - drm_err(dev, "Read EDID byte %zu failed\n", i); - goto err_kfree; - } - - buf[i] = read_buff[1]; - } - - kfree(read_buff); - - return 0; - -err_kfree: - kfree(read_buff); - return ret; -} - -static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) -{ - struct drm_device *dev = connector->dev; - struct udl_device *udl = to_udl(dev); - struct udl_connector *udl_connector = to_udl_connector(connector); - enum drm_connector_status status = connector_status_disconnected; - int idx; - - /* cleanup previous EDID */ - kfree(udl_connector->edid); - udl_connector->edid = NULL; - - if (!drm_dev_enter(dev, &idx)) - return connector_status_disconnected; - - udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); - if (udl_connector->edid) - status = connector_status_connected; - - drm_dev_exit(idx); - - return status; + return connector_status_disconnected; } -static void udl_connector_destroy(struct drm_connector *connector) -{ - struct udl_connector *udl_connector = to_udl_connector(connector); - - drm_connector_cleanup(connector); - kfree(udl_connector->edid); - kfree(udl_connector); -} +static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { + .get_modes = udl_connector_helper_get_modes, + .detect_ctx = udl_connector_helper_detect_ctx, +}; static const struct drm_connector_funcs udl_connector_funcs = { .reset = drm_atomic_helper_connector_reset, - .detect = udl_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = udl_connector_destroy, + .destroy = drm_connector_cleanup, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -struct drm_connector *udl_connector_init(struct drm_device *dev) -{ - struct udl_connector *udl_connector; - struct drm_connector *connector; - int ret; - - udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); - if (!udl_connector) - return ERR_PTR(-ENOMEM); - - connector = &udl_connector->connector; - ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); - if (ret) - goto err_kfree; - - drm_connector_helper_add(connector, &udl_connector_helper_funcs); - - connector->polled = DRM_CONNECTOR_POLL_HPD | - DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; - - return connector; - -err_kfree: - kfree(udl_connector); - return ERR_PTR(ret); -} - /* * Modesetting */ @@ -562,9 +479,9 @@ static const struct drm_mode_config_funcs udl_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -int udl_modeset_init(struct drm_device *dev) +int udl_modeset_init(struct udl_device *udl) { - struct udl_device *udl = to_udl(dev); + struct drm_device *dev = &udl->drm; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -607,14 +524,21 @@ int udl_modeset_init(struct drm_device *dev) return ret; encoder->possible_crtcs = drm_crtc_mask(crtc); - connector = udl_connector_init(dev); - if (IS_ERR(connector)) - return PTR_ERR(connector); + connector = &udl->connector; + ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); + if (ret) + return ret; + drm_connector_helper_add(connector, &udl_connector_helper_funcs); + + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; drm_mode_config_reset(dev); + drmm_kms_helper_poll_init(dev); return 0; } diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 5ff1037a3453..7d670b3a5293 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -7,7 +7,7 @@ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "udl_drv.h" #include "udl_proto.h" @@ -170,7 +170,7 @@ static void udl_compress_hline16( * (that we can only write to, slowly, and can never read), and (optionally) * our shadow copy that tracks what's been sent to that hardware buffer. */ -int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, +int udl_render_hline(struct udl_device *udl, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width) @@ -199,10 +199,10 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, if (cmd >= cmd_end) { int len = cmd - (u8 *) urb->transfer_buffer; - int ret = udl_submit_urb(dev, urb, len); + int ret = udl_submit_urb(udl, urb, len); if (ret) return ret; - urb = udl_get_urb(dev); + urb = udl_get_urb(udl); if (!urb) return -EAGAIN; *urb_ptr = urb; |