GUD Protocol - notro/gud GitHub Wiki
GUD doesn’t have a formal protocol specification, it’s the Linux implementation that defines the protocol.
The following tries to give an overview of the protocol and how the host driver uses it.
The GUD protocol requires 2 endpoints:
-
The default control endpoint 0
-
A bulk OUT endpoint for pixel data
Control requests are sent as VENDOR type and INTERFACE recipient.
- bRequestType
-
IN = 0xc1, OUT = 0x41
- wValue
-
index for connector requests, 0 otherwise
- wIndex
-
USB interface index
Reference: gud_usb_control_msg()
If the device stalls a control request the driver issues a GUD_REQ_GET_STATUS to find out the reason.
If GUD_DISPLAY_FLAG_STATUS_ON_SET is set, the driver also checks status after each GUD_REQ_SET request.
The only status value that has special meaning is GUD_STATUS_INVALID_PARAMETER for GUD_REQ_SET_STATE_CHECK (see further down).
When a USB device is plugged in and there’s a match in gud_id_table[], gud_probe() is called. The probe function issues requests to determine the device capabilities
- GUD_REQ_GET_DESCRIPTOR
-
If the returned values look sane probing continues. If not the driver returns
-ENODEV
and another driver can give it a go. This makes it possible for the device to include other VENDOR class interfaces for other purposes. - GUD_REQ_GET_FORMATS
-
Get supported pixel formats. If the device doesn’t support XRGB8888, the driver will provide emulation for this format (a format all of userspace supports).
- GUD_REQ_GET_PROPERTIES
-
Get the device properties (currently only rotation). The device returns zero if it doesn’t support any device properties.
- GUD_REQ_GET_CONNECTORS
-
Get array of connector descriptors.
- GUD_REQ_GET_CONNECTOR_PROPERTIES
-
For each connector fetch supported properties if any.
wValue
is set to the connector index. - GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES
-
If property is GUD_PROPERTY_TV_MODE fetch the possible values as strings.
wValue
is set to the connector index.
If GUD_CONNECTOR_FLAGS_POLL_STATUS is set the driver polls the connector status every 10 seconds.
- GUD_REQ_SET_CONNECTOR_FORCE_DETECT
-
Issued first if userspace asks for status, but not on poll requests.
- GUD_REQ_GET_CONNECTOR_STATUS
-
Get connector status. If status has changed or GUD_CONNECTOR_STATUS_CHANGED is set, userspace is notified. Userspace will now refetch the display modes.
Display modes can be fetched as either EDID data or an array of display modes. If GUD_REQ_GET_CONNECTOR_MODES returns zero, EDID is used to create the display modes. If both display modes and EDID are returned, EDID is just passed on to userspace in the EDID connector property.
- GUD_REQ_GET_CONNECTOR_EDID
-
Get Extended Display Identification Data. The device returns the EDID blocks it has or zero if None. One benefit of using EDID even for fixed size displays is that it provides a means for userspace to give a name to the monitor/display.
- GUD_REQ_GET_CONNECTOR_MODES
-
Get array of display modes. The preferred mode should be marked using GUD_DISPLAY_MODE_FLAG_PREFERRED. Even if there’s just one mode it should be marked (mpv issues a warning if not and says it will use the first mode).
State changes can be triggered from several sources: DRM_IOCTL/fbdev/sysfs.
- GUD_REQ_SET_STATE_CHECK
-
Check the provided state. The entire state is sent each time with all properties included even if they haven’t changed. The device shall stall the request and set status GUD_STATUS_INVALID_PARAMETER if it can’t implement the state. This will tell userspace to try something else. The device must always check that the state is valid. The host can override the device provided display modes using the video= kernel command line parameter or by providing custom EDID data. Userspace can do state checks without following up with a state commit.
- GUD_REQ_SET_STATE_COMMIT
-
Apply the previously sent
GUD_REQ_SET_STATE_CHECK
state. - GUD_REQ_SET_CONTROLLER_ENABLE
-
Enable/disable the display controller.
- GUD_REQ_SET_DISPLAY_ENABLE
-
Enable/disable display output.
This is what happens on the first state commit on a disabled display pipeline (gud_pipe_update()):
-
GUD_REQ_SET_STATE_CHECK
-
GUD_REQ_SET_CONTROLLER_ENABLE=1
-
GUD_REQ_SET_STATE_COMMIT
-
GUD_REQ_SET_DISPLAY_ENABLE=1 (unless the crtc ACTIVE property in the DRM state is 0, see tests/test_properties.py::test_active)
-
Update framebuffer
The sending of framebuffer changes can be triggered several ways:
-
DRM_IOCTL_MODE_ATOMIC (state commit) when the fb has changed or plane property FB_DAMAGE_CLIPS is set.
-
- GUD_REQ_SET_BUFFER
-
Info about the following buffer transfer: placement, size and compression.
- BULK
-
The buffer is transferred on the bulk OUT endpoint.
If GUD_DISPLAY_FLAG_FULL_UPDATE is set the entire framebuffer is transferred each time and the control request is not issued. It will be issued however on the retry should the bulk transfer return an error.
Ideas for future enhancements of the GUD protocol.
Pixel formats and properties can be added without using flags or bumping the protocol version.
-
Add
parts
field to tell if the buffer has been split up. The first request sets the parts field to the number of parts and the following reqs sets it to zero. Can be used to avoid split induced tearing on some devices. Or maybe the device can be clever and detect this without this info. -
CRC on frames for automatic testing. Maybe too much work and complexity for little gain.