STRUCT DRM_CRTC_FUNCS(9)
π struct drm_crtc_funcs
okay so this is the Kernel API Manual page for struct drm_crtc_funcs, and it's literally the entire personality of a CRTC (that's the thing that scans out a display, bestie) β all the callbacks a driver hands over so the DRM core knows how to drive it. Buckle up, this one's long, we're doing it in parts π
β¨ NAME β¨
struct drm_crtc_funcs β control CRTCs for a given device π
π¦ SYNOPSIS π¦
struct drm_crtc_funcs {
void (*reset)(struct drm_crtc *crtc);
int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height);
int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y);
int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size, struct drm_modeset_acquire_ctx *ctx);
void (*destroy)(struct drm_crtc *crtc);
int (*set_config)(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx);
int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, struct drm_modeset_acquire_ctx *ctx);
int (*page_flip_target)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx);
int (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t val);
struct drm_crtc_state *(*atomic_create_state)(struct drm_crtc *crtc);
struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
void (*atomic_destroy_state)(struct drm_crtc *crtc, struct drm_crtc_state *state);
int (*atomic_set_property)(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val);
int (*atomic_get_property)(struct drm_crtc *crtc, const struct drm_crtc_state *state, struct drm_property *property, uint64_t *val);
int (*late_register)(struct drm_crtc *crtc);
void (*early_unregister)(struct drm_crtc *crtc);
int (*set_crc_source)(struct drm_crtc *crtc, const char *source);
int (*verify_crc_source)(struct drm_crtc *crtc, const char *source, size_t *values_cnt);
const char *const *(*get_crc_sources)(struct drm_crtc *crtc, size_t *count);
void (*atomic_print_state)(struct drm_printer *p, const struct drm_crtc_state *state);
u32 (*get_vblank_counter)(struct drm_crtc *crtc);
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
bool (*get_vblank_timestamp)(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, bool in_vblank_irq);
};
π Members π
π reset
Reset CRTC hardware and software state to off. Heads up: this function isn't called by the core directly β it only ever gets called through drm_mode_config_reset. And no, it's not a helper hook, and the only reason it isn't is historical. iykyk π«
Atomic drivers can use drm_atomic_helper_crtc_reset to reset atomic state using this hook.
π cursor_set
Update the cursor image. The cursor position is relative to the CRTC and can be partially or fully outside of the visible area (yes, it can just vibe off the edge, that's legal πΈ).
Note that contrary to all other KMS functions, the legacy cursor entry points don't take a framebuffer object. Instead they take directly a raw buffer object id from the driver's buffer manager (which is either GEM or TTM for current drivers). No cap.
This entry point is deprecated β drivers should instead implement universal plane support and register a proper cursor plane using drm_crtc_init_with_planes. Like, please stop using this one bestie π
This callback is optional.
RETURNS:
0 on success or a negative error code on failure.
π cursor_set2
Update the cursor image, including hotspot information. The hotspot must not affect the cursor position in CRTC coordinates β it's only meant as a hint for virtualized display hardware to coordinate the guests' and hosts' cursor position. The cursor hotspot is relative to the cursor image. Other than that, this works exactly like cursor_set.
This entry point is deprecated, drivers should instead implement universal plane support and register a proper cursor plane using drm_crtc_init_with_planes.
This callback is optional.
RETURNS:
0 on success or a negative error code on failure.
π cursor_move
Update the cursor position. The cursor does not need to be visible when this hook is called β it can be fully in its hide era π
This entry point is deprecated, drivers should instead implement universal plane support and register a proper cursor plane using drm_crtc_init_with_planes.
This callback is optional.
RETURNS:
0 on success or a negative error code on failure.
π gamma_set
Set gamma on the CRTC. Colour go brrr π
This callback is optional.
Atomic drivers who want to support gamma tables should implement the atomic color management support, enabled by calling drm_crtc_enable_color_mgmt, which then supports the legacy gamma interface through the drm_atomic_helper_legacy_gamma_set compatibility implementation. slay, backwards compat icon β¨
π destroy
Clean up CRTC resources. This is only called at driver unload time through drm_mode_config_cleanup, since a CRTC cannot be hotplugged in DRM. So like, one farewell and it's forever π₯
π set_config
This is the main legacy entry point to change the modeset state on a CRTC. All the details of the desired configuration are passed in a struct drm_mode_set β see there for details. main character energy fr fr π
Drivers implementing atomic modeset should use drm_atomic_helper_set_config to implement this hook.
RETURNS:
0 on success or a negative error code on failure.
π page_flip
Legacy entry point to schedule a flip to the given framebuffer. π¦
Page flipping is a synchronization mechanism that replaces the frame buffer being scanned out by the CRTC with a new frame buffer during vertical blanking, avoiding tearing (except when requested otherwise through the DRM_MODE_PAGE_FLIP_ASYNC flag). When an application requests a page flip the DRM core verifies that the new frame buffer is large enough to be scanned out by the CRTC in the currently configured mode and then calls this hook with a pointer to the new frame buffer.
The driver must wait for any pending rendering to the new framebuffer to complete before executing the flip. It should also wait for any pending rendering from other drivers if the underlying buffer is a shared dma-buf. no cutting corners bestie π«Ά
An application can request to be notified when the page flip has completed. The drm core will supply a struct drm_event in the event parameter in this case. This can be handled by the drm_crtc_send_vblank_event function, which the driver should call on the provided event upon completion of the flip. Note that if the driver supports vblank signalling and timestamping the vblank counters and timestamps must agree with the ones returned from page flip events. With the current vblank helper infrastructure this can be achieved by holding a vblank reference while the page flip is pending, acquired through drm_crtc_vblank_get and released with drm_crtc_vblank_put. Drivers are free to implement their own vblank counter and timestamp tracking though, e.g. if they have accurate timestamp registers in hardware.
This callback is optional.
NOTE: Very early versions of the KMS ABI mandated that the driver must block (but not reject) any rendering to the old framebuffer until the flip operation has completed and the old framebuffer is no longer visible. This requirement has been lifted, and userspace is instead expected to request delivery of an event and wait with recycling old buffers until such has been received. ty for your service, ancient rule π―οΈ
RETURNS:
0 on success or a negative error code on failure. Note that if a page flip operation is already pending the callback should return -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode or just runtime disabled through DPMS respectively the new atomic "ACTIVE" state) should result in an -EINVAL error code. Note that drm_atomic_helper_page_flip checks this already for atomic drivers. π the error codes matter, do not skip them
π page_flip_target
Same as page_flip but with an additional parameter specifying the absolute target vertical blank period (as reported by drm_crtc_vblank_count) when the flip should take effect. basically: flip, but make it scheduled π
Note that the core code calls drm_crtc_vblank_get before this entry point, and will call drm_crtc_vblank_put if this entry point returns any non-0 error code. It's the driver's responsibility to call drm_crtc_vblank_put after this entry point returns 0, typically when the flip completes. so, like, the refcount handoff is on you, don't fumble it π«
π set_property
This is the legacy entry point to update a property attached to the CRTC.
This callback is optional if the driver does not support any legacy driver-private properties. For atomic drivers it is not used because property handling is done entirely in the DRM core. (atomic drivers: not invited to this party π)
RETURNS:
0 on success or a negative error code on failure.
π atomic_create_state
Allocate a pristine, initialized, state for the CRTC object and return it. This callback must have no side effects: in particular, the returned state must not be assigned to the object's state pointer and it must not affect the hardware state. pristine. untouched. brand new. π§
RETURNS:
A new, pristine, CRTC state instance or an error pointer on failure.
π atomic_duplicate_state
Duplicate the current atomic state for this CRTC and return it. The core and helpers guarantee that any atomic state duplicated with this hook and still owned by the caller (i.e. not transferred to the driver by calling drm_mode_config_funcs.atomic_commit) will be cleaned up by calling the atomic_destroy_state hook in this structure.
This callback is mandatory for atomic drivers. no skips π
Atomic drivers which don't subclass struct drm_crtc_state should use drm_atomic_helper_crtc_duplicate_state. Drivers that subclass the state structure to extend it with driver-private state should use __drm_atomic_helper_crtc_duplicate_state to make sure shared state is duplicated in a consistent fashion across drivers. consistency is the vibe check β¨
It is an error to call this hook before drm_crtc.state has been initialized correctly. like, do not do that π
NOTE: If the duplicate state references refcounted resources this hook must acquire a reference for each of them. The driver must release these references again in atomic_destroy_state. what you take, you give back π«Ά
RETURNS:
Duplicated atomic state or NULL when the allocation failed.
π atomic_destroy_state
Destroy a state duplicated with atomic_duplicate_state and release or unreference all resources it references. cleanup era πΈ
This callback is mandatory for atomic drivers.
atomic_set_property
okay so this one decodes a driver-private property value and stashes the decoded value into the state structure you pass in β¨ and here's the thing β the atomic core already decodes, like, all the standardized properties (even the extensions beyond the core set that maybe not every driver implements), which is exactly why drivers have to subclass the state structure. iykyk π
ngl, driver-private properties should really only be a thing for genuinely hardware/vendor specific state. the preferred move is to standardize the atomic extension and decode the properties that expose it in the core instead π«Ά
π¨ do not call this function directly β use drm_atomic_crtc_set_property instead, bestie.
this callback is optional if the driver doesn't support any driver-private atomic properties.
NOTE:
this function gets called in the state assembly phase of atomic modesets, and that phase can be aborted for literally any reason (including userspace just asking "hey would this config even be possible?"). so drivers MUST NOT touch any persistent state (hardware or software) or data structures, except the state parameter that was passed in. periodt π
also, since userspace controls the order the properties get set in, this function must not do any input validation (the state update is incomplete and therefore probably inconsistent, so likeβ¦ don't π). any validation like that has to happen in the various atomic_check callbacks.
RETURNS:
0 if the property has been found, -EINVAL if the property isn't implemented by the driver (which should never happen β the core only asks for properties attached to this CRTC). no other validation is allowed by the driver π
ββοΈ the core already checks that the property value is within the range (integer, valid enum value, ...) that the driver set when registering the property. slay.
atomic_get_property
reads out the decoded driver-private property π this is what implements the GETCRTC IOCTL.
do not call this function directly β use drm_atomic_crtc_get_property instead.
optional callback if the driver doesn't support any driver-private atomic properties.
RETURNS:
0 on success, -EINVAL if the property isn't implemented by the driver (which should never happen, the core only asks for properties attached to this CRTC) β¨
late_register
this optional hook is your moment to register extra userspace interfaces attached to the crtc β like debugfs interfaces, for example π it's called late in the driver load sequence, from drm_dev_register. and everything you add from this callback should be unregistered in the early_unregister callback. no crumbs left behind, bestie π§Ή
Returns:
0 on success, or a negative error code on failure.
early_unregister
this optional hook cleans up the extra userspace interfaces attached to the crtc that you added in late_register πΈ it's called from drm_dev_unregister, early in the driver unload sequence, so userspace access gets disabled before the data structures are torndown. iconic order of operations, honestly π¦
set_crc_source
changes the source of CRC checksums of frames at the request of userspace, typically for testing purposes π§ͺ the sources available are specific to each driver, and a NULL value means "turn CRC generation off" β¨
when CRC generation is enabled, the driver should call drm_crtc_add_crc_entry at each frame, providing any information that characterizes the frame contents in the crcN arguments, as provided from the configured source. drivers must accept an "auto" source name that picks a default source for this CRTC π
this may trigger an atomic modeset commit if necessary, to enable CRC generation.
note that "auto" can depend upon the current modeset configuration β e.g. it could pick an encoder or output specific CRC sampling point π
this callback is optional if the driver doesn't support any CRC generation functionality.
RETURNS:
0 on success or a negative error code on failure.
verify_crc_source
verifies the source of CRC checksums of frames before setting the source for CRC and during crc open π the source parameter can be NULL while disabling crc source.
this callback is optional if the driver doesn't support any CRC generation functionality.
RETURNS:
0 on success or a negative error code on failure.
get_crc_sources
driver callback for getting a list of all the available sources for CRC generation π this callback depends upon verify_crc_source, so the verify_crc_source callback should be implemented before implementing this one. the driver can pass the full list of available crc sources, and this callback does the verification on each crc-source before passing it to userspace π
this callback is optional if the driver doesn't support exporting the possible CRC sources list.
RETURNS:
a constant character pointer to the list of all the available CRC sources π«Ά on failure the driver should return NULL. count should be updated with the number of sources in the list. if zero, we don't process any source from the list.
atomic_print_state
if the driver subclasses struct drm_crtc_state, it should implement this optional hook for printing additional driver specific state π¨οΈβ¨
do not call this directly β use drm_atomic_crtc_print_state instead.
get_vblank_counter
driver callback for fetching a raw hardware vblank counter for the CRTC π it's meant to be used by new drivers as the replacement of the drm_driver.get_vblank_counter hook.
this callback is optional. if a device doesn't have a hardware counter, the driver can simply leave the hook as NULL π the DRM core will account for missed vblank events while interrupts where disabled, based on system timestamps.
wraparound handling and loss of events due to modesetting is dealt with in the DRM core code β as long as drivers call drm_crtc_vblank_off and drm_crtc_vblank_on when disabling or enabling a CRTC π
see also drm_device.vblank_disable_immediate and drm_device.max_vblank_count.
Returns:
raw vblank counter value π
enable_vblank
enables vblank interrupts for the CRTC β‘ it's meant to be used by new drivers as the replacement of the drm_driver.enable_vblank hook.
Returns:
zero on success, appropriate errno if the vblank interrupt cannot be enabled π
disable_vblank
disables vblank interrupts for the CRTC π€ it's meant to be used by new drivers as the replacement of the drm_driver.disable_vblank hook.
get_vblank_timestamp
called by drm_get_last_vbltimestamp β° should return a precise timestamp for when the most recent vblank interval ended or will end.
specifically: the timestamp in vblank_time should correspond as closely as possible to the time when the first video scanline of the video frame after the end of vblank will start scanning out β like, the time immediately after the end of the vblank interval β¨ if the crtc is currently inside vblank, this will be a time in the future. if the crtc is currently scanning out a frame, this will be the past start time of the current scanout. this is meant to adhere to the OpenML OML_sync_control extension specification π
Parameters:
crtc: CRTC for which the timestamp should be returned.max_error: maximum allowable timestamp error in nanoseconds π the implementation should strive to provide a timestamp with an error of at mostmax_errornanoseconds. returns true upper bound on error for timestamp.vblank_time: target location for the returned vblank timestamp π―in_vblank_irq: true when called fromdrm_crtc_handle_vblank. some drivers need to apply some workarounds for gpu-specific vblank irq quirks if the flag is set π
Returns:
true on success, false on failure β and failure means the core should fallback to a simple timestamp taken in drm_crtc_handle_vblank π
π DESCRIPTION π
the drm_crtc_funcs structure is the central CRTC management structure in the DRM π each CRTC controls one or more connectors (and yes, the name CRTC is simply historical β a CRTC may control LVDS, VGA, DVI, TV out, etc. connectors, not just CRTs π₯οΈ nostalgic much?).
each driver is responsible for filling out this structure at startup time, in addition to providing other modesetting features, like i2c and DDC bus accessors β¨ no cap, it's a whole vibe.
π¦ SEE ALSO π¦
kernel file ./include/drm/drm_crtc.h, struct drm_crtc_state(9), struct drm_crtc(9), struct drm_mode_set(9), drmm_crtc_alloc_with_planes(9), drm_crtc_index(9), drm_crtc_mask(9), drm_crtc_find(9), drm_for_each_crtc(9), drm_for_each_crtc_reverse(9) π«Ά go read them, bestie, they're all icons fr fr.
and that's the whole page, babes π this one came straight out of ./include/drm, dated October 2026, version struct drm_crtc_funcs(9) β you're so welcome, now go fill out that structure at startup time like the main character you are π
β¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms