| 1 | //! |
| 2 | //! Foreign function interface |
| 3 | //! |
| 4 | |
| 5 | #![warn (missing_docs)] |
| 6 | #![allow (unused_doc_comments)] |
| 7 | |
| 8 | pub use drm_sys::{self, *}; |
| 9 | |
| 10 | #[macro_use ] |
| 11 | pub(crate) mod utils; |
| 12 | |
| 13 | pub mod gem; |
| 14 | mod ioctl; |
| 15 | pub mod mode; |
| 16 | pub mod syncobj; |
| 17 | |
| 18 | use std::{ |
| 19 | ffi::{c_int, c_ulong}, |
| 20 | io, |
| 21 | os::unix::io::BorrowedFd, |
| 22 | }; |
| 23 | |
| 24 | /// |
| 25 | /// Bindings to the methods of authentication the DRM provides. |
| 26 | /// |
| 27 | pub mod auth { |
| 28 | use crate::ioctl; |
| 29 | use drm_sys::*; |
| 30 | |
| 31 | use std::{io, os::unix::io::BorrowedFd}; |
| 32 | |
| 33 | /// Get the 'Magic Authentication Token' for this file descriptor. |
| 34 | pub fn get_magic_token(fd: BorrowedFd<'_>) -> io::Result<drm_auth> { |
| 35 | unsafe { ioctl::get_token(fd) } |
| 36 | } |
| 37 | |
| 38 | /// Authorize another process' 'Magic Authentication Token'. |
| 39 | pub fn auth_magic_token(fd: BorrowedFd<'_>, auth: u32) -> io::Result<drm_auth> { |
| 40 | let token = drm_auth { magic: auth }; |
| 41 | |
| 42 | unsafe { |
| 43 | ioctl::auth_token(fd, &token)?; |
| 44 | } |
| 45 | |
| 46 | Ok(token) |
| 47 | } |
| 48 | |
| 49 | /// Acquire the 'Master DRM Lock' for this file descriptor. |
| 50 | pub fn acquire_master(fd: BorrowedFd<'_>) -> io::Result<()> { |
| 51 | unsafe { ioctl::acquire_master(fd) } |
| 52 | } |
| 53 | |
| 54 | /// Release the 'Master DRM Lock' for this file descriptor. |
| 55 | pub fn release_master(fd: BorrowedFd<'_>) -> io::Result<()> { |
| 56 | unsafe { ioctl::release_master(fd) } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | /// Load this device's Bus ID into a buffer. |
| 61 | pub fn get_bus_id(fd: BorrowedFd<'_>, mut buf: Option<&mut Vec<u8>>) -> io::Result<drm_unique> { |
| 62 | let mut sizes = drm_unique::default(); |
| 63 | unsafe { |
| 64 | ioctl::get_bus_id(fd, &mut sizes)?; |
| 65 | } |
| 66 | |
| 67 | if buf.is_none() { |
| 68 | return Ok(sizes); |
| 69 | } |
| 70 | |
| 71 | map_reserve!(buf, sizes.unique_len as usize); |
| 72 | |
| 73 | let mut busid = drm_unique { |
| 74 | unique_len: sizes.unique_len, |
| 75 | unique: map_ptr!(&buf), |
| 76 | }; |
| 77 | |
| 78 | unsafe { |
| 79 | ioctl::get_bus_id(fd, &mut busid)?; |
| 80 | } |
| 81 | |
| 82 | map_set!(buf, busid.unique_len as usize); |
| 83 | |
| 84 | Ok(busid) |
| 85 | } |
| 86 | |
| 87 | /// Get a device's IRQ. |
| 88 | pub fn get_interrupt_from_bus_id( |
| 89 | fd: BorrowedFd<'_>, |
| 90 | bus: c_int, |
| 91 | dev: c_int, |
| 92 | func: c_int, |
| 93 | ) -> io::Result<drm_irq_busid> { |
| 94 | let mut irq: drm_irq_busid = drm_irq_busid { |
| 95 | busnum: bus, |
| 96 | devnum: dev, |
| 97 | funcnum: func, |
| 98 | ..Default::default() |
| 99 | }; |
| 100 | |
| 101 | unsafe { |
| 102 | ioctl::get_irq_from_bus_id(fd, &mut irq)?; |
| 103 | } |
| 104 | |
| 105 | Ok(irq) |
| 106 | } |
| 107 | |
| 108 | /// Get client information given a client's ID. |
| 109 | pub fn get_client(fd: BorrowedFd<'_>, idx: c_int) -> io::Result<drm_client> { |
| 110 | let mut client: drm_client = drm_client { |
| 111 | idx, |
| 112 | ..Default::default() |
| 113 | }; |
| 114 | |
| 115 | unsafe { |
| 116 | ioctl::get_client(fd, &mut client)?; |
| 117 | } |
| 118 | |
| 119 | Ok(client) |
| 120 | } |
| 121 | |
| 122 | /// Check if a capability is set. |
| 123 | pub fn get_capability(fd: BorrowedFd<'_>, cty: u64) -> io::Result<drm_get_cap> { |
| 124 | let mut cap: drm_get_cap = drm_get_cap { |
| 125 | capability: cty, |
| 126 | ..Default::default() |
| 127 | }; |
| 128 | |
| 129 | unsafe { |
| 130 | ioctl::get_cap(fd, &mut cap)?; |
| 131 | } |
| 132 | |
| 133 | Ok(cap) |
| 134 | } |
| 135 | |
| 136 | /// Attempt to enable/disable a client's capability. |
| 137 | pub fn set_capability(fd: BorrowedFd<'_>, cty: u64, val: bool) -> io::Result<drm_set_client_cap> { |
| 138 | let cap: drm_set_client_cap = drm_set_client_cap { |
| 139 | capability: cty, |
| 140 | value: val as u64, |
| 141 | }; |
| 142 | |
| 143 | unsafe { |
| 144 | ioctl::set_cap(fd, &cap)?; |
| 145 | } |
| 146 | |
| 147 | Ok(cap) |
| 148 | } |
| 149 | |
| 150 | /// Sets the requested interface version |
| 151 | pub fn set_version(fd: BorrowedFd<'_>, version: &mut drm_set_version) -> io::Result<()> { |
| 152 | unsafe { ioctl::set_version(fd, data:version) } |
| 153 | } |
| 154 | |
| 155 | /// Gets the driver version for this device. |
| 156 | pub fn get_version( |
| 157 | fd: BorrowedFd<'_>, |
| 158 | mut name_buf: Option<&mut Vec<i8>>, |
| 159 | mut date_buf: Option<&mut Vec<i8>>, |
| 160 | mut desc_buf: Option<&mut Vec<i8>>, |
| 161 | ) -> io::Result<drm_version> { |
| 162 | let mut sizes = drm_version::default(); |
| 163 | unsafe { ioctl::get_version(fd, &mut sizes) }?; |
| 164 | |
| 165 | map_reserve!(name_buf, sizes.name_len as usize); |
| 166 | map_reserve!(date_buf, sizes.date_len as usize); |
| 167 | map_reserve!(desc_buf, sizes.desc_len as usize); |
| 168 | |
| 169 | let mut version = drm_version { |
| 170 | name_len: map_len!(&name_buf), |
| 171 | name: map_ptr!(&name_buf), |
| 172 | date_len: map_len!(&date_buf), |
| 173 | date: map_ptr!(&date_buf), |
| 174 | desc_len: map_len!(&desc_buf), |
| 175 | desc: map_ptr!(&desc_buf), |
| 176 | ..Default::default() |
| 177 | }; |
| 178 | |
| 179 | unsafe { ioctl::get_version(fd, &mut version) }?; |
| 180 | |
| 181 | map_set!(name_buf, version.name_len as usize); |
| 182 | map_set!(date_buf, version.date_len as usize); |
| 183 | map_set!(desc_buf, version.desc_len as usize); |
| 184 | |
| 185 | Ok(version) |
| 186 | } |
| 187 | |
| 188 | /// Waits for a vblank. |
| 189 | pub fn wait_vblank( |
| 190 | fd: BorrowedFd<'_>, |
| 191 | type_: u32, |
| 192 | sequence: u32, |
| 193 | signal: usize, |
| 194 | ) -> io::Result<drm_wait_vblank_reply> { |
| 195 | // We can't assume the kernel will completely fill the reply in the union |
| 196 | // with valid data (it won't populate the timestamp if the event flag is |
| 197 | // set, for example), so use `default` to ensure the structure is completely |
| 198 | // initialized with zeros |
| 199 | let mut wait_vblank: drm_wait_vblank = drm_wait_vblank::default(); |
| 200 | wait_vblank.request = drm_wait_vblank_request { |
| 201 | type_, |
| 202 | sequence, |
| 203 | signal: signal as c_ulong, |
| 204 | }; |
| 205 | |
| 206 | unsafe { |
| 207 | ioctl::wait_vblank(fd, &mut wait_vblank)?; |
| 208 | }; |
| 209 | |
| 210 | Ok(unsafe { wait_vblank.reply }) |
| 211 | } |
| 212 | |