190e0fd1eSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 290e0fd1eSThomas Zimmermann 390e0fd1eSThomas Zimmermann #include <linux/string.h> 490e0fd1eSThomas Zimmermann 590e0fd1eSThomas Zimmermann #include <drm/drm_drv.h> 690e0fd1eSThomas Zimmermann #include <drm/drm_edid.h> 790e0fd1eSThomas Zimmermann 890e0fd1eSThomas Zimmermann #include "udl_drv.h" 990e0fd1eSThomas Zimmermann #include "udl_edid.h" 1090e0fd1eSThomas Zimmermann 1190e0fd1eSThomas Zimmermann static int udl_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len) 1290e0fd1eSThomas Zimmermann { 1390e0fd1eSThomas Zimmermann struct udl_device *udl = data; 1490e0fd1eSThomas Zimmermann struct drm_device *dev = &udl->drm; 1590e0fd1eSThomas Zimmermann struct usb_device *udev = udl_to_usb_device(udl); 1690e0fd1eSThomas Zimmermann u8 *read_buff; 1790e0fd1eSThomas Zimmermann int idx, ret; 1890e0fd1eSThomas Zimmermann size_t i; 1990e0fd1eSThomas Zimmermann 2090e0fd1eSThomas Zimmermann read_buff = kmalloc(2, GFP_KERNEL); 2190e0fd1eSThomas Zimmermann if (!read_buff) 2290e0fd1eSThomas Zimmermann return -ENOMEM; 2390e0fd1eSThomas Zimmermann 2490e0fd1eSThomas Zimmermann if (!drm_dev_enter(dev, &idx)) { 2590e0fd1eSThomas Zimmermann ret = -ENODEV; 2690e0fd1eSThomas Zimmermann goto err_kfree; 2790e0fd1eSThomas Zimmermann } 2890e0fd1eSThomas Zimmermann 2990e0fd1eSThomas Zimmermann for (i = 0; i < len; i++) { 3090e0fd1eSThomas Zimmermann int bval = (i + block * EDID_LENGTH) << 8; 3190e0fd1eSThomas Zimmermann 3290e0fd1eSThomas Zimmermann ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 3390e0fd1eSThomas Zimmermann 0x02, (0x80 | (0x02 << 5)), bval, 3490e0fd1eSThomas Zimmermann 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); 3590e0fd1eSThomas Zimmermann if (ret < 0) { 3690e0fd1eSThomas Zimmermann drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); 3790e0fd1eSThomas Zimmermann goto err_drm_dev_exit; 3890e0fd1eSThomas Zimmermann } else if (ret < 1) { 3990e0fd1eSThomas Zimmermann ret = -EIO; 4090e0fd1eSThomas Zimmermann drm_err(dev, "Read EDID byte %zu failed\n", i); 4190e0fd1eSThomas Zimmermann goto err_drm_dev_exit; 4290e0fd1eSThomas Zimmermann } 4390e0fd1eSThomas Zimmermann 4490e0fd1eSThomas Zimmermann buf[i] = read_buff[1]; 4590e0fd1eSThomas Zimmermann } 4690e0fd1eSThomas Zimmermann 4790e0fd1eSThomas Zimmermann drm_dev_exit(idx); 4890e0fd1eSThomas Zimmermann kfree(read_buff); 4990e0fd1eSThomas Zimmermann 5090e0fd1eSThomas Zimmermann return 0; 5190e0fd1eSThomas Zimmermann 5290e0fd1eSThomas Zimmermann err_drm_dev_exit: 5390e0fd1eSThomas Zimmermann drm_dev_exit(idx); 5490e0fd1eSThomas Zimmermann err_kfree: 5590e0fd1eSThomas Zimmermann kfree(read_buff); 5690e0fd1eSThomas Zimmermann return ret; 5790e0fd1eSThomas Zimmermann } 5890e0fd1eSThomas Zimmermann 5990e0fd1eSThomas Zimmermann bool udl_probe_edid(struct udl_device *udl) 6090e0fd1eSThomas Zimmermann { 6190e0fd1eSThomas Zimmermann u8 hdr[8]; 6290e0fd1eSThomas Zimmermann int ret; 6390e0fd1eSThomas Zimmermann 6490e0fd1eSThomas Zimmermann ret = udl_read_edid_block(udl, hdr, 0, sizeof(hdr)); 6590e0fd1eSThomas Zimmermann if (ret) 6690e0fd1eSThomas Zimmermann return false; 6790e0fd1eSThomas Zimmermann 6890e0fd1eSThomas Zimmermann /* 6990e0fd1eSThomas Zimmermann * The adapter sends all-zeros if no monitor has been 7090e0fd1eSThomas Zimmermann * connected. We consider anything else a connection. 7190e0fd1eSThomas Zimmermann */ 72*f7650635SJani Nikula return !mem_is_zero(hdr, sizeof(hdr)); 7390e0fd1eSThomas Zimmermann } 7490e0fd1eSThomas Zimmermann 7590e0fd1eSThomas Zimmermann const struct drm_edid *udl_edid_read(struct drm_connector *connector) 7690e0fd1eSThomas Zimmermann { 7790e0fd1eSThomas Zimmermann struct udl_device *udl = to_udl(connector->dev); 7890e0fd1eSThomas Zimmermann 7990e0fd1eSThomas Zimmermann return drm_edid_read_custom(connector, udl_read_edid_block, udl); 8090e0fd1eSThomas Zimmermann } 81