[PATCH v8 3/3] drm: Add GUD USB Display driver

Noralf Trønnes noralf at tronnes.org
Tue Mar 16 20:28:37 UTC 2021



Den 15.03.2021 20.37, skrev Peter Stuge:
> Hi Noralf,
> 
> super fair call with the BE testing, let's hope for some testing soonish.
> 
> 
> I was thinking about my device doing protocol STALL when I try to
> return 0 bytes, and while it *is* a bug in my device, from a standards
> point of view it's actually completely valid, if not expected:
> 
> --8<-- usb_20.pdf 8.5.3.4 STALL Handshakes Returned by Control Pipes
> If the device is unable to complete a command, it returns a STALL in the
> Data and/or Status stages of the control transfer. Unlike the case of a
> functional stall, protocol stall does not indicate an error with the device.
> -->8--
> 
> I think it's fair to say that a device can't complete the command
> when it has no data to return.
> 
> So how about allowing STALL for optional GUD_REQ_GET_:s to mean the same
> as a 0 byte response? Should I propose a separate patch for it later?
> 

Yeah, that would be nice.

We can't look for -EPIPE though, since GUD_REQ_GET_STATUS will ask for
the actual error. We have these to choose from currently:

  #define GUD_STATUS_OK				0x00
  #define GUD_STATUS_BUSY			0x01
  #define GUD_STATUS_REQUEST_NOT_SUPPORTED	0x02
  #define GUD_STATUS_PROTOCOL_ERROR		0x03
  #define GUD_STATUS_INVALID_PARAMETER		0x04
  #define GUD_STATUS_ERROR			0x05

Maybe REQUEST_NOT_SUPPORTED (-EOPNOTSUPP) or add a more fitting status
value.

If the driver sees -EPIPE this means that the device has failed to
respond properly. See gud_usb_transfer().

> 
> Noralf Trønnes wrote:
>> +++ b/drivers/gpu/drm/gud/gud_connector.c
> ..
>> +static int gud_connector_get_modes(struct drm_connector *connector)
> ..
>> +	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
>> +			  edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
> 
> if (ret == -EPIPE)
> 	ret = 0;
> 
>> +	if (ret > 0 && ret % EDID_LENGTH) {
>> +		gud_conn_err(connector, "Invalid EDID size", ret);
>> +	} else if (ret > 0) {
>> +		edid_ctx.len = ret;
>> +		edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
>> +	}
> 
> 
>> +static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
> ..
>> +	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
>> +			  properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
> 
> if (ret == -EPIPE)
> 	ret = 0;
> 
>> +	if (ret <= 0)
>> +		goto out;
>> +	if (ret % sizeof(*properties)) {
>> +		ret = -EIO;
>> +		goto out;
>> +	}
> 
> 
>> +++ b/drivers/gpu/drm/gud/gud_drv.c
> ..
> ..
>> +static int gud_get_properties(struct gud_device *gdrm)
> ..
>> +	ret = gud_usb_get(gdrm, GUD_REQ_GET_PROPERTIES, 0,
>> +			  properties, GUD_PROPERTIES_MAX_NUM * sizeof(*properties));
> 
> if (ret == -EPIPE)
> 	ret = 0;
> 
>> +	if (ret <= 0)
>> +		goto out;
>> +	if (ret % sizeof(*properties)) {
>> +		ret = -EIO;
>> +		goto out;
>> +	}
> 
> 
> Then I looked whether a device could cause trouble in the driver by
> returning complex/unexpected data, and found this:
> 
>> +static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
> ..
>> +	/* Add room for emulated XRGB8888 */
>> +	formats = devm_kmalloc_array(dev, GUD_FORMATS_MAX_NUM + 1, sizeof(*formats), GFP_KERNEL);
> 
> It looks like this +1 and the way xrgb8888_emulation_format works means
> that an interface will not always work correctly if multiple emulated
> formats (R1, XRGB1111, RGB565) are returned, because only one emulated
> mode is added after the loop, with struct drm_format_info for the last
> emulated format returned by the device. So userspace would only see the
> last emulated mode and the bulk output would only ever use that
> particular pixel format, any earlier ones would be unavailable?
> 
> If this is EWONTFIX then how about adding an error message if multiple
> emulated modes are returned and ignore all but the first, rather than
> all but the last?
> 

It does ignore all but the first... doesn't it?

You could make a patch if you care about this:

		case GUD_DRM_FORMAT_R1:
			fallthrough;
		case GUD_DRM_FORMAT_XRGB1111:
			if (!xrgb8888_emulation_format)
				xrgb8888_emulation_format = info;
+			else
+				dev_err(dev, "...");
			break;

It's only needed for the formats that are not exported to userspace.

> 
> Related: Can userspace find out which GUD_PIXEL_FORMAT_* is behind an
> emulated format? It's needed to decide how the emulated framebuffer
> should be used, in particular to not use G or B if GUD_PIXEL_FORMAT_R1.
> 

There's no way for userspace to know that. drm_fb_xrgb8888_to_gray8()
uses ITU BT.601 rgb conversion so userspace doesn't have to know which
colors to use, but ofc it will need to know there's a monochrome display
for it to look good.

XRGB8888 is the only format that is allowed to be emulated since some
userspace only supports that one format. So we can't have a device that
supports both R1 and XRGB1111.

> 
>> +		switch (format) {
>> +		case GUD_DRM_FORMAT_R1:
>> +			fallthrough;
>> +		case GUD_DRM_FORMAT_XRGB1111:
>> +			if (!xrgb8888_emulation_format)
>> +				xrgb8888_emulation_format = info;
>> +			break;
>> +		case DRM_FORMAT_RGB565:
>> +			rgb565_supported = true;
>> +			if (!xrgb8888_emulation_format)
>> +				xrgb8888_emulation_format = info;
>> +			break;
> 
> Could RGB565 go before XRGB111 (or R1) and also fallthrough; in this
> construct? Not terribly important, but the repetition caught my eye.
> 

It could but I'd like to keep the increasing bits-per-pixel order.

> 
> Then, in gud_connector.c I saw this, which surprised me:
> 
> +int gud_connector_fill_properties(struct drm_connector_state *connector_state,
> ..
> +		if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
> +			val = connector_state->tv.brightness;
> +		} else {
> 
> Why is this using tv.brightness rather than say gconn->initial_brightness?
> 
> It looks like the end result might be the same because tv.brightness is
> set to gconn->initial_brightness in gud_connector_reset() but it's a
> little confusing to me, since a GUD backlight isn't a drm/TV thing?
> 

I'm reusing the tv state property since that saves me from subclassing
the connector state. I want to have the value in the state because that
makes it less of a special case. Some time in the future DRM will have
proper backlight support as a DRM property, but so far no one has been
willing to invest the necessary time and effort to make it happen.

Noralf.


More information about the dri-devel mailing list