Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lyudess/linux
1 result
Show changes
Commits on Source (79)
  • Greg Kroah-Hartman's avatar
    driver core: add a faux bus for use when a simple device/bus is needed · ff728fd4
    Greg Kroah-Hartman authored and Lyude Paul's avatar Lyude Paul committed
    
    Many drivers abuse the platform driver/bus system as it provides a
    simple way to create and bind a device to a driver-specific set of
    probe/release functions.  Instead of doing that, and wasting all of the
    memory associated with a platform device, here is a "faux" bus that
    can be used instead.
    
    Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
    Reviewed-by: default avatarDanilo Krummrich <dakr@kernel.org>
    Reviewed-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    Reviewed-by: default avatarThomas Weißschuh <thomas.weissschuh@linutronix.de>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    ff728fd4
  • Lyude Paul's avatar
    rust/kernel: Add faux device bindings · 653f6a88
    Lyude Paul authored
    
    This introduces a module for working with faux devices in rust, along with
    adding sample code to show how the API is used. Unlike other types of
    devices, we don't provide any hooks for device probe/removal - since these
    are optional for the faux API and are unnecessary in rust.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    Cc: Maíra Canal <mairacanal@riseup.net>
    Cc: Danilo Krummrich <dakr@kernel.org>
    Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    653f6a88
  • Lyude Paul's avatar
    rust: helpers/drm.c: Split into its own folder · 8ed7a74a
    Lyude Paul authored
    
    There's not that many bindings in here right now, but we're about to add
    quite a lot more - which means it's probably worth it to further split out
    the current helpers we have in helpers/drm.c into their own folder.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    8ed7a74a
  • Asahi Lina's avatar
    rust: helpers: Add bindings/wrappers for dma_resv · 876b4a32
    Asahi Lina authored and Lyude Paul's avatar Lyude Paul committed
    
    This is just for basic usage in the DRM shmem abstractions for implied
    locking, not intended as a full DMA Reservation abstraction yet.
    
    Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
    876b4a32
  • Asahi Lina's avatar
    drm/gem-shmem: Export VM ops functions · fabb480a
    Asahi Lina authored and Lyude Paul's avatar Lyude Paul committed
    
    There doesn't seem to be a way for the Rust bindings to get a
    compile-time constant reference to drm_gem_shmem_vm_ops, so we need to
    duplicate that structure in Rust... this isn't nice...
    
    Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
    fabb480a
  • Asahi Lina's avatar
    rust: drm: gem: shmem: Add DRM shmem helper abstraction · bca3c3d0
    Asahi Lina authored and Lyude Paul's avatar Lyude Paul committed
    
    The DRM shmem helper includes common code useful for drivers which
    allocate GEM objects as anonymous shmem. Add a Rust abstraction for
    this. Drivers can choose the raw GEM implementation or the shmem layer,
    depending on their needs.
    
    Lyude changelog:
    * Rebase
    * Squash "rust: drm: device: Convert Device to AlwaysRefCounted" as this
      commit doesn't compile without it anyway
    
    Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
    bca3c3d0
  • Asahi Lina's avatar
    rust: helpers: Add bindings/wrappers for dma_resv · 18c18a6b
    Asahi Lina authored and Lyude Paul's avatar Lyude Paul committed
    
    This is just for basic usage in the DRM shmem abstractions for implied
    locking, not intended as a full DMA Reservation abstraction yet.
    
    Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
    18c18a6b
  • Lyude Paul's avatar
    WIP: rust/drm: Add fourcc bindings · 5a6dfdc9
    Lyude Paul authored
    
    This adds some very basic rust bindings for fourcc. We only have a single
    format code added for the moment, but this is enough to get a driver
    registered.
    
    TODO:
    * Write up something to automatically generate constants from the fourcc
      headers
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    V3:
    * Drop FormatList and ModifierList
      These aren't actually needed as pointed out by Louis Chauvet
    * Add a constant for FORMAT_MOD_INVALID
      I realized that we actually need this because the format list isn't
      terminated with a 0 like I thought, and we can't pick this up
      automatically through bindgen
    5a6dfdc9
  • Lyude Paul's avatar
    WIP: rust: drm: Add traits for registering KMS devices · 5cc88af2
    Lyude Paul authored
    
    This commit adds some traits for registering DRM devices with KMS support,
    implemented through the kernel::drm::kms::Kms trait. Devices which don't
    have KMS support can simply use PhantomData<Self>.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Generate feature flags automatically, these shouldn't need to be
      specified by the user
    * Fix typo on KmsImpl documentation
    
    V3:
    * Get rid of Kms, long live KmsDriver
      After Daniel pointed out that we should just make KmsDriver a supertrait
      of Driver, it immediately occurred to me that there's no actual need for
      Kms to be a separate trait at all. So, drop Kms entirely and move its
      requirements over to KmsDriver.
    * Drop fbdev module entirely and move setup_fbdev() into AllocImpl (Daniel)
    5cc88af2
  • Lyude Paul's avatar
    rust: drm/kms: Introduce the main ModeConfigObject traits · 35719fee
    Lyude Paul authored
    
    The KMS API has a very consistent idea of a "mode config object", which
    includes any object with a drm_mode_object struct embedded in it. These
    objects have their own object IDs which DRM exposes to userspace, and we
    introduce the ModeConfigObject trait to represent any object matching these
    characteristics.
    
    One slightly less consistent trait of these objects however: some mode
    objects have a reference count, while others don't. Since rust requires
    that we are able to define the lifetime of an object up-front, we introduce
    two other super-traits of ModeConfigObject for this:
    
    * StaticModeObject - this trait represents any mode object which does not
      have a reference count of its own. Such objects can be considered to
      share the lifetime of their parent KMS device
    * RcModeObject - this trait represents any mode object which does have its
      own reference count. Objects implementing this trait get a free blanket
      implementation of AlwaysRefCounted, and as such can be used with the ARef
      container without us having to implement AlwaysRefCounted for each
      individual mode object.
    
    This will be able to handle most lifetimes we'll need with one exception:
    it's entirely possible a driver may want to hold a "owned" reference to a
    static mode object. We allow for this by introducing the KmsRef container,
    which grabs an owned refcount to the parent KMS device of a
    StaticModeObject and holds a pointer to said object - essentially allowing
    it to act identically to an owned refcount by preventing the device's
    lifetime from ending until the KmsRef is dropped. I choose not to use
    AlwaysRefCounted for this as holding a refcount to the device has its own
    set of implications since if you forget to drop the KmsRef the device will
    never be destroyed.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Document why modesetting objects require Send + Sync
    * Make `ModeObject` an unsafe trait
      I was prompted to make this change in response to one of Daniel's
      comments, as it occurred to me that we need something that ensures that
      implementers are only returning valid `drm_mode_object` pointers so we
      have something to put down for the various related safety comments in
      RcModeObject.
      Also, update the safety comments there.
    35719fee
  • Lyude Paul's avatar
    rust: drm/kms: Add bindings for drm_connector · 00582d66
    Lyude Paul authored
    
    We start off by introducing wrappers for the first important type of mode
    object: a DRM display connector. This introduces Connector<T:
    DriverConnector> and ConnectorState<T: DriverConnectorState>. Both
    DriverConnector and DriverConnectorState must be implemented by KMS
    drivers, and a driver may have as many implementations of these two traits
    as it needs. This also introduces the general data pattern we'll be using
    for all of the core mode objects that can be used in atomic commits.
    
    It's important to note that both Connector<T> and ConnectorState<T> are
    intended to be "subclassable". To explain what this means, we need to look
    at how a DRM driver normally uses objects like DRM connectors.
    
    Typically, a driver in C will define its connectors like so:
    
    struct foo_connector {
      struct drm_connector base;
      int bar;
    }
    
    Note that we have a drm_connector struct embedded in foo_connector, but we
    have data which comes after it which is defined by the driver. This is
    important for a number of reasons: connectors can have their own mutexes
    and various other hardware-specific information that a driver may want
    access to at any time. The same goes for drm_connector_state, where drivers
    will subclass this struct in the same way. It's worth noting as well that
    it isn't uncommon for a driver to have multiple types of connectors, but
    we'll handle in a later commit.
    
    As a result, we've designed Connector<T> and ConnectorState<T> so that for
    both types: a DRM driver can add custom data into the T. As well, there's
    some basic limitations on how this data may be accessed:
    
    * Data within the `DriverConnector` struct is pinned in order to allow
      mutexes and other structs which need pinning to be stored within it. As
      well, it is impossible to get a direct mutable reference to the data
      within DriverConnector - as there's no locks for doing so which would
      cause a race condition.
    * Data within the `DriverConnectorState` struct is currently not pinned.
      While it's not unheard of for a driver to put something like a mutex in
      its atomic states, (VKMS actually does this in some spots) this quickly
      complicates things especially with nonblocking modesets - and doesn't
      really fit into the philosophy of an atomic state anyway. We may add
      support for this in the future later if this does end up being needed,
      but for now we hold back in order to make it much easier for drivers to
      access private data within the atomic state.
      As well, the functions we provide for converting to/from raw connector
      state pointers are notably different from many other rust types in the
      kernel. Instead of converting raw state pointers to raw ConnectorState<T>
      pointers, we allow for direct immutable and mutable references. The
      reason for this is that it makes accessing private driver data in the
      state much easier, and unlike Connector<T> - we can actually uphold
      all of the required data aliasing rules thanks to states only being
      mutable by a single thread before they've been swapped in.
      Note that currently, we don't provide a way to access said private data
      for ConnectorState<T> since allowing direct access to a &mut
      ConnectorState<T> could allow a caller to modify portions of
      drm_connector_state which are meant to be invariant throughout the
      lifetime of the connector state. We'll address this in the next few
      commits when we introduce the global atomic state type.
    
    And finally - we introduce the following internal traits for the crate side
    of things:
    
      * AsRawConnector - any type which can spit out a *mut
        bindings::drm_connector or be recovered from one
      * AsRawConnectorState - any type which can return a reference to a
        bindings::drm_connector_state
      * private::AsRawConnectorState - just methods for AsRawConnectorState
        that we don't want to be accessible to our users (since they could be
        used to introduce UB)
      * FromRawConnectorState - any type which can be recovered from a raw
        pointer to a bindings::drm_connector_state
    
    The reason for having AsRawConnectorState and FromRawConnectorState as
    separate traits unlike AsRawConnector is due to the fact that we'll
    introduce objects later on which can be used as DRM connector states, but
    cannot be directly derived from a *mut bindings::drm_connector_state
    because they hold additional state or have additional side-effects.
    
    Likewise, we'll also have other objects which can be used as raw DRM
    connectors - hence AsRawConnector.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Add safety comment to implementation of ModeObject
    * Make AsRawConnector an unsafe trait, we need a guarantee that as_raw()
      always returns a valid pointer.
    * Improve safety comments in atomic_duplicate_state_callback
    * Improve safety comments in Connector::new()
    * Switch to requiring a UnregisteredKmsDevice instead of a Device
      This is in preparation for the static/dynamic connector split, which we
      may as well prepare for since we don't have any use for dynamic
      connectors yet.
    * Drop redundant Connector associated type in AsRawConnector trait
    * Improve safety comments in FromRawConnectorState
    * Introduce UnregisteredConnector type
    * Don't have AsRawConnector be a supertrait of StaticModeObject. We don't
      want Unregistered mode object variants to be able to return a pointer to
      the DRM device since that would break the UnregisteredKmsDevice pattern.
    00582d66
  • Lyude Paul's avatar
    rust: drm/kms: Add drm_plane bindings · 0400fb37
    Lyude Paul authored
    
    The next step is adding a set of basic bindings to create a plane, which
    has to happen before we can create a CRTC (since we need to be able to at
    least specify a primary plane for a CRTC upon creation). This mostly
    follows the same general pattern as connectors (AsRawPlane,
    AsRawPlaneState, etc.).
    
    There is one major difference with planes vs. other types of atomic mode
    objects: drm_plane_state isn't the only base plane struct used in DRM
    drivers, as some drivers will use helpers like drm_shadow_plane_state which
    have a drm_plane_state embedded within them.
    
    Since we'll eventually be adding bindings for shadow planes, we introduce a
    PlaneStateHelper trait - which represents any data type which can be used
    as the main wrapping structure around a drm_plane_state - and we implement
    this trait for PlaneState<T>. This trait can be used in our C callbacks to
    allow for drivers to use different wrapping structures without needing to
    implement a separate set of FFI callbacks for each type. Currently planes
    are the only type I'm aware of which do this.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V2:
    * Start using Gerry Guo's updated #[vtable] function so that our driver
      operations table has a static location in memory
    
    V3:
    * Add safety comment for implementation of ModeObject
    * Make AsRawPlane unsafe, since we need a guarantee that `as_raw()` always
      returns a valid pointer to an initialized drm_plane.
    * Add comments to __drm_atomic_helper_duplicate_state()
    * Switch `PlaneType` to camel casing
    * Improve safety comment in `Plane::<T>::new()`
    * Fix parameter types for `formats` and `format_modifiers`, as pointed out
      by Louis Chauvet DRM will copy all of these into its own storage.
    * Improve safety comments in FromRawPlaneState
    * Introduce UnregisteredPlane type
    * Don't have AsRawPlane be a supertrait of StaticModeObject. We don't want
      Unregistered mode object variants to be able to return a pointer to the
      DRM device since that would break the UnregisteredKmsDevice pattern.
    0400fb37
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add drm_crtc bindings · 45290373
    Lyude Paul authored
    
    This introduces basic bindings for DRM CRTCs which follow the same general
    pattern as connectors and planes (e.g. AsRawCrtc, AsRawCrtcState, etc.).
    There is one big difference though - drm_crtc_state appears to be the one
    atomic state that actually has data which can be mutated from outside of
    the atomic commit phase - which means we can't keep rust referencs to it,
    and instead need to use the Opaque type and implement things through
    pointers instead.
    
    This should be the last mode object we're introducing for the time being
    with its own atomic state. Note that we've not added bindings for private
    modesetting objects yet, but I don't think those will be needed for rvkms -
    and the same general patterns we're using here should work for adding
    private modesetting objects.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Add commit data in the future
    
    V3:
    * Add safety comments for ModeObject implementation
    * Make AsRawCrtc unsafe, as we need a guarantee that `as_raw()` will always
      return a pointer to a valid `drm_crtc`.
    * Update safety comments in atomic_duplicate_state_callback
    * Rename generics in Crtc::new to PrimaryData and CursorData
    * Add missing safety comment in Crtc::new()
    * Improve safety comments in AsRawCrtc
    * Break up the conversion from Pin<Box<Crtc>> to &Crtc a bit
    * Document why there's an UnsafeCell in CrtcState, because even I forgot
      the reason for this :).
    * Introduce UnregisteredCrtc type
    * Don't have AsRawCrtc be a supertrait of StaticModeObject. We don't want
      Unregistered mode object variants to be able to return a pointer to the
      DRM device since that would break the UnregisteredKmsDevice pattern.
    45290373
  • Lyude Paul's avatar
    rust: drm/kms: Add bindings for drm_encoder · 115c894d
    Lyude Paul authored
    
    The last thing we need to be able to register a KMS driver is the ability
    to create DRM encoders, so let's add bindings for that. Again, these
    bindings follow the same general pattern as CRTCs, planes, and connector
    with one difference: encoders don't have an atomic state.
    
    Note that not having an atomic state doesn't mean there aren't plenty of
    valid usecases for a driver to stick private data within a DRM encoder,
    hence why we reuse the aforementioned pattern.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Add safety comments for ModeObject implementation
    * Make AsRawEncoder unsafe so that we have a guarantee that `as_raw()`
      always returns a valid pointer.
    * Introduce UnregisteredEncoder type
    * Don't have AsRawEncoder be a supertrait of StaticModeObject. We don't want
      Unregistered mode object variants to be able to return a pointer to the
      DRM device since that would break the UnregisteredKmsDevice pattern.
    115c894d
  • Lyude Paul's avatar
    rust: drm/kms: Add UnregisteredConnector.attach_encoder() · 361e5bb3
    Lyude Paul authored
    
    This adds a simple binding for completing the last step of creating a DRM
    connector - attaching its encoder. This function should only be called
    before the connector is registered, and DRM should enforce this itself by
    returning an error if a driver tries to add an encoder to an
    already-registered DRM connector.
    
    Note that unlike most of the methods we'll be adding to DRM mode objects,
    this is directly implemented on the Connector<T> type since I don't really
    think it would make sense for us to allow this operation on an
    OpaqueConnector (a DRM connector without a known DriverConnector
    implementation, something we'll be adding in the next few commits).
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Move to UnregisteredConnector interface
    361e5bb3
  • Lyude Paul's avatar
    rust: drm/kms: Add DriverConnector::get_mode callback · 72a0b0b1
    Lyude Paul authored
    
    Next up is filling out some of the basic connector hotplugging callbacks -
    which we'll need for setting up the fbdev helpers for KMS devices. Note
    that connector hotplugging in DRM follows a BFL scheme: pretty much all
    probing is protected under the mighty drm_device->mode_config.lock, which
    of course is a bit counter-intuitive to rust's locking schemes where data
    is always associated with its lock.
    
    Since that lock is embedded in an FFI type and not a rust type, we need to
    introduce our own wrapper type that acts as a lock acquisition for this.
    This brings us to introducing a few new types:
    
    * ModeConfigGuard - the most basic lock guard, as long as this object is
      alive we are guaranteed to be holding drm_device->mode_config.lock. This
      object doesn't do much else on its own currently.
    * ConnectorGuard - an object which corresponds to a specific typed DRM
      connector. This can only be acquired with a ModeConfigGuard, and will be
      used to allow calling methods that are only safe to call with
      drm_device->mode_config.lock held. Since it implements
      Deref<Target=Connector<T>> as well, it can also be used for any other
      operations that would normally be available on a DRM connector.
    
    And finally, we add the DriverConnector::get_modes() trait method which
    drivers can use to implement the drm_connector_helper_funcs.get_modes
    callback. Note that while we make this trait method mandatory, we only do
    so for the time being since VKMS doesn't do very much with DRM connectors -
    and as such we have no need yet to implement alternative connector probing
    schemes outside of get_modes().
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    72a0b0b1
  • Lyude Paul's avatar
    rust: drm/kms: Add ConnectorGuard::add_modes_noedid() · 88e787b3
    Lyude Paul authored
    
    A simple binding for drm_add_modes_noedid() using the ConnectorGuard type
    we just added.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    88e787b3
  • Lyude Paul's avatar
    rust: drm/kms: Add ConnectorGuard::set_preferred_mode · 48f8f3e3
    Lyude Paul authored
    
    Add a wrapper for `drm_set_preferred_mode()` for our new
    `ConnectorGuard` type so we can set the preferred mode for RVKMS
    connectors.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    48f8f3e3
  • Lyude Paul's avatar
    rust: drm/kms: Add RawConnector and RawConnectorState · 841dc94d
    Lyude Paul authored
    
    Now that we have more then one way to refer to connectors, we also want to
    ensure that any methods which are common to any kind of connector type can
    be used on all connector representations. This is where RawConnector and
    RawConnectorState come in: we implement these traits for any type which
    implements AsRawConnector or AsRawConnectorState respectively.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    841dc94d
  • Lyude Paul's avatar
    rust: drm/kms: Add RawCrtc and RawCrtcState · a9b70b2b
    Lyude Paul authored
    
    Same thing as RawConnector and RawConnectorState, just for CRTCs now.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    a9b70b2b
  • Lyude Paul's avatar
    rust: drm/kms: Add RawPlane and RawPlaneState · bbde8f19
    Lyude Paul authored
    
    Same thing as RawCrtc and RawCrtcState, but for DRM planes now
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Limit unsafe scope in RawPlane::index()
    * Improve safety comments
    bbde8f19
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add OpaqueConnector and OpaqueConnectorState · 08e6c4e8
    Lyude Paul authored
    
    Since we allow drivers to have multiple implementations of DriverConnector
    and DriverConnectorState (in C, the equivalent of this is having multiple
    structs which embed drm_connector) - there are some situations we will run
    into where it's not possible for us to know the corresponding
    DriverConnector or DriverConnectorState for a given connector. The most
    obvious one is iterating through all connectors on a KMS device.
    
    So, take advantage of the various connector traits we added to introduce
    OpaqueConnector<> and OpaqueConnectorState<> which both can be used as a
    DRM connector and connector state respectively without needing to know the
    corresponding traits.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Add upcast functions for these types
    
    V3:
    * Add safety comment to implementation of ModeObject
    * Add safety comments to AsRawConnector implementation
    * Implement try_from_opaque() and from_opaque() using a macro
    * Ensure all Opaque types have the ability to "upcast"
    
    LYUDE NOTE:
    
    * We need to move the AsRaw* work before this now that we're actually using
      macros for generating all of the upcast functions, since we now rely on
      crtc(), plane(), etc. for the state functions to get their respective
      mode objects so we can check their vtables.
    * Start using a macro for implementing the conversions here, and introduce
      the ModesetObjectVtable function for using the macro
    08e6c4e8
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add OpaqueCrtc and OpaqueCrtcState · 85b66422
    Lyude Paul authored
    
    This is the same thing as OpaqueConnector and OpaqueConnectorState, but for
    CRTCs now.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Add upcast functions
    
    V3:
    * Add safety comment for implementation of ModeObject
    * Add safety comments to AsRawCrtc implementation
    * Implement try_from_opaque() and from_opaque() using a macro
    85b66422
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add OpaquePlane and OpaquePlaneState · e4724566
    Lyude Paul authored
    
    Same thing as OpaqueCrtc and OpaqueCrtcState, but for plane states now.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Finish adding upcast functions.
    
    V3:
    * Add safety comment to implementation of ModeObject
    * Add safety comments to implementation of AsRawPlane
    * Implement try_from_opaque() and from_opaque() using a macro
    * Add missing upcasts
    e4724566
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add OpaqueEncoder · 26928f26
    Lyude Paul authored
    
    Same thing as OpaquePlane, but for encoders now.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Add upcast functions for this
    
    V3:
    * Add safety comment to ModeObject implementation
    * Add safety comments for AsRawEncoder
    * Implement try_from_opaque() and from_opaque() using a macro
    26928f26
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add drm_atomic_state bindings · 553c6a9a
    Lyude Paul authored
    
    Next up is introducing bindings that we can use to represent the global DRM
    atomic state, along with all of the various object states contained within.
    We do this by introducing a few new concepts: borrowed states, atomic state
    mutators, and atomic state composers.
    
    To understand these, we need to quickly touch upon the general life of an
    atomic commit. Assuming a driver does its own internal atomic commit, the
    procedure looks something like this:
    
    * Allocate a new atomic state
    * Duplicate the atomic state of each mode object we want to mutate, and add
      the duplicated state to the new atomic state
    * Check (possibly more then once) the atomic state, possibly modifying it
      along the way
    * Commit the atomic state to software (we'll call this commit time). At
      this point no new objects can be added to the state
    * Finish committing the atomic state to hardware asynchronously
    
    With this in mind, we introduce AtomicStateMutator and AtomicStateComposer
    (along with leaky variants intended for uses in FFI calls). An
    AtomicStateMutator allows mutating an atomic state but does not allow for
    adding new objects to the state. Subsequently, an AtomicStateComposer
    allows for both mutating an atomic state and adding new mode objects. We
    control when we expose each of these types in order to implement the
    limitations required by the aforementioned example.
    
    Note as well that AtomicStateComposer is intended to eventually be usable
    directly by drivers. In this scenario, a driver will be able to create an
    AtomicStateComposer (the equivalent of allocating an atomic state in C) and
    then commit it by passing it to our DRM bindings by-value, insuring that
    once the commit process begins it is impossible to keep using the
    AtomicStateComposer.
    
    The next part of this is allowing users to modify the atomic states of all
    of the objects contained within an atomic state. Since it's an extremely
    common usecase for objects to mutate the atomic state of multiple objects
    at once in an unpredictable order, we need a mechanism that will allow us
    to hand out &mut references to each state while ensuring at runtime that we
    do not break rust's data aliasing rules (which disallow us from ever having
    more then one &mut reference to the same piece of data).
    
    We do this by introducing the concept of a "borrowed" state. This is a very
    similar concept to RefCell, where it is ensured during runtime that when a
    &mut reference is taken out another one cannot be created until the
    corresponding Ref object has been dropped. Our equivalent Ref types are
    BorrowedConnectorState, BorrowedCrtcState, and BorrowedPlaneState.
    
    Each one of these types can be used in the same manner as a Ref - no
    additional borrows for an atomic state may be taken until the existing one
    has been dropped. Subsequently, all of these types implement their
    respective AsRaw* and FromRaw* counter-parts - and allow dereferencing to
    each driver-private data structure for fully qualified borrows (like
    BorrowedCrtcState<'a, CrtcState<T>>. This allows a pretty clean way of
    mutating multiple states at once without ever breaking rust's mutability
    rules.
    
    We'll use all of these types over the next few commits to begin introducing
    various atomic modeset callbacks to each mode object type.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Drop the TODO about printing a kernel error in BorrowedConnectorState
      I thought this was something we'd want early on in designing this, but
      since then I'm pretty sure we just want to return None - there are valid
      cases where we'd get None while doing connector iteration through an
      atomic state
    * Improve safety comments in BorrowedConnectorState::new()
    * Rename Borrowed*State to *StateMutator
      I think this makes things a lot clearer, as well - cleanup the
      documentation regarding this.
    * Drop plane state iterator for now. It's not that we don't need this, it's
      just that I haven't actually finished writing these up for all types so
      I'd rather focus on that later now that we've demonstrated it's a thing
      that is possible. And it at least shouldn't be needed for getting these
      bindings/rvkms upstream.
    553c6a9a
  • Lyude Paul's avatar
    DROP THIS FROM SUBMIT: WIP: plane state iterator · dc8e5c82
    Lyude Paul authored
    We should submit these seperately since I'm trying to get rid of all of the
    WIPs here.
    dc8e5c82
  • Lyude Paul's avatar
    squash! WIP: rust: drm/kms: Add drm_atomic_state bindings · 0fd5ff30
    Lyude Paul authored
    * Drop num_plane() for the time being
      Without the plane state iterator in this patch series there's no current
      usecase for this, so just drop the function for the time being and we'll
      reintroduce it when it's ready.
    0fd5ff30
  • Lyude Paul's avatar
    820eb803
  • Lyude Paul's avatar
    rust: drm/kms: Introduce DriverCrtc::atomic_check() · 6990943c
    Lyude Paul authored
    
    An optional trait method for implementing a CRTC's atomic state check.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    V3:
    * Document uses of ManuallyDrop
    6990943c
  • Lyude Paul's avatar
    rust: drm/kms: Add DriverPlane::atomic_update() · f2fe8aca
    Lyude Paul authored
    
    A mandatory trait method used for implementing DRM's atomic plane update
    callback.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    f2fe8aca
  • Lyude Paul's avatar
    rust: drm/kms: Add DriverPlane::atomic_check() · dad41985
    Lyude Paul authored
    
    Optional trait method for implementing a plane's atomic_check().
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    V3:
    * Document ManuallyDrop uses better
    dad41985
  • Lyude Paul's avatar
    rust: drm/kms: Add RawCrtcState::active() · 877261dd
    Lyude Paul authored
    
    A binding for checking drm_crtc_state.active.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    877261dd
  • Lyude Paul's avatar
    rust: drm/kms: Add RawPlaneState::crtc() · a5fb73a8
    Lyude Paul authored
    
    Add a binding for checking drm_plane_state.crtc. Note that we don't have a
    way of knowing what DriverCrtc implementation would be used here (and want
    to make this function also available on OpaquePlaneState types), so we
    return an OpaqueCrtc.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    a5fb73a8
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add RawPlaneState::atomic_helper_check() · 2b4798ce
    Lyude Paul authored
    
    Add a binding for drm_atomic_helper_check_plane_state(). Since we want to
    make sure that the user is passing in the new state for a Crtc instead of
    an old state, we explicitly ask for a reference to a BorrowedCrtcState.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    * Add support for scaling options
    2b4798ce
  • Lyude Paul's avatar
    rust: drm/kms: Add drm_framebuffer bindings · 3b1193e7
    Lyude Paul authored
    
    This adds some very simple bindings for drm_framebuffer. We don't use them
    much yet, but we'll eventually be using them when rvkms eventually gets CRC
    and writeback support. Just like Connector objects, these use RcModeObject.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    V3:
    * Replace Framebuffer struct with tuple
    * Add safety comments for ModeObject implementation
    * Add comment for why we're using Sealed
    3b1193e7
  • Lyude Paul's avatar
    rust: drm/kms: Add RawPlane::framebuffer() · 21ff5426
    Lyude Paul authored
    
    Returns the Framebuffer currently assigned in an atomic plane state.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    21ff5426
  • Lyude Paul's avatar
    rust: drm/kms: Add DriverCrtc::atomic_begin() and atomic_flush() · 062138e6
    Lyude Paul authored
    
    Optional trait methods for implementing the atomic_begin and atomic_flush
    callbacks for a CRTC.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    062138e6
  • Lyude Paul's avatar
    rust: drm/kms: Add DriverCrtc::atomic_enable() and atomic_disable() · a86f9461
    Lyude Paul authored
    
    Optional trait methods for implementing the atomic_enable and
    atomic_disable callbacks of a CRTC.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    a86f9461
  • Lyude Paul's avatar
    rust: drm: Add Device::event_lock() · b784f9b9
    Lyude Paul authored
    
    This is just a crate-private helper to use Lock::from_raw() to provide an
    immutable reference to the DRM event_lock, so that it can be used like a
    normal rust spinlock. We'll need this for adding vblank related bindings.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    b784f9b9
  • Lyude Paul's avatar
    rust: drm/kms: Add Device::num_crtcs() · 02fbae62
    Lyude Paul authored
    
    A binding for checking drm_device.num_crtcs. We'll need this in a moment
    for vblank support, since setting it up requires knowing the number of
    CRTCs that a driver has initialized.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    02fbae62
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add VblankSupport · dc5cc718
    Lyude Paul authored
    
    This commit adds bindings for implementing vblank support for a driver's
    CRTCs. These bindings are optional, to account for the fact that not all
    drivers have dedicated hardware vblanks.
    
    In order to accomplish this, we introduce the VblankSupport trait which can
    be implemented on DriverCrtc by drivers which support vblanks. This works
    in the same way as the main Kms trait - drivers which don't support
    hardware vblanks can simply pass PhantomData<Self> to the associated type
    on DriverCrtc. If a driver chooses to implement VblankSupport, VblankImpl
    will be implemented by DRM automatically - and can be passed to the
    VblankImpl associated type on DriverCrtc.
    
    Additionally, we gate methods which only apply to vblank-supporting drivers
    by introducing a VblankDriverCrtc trait that is automatically implemented
    by DRM for CRTC drivers implementing VblankSupport. This works basically in
    the same way as Kms and KmsDriver, but for CRTCs.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    Notes:
    
    * One thing to keep in mind: this trait is implemented on the CRTC as
      opposed to the KMS driver due to the possibility that a driver may have
      multiple different types of CRTCs. As a result, it's not impossible that
      there could potentially be differences in each type's vblank hardware
      implementation. In theory this could lead to a driver mistakenly only
      implementing VblankSupport for some CRTCs and not others, which isn't
      really defined behavior in DRM. As such, one of the dependencies in the
      branch for this patch series preview is a fix to ensure that DRM
      disallows registering drivers that make this mistake.
    
    V3:
    * Update to the latest SpinlockIrq changes
    * Fix typo on get_vblank_timestamp()
    * Break statements in vblank_crtc() up a bit
    * Add comments around all uses of ManuallyDrop
    * Improve SAFETY comments
    * Make some unsafe scopes smaller
    dc5cc718
  • Lyude Paul's avatar
    WIP: rust: drm/kms: Add Kms::atomic_commit_tail · 43548dcb
    Lyude Paul authored
    
    A quick note: this is one of my favorite bindings so far :). It sounds way
    overly complicated, but so far actually writing implementations of this in
    rust has been a breeze.
    
    Anyway: RVKMS has a slightly different atomic_commit_tail than normal,
    which means we need to write up some bindings for atomic_commit_tail. This
    is a lot more interesting then it might seem on the surface as implementing
    atomic_commit_tail incorrectly could result in UB. And in general, DRM has
    up until now relied entirely on the programmer to do this correctly through
    implicit ordering requirements.
    
    In the universe of rust though, we want no UB at all! To ensure this, we
    need to make sure that all atomic commit callbacks follow all of these
    requirements:
    
    * Disable/enable modeset commits must happen exactly once
    * A disable modeset must be committed for a resource before an enable
      modeset may be committed for a resource
    * Plane updates must happen exactly once
    * drm_atomic_commit_hw_done() must be called exactly once, and only after
      all commits have been completed.
    * The state may not be mutated after drm_atomic_commit_hw_done() is called
    * Access to the prior atomic states are revoked after
      drm_atomic_commit_hw_done() is called (and our "new" states become "old"
      states)
    
    To handle this, we introduce a number of new objects and types:
    tokens:
    
    * AtomicCommitTail
      Main object for controlling the commit_tail process
      * ModesetsReadyToken
        A single use token indicating that no modesets have been committed with
        the AtomicCommitTail yet
      * commit_modeset_disables() -> DisablesCommittedToken
        This function consumes the ModesetsReadyToken, commits modeset
        disables, and then returns a DisablesCommittedToken
      * commit_modeset_enables() -> EnablesCommittedToken
        This function consumes a DisablesCommittedToken, commits modeset
        enables, and then returns a EnablesCommittedToken
        EnablesCommittedToken - enforcing the disables -> enables order.
      * commit_planes() -> PlaneUpdatesCommittedToken
        Consumes a PlaneUpdatesReadyToken and returns a
        PlaneUpdatesCommittedToken.
      * commit_hw_done() -> CommittedAtomicState
        Revokes access to the AtomicCommitTailObject, and consumes both the
        EnablesCommittedToken and PlaneUpdatesCommitted tokens. This ensures
        that all modesets and plane updates have occurred exactly once.
    * CommittedAtomicState - main object for controlling the atomic_commit_tail
      after the state has been swapped in. This must be returned from the
      atomic_commit_tail function to prove that all of the required commits
      have occurred.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    
    TODO:
    
    * Currently this solution wouldn't be sufficient for drivers that need
      precise control over the order of each individual modeset or plane
      update. However, this should be very easy to add.
    * Figure out something better for enforcing the plane cleanup then what we
      have right now (e.g. cleaning up planes in the destructor for
      CommittedAtomicState).
    * Add iterator functions that take mutable references to the atomic state
      objects here. This will prevent functions like commit_modeset_disables()
      from being called while a state borrow is taken out, while still allowing
      easy access to the contents of the atomic state at any portion of the
      atomic commit tail.
    * Actually add some macros for generating bitmasks like we do with
      PlaneCommitFlags - right now we just do this by hand.
    43548dcb
  • Lyude Paul's avatar
    WIP: drm: Introduce RVKMS! · f121122a
    Lyude Paul authored
    
    Now that we've added all of the bits that we need for the KMS API, it's
    time to introduce rvkms! This is a port of the VKMS driver to rust, with
    the intent of acting as an example usecase of the KMS bindings that we've
    come up with so far in preparation for writing a display driver for nova.
    
    Currently RVKMS is an extremely bear bones driver - it only registers a
    device and emulates vblanking, but it exercises a good portion of the API
    that we've introduced so far! Eventually I hope to introduce CRC generation
    and maybe writeback connectors like.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    
    ---
    V3:
    * Replace platform device usage with faux device
    f121122a
  • Lyude Paul's avatar
    rust: sync: Add MutexGuard type alias · 0e6e86ac
    Lyude Paul authored
    
    A simple helper alias for code that needs to deal with Guard types returned
    from Mutexes.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    0e6e86ac
  • Lyude Paul's avatar
    rust: sync: Add SpinLockGuard type alias · a47a10f8
    Lyude Paul authored
    
    A simple helper alias for code that needs to deal with Guard types returned
    from SpinLocks.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    a47a10f8
  • Lyude Paul's avatar
    DROP EVENTUALLY: rust: sync: Add SpinLockIrqGuard type alias · a819edaf
    Lyude Paul authored
    
    same for irq spinlocks. This will get dropped in the future since it's no
    longer the solution that we're going to be going for upstream, but it is
    taking forever for simple patches to be merged :(.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    a819edaf
  • Lyude Paul's avatar
    HACKHACKHACK: workaround hrtimer break · b0f4bd15
    Lyude Paul authored
    gotta poke andreas about this one! looks like we forgot to actually expose
    this type
    b0f4bd15
  • Lyude Paul's avatar
    rust: drm: Add Driver::AllocImpl<Driver = Self> bound · 19053f50
    Lyude Paul authored
    
    We're going to be calling some methods from AllocImpl directly in
    Registration::new() - which means that the rust compiler needs to know that
    our associated AllocImpl trait uses us as a Driver trait. Otherwise, it'll
    complain about a missing trait bound.
    
    The simplest way to do this is to just add this as a trait bound for the
    associated Driver::Object trait.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    19053f50
  • Lyude Paul's avatar
  • Lyude Paul's avatar
  • Lyude Paul's avatar
  • Lyude Paul's avatar
  • Lyude Paul's avatar
    drm/connector: Add _DRM_MODE_CONNECTOR_COUNT · fd862ed0
    Lyude Paul authored
    
    In order to add rust bindings for the various DRM_MODE_CONNECTOR_* type
    IDs, we need a way to know the range of defined connector types - since
    each type corresponds to an actual array entry in drm_connector_enum_list.
    
    So, let's make this easy to figure out by adding a new
    _DRM_MODE_CONNECTOR_COUNT macro that always matches the number of available
    connector type IDs. Also, use that macro to define the size of
    drm_connector_enum_list to ensure that builds fail if someone attempts to
    add a new entry to drm_connector_enum_list without updating this macro.
    
    Signed-off-by: Lyude Paul's avatarLyude Paul <lyude@redhat.com>
    fd862ed0
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add bindings for drm_connector · bc39d605
    Lyude Paul authored
    * Introduce an actual enum for connector types
      I realized we actually could do this fairly easy by using
      #[non_exhaustive], which should future-proof us against new connector
      types being added someday (if that ever happens).
    bc39d605
  • Lyude Paul's avatar
    e39f6a06
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add bindings for drm_encoder · b56fdbe3
    Lyude Paul authored
    * Turn all of the encoder type IDs into an enum using a new macro
    b56fdbe3
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add UnregisteredConnector.attach_encoder() · da632c81
    Lyude Paul authored
    * Improve safety comments
    da632c81
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add DriverConnector::get_mode callback · 03998fa7
    Lyude Paul authored
    * Document uses of ManuallyDrop
    03998fa7
  • Lyude Paul's avatar
    69eb49fd
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add bindings for drm_connector · 8d71a2a8
    Lyude Paul authored
    * Use addr_of_mut! for accessing fields we were using &mut for.
      I think this is correct after going through some other rfl work?
    8d71a2a8
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add drm_plane bindings · 2c6b9133
    Lyude Paul authored
    * Change name of PlaneType to Type (for consistency with the other type IDs
      we've adde)
    2c6b9133
  • Lyude Paul's avatar
    fixup! rust: drm/kms: Add drm_plane bindings · 2a4467cc
    Lyude Paul authored
    2a4467cc
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add drm_plane bindings · 33e69870
    Lyude Paul authored
    * Use addr_of_mut! in more places instead of &mut
    33e69870
  • Lyude Paul's avatar
    squash! WIP: rust: drm/kms: Add OpaquePlane and OpaquePlaneState · 2e2eb3f9
    Lyude Paul authored
    * Use addr_of_mut!() instead of &mut
    2e2eb3f9
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add DriverConnector::get_mode callback · 0ce0ea84
    Lyude Paul authored
    * Use addr_of_mut!() instead of &mut
    0ce0ea84
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add DriverConnector::get_mode callback · 668830c6
    Lyude Paul authored
    * Add some missing invariant comments
    668830c6
  • Lyude Paul's avatar
  • Lyude Paul's avatar
    squash! rust: drm/kms: Add bindings for drm_encoder · 00617866
    Lyude Paul authored
    * Use addr_of_mut!() instead of &mut for accessing C struct fields
    00617866
  • Lyude Paul's avatar
    aee25c37
  • Lyude Paul's avatar
    fixup! WIP: rust: drm/kms: Add VblankSupport · 80499930
    Lyude Paul authored
    80499930
  • Lyude Paul's avatar
    fixup! WIP: rust: drm/kms: Add VblankSupport · 4c5e3b07
    Lyude Paul authored
    4c5e3b07
  • Lyude Paul's avatar
    fixup! WIP: drm: Introduce RVKMS! · 4a64d74f
    Lyude Paul authored
    4a64d74f
  • Lyude Paul's avatar
    e56deb72
  • Lyude Paul's avatar
    563fa74b
  • Lyude Paul's avatar
  • Lyude Paul's avatar
    fixup! WIP: rust: drm/kms: Add VblankSupport · a11dfb51
    Lyude Paul authored
    a11dfb51
  • Lyude Paul's avatar
    fixup! WIP: rust: drm/kms: Add VblankSupport · c7f2b69e
    Lyude Paul authored
    c7f2b69e
  • Lyude Paul's avatar
    fixup! WIP: rust: drm/kms: Add VblankSupport · 7738c42b
    Lyude Paul authored
    7738c42b
Showing
with 923 additions and 5 deletions
......@@ -41,6 +41,12 @@ Device Drivers Base
.. kernel-doc:: drivers/base/class.c
:export:
.. kernel-doc:: include/linux/device/faux.h
:internal:
.. kernel-doc:: drivers/base/faux.c
:export:
.. kernel-doc:: drivers/base/node.c
:internal:
......
......@@ -6985,8 +6985,10 @@ F: rust/kernel/device.rs
F: rust/kernel/device_id.rs
F: rust/kernel/devres.rs
F: rust/kernel/driver.rs
F: rust/kernel/faux.rs
F: rust/kernel/platform.rs
F: samples/rust/rust_driver_platform.rs
F: samples/rust/rust_driver_faux.rs
 
DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS)
M: Nishanth Menon <nm@ti.com>
......
......@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
topology.o container.o property.o cacheinfo.o \
swnode.o
swnode.o faux.o
obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/
......
......@@ -137,6 +137,7 @@ int hypervisor_init(void);
static inline int hypervisor_init(void) { return 0; }
#endif
int platform_bus_init(void);
int faux_bus_init(void);
void cpu_dev_init(void);
void container_dev_init(void);
#ifdef CONFIG_AUXILIARY_BUS
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* Copyright (c) 2025 The Linux Foundation
*
* A "simple" faux bus that allows devices to be created and added
* automatically to it. This is to be used whenever you need to create a
* device that is not associated with any "real" system resources, and do
* not want to have to deal with a bus/driver binding logic. It is
* intended to be very simple, with only a create and a destroy function
* available.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/container_of.h>
#include <linux/device/faux.h>
#include "base.h"
/*
* Internal wrapper structure so we can hold a pointer to the
* faux_device_ops for this device.
*/
struct faux_object {
struct faux_device faux_dev;
const struct faux_device_ops *faux_ops;
};
#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev)
static struct device faux_bus_root = {
.init_name = "faux",
};
static int faux_match(struct device *dev, const struct device_driver *drv)
{
/* Match always succeeds, we only have one driver */
return 1;
}
static int faux_probe(struct device *dev)
{
struct faux_object *faux_obj = to_faux_object(dev);
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
int ret = 0;
if (faux_ops && faux_ops->probe)
ret = faux_ops->probe(faux_dev);
return ret;
}
static void faux_remove(struct device *dev)
{
struct faux_object *faux_obj = to_faux_object(dev);
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
if (faux_ops && faux_ops->remove)
faux_ops->remove(faux_dev);
}
static const struct bus_type faux_bus_type = {
.name = "faux",
.match = faux_match,
.probe = faux_probe,
.remove = faux_remove,
};
static struct device_driver faux_driver = {
.name = "faux_driver",
.bus = &faux_bus_type,
.probe_type = PROBE_FORCE_SYNCHRONOUS,
};
static void faux_device_release(struct device *dev)
{
struct faux_object *faux_obj = to_faux_object(dev);
kfree(faux_obj);
}
/**
* faux_device_create_with_groups - Create and register with the driver
* core a faux device and populate the device with an initial
* set of sysfs attributes.
* @name: The name of the device we are adding, must be unique for
* all faux devices.
* @parent: Pointer to a potential parent struct device. If set to
* NULL, the device will be created in the "root" of the faux
* device tree in sysfs.
* @faux_ops: struct faux_device_ops that the new device will call back
* into, can be NULL.
* @groups: The set of sysfs attributes that will be created for this
* device when it is registered with the driver core.
*
* Create a new faux device and register it in the driver core properly.
* If present, callbacks in @faux_ops will be called with the device that
* for the caller to do something with at the proper time given the
* device's lifecycle.
*
* Note, when this function is called, the functions specified in struct
* faux_ops can be called before the function returns, so be prepared for
* everything to be properly initialized before that point in time.
*
* Return:
* * NULL if an error happened with creating the device
* * pointer to a valid struct faux_device that is registered with sysfs
*/
struct faux_device *faux_device_create_with_groups(const char *name,
struct device *parent,
const struct faux_device_ops *faux_ops,
const struct attribute_group **groups)
{
struct faux_object *faux_obj;
struct faux_device *faux_dev;
struct device *dev;
int ret;
faux_obj = kzalloc(sizeof(*faux_obj), GFP_KERNEL);
if (!faux_obj)
return NULL;
/* Save off the callbacks so we can use them in the future */
faux_obj->faux_ops = faux_ops;
/* Initialize the device portion and register it with the driver core */
faux_dev = &faux_obj->faux_dev;
dev = &faux_dev->dev;
device_initialize(dev);
dev->release = faux_device_release;
if (parent)
dev->parent = parent;
else
dev->parent = &faux_bus_root;
dev->bus = &faux_bus_type;
dev->groups = groups;
dev_set_name(dev, "%s", name);
ret = device_add(dev);
if (ret) {
pr_err("%s: device_add for faux device '%s' failed with %d\n",
__func__, name, ret);
put_device(dev);
return NULL;
}
return faux_dev;
}
EXPORT_SYMBOL_GPL(faux_device_create_with_groups);
/**
* faux_device_create - create and register with the driver core a faux device
* @name: The name of the device we are adding, must be unique for all
* faux devices.
* @parent: Pointer to a potential parent struct device. If set to
* NULL, the device will be created in the "root" of the faux
* device tree in sysfs.
* @faux_ops: struct faux_device_ops that the new device will call back
* into, can be NULL.
*
* Create a new faux device and register it in the driver core properly.
* If present, callbacks in @faux_ops will be called with the device that
* for the caller to do something with at the proper time given the
* device's lifecycle.
*
* Note, when this function is called, the functions specified in struct
* faux_ops can be called before the function returns, so be prepared for
* everything to be properly initialized before that point in time.
*
* Return:
* * NULL if an error happened with creating the device
* * pointer to a valid struct faux_device that is registered with sysfs
*/
struct faux_device *faux_device_create(const char *name,
struct device *parent,
const struct faux_device_ops *faux_ops)
{
return faux_device_create_with_groups(name, parent, faux_ops, NULL);
}
EXPORT_SYMBOL_GPL(faux_device_create);
/**
* faux_device_destroy - destroy a faux device
* @faux_dev: faux device to destroy
*
* Unregisters and cleans up a device that was created with a call to
* faux_device_create()
*/
void faux_device_destroy(struct faux_device *faux_dev)
{
struct device *dev = &faux_dev->dev;
if (!faux_dev)
return;
device_del(dev);
/* The final put_device() will clean up the memory we allocated for this device. */
put_device(dev);
}
EXPORT_SYMBOL_GPL(faux_device_destroy);
int __init faux_bus_init(void)
{
int ret;
ret = device_register(&faux_bus_root);
if (ret) {
put_device(&faux_bus_root);
return ret;
}
ret = bus_register(&faux_bus_type);
if (ret)
goto error_bus;
ret = driver_register(&faux_driver);
if (ret)
goto error_driver;
return ret;
error_driver:
bus_unregister(&faux_bus_type);
error_bus:
device_unregister(&faux_bus_root);
return ret;
}
......@@ -32,6 +32,7 @@ void __init driver_init(void)
/* These are also core pieces, but must come after the
* core core pieces.
*/
faux_bus_init();
of_core_init();
platform_bus_init();
auxiliary_bus_init();
......
......@@ -354,6 +354,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
source "drivers/gpu/drm/nouveau/Kconfig"
source "drivers/gpu/drm/rvkms/Kconfig"
source "drivers/gpu/drm/i915/Kconfig"
source "drivers/gpu/drm/xe/Kconfig"
......
......@@ -172,6 +172,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
obj-$(CONFIG_DRM_VGEM) += vgem/
obj-$(CONFIG_DRM_VKMS) += vkms/
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
obj-$(CONFIG_DRM_RVKMS) += rvkms/
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
obj-$(CONFIG_DRM_GMA500) += gma500/
......
......@@ -88,7 +88,7 @@ struct drm_conn_prop_enum_list {
/*
* Connector and encoder types.
*/
static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
static struct drm_conn_prop_enum_list drm_connector_enum_list[_DRM_MODE_CONNECTOR_COUNT] = {
{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
......
......@@ -509,7 +509,7 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
......@@ -538,8 +538,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
return ret;
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_fault);
static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
......@@ -560,8 +561,9 @@ static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
drm_gem_vm_open(vma);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_open);
static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
......@@ -572,6 +574,7 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
drm_gem_vm_close(vma);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_close);
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
.fault = drm_gem_shmem_fault,
......
config DRM_RVKMS
tristate "Rust VKMS PoC driver (EXPERIMENTAL)"
depends on RUST && DRM && DRM_GEM_SHMEM_HELPER=y
obj-$(CONFIG_DRM_RVKMS) += rvkms.o
// SPDX-License-Identifier: GPL-2.0
use super::{RvkmsDriver, RvkmsDevice, MAX_RES, DEFAULT_RES};
use kernel::{
prelude::*,
drm::{
device::Device,
kms::{
connector::{self, ConnectorGuard, DriverConnectorOps},
ModeConfigGuard
}
},
prelude::*
};
use core::marker::PhantomPinned;
#[pin_data]
pub(crate) struct DriverConnector {
#[pin]
_p: PhantomPinned
}
pub(crate) type Connector = connector::Connector<DriverConnector>;
pub(crate) type UnregisteredConnector = connector::UnregisteredConnector<DriverConnector>;
#[vtable]
impl connector::DriverConnector for DriverConnector {
#[unique]
const OPS: &'static DriverConnectorOps;
type State = ConnectorState;
type Driver = RvkmsDriver;
type Args = ();
fn new(dev: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
try_pin_init!(Self { _p: PhantomPinned })
}
fn get_modes(
connector: ConnectorGuard<'_, Self>,
_guard: &ModeConfigGuard<'_, Self::Driver>
) -> i32 {
let count = connector.add_modes_noedid(MAX_RES);
connector.set_preferred_mode(DEFAULT_RES);
count
}
}
#[derive(Clone, Default)]
pub(crate) struct ConnectorState;
impl connector::DriverConnectorState for ConnectorState {
type Connector = DriverConnector;
}
// TODO: License and stuff
// Contain's rvkms's drm_crtc implementation
use core::marker::*;
use super::{RvkmsDriver, plane::*};
use kernel::{
prelude::*,
drm::{
device::Device,
kms::{
atomic::*,
crtc::{self, RawCrtcState, DriverCrtcOps},
ModeObject,
KmsRef,
vblank::*,
}
},
sync::{
lock::Guard,
SpinLockIrq,
LockedBy,
},
hrtimer::*,
time::*,
local_irq::*,
sync::{Arc, ArcBorrow},
new_spinlock_irq,
impl_has_timer
};
pub(crate) type Crtc = crtc::Crtc<RvkmsCrtc>;
pub(crate) type UnregisteredCrtc = crtc::UnregisteredCrtc<RvkmsCrtc>;
pub(crate) type CrtcState = crtc::CrtcState<RvkmsCrtcState>;
#[derive(Default)]
pub(crate) struct VblankState {
/// A reference to the current VblankTimer
timer: Option<Arc<VblankTimer>>,
/// A reference to a handle for the current VblankTimer
handle: Option<ArcTimerHandle<VblankTimer>>,
/// The current frame duration in ns
///
/// Stored separately here so it can be read safely without the vblank lock
period_ns: i32,
}
#[pin_data]
pub(crate) struct RvkmsCrtc {
/// The current vblank emulation state
///
/// This is uninitalized when the CRTC is disabled to prevent circular references
#[pin]
vblank_state: SpinLockIrq<VblankState>
}
#[vtable]
impl crtc::DriverCrtc for RvkmsCrtc {
#[unique]
const OPS: &'static DriverCrtcOps;
type Args = ();
type State = RvkmsCrtcState;
type Driver = RvkmsDriver;
type VblankImpl = Self;
fn new(device: &Device<Self::Driver>, args: &Self::Args) -> impl PinInit<Self, Error> {
try_pin_init!(Self {
vblank_state <- new_spinlock_irq!(VblankState::default(), "vblank_handle_lock")
})
}
fn atomic_check(
crtc: &Crtc,
old_state: &CrtcState,
mut new_state: crtc::CrtcStateMutator<'_, CrtcState>,
state: &AtomicStateComposer<Self::Driver>
) -> Result {
state.add_affected_planes(crtc)?;
// Create a vblank timer when enabling a CRTC, and destroy said timer when disabling to
// resolve the circular reference to CRTC it creates
if old_state.active() != new_state.active() {
new_state.vblank_timer = if new_state.active() {
Some(VblankTimer::new(crtc)?)
} else {
None
};
}
Ok(())
}
fn atomic_flush(
crtc: &Crtc,
_old_state: &CrtcState,
mut new_state: crtc::CrtcStateMutator<'_, CrtcState>,
_state: &AtomicStateMutator<Self::Driver>
) {
if let Some(event) = new_state.get_pending_vblank_event() {
if let Ok(vbl_ref) = crtc.vblank_get() {
event.arm(vbl_ref);
} else {
event.send();
}
}
}
fn atomic_enable(
crtc: &Crtc,
old_state: &CrtcState,
new_state: crtc::CrtcStateMutator<'_, CrtcState>,
_state: &AtomicStateMutator<Self::Driver>
) {
crtc.vblank_state.lock_with_new(|state, _| {
// Store a reference to the newly created vblank timer for this CRTC
state.timer = new_state.vblank_timer.clone()
});
crtc.vblank_on();
}
fn atomic_disable(
crtc: &Crtc,
_old_state: &CrtcState,
_new_state: crtc::CrtcStateMutator<'_, CrtcState>,
_state: &AtomicStateMutator<Self::Driver>
) {
crtc.vblank_off();
// Since we just explicitly disabled vblanks, destroy the vblank state to resolve circular
// reference to this CRTC that it holds. Note that dropping the handle will cause us to wait
// for the timer to finish, so we return it from with_irqs_disabled so that it is only
// dropped once the vblank_state lock has been released
drop(crtc.vblank_state.lock_with_new(|mut state, _| {
(state.timer.take(), state.handle.take())
}));
}
}
impl VblankSupport for RvkmsCrtc {
type Crtc = Self;
fn enable_vblank(
crtc: &Crtc,
vblank: &VblankGuard<'_, Self::Crtc>,
irq: IrqDisabled<'_>,
) -> Result {
let period_ns = vblank.frame_duration();
let mut vbl_state = crtc.vblank_state.lock_with(irq);
if let Some(timer) = vbl_state.timer.clone() {
vbl_state.period_ns = period_ns;
vbl_state.handle = Some(timer.start(Ktime::from_raw(period_ns as _)));
}
Ok(())
}
fn disable_vblank(crtc: &Crtc, _vbl_guard: &VblankGuard<'_, Self::Crtc>, irq: IrqDisabled<'_>) {
let handle = crtc.vblank_state.lock_with(irq).handle.take();
// Now that we're outside of the vblank lock, we can safely drop the handle
drop(handle);
}
fn get_vblank_timestamp(crtc: &Crtc, _handling_vblank_irq: bool) -> Option<VblankTimestamp> {
let time = crtc.vblank_state.lock_with_new(|state, _| {
// Return the expiration of our vblank timer if we have one (if not, vblanks are
// disabled)
state.timer.as_ref().map(|t| {
// To prevent races, we roll the hrtimer forward before we do any interrupt
// processing - this is how real hw works (the interrupt is only generated after all
// the vblank registers are updated) and what the vblank core expects. Therefore we
// need to always correct the timestamps by one frame.
t.timer.expires() - Ktime::from_ns(state.period_ns)
})
});
Some(VblankTimestamp {
// …otherwise, just use the current time
time: time.unwrap_or_else(|| Ktime::ktime_get()),
max_error: 0
})
}
}
#[derive(Clone, Default)]
pub(crate) struct RvkmsCrtcState {
vblank_timer: Option<Arc<VblankTimer>>
}
impl crtc::DriverCrtcState for RvkmsCrtcState {
type Crtc = RvkmsCrtc;
}
/// The main hrtimer structure for emulating vblanks.
#[pin_data]
pub(crate) struct VblankTimer {
/// The actual hrtimer used for sending out vblanks
#[pin]
timer: Timer<Self>,
/// An owned reference to the CRTC that this [`VblankTimer`] belongs to
crtc: KmsRef<Crtc>,
}
impl_has_timer! {
impl HasTimer<Self> for VblankTimer { self.timer }
}
impl VblankTimer {
pub(crate) fn new(crtc: &Crtc) -> Result<Arc<Self>> {
Arc::pin_init(
pin_init!(Self {
timer <- Timer::<Self>::new(TimerMode::Relative, ClockSource::Monotonic),
crtc: crtc.into(),
}),
GFP_KERNEL
)
}
}
impl TimerCallback for VblankTimer {
type CallbackTarget<'a> = Arc<Self>;
type CallbackTargetParameter<'a> = ArcBorrow<'a, Self>;
fn run<T>(
this: Self::CallbackTargetParameter<'_>,
context: TimerCallbackContext<'_, T>
) -> TimerRestart
where
Self: Sized
{
let period_ns = this.crtc.vblank_state.lock_with_new(|guard, _| guard.period_ns);
let overrun = context.forward_now(Ktime::from_ns(period_ns));
if overrun != 1 {
dev_warn!(
this.crtc.drm_dev().as_ref(),
"vblank timer overrun (expected 1, got {overrun})\n"
);
}
this.crtc.handle_vblank();
TimerRestart::Restart
}
}
// SPDX-License-Identifier: GPL-2.0
use core::marker::PhantomPinned;
use kernel::{
drm::{device::Device, kms::encoder},
prelude::*,
};
use crate::RvkmsDriver;
#[pin_data]
pub(crate) struct DriverEncoder {
#[pin]
_p: PhantomPinned,
}
pub(crate) type Encoder = encoder::Encoder<DriverEncoder>;
pub(crate) type UnregisteredEncoder = encoder::UnregisteredEncoder<DriverEncoder>;
#[vtable]
impl encoder::DriverEncoder for DriverEncoder {
#[unique]
const OPS: &'static encoder::DriverEncoderOps;
type Driver = RvkmsDriver;
type Args = ();
fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
try_pin_init!(Self { _p: PhantomPinned })
}
}
use super::RvkmsDriver;
use kernel::{
alloc::*,
drm::{
self,
device::Device as DrmDevice
},
prelude::*,
};
use core::option::*;
pub(crate) struct File;
impl drm::file::DriverFile for File {
type Driver = RvkmsDriver;
fn open(device: &DrmDevice<Self::Driver>) -> Result<Pin<KBox<Self>>> {
pr_info!("Someone opened a file! But I do not yet know which one...\n");
Box::pin_init(init!(File { }), GFP_KERNEL)
}
}
use crate::{RvkmsDriver, RvkmsDevice};
use core::sync::atomic::{AtomicU64, Ordering};
use kernel::{
drm::{self, gem},
prelude::*,
};
static GEM_ID: AtomicU64 = AtomicU64::new(0);
/// GEM Object implementation
#[pin_data]
pub(crate) struct DriverObject {
/// ID for debugging
id: u64,
}
pub(crate) type Object = gem::shmem::Object<DriverObject>;
impl gem::BaseDriverObject<Object> for DriverObject {
fn new(dev: &RvkmsDevice, size: usize) -> impl PinInit<Self, Error> {
let id = GEM_ID.fetch_add(1, Ordering::Relaxed);
pr_debug!("DriverObject::new id={id}\n");
DriverObject { id }
}
}
impl gem::shmem::DriverObject for DriverObject {
type Driver = RvkmsDriver;
}
// SPDX-License-Identifier: GPL-2.0
use crate::{
crtc::UnregisteredCrtc,
plane::UnregisteredPlane,
connector::UnregisteredConnector,
encoder::UnregisteredEncoder,
RvkmsDevice,
RvkmsDriver
};
use kernel::{
drm::{
fourcc::*,
kms::{
connector,
encoder,
plane,
framebuffer::*,
UnregisteredKmsDevice,
},
},
sync::Arc,
prelude::*,
types::ARef,
};
pub(crate) fn create_output(dev: &UnregisteredKmsDevice<'_, RvkmsDriver>, index: u8) -> Result {
let possible_crtcs = 1 << index;
let primary = UnregisteredPlane::new(
dev,
possible_crtcs,
&[XRGB888],
None,
plane::Type::Primary,
None,
()
)?;
let crtc = UnregisteredCrtc::new(dev, primary, Option::<&UnregisteredPlane>::None, None, ())?;
let connector = UnregisteredConnector::new(dev, connector::Type::Virtual, ())?;
let encoder = UnregisteredEncoder::new(
dev,
encoder::Type::Virtual,
possible_crtcs,
0,
None,
()
)?;
connector.attach_encoder(encoder)
}
// SPDX-License-Identifier: GPL-2.0
use core::marker::PhantomPinned;
use super::{RvkmsDriver, crtc::{RvkmsCrtc, Crtc}};
use kernel::{
prelude::*,
drm::{
device::Device,
kms::{
atomic::*,
plane::{
self,
AsRawPlaneState,
FromRawPlaneState,
DriverPlaneState,
RawPlane,
RawPlaneState,
PlaneStateMutator,
DriverPlaneOps,
},
ModeObject
}
},
};
#[pin_data]
pub(crate) struct RvkmsPlane {
#[pin]
_p: PhantomPinned,
}
pub(crate) type Plane = plane::Plane<RvkmsPlane>;
pub(crate) type UnregisteredPlane = plane::UnregisteredPlane<RvkmsPlane>;
pub(crate) type PlaneState = plane::PlaneState<RvkmsPlaneState>;
#[vtable]
impl plane::DriverPlane for RvkmsPlane {
#[unique]
const OPS: &'static DriverPlaneOps;
type State = RvkmsPlaneState;
type Driver = RvkmsDriver;
type Args = ();
fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
try_pin_init!(Self { _p: PhantomPinned })
}
fn atomic_check(
plane: &Plane,
mut new_state: PlaneStateMutator<'_, PlaneState>,
_old_state: &PlaneState,
state: &AtomicStateComposer<Self::Driver>
) -> Result {
if new_state.framebuffer().is_none() {
return Ok(());
}
if let Some(crtc) = new_state.crtc() {
let crtc_state = state.add_crtc_state(crtc)?;
new_state.atomic_helper_check(&crtc_state, true, true)
} else {
// TODO: We should be printing a warning here if we have no CRTC but do have an fb
return Ok(());
}
}
fn atomic_update(
_plane: &Plane,
_new_state: PlaneStateMutator<'_, PlaneState>,
_old_state: &PlaneState,
_state: &AtomicStateMutator<Self::Driver>,
) {
// TODO, no-op for now
}
}
#[derive(Clone, Default)]
pub(crate) struct RvkmsPlaneState;
impl DriverPlaneState for RvkmsPlaneState {
type Plane = RvkmsPlane;
}
// SPDX-License-Identifier: GPL-2.0
mod connector;
mod crtc;
mod file;
mod gem;
mod plane;
mod output;
mod encoder;
use core::{option::*, marker::*};
use kernel::{
c_str,
str::CStr,
device,
driver,
drm::{
self,
drv,
kms::{
KmsDriver,
ModeConfigInfo,
UnregisteredKmsDevice,
atomic::*,
},
},
faux,
prelude::*,
sync::Arc,
of,
alloc::*,
};
/// Convienence type alias for the DRM device type for this driver
pub(crate) type RvkmsDevice = drm::device::Device<RvkmsDriver>;
/// The name of the driver
const NAME: &'static CStr = c_str!("rvkms");
/// Driver metadata
const INFO: drv::DriverInfo = drv::DriverInfo {
major: 0,
minor: 0,
patchlevel: 0,
name: &NAME,
desc: c_str!("Rust VKMS PoC"),
date: c_str!("20240115"),
};
/// The minimum supported resolution
const MIN_RES: (i32, i32) = (10, 10);
/// The maximum supported resolution
const MAX_RES: (i32, i32) = (8192, 8192);
/// The "preferred" resolution
const DEFAULT_RES: (i32, i32) = (1024, 768);
/// DRM Driver implementation for `RvkmsDriver`
#[vtable]
impl drv::Driver for RvkmsDriver {
type Data = ();
type Object = gem::Object;
type File = file::File;
type Kms = Self;
const INFO: drv::DriverInfo = INFO;
const FEATURES:u32 = drv::FEAT_GEM | drv::FEAT_MODESET | drv::FEAT_ATOMIC;
kernel::declare_drm_ioctls! {}
}
#[vtable]
impl KmsDriver for RvkmsDriver {
fn mode_config_info(
_dev: &device::Device,
_drm_data: <Self::Data as kernel::types::ForeignOwnable>::Borrowed<'_>,
) -> Result<ModeConfigInfo> {
Ok(MODE_CONFIG_INFO)
}
fn create_objects(drm: &UnregisteredKmsDevice<'_, Self>) -> Result
where
Self: Sized
{
output::create_output(drm, 0)
}
fn atomic_commit_tail<'a>(
mut state: AtomicCommitTail<'a, Self>,
modeset_token: ModesetsReadyToken<'_>,
plane_update_token: PlaneUpdatesReadyToken<'_>,
) -> CommittedAtomicState<'a, Self>
where
Self: Sized
{
let modeset_token = state.commit_modeset_disables(modeset_token);
let plane_update_token = state.commit_planes(plane_update_token, Default::default());
let modeset_token = state.commit_modeset_enables(modeset_token);
state.fake_vblank();
let state = state.commit_hw_done(modeset_token, plane_update_token);
state.wait_for_flip_done();
state
}
}
pub(crate) struct RvkmsDriver;
const MODE_CONFIG_INFO: ModeConfigInfo = ModeConfigInfo {
min_resolution: MIN_RES,
max_resolution: MAX_RES,
max_cursor: (512, 512),
preferred_depth: 0,
};
pub(crate) struct RvkmsModule {
dev: faux::Registration,
drm: drv::Registration<RvkmsDriver>,
}
impl kernel::Module for RvkmsModule {
fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
pr_info!("RVKMS Loaded\n");
let dev = faux::Registration::new(NAME)?;
dev_info!(dev.as_ref(), "Setting up DRM\n");
let drm = drv::Registration::<RvkmsDriver>::new(dev.as_ref(), (), 0)?;
Ok(Self { dev, drm })
}
}
module! {
type: RvkmsModule,
name: "rvkms",
author: "Lyude Paul",
description: "Rust VKMS Proof of Concept driver",
license: "GPL v2",
}