GUD Protocol - notro/gud GitHub Wiki

GUD USB Display Protocol

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.

Endpoints

The GUD protocol requires 2 endpoints:

  • The default control endpoint 0

  • A bulk OUT endpoint for pixel data

Control requests

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

Device status

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).

Driver probe

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.

Connector

wValue is set to the connector index.

Status

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

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).

Display state

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()):

  1. GUD_REQ_SET_STATE_CHECK

  2. GUD_REQ_SET_CONTROLLER_ENABLE=1

  3. GUD_REQ_SET_STATE_COMMIT

  4. GUD_REQ_SET_DISPLAY_ENABLE=1 (unless the crtc ACTIVE property in the DRM state is 0, see tests/test_properties.py::test_active)

  5. Update framebuffer

Framebuffer update

The sending of framebuffer changes can be triggered several ways:

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.

Protocol changes

Linux 5.13

Initial version

Linux 5.16

Added pixel formats:

  • GUD_PIXEL_FORMAT_R8

  • GUD_PIXEL_FORMAT_RGB332

  • GUD_PIXEL_FORMAT_RGB888

Future enhancements

Ideas for future enhancements of the GUD protocol.

Pixel formats and properties can be added without using flags or bumping the protocol version.

GUD_REQ_SET_BUFFER

  • 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.

New requests

GUD_REQ_GET_LOG or GUD_REQ_GET_ERROR

The Linux gadget can return the kernel log, others can return a string representation of the error counter and last error. Exposed in debugfs.

⚠️ **GitHub.com Fallback** ⚠️