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.