[PATCH] drm/udl: Refactor edid retreiving in UDL driver (v2)

2019-03-15 Thread Robert Tarasov
Now drm/udl driver uses drm_do_get_edid() function to retreive and
validate all blocks of EDID data. Old approach had insufficient
validation routine and had problems with retreiving of extra blocks

Signed-off-by: Robert Tarasov 
---
 drivers/gpu/drm/udl/udl_connector.c | 72 +
 1 file changed, 11 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index c3dc1fd20cb4..c7f8ac2cdbe5 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -17,18 +17,19 @@
 #include "udl_connector.h"
 #include "udl_drv.h"
 
-static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
-  u8 *buff)
+static int udl_get_edid_block(void *data, u8 *buf, unsigned int block,
+   size_t len)
 {
int ret, i;
u8 *read_buff;
+   struct udl_device *udl = data;
 
read_buff = kmalloc(2, GFP_KERNEL);
if (!read_buff)
-   return false;
+   return -1;
 
-   for (i = 0; i < EDID_LENGTH; i++) {
-   int bval = (i + block_idx * EDID_LENGTH) << 8;
+   for (i = 0; i < len; i++) {
+   int bval = (i + block * EDID_LENGTH) << 8;
ret = usb_control_msg(udl->udev,
  usb_rcvctrlpipe(udl->udev, 0),
  (0x02), (0x80 | (0x02 << 5)), bval,
@@ -36,60 +37,13 @@ static bool udl_get_edid_block(struct udl_device *udl, int 
block_idx,
if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
kfree(read_buff);
-   return false;
+   return -1;
}
-   buff[i] = read_buff[1];
+   buf[i] = read_buff[1];
}
 
kfree(read_buff);
-   return true;
-}
-
-static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
-int *result_buff_size)
-{
-   int i, extensions;
-   u8 *block_buff = NULL, *buff_ptr;
-
-   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
-   if (block_buff == NULL)
-   return false;
-
-   if (udl_get_edid_block(udl, 0, block_buff) &&
-   memchr_inv(block_buff, 0, EDID_LENGTH)) {
-   extensions = ((struct edid *)block_buff)->extensions;
-   if (extensions > 0) {
-   /* we have to read all extensions one by one */
-   *result_buff_size = EDID_LENGTH * (extensions + 1);
-   *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
-   buff_ptr = *result_buff;
-   if (buff_ptr == NULL) {
-   kfree(block_buff);
-   return false;
-   }
-   memcpy(buff_ptr, block_buff, EDID_LENGTH);
-   kfree(block_buff);
-   buff_ptr += EDID_LENGTH;
-   for (i = 1; i < extensions; ++i) {
-   if (udl_get_edid_block(udl, i, buff_ptr)) {
-   buff_ptr += EDID_LENGTH;
-   } else {
-   kfree(*result_buff);
-   *result_buff = NULL;
-   return false;
-   }
-   }
-   return true;
-   }
-   /* we have only base edid block */
-   *result_buff = block_buff;
-   *result_buff_size = EDID_LENGTH;
-   return true;
-   }
-
-   kfree(block_buff);
-
-   return false;
+   return 0;
 }
 
 static int udl_get_modes(struct drm_connector *connector)
@@ -121,8 +75,6 @@ static int udl_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 udl_detect(struct drm_connector *connector, bool force)
 {
-   u8 *edid_buff = NULL;
-   int edid_buff_size = 0;
struct udl_device *udl = connector->dev->dev_private;
struct udl_drm_connector *udl_connector =
container_of(connector,
@@ -135,12 +87,10 @@ udl_detect(struct drm_connector *connector, bool force)
udl_connector->edid = NULL;
}
 
-
-   if (!udl_get_edid(udl, _buff, _buff_size))
+   udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, 
udl);
+   if (!udl_connector->edid)
return connector_status_disconnected;
 
-   udl_connector->edid = (struct edid *)edid_buff;
-   
return connector_status_connected;
 }
 
-- 
2.21.0.360.g471c308f928-goog

__

[PATCH] drm/udl: Refactor edid retreiving in UDL driver

2019-03-14 Thread Robert Tarasov
Now drm/udl driver uses drm_do_get_edid() function to retreive and
validate all blocks of EDID data. Old approach had insufficient
validation routine and had problems with retreiving of extra blocks

Signed-off-by: Robert Tarasov 
---
 drivers/gpu/drm/udl/udl_connector.c | 72 +
 1 file changed, 11 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index c3dc1fd20cb4..c7f8ac2cdbe5 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -17,18 +17,19 @@
 #include "udl_connector.h"
 #include "udl_drv.h"
 
-static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
-  u8 *buff)
+static int udl_get_edid_block(void *data, u8 *buf, unsigned int block,
+   size_t len)
 {
int ret, i;
u8 *read_buff;
+   struct udl_device *udl = data;
 
read_buff = kmalloc(2, GFP_KERNEL);
if (!read_buff)
-   return false;
+   return -1;
 
-   for (i = 0; i < EDID_LENGTH; i++) {
-   int bval = (i + block_idx * EDID_LENGTH) << 8;
+   for (i = 0; i < len; i++) {
+   int bval = (i + block * EDID_LENGTH) << 8;
ret = usb_control_msg(udl->udev,
  usb_rcvctrlpipe(udl->udev, 0),
  (0x02), (0x80 | (0x02 << 5)), bval,
@@ -36,60 +37,13 @@ static bool udl_get_edid_block(struct udl_device *udl, int 
block_idx,
if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
kfree(read_buff);
-   return false;
+   return -1;
}
-   buff[i] = read_buff[1];
+   buf[i] = read_buff[1];
}
 
kfree(read_buff);
-   return true;
-}
-
-static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
-int *result_buff_size)
-{
-   int i, extensions;
-   u8 *block_buff = NULL, *buff_ptr;
-
-   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
-   if (block_buff == NULL)
-   return false;
-
-   if (udl_get_edid_block(udl, 0, block_buff) &&
-   memchr_inv(block_buff, 0, EDID_LENGTH)) {
-   extensions = ((struct edid *)block_buff)->extensions;
-   if (extensions > 0) {
-   /* we have to read all extensions one by one */
-   *result_buff_size = EDID_LENGTH * (extensions + 1);
-   *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
-   buff_ptr = *result_buff;
-   if (buff_ptr == NULL) {
-   kfree(block_buff);
-   return false;
-   }
-   memcpy(buff_ptr, block_buff, EDID_LENGTH);
-   kfree(block_buff);
-   buff_ptr += EDID_LENGTH;
-   for (i = 1; i < extensions; ++i) {
-   if (udl_get_edid_block(udl, i, buff_ptr)) {
-   buff_ptr += EDID_LENGTH;
-   } else {
-   kfree(*result_buff);
-   *result_buff = NULL;
-   return false;
-   }
-   }
-   return true;
-   }
-   /* we have only base edid block */
-   *result_buff = block_buff;
-   *result_buff_size = EDID_LENGTH;
-   return true;
-   }
-
-   kfree(block_buff);
-
-   return false;
+   return 0;
 }
 
 static int udl_get_modes(struct drm_connector *connector)
@@ -121,8 +75,6 @@ static int udl_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 udl_detect(struct drm_connector *connector, bool force)
 {
-   u8 *edid_buff = NULL;
-   int edid_buff_size = 0;
struct udl_device *udl = connector->dev->dev_private;
struct udl_drm_connector *udl_connector =
container_of(connector,
@@ -135,12 +87,10 @@ udl_detect(struct drm_connector *connector, bool force)
udl_connector->edid = NULL;
}
 
-
-   if (!udl_get_edid(udl, _buff, _buff_size))
+   udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, 
udl);
+   if (!udl_connector->edid)
return connector_status_disconnected;
 
-   udl_connector->edid = (struct edid *)edid_buff;
-   
return connector_status_connected;
 }
 
-- 
2.21.0.360.g471c308f928-goog

__

Re: [PATCH] drm/udl: Refactor edid retreiving in UDL driver

2019-03-14 Thread Robert Tarasov
On Wed, Mar 13, 2019 at 2:26 AM Jani Nikula 
wrote:

> You'll also get support for debugfs and firmware loader EDID override
> mechanisms for free.
>

Yep :)


> Signed-off-by missing!
>

Fixed.

 read_buff = kmalloc(2, GFP_KERNEL);
>
> A follow-up cleanup might be to switch to using "u8 read_buff[2];"
> instead of kmallocing it.
>
> I don't claim to understand how the usb stuff works, but otherwise the
> patch looks good to me. Nice refactoring!
>
>
"The buffer passed to usb_control_msg may end up in scatter-gather list,
and may thus not be on the stack. Having it on the stack usually works on
x86,   but not on other archs. "
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH] drm/udl: Bugfix in EDID reading routine

2019-03-13 Thread Robert Tarasov
I've already submitted the new one.

On Tue, Mar 12, 2019 at 1:02 AM Jani Nikula 
wrote:

> On Mon, 11 Mar 2019, Robert Tarasov  wrote:
> > Yes, you're right. Will prepare another patch which will use
> > drm_do_get_edid()
>
> Oh, you might want to have this patch first with cc: stable and all
> that, and do the cleanup afterwards.
>
> BR,
> Jani.
>
>
> >
> > On Mon, Mar 11, 2019 at 4:33 AM Jani Nikula  >
> > wrote:
> >
> >> On Fri, 08 Mar 2019, Robert Tarasov  wrote:
> >> > Fixed bug with reading of last EDID extra block in drm/udl driver.
> >> > Previouse approach read all the blocks except the last one.
> >> >
> >> > Signed-off-by: Robert Tarasov 
> >> > ---
> >> >  drivers/gpu/drm/udl/udl_connector.c | 2 +-
> >> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >> >
> >> > diff --git a/drivers/gpu/drm/udl/udl_connector.c
> >> b/drivers/gpu/drm/udl/udl_connector.c
> >> > index c3dc1fd20cb4..68b221b9a01f 100644
> >> > --- a/drivers/gpu/drm/udl/udl_connector.c
> >> > +++ b/drivers/gpu/drm/udl/udl_connector.c
> >> > @@ -70,7 +70,7 @@ static bool udl_get_edid(struct udl_device *udl, u8
> >> **result_buff,
> >> >   memcpy(buff_ptr, block_buff, EDID_LENGTH);
> >> >   kfree(block_buff);
> >> >   buff_ptr += EDID_LENGTH;
> >> > - for (i = 1; i < extensions; ++i) {
> >> > + for (i = 1; i <= extensions; ++i) {
> >> >   if (udl_get_edid_block(udl, i,
> buff_ptr)) {
> >> >   buff_ptr += EDID_LENGTH;
> >> >   } else {
> >>
> >> Ugh. Why doesn't udl use drm_do_get_edid()?
> >>
> >> BR,
> >> Jani.
> >>
> >>
> >> --
> >> Jani Nikula, Intel Open Source Graphics Center
> >>
>
> --
> Jani Nikula, Intel Open Source Graphics Center
>
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH] drm/udl: Refactor edid retreiving in UDL driver

2019-03-13 Thread Robert Tarasov
Now drm/udl driver uses drm_do_get_edid() function to retreive and
validate all blocks of EDID data. Old approach had insufficient
validation routine and had problems with retreiving of extra blocks
---
 drivers/gpu/drm/udl/udl_connector.c | 72 +
 1 file changed, 11 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index c3dc1fd20cb4..c7f8ac2cdbe5 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -17,18 +17,19 @@
 #include "udl_connector.h"
 #include "udl_drv.h"
 
-static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
-  u8 *buff)
+static int udl_get_edid_block(void *data, u8 *buf, unsigned int block,
+   size_t len)
 {
int ret, i;
u8 *read_buff;
+   struct udl_device *udl = data;
 
read_buff = kmalloc(2, GFP_KERNEL);
if (!read_buff)
-   return false;
+   return -1;
 
-   for (i = 0; i < EDID_LENGTH; i++) {
-   int bval = (i + block_idx * EDID_LENGTH) << 8;
+   for (i = 0; i < len; i++) {
+   int bval = (i + block * EDID_LENGTH) << 8;
ret = usb_control_msg(udl->udev,
  usb_rcvctrlpipe(udl->udev, 0),
  (0x02), (0x80 | (0x02 << 5)), bval,
@@ -36,60 +37,13 @@ static bool udl_get_edid_block(struct udl_device *udl, int 
block_idx,
if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
kfree(read_buff);
-   return false;
+   return -1;
}
-   buff[i] = read_buff[1];
+   buf[i] = read_buff[1];
}
 
kfree(read_buff);
-   return true;
-}
-
-static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
-int *result_buff_size)
-{
-   int i, extensions;
-   u8 *block_buff = NULL, *buff_ptr;
-
-   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
-   if (block_buff == NULL)
-   return false;
-
-   if (udl_get_edid_block(udl, 0, block_buff) &&
-   memchr_inv(block_buff, 0, EDID_LENGTH)) {
-   extensions = ((struct edid *)block_buff)->extensions;
-   if (extensions > 0) {
-   /* we have to read all extensions one by one */
-   *result_buff_size = EDID_LENGTH * (extensions + 1);
-   *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
-   buff_ptr = *result_buff;
-   if (buff_ptr == NULL) {
-   kfree(block_buff);
-   return false;
-   }
-   memcpy(buff_ptr, block_buff, EDID_LENGTH);
-   kfree(block_buff);
-   buff_ptr += EDID_LENGTH;
-   for (i = 1; i < extensions; ++i) {
-   if (udl_get_edid_block(udl, i, buff_ptr)) {
-   buff_ptr += EDID_LENGTH;
-   } else {
-   kfree(*result_buff);
-   *result_buff = NULL;
-   return false;
-   }
-   }
-   return true;
-   }
-   /* we have only base edid block */
-   *result_buff = block_buff;
-   *result_buff_size = EDID_LENGTH;
-   return true;
-   }
-
-   kfree(block_buff);
-
-   return false;
+   return 0;
 }
 
 static int udl_get_modes(struct drm_connector *connector)
@@ -121,8 +75,6 @@ static int udl_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 udl_detect(struct drm_connector *connector, bool force)
 {
-   u8 *edid_buff = NULL;
-   int edid_buff_size = 0;
struct udl_device *udl = connector->dev->dev_private;
struct udl_drm_connector *udl_connector =
container_of(connector,
@@ -135,12 +87,10 @@ udl_detect(struct drm_connector *connector, bool force)
udl_connector->edid = NULL;
}
 
-
-   if (!udl_get_edid(udl, _buff, _buff_size))
+   udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, 
udl);
+   if (!udl_connector->edid)
return connector_status_disconnected;
 
-   udl_connector->edid = (struct edid *)edid_buff;
-   
return connector_status_connected;
 }
 
-- 
2.21.0.360.g471c308f928-goog

___
dri-devel mailing list
dri-devel@lists.freedesktop.org

Re: [PATCH] drm/udl: Bugfix in EDID reading routine

2019-03-12 Thread Robert Tarasov
Yes, you're right. Will prepare another patch which will use
drm_do_get_edid()

On Mon, Mar 11, 2019 at 4:33 AM Jani Nikula 
wrote:

> On Fri, 08 Mar 2019, Robert Tarasov  wrote:
> > Fixed bug with reading of last EDID extra block in drm/udl driver.
> > Previouse approach read all the blocks except the last one.
> >
> > Signed-off-by: Robert Tarasov 
> > ---
> >  drivers/gpu/drm/udl/udl_connector.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/udl/udl_connector.c
> b/drivers/gpu/drm/udl/udl_connector.c
> > index c3dc1fd20cb4..68b221b9a01f 100644
> > --- a/drivers/gpu/drm/udl/udl_connector.c
> > +++ b/drivers/gpu/drm/udl/udl_connector.c
> > @@ -70,7 +70,7 @@ static bool udl_get_edid(struct udl_device *udl, u8
> **result_buff,
> >   memcpy(buff_ptr, block_buff, EDID_LENGTH);
> >   kfree(block_buff);
> >   buff_ptr += EDID_LENGTH;
> > - for (i = 1; i < extensions; ++i) {
> > + for (i = 1; i <= extensions; ++i) {
> >   if (udl_get_edid_block(udl, i, buff_ptr)) {
> >   buff_ptr += EDID_LENGTH;
> >   } else {
>
> Ugh. Why doesn't udl use drm_do_get_edid()?
>
> BR,
> Jani.
>
>
> --
> Jani Nikula, Intel Open Source Graphics Center
>
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH] drm/udl: Cut >165 MHz modes for DVI

2019-03-09 Thread Robert Tarasov
Filter out all modes with clock higher than 165 MHz for DVI connector in
drm/udl driver.

Signed-off-by: Robert Tarasov 
---
 drivers/gpu/drm/udl/udl_connector.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index 68b221b9a01f..3b9be500b9ae 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -109,6 +109,14 @@ static int udl_mode_valid(struct drm_connector *connector,
  struct drm_display_mode *mode)
 {
struct udl_device *udl = connector->dev->dev_private;
+   int con_type = connector->connector_type;
+
+   if ((con_type == DRM_MODE_CONNECTOR_DVII ||
+con_type == DRM_MODE_CONNECTOR_DVID ||
+con_type == DRM_MODE_CONNECTOR_DVIA) &&
+   mode->clock > 165000)
+   return MODE_CLOCK_HIGH;
+
if (!udl->sku_pixel_limit)
return 0;
 
-- 
2.21.0.360.g471c308f928-goog

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH] drm/udl: Bugfix in EDID reading routine

2019-03-09 Thread Robert Tarasov
Fixed bug with reading of last EDID extra block in drm/udl driver.
Previouse approach read all the blocks except the last one.

Signed-off-by: Robert Tarasov 
---
 drivers/gpu/drm/udl/udl_connector.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index c3dc1fd20cb4..68b221b9a01f 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -70,7 +70,7 @@ static bool udl_get_edid(struct udl_device *udl, u8 
**result_buff,
memcpy(buff_ptr, block_buff, EDID_LENGTH);
kfree(block_buff);
buff_ptr += EDID_LENGTH;
-   for (i = 1; i < extensions; ++i) {
+   for (i = 1; i <= extensions; ++i) {
if (udl_get_edid_block(udl, i, buff_ptr)) {
buff_ptr += EDID_LENGTH;
} else {
-- 
2.21.0.360.g471c308f928-goog

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH] drm/udl: Fixed problem with UDL adpater reconnection

2017-10-13 Thread Robert Tarasov
Fixed.

On Thu, Oct 12, 2017 at 12:56 PM, Alex Deucher <alexdeuc...@gmail.com>
wrote:

> On Wed, Oct 11, 2017 at 4:41 PM, Robert Tarasov
> <tutankha...@chromium.org> wrote:
> > Fixed problem with DisplayLink and DisplayLink certified adapters when
> they
> > didn't want to work if they were initialized with disconnected DVI
> cable. Now
> > udl driver checks and updates adapter's connection state every 10
> seconds, as
> > well as retreives all the edid data blocks instead of only base one.
> Previous
> > approch could lead to improper initialization of video mode with certain
> > monitors.
> >
>
> Seems like this should be split into two patches:
>
> 1. rework the EDID handling in the driver
> 2. enable drm connector polling.
>
> Alex
>
> > Signed-off-by: Robert Tarasov <tutankha...@chromium.org>
> > ---
> >  drivers/gpu/drm/udl/udl_connector.c | 153
> 
> >  drivers/gpu/drm/udl/udl_connector.h |  13 +++
> >  drivers/gpu/drm/udl/udl_drv.c   |   4 +
> >  drivers/gpu/drm/udl/udl_main.c  |   5 ++
> >  4 files changed, 125 insertions(+), 50 deletions(-)
> >  create mode 100644 drivers/gpu/drm/udl/udl_connector.h
> >
> > diff --git a/drivers/gpu/drm/udl/udl_connector.c
> b/drivers/gpu/drm/udl/udl_connector.c
> > index 9f9a49748d17..b2d9ffcc29aa 100644
> > --- a/drivers/gpu/drm/udl/udl_connector.c
> > +++ b/drivers/gpu/drm/udl/udl_connector.c
> > @@ -14,70 +14,95 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include "udl_connector.h"
> >  #include "udl_drv.h"
> >
> > -/* dummy connector to just get EDID,
> > -   all UDL appear to have a DVI-D */
> > -
> > -static u8 *udl_get_edid(struct udl_device *udl)
> > +static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
> > +  u8 *buff)
> >  {
> > -   u8 *block;
> > -   char *rbuf;
> > int ret, i;
> > +   u8 *read_buff;
> >
> > -   block = kmalloc(EDID_LENGTH, GFP_KERNEL);
> > -   if (block == NULL)
> > -   return NULL;
> > -
> > -   rbuf = kmalloc(2, GFP_KERNEL);
> > -   if (rbuf == NULL)
> > -   goto error;
> > +   read_buff = kmalloc(2, GFP_KERNEL);
> > +   if (!read_buff)
> > +   return false;
> >
> > for (i = 0; i < EDID_LENGTH; i++) {
> > +   int bval = (i + block_idx * EDID_LENGTH) << 8;
> > ret = usb_control_msg(udl->udev,
> > - usb_rcvctrlpipe(udl->udev, 0),
> (0x02),
> > - (0x80 | (0x02 << 5)), i << 8,
> 0xA1, rbuf, 2,
> > - HZ);
> > + usb_rcvctrlpipe(udl->udev, 0),
> > + (0x02), (0x80 | (0x02 << 5)),
> bval,
> > + 0xA1, read_buff, 2, HZ);
> > if (ret < 1) {
> > DRM_ERROR("Read EDID byte %d failed err %x\n",
> i, ret);
> > -   goto error;
> > +   kfree(read_buff);
> > +   return false;
> > }
> > -   block[i] = rbuf[1];
> > +   buff[i] = read_buff[1];
> > }
> >
> > -   kfree(rbuf);
> > -   return block;
> > -
> > -error:
> > -   kfree(block);
> > -   kfree(rbuf);
> > -   return NULL;
> > +   kfree(read_buff);
> > +   return true;
> >  }
> >
> > -static int udl_get_modes(struct drm_connector *connector)
> > +static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
> > +int *result_buff_size)
> >  {
> > -   struct udl_device *udl = connector->dev->dev_private;
> > -   struct edid *edid;
> > -   int ret;
> > -
> > -   edid = (struct edid *)udl_get_edid(udl);
> > -   if (!edid) {
> > -   drm_mode_connector_update_edid_property(connector,
> NULL);
> > -   return 0;
> > +   int i, extensions;
> > +   u8 *block_buff = NULL, *buff_ptr;
> > +
> > +   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
> > +   if (block_buff == NULL)
> > +   return false;
> > +
> > +   if (udl_get_edi

[PATCH 2/2] drm/udl: Reading all edid blocks in DRM/UDL driver

2017-10-13 Thread Robert Tarasov
Now DRM/UDL driver retreives all edid data blocks instead of only base one.
Previous approch could lead to improper initialization of video mode with
certain monitors.

Signed-off-by: Robert Tarasov <tutankha...@chromium.org>
---
 drivers/gpu/drm/udl/udl_connector.c | 106 +++-
 1 file changed, 68 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index 6a9250ac8f29..c3dc1fd20cb4 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -17,42 +17,79 @@
 #include "udl_connector.h"
 #include "udl_drv.h"
 
-/* dummy connector to just get EDID,
-   all UDL appear to have a DVI-D */
-
-static u8 *udl_get_edid(struct udl_device *udl)
+static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
+  u8 *buff)
 {
-   u8 *block;
-   char *rbuf;
int ret, i;
+   u8 *read_buff;
 
-   block = kmalloc(EDID_LENGTH, GFP_KERNEL);
-   if (block == NULL)
-   return NULL;
-
-   rbuf = kmalloc(2, GFP_KERNEL);
-   if (rbuf == NULL)
-   goto error;
+   read_buff = kmalloc(2, GFP_KERNEL);
+   if (!read_buff)
+   return false;
 
for (i = 0; i < EDID_LENGTH; i++) {
+   int bval = (i + block_idx * EDID_LENGTH) << 8;
ret = usb_control_msg(udl->udev,
- usb_rcvctrlpipe(udl->udev, 0), (0x02),
- (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 
2,
- HZ);
+ usb_rcvctrlpipe(udl->udev, 0),
+ (0x02), (0x80 | (0x02 << 5)), bval,
+ 0xA1, read_buff, 2, HZ);
if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
-   goto error;
+   kfree(read_buff);
+   return false;
}
-   block[i] = rbuf[1];
+   buff[i] = read_buff[1];
}
 
-   kfree(rbuf);
-   return block;
+   kfree(read_buff);
+   return true;
+}
 
-error:
-   kfree(block);
-   kfree(rbuf);
-   return NULL;
+static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
+int *result_buff_size)
+{
+   int i, extensions;
+   u8 *block_buff = NULL, *buff_ptr;
+
+   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
+   if (block_buff == NULL)
+   return false;
+
+   if (udl_get_edid_block(udl, 0, block_buff) &&
+   memchr_inv(block_buff, 0, EDID_LENGTH)) {
+   extensions = ((struct edid *)block_buff)->extensions;
+   if (extensions > 0) {
+   /* we have to read all extensions one by one */
+   *result_buff_size = EDID_LENGTH * (extensions + 1);
+   *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
+   buff_ptr = *result_buff;
+   if (buff_ptr == NULL) {
+   kfree(block_buff);
+   return false;
+   }
+   memcpy(buff_ptr, block_buff, EDID_LENGTH);
+   kfree(block_buff);
+   buff_ptr += EDID_LENGTH;
+   for (i = 1; i < extensions; ++i) {
+   if (udl_get_edid_block(udl, i, buff_ptr)) {
+   buff_ptr += EDID_LENGTH;
+   } else {
+   kfree(*result_buff);
+   *result_buff = NULL;
+   return false;
+   }
+   }
+   return true;
+   }
+   /* we have only base edid block */
+   *result_buff = block_buff;
+   *result_buff_size = EDID_LENGTH;
+   return true;
+   }
+
+   kfree(block_buff);
+
+   return false;
 }
 
 static int udl_get_modes(struct drm_connector *connector)
@@ -84,33 +121,26 @@ static int udl_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 udl_detect(struct drm_connector *connector, bool force)
 {
-   struct edid *edid;
+   u8 *edid_buff = NULL;
+   int edid_buff_size = 0;
struct udl_device *udl = connector->dev->dev_private;
struct udl_drm_connector *udl_connector =
container_of(connector,
struct udl_drm_connector,
connector);
 
+ 

[PATCH 1/2] drm/udl: Fixed problem with UDL adpater reconnection

2017-10-13 Thread Robert Tarasov
Fixed problem with DisplayLink and DisplayLink certified adapers in drm/udl
driver when adapter doesn't want to work if it was initialized with
disconnected DVI cable by enabling drm connectot polling and updating
current connector's state.

Signed-off-by: Robert Tarasov <tutankha...@chromium.org>
---
 drivers/gpu/drm/udl/udl_connector.c | 76 -
 drivers/gpu/drm/udl/udl_connector.h | 13 +++
 drivers/gpu/drm/udl/udl_drv.c   |  4 ++
 drivers/gpu/drm/udl/udl_main.c  |  5 +++
 4 files changed, 72 insertions(+), 26 deletions(-)
 create mode 100644 drivers/gpu/drm/udl/udl_connector.h

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index 091ca81658eb..6a9250ac8f29 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include "udl_connector.h"
 #include "udl_drv.h"
 
 /* dummy connector to just get EDID,
@@ -56,28 +57,15 @@ static u8 *udl_get_edid(struct udl_device *udl)
 
 static int udl_get_modes(struct drm_connector *connector)
 {
-   struct udl_device *udl = connector->dev->dev_private;
-   struct edid *edid;
-   int ret;
-
-   edid = (struct edid *)udl_get_edid(udl);
-   if (!edid) {
-   drm_mode_connector_update_edid_property(connector, NULL);
-   return 0;
-   }
-
-   /*
-* We only read the main block, but if the monitor reports extension
-* blocks then the drm edid code expects them to be present, so patch
-* the extension count to 0.
-*/
-   edid->checksum += edid->extensions;
-   edid->extensions = 0;
-
-   drm_mode_connector_update_edid_property(connector, edid);
-   ret = drm_add_edid_modes(connector, edid);
-   kfree(edid);
-   return ret;
+   struct udl_drm_connector *udl_connector =
+   container_of(connector,
+   struct udl_drm_connector,
+   connector);
+
+   drm_mode_connector_update_edid_property(connector, udl_connector->edid);
+   if (udl_connector->edid)
+   return drm_add_edid_modes(connector, udl_connector->edid);
+   return 0;
 }
 
 static int udl_mode_valid(struct drm_connector *connector,
@@ -96,8 +84,33 @@ static int udl_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 udl_detect(struct drm_connector *connector, bool force)
 {
-   if (drm_dev_is_unplugged(connector->dev))
+   struct edid *edid;
+   struct udl_device *udl = connector->dev->dev_private;
+   struct udl_drm_connector *udl_connector =
+   container_of(connector,
+   struct udl_drm_connector,
+   connector);
+
+   if (udl_connector->edid != NULL) {
+   kfree(udl_connector->edid);
+   udl_connector->edid = NULL;
+   }
+
+   edid = (struct edid *)udl_get_edid(udl);
+   if (!edid || !memchr_inv(edid, 0, EDID_LENGTH))
return connector_status_disconnected;
+
+   udl_connector->edid = edid;
+
+   /*
+* We only read the main block, but if the monitor reports extension
+* blocks then the drm edid code expects them to be present, so patch
+* the extension count to 0.
+*/
+   udl_connector->edid->checksum +=
+   udl_connector->edid->extensions;
+   udl_connector->edid->extensions = 0;
+
return connector_status_connected;
 }
 
@@ -117,8 +130,14 @@ static int udl_connector_set_property(struct drm_connector 
*connector,
 
 static void udl_connector_destroy(struct drm_connector *connector)
 {
+   struct udl_drm_connector *udl_connector =
+   container_of(connector,
+   struct udl_drm_connector,
+   connector);
+
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
+   kfree(udl_connector->edid);
kfree(connector);
 }
 
@@ -138,17 +157,22 @@ static const struct drm_connector_funcs 
udl_connector_funcs = {
 
 int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)
 {
+   struct udl_drm_connector *udl_connector;
struct drm_connector *connector;
 
-   connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);
-   if (!connector)
+   udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL);
+   if (!udl_connector)
return -ENOMEM;
 
-   drm_connector_init(dev, connector, _connector_funcs, 
DRM_MODE_CONNECTOR_DVII);
+   connector = _connector->connector;
+   drm_connector_init(dev, connector, _connector_funcs,

[PATCH] drm/udl: Fixed problem with UDL adpater reconnection

2017-10-12 Thread Robert Tarasov
Fixed problem with DisplayLink and DisplayLink certified adapters when they
didn't want to work if they were initialized with disconnected DVI cable. Now
udl driver checks and updates adapter's connection state every 10 seconds, as
well as retreives all the edid data blocks instead of only base one. Previous
approch could lead to improper initialization of video mode with certain
monitors.

Signed-off-by: Robert Tarasov <tutankha...@chromium.org>
---
 drivers/gpu/drm/udl/udl_connector.c | 153 
 drivers/gpu/drm/udl/udl_connector.h |  13 +++
 drivers/gpu/drm/udl/udl_drv.c   |   4 +
 drivers/gpu/drm/udl/udl_main.c  |   5 ++
 4 files changed, 125 insertions(+), 50 deletions(-)
 create mode 100644 drivers/gpu/drm/udl/udl_connector.h

diff --git a/drivers/gpu/drm/udl/udl_connector.c 
b/drivers/gpu/drm/udl/udl_connector.c
index 9f9a49748d17..b2d9ffcc29aa 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -14,70 +14,95 @@
 #include 
 #include 
 #include 
+#include "udl_connector.h"
 #include "udl_drv.h"
 
-/* dummy connector to just get EDID,
-   all UDL appear to have a DVI-D */
-
-static u8 *udl_get_edid(struct udl_device *udl)
+static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
+  u8 *buff)
 {
-   u8 *block;
-   char *rbuf;
int ret, i;
+   u8 *read_buff;
 
-   block = kmalloc(EDID_LENGTH, GFP_KERNEL);
-   if (block == NULL)
-   return NULL;
-
-   rbuf = kmalloc(2, GFP_KERNEL);
-   if (rbuf == NULL)
-   goto error;
+   read_buff = kmalloc(2, GFP_KERNEL);
+   if (!read_buff)
+   return false;
 
for (i = 0; i < EDID_LENGTH; i++) {
+   int bval = (i + block_idx * EDID_LENGTH) << 8;
ret = usb_control_msg(udl->udev,
- usb_rcvctrlpipe(udl->udev, 0), (0x02),
- (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 
2,
- HZ);
+ usb_rcvctrlpipe(udl->udev, 0),
+ (0x02), (0x80 | (0x02 << 5)), bval,
+ 0xA1, read_buff, 2, HZ);
if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
-   goto error;
+   kfree(read_buff);
+   return false;
}
-   block[i] = rbuf[1];
+   buff[i] = read_buff[1];
}
 
-   kfree(rbuf);
-   return block;
-
-error:
-   kfree(block);
-   kfree(rbuf);
-   return NULL;
+   kfree(read_buff);
+   return true;
 }
 
-static int udl_get_modes(struct drm_connector *connector)
+static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
+int *result_buff_size)
 {
-   struct udl_device *udl = connector->dev->dev_private;
-   struct edid *edid;
-   int ret;
-
-   edid = (struct edid *)udl_get_edid(udl);
-   if (!edid) {
-   drm_mode_connector_update_edid_property(connector, NULL);
-   return 0;
+   int i, extensions;
+   u8 *block_buff = NULL, *buff_ptr;
+
+   block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
+   if (block_buff == NULL)
+   return false;
+
+   if (udl_get_edid_block(udl, 0, block_buff) &&
+   memchr_inv(block_buff, 0, EDID_LENGTH)) {
+   extensions = ((struct edid *)block_buff)->extensions;
+   if (extensions > 0) {
+   /* we have to read all extensions one by one */
+   *result_buff_size = EDID_LENGTH * (extensions + 1);
+   *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
+   buff_ptr = *result_buff;
+   if (buff_ptr == NULL) {
+   kfree(block_buff);
+   return false;
+   }
+   memcpy(buff_ptr, block_buff, EDID_LENGTH);
+   kfree(block_buff);
+   buff_ptr += EDID_LENGTH;
+   for (i = 1; i < extensions; ++i) {
+   if (udl_get_edid_block(udl, i, buff_ptr)) {
+   buff_ptr += EDID_LENGTH;
+   } else {
+   kfree(*result_buff);
+   *result_buff = NULL;
+   return false;
+   }
+   }
+   return true;
+   }
+   /* we have only base edid block */
+