udl_edid.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/string.h>
  3. #include <drm/drm_drv.h>
  4. #include <drm/drm_edid.h>
  5. #include <drm/drm_print.h>
  6. #include "udl_drv.h"
  7. #include "udl_edid.h"
  8. static int udl_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
  9. {
  10. struct udl_device *udl = data;
  11. struct drm_device *dev = &udl->drm;
  12. struct usb_device *udev = udl_to_usb_device(udl);
  13. u8 *read_buff;
  14. int idx, ret;
  15. size_t i;
  16. read_buff = kmalloc(2, GFP_KERNEL);
  17. if (!read_buff)
  18. return -ENOMEM;
  19. if (!drm_dev_enter(dev, &idx)) {
  20. ret = -ENODEV;
  21. goto err_kfree;
  22. }
  23. for (i = 0; i < len; i++) {
  24. int bval = (i + block * EDID_LENGTH) << 8;
  25. ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  26. 0x02, (0x80 | (0x02 << 5)), bval,
  27. 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT);
  28. if (ret < 0) {
  29. drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret);
  30. goto err_drm_dev_exit;
  31. } else if (ret < 1) {
  32. ret = -EIO;
  33. drm_err(dev, "Read EDID byte %zu failed\n", i);
  34. goto err_drm_dev_exit;
  35. }
  36. buf[i] = read_buff[1];
  37. }
  38. drm_dev_exit(idx);
  39. kfree(read_buff);
  40. return 0;
  41. err_drm_dev_exit:
  42. drm_dev_exit(idx);
  43. err_kfree:
  44. kfree(read_buff);
  45. return ret;
  46. }
  47. bool udl_probe_edid(struct udl_device *udl)
  48. {
  49. u8 hdr[8];
  50. int ret;
  51. ret = udl_read_edid_block(udl, hdr, 0, sizeof(hdr));
  52. if (ret)
  53. return false;
  54. /*
  55. * The adapter sends all-zeros if no monitor has been
  56. * connected. We consider anything else a connection.
  57. */
  58. return !mem_is_zero(hdr, sizeof(hdr));
  59. }
  60. const struct drm_edid *udl_edid_read(struct drm_connector *connector)
  61. {
  62. struct udl_device *udl = to_udl(connector->dev);
  63. return drm_edid_read_custom(connector, udl_read_edid_block, udl);
  64. }