From 22060149c28eb17fc3602ced6e0b234ffc143bad Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 17:22:15 +0200 Subject: [PATCH 1/6] drivers/graphics/driver-graphics: Extract ioctl implementations into a function --- drivers/graphics/driver-graphics/src/lib.rs | 1249 +++++++++---------- 1 file changed, 622 insertions(+), 627 deletions(-) diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index 321cdb3096..af1ec4dd34 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -485,635 +485,17 @@ impl SchemeSync for GraphicsSchemeInner { metadata: &[u64], _ctx: &CallerCtx, ) -> Result { - use redox_ioctl::drm as ipc; - match self.handles.get_mut(id)? { Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), - Handle::V2(handle) => match metadata[0] { - ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| { - data.set_version_major(1); - data.set_version_minor(4); - data.set_version_patchlevel(0); - - data.set_name(unsafe { mem::transmute(self.adapter.name()) }); - data.set_date(unsafe { mem::transmute(&b"0"[..]) }); - data.set_desc(unsafe { mem::transmute(self.adapter.desc()) }); - - Ok(0) - }), - ipc::GET_UNIQUE => ipc::DrmUnique::with(payload, |mut data| { - if let Some(unique) = &handle.unique { - data.set_unique(unsafe { - mem::transmute::<&[u8], &[c_char]>(unique.as_bytes()) - }); - } else { - data.set_unique_len(0); - } - Ok(0) - }), - ipc::SET_VERSION => ipc::DrmSetVersion::with(payload, |mut data| { - // We only support version 1.4 currently - if data.drm_di_major() != 0 || data.drm_di_minor() != 4 { - return Err(Error::new(EINVAL)); - } - if data.drm_dd_major() != 0 || data.drm_dd_minor() != 4 { - return Err(Error::new(EINVAL)); - } - data.set_drm_di_major(1); - data.set_drm_di_minor(4); - data.set_drm_dd_major(1); - data.set_drm_dd_minor(4); - - handle.unique = Some(self.adapter.get_unique()); - - Ok(0) - }), - ipc::GET_CAP => ipc::DrmGetCap::with(payload, |mut data| { - data.set_value( - self.adapter.get_cap( - data.capability() - .try_into() - .map_err(|_| Error::new(EINVAL))?, - )?, - ); - Ok(0) - }), - ipc::SET_CLIENT_CAP => ipc::DrmSetClientCap::with(payload, |data| { - self.adapter.set_client_cap( - data.capability() - .try_into() - .map_err(|_| Error::new(EINVAL))?, - data.value(), - )?; - Ok(0) - }), - ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| { - let conn_ids = self - .objects - .connector_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let crtc_ids = self - .objects - .crtc_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let enc_ids = self - .objects - .encoder_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let fb_ids = self - .objects - .fb_ids() - .iter() - .map(|id| id.0) - .collect::>(); - data.set_fb_id_ptr(&fb_ids); - data.set_crtc_id_ptr(&crtc_ids); - data.set_connector_id_ptr(&conn_ids); - data.set_encoder_id_ptr(&enc_ids); - data.set_min_width(0); - data.set_max_width(16384); - data.set_min_height(0); - data.set_max_height(16384); - Ok(0) - }), - ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| { - let crtc = self - .objects - .get_crtc(KmsObjectId(data.crtc_id()))? - .lock() - .unwrap(); - // Don't touch set_connectors, that is only used by MODE_SET_CRTC - data.set_fb_id( - self.objects - .get_plane(crtc.primary_plane) - .unwrap() - .lock() - .unwrap() - .state - .fb_id - .unwrap_or(KmsObjectId::INVALID) - .0, - ); - // FIXME fill x and y with the data from the primary plane - data.set_x(0); - data.set_y(0); - data.set_gamma_size(crtc.gamma_size); - if let Some(mode) = crtc.state.mode { - data.set_mode_valid(1); - data.set_mode(mode); - } else { - data.set_mode_valid(0); - data.set_mode(Default::default()); - } - Ok(0) - }), - ipc::MODE_SET_CRTC => ipc::DrmModeCrtc::with(payload, |data| { - let crtc_id = KmsObjectId(data.crtc_id()); - let crtc = self.objects.get_crtc(crtc_id)?; - let connector_ids: Vec = data - .set_connectors_ptr() - .iter() - .take(data.count_connectors() as usize) - .map(|&id| KmsObjectId(id)) - .collect(); - let fb_id = if data.fb_id() != 0 { - Some(KmsObjectId(data.fb_id())) - } else { - None - }; - let mode = if data.mode_valid() != 0 { - Some(data.mode()) - } else { - None - }; - - let primary_plane_id = crtc.lock().unwrap().primary_plane; - let plane = self.objects.get_plane(primary_plane_id)?; - let mut new_crtc_state = crtc.lock().unwrap().state.clone(); - new_crtc_state.mode = mode; - let mut new_plane_state = plane.lock().unwrap().state.clone(); - new_plane_state.fb_id = fb_id; - new_plane_state.crtc_id = Some(crtc_id); - if handle.vt == self.active_vt { - self.adapter - .set_crtc(&self.objects, crtc, new_crtc_state.clone())?; - self.adapter.set_plane( - &self.objects, - plane, - new_plane_state.clone(), - Damage { - x: data.x(), - y: data.y(), - width: mode.map_or(0, |m| m.hdisplay as u32), - height: mode.map_or(0, |m| m.vdisplay as u32), - }, - )?; - for connector in connector_ids { - self.objects - .get_connector(connector)? - .lock() - .unwrap() - .state - .crtc_id = crtc_id - } - } - crtc.lock().unwrap().state = new_crtc_state.clone(); - plane.lock().unwrap().state = new_plane_state.clone(); - self.vts.get_mut(&handle.vt).unwrap().crtc_state - [crtc.lock().unwrap().crtc_index as usize] = new_crtc_state; - self.vts.get_mut(&handle.vt).unwrap().plane_state - [plane.lock().unwrap().plane_index as usize] = new_plane_state; - Ok(0) - }), - ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { - let vt_state = self.vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - self.adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { - let encoder = self.objects.get_encoder(KmsObjectId(data.encoder_id()))?; - data.set_crtc_id(encoder.crtc_id.0); - data.set_possible_crtcs(encoder.possible_crtcs); - data.set_possible_clones(encoder.possible_clones); - Ok(0) - }), - ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { - if data.count_modes() == 0 { - self.adapter - .probe_connector(&mut self.objects, KmsObjectId(data.connector_id())); - } - let connector = self - .objects - .get_connector(KmsObjectId(data.connector_id()))? - .lock() - .unwrap(); - data.set_encoders_ptr(&[connector.encoder_id.0]); - data.set_modes_ptr(&connector.modes); - data.set_connector_type(data.connector_type()); - data.set_connector_type_id(data.connector_type_id()); - data.set_connection(connector.connection as u32); - data.set_mm_width(connector.mm_width); - data.set_mm_height(connector.mm_width); - data.set_subpixel(connector.subpixel as u32); - drop(connector); - let (props, prop_vals) = self - .objects - .get_object_properties_data(KmsObjectId(data.connector_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - Ok(0) - }), - ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { - let property = self.objects.get_property(KmsObjectId(data.prop_id()))?; - data.set_name(property.name.0); - let mut flags = 0; - if property.immutable { - flags |= DRM_MODE_PROP_IMMUTABLE; - } - if property.atomic { - flags |= DRM_MODE_PROP_ATOMIC; - } - match &property.kind { - &KmsPropertyKind::Range(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_RANGE); - data.set_values_ptr(&[start, end]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Enum(variants) => { - data.set_flags(flags | DRM_MODE_PROP_ENUM); - data.set_values_ptr( - &variants.iter().map(|&(_, value)| value).collect::>(), - ); - data.set_enum_blob_ptr( - &variants - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Blob => { - data.set_flags(flags | DRM_MODE_PROP_BLOB); - data.set_values_ptr(&[]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Bitmask(bitmask_flags) => { - data.set_flags(flags | DRM_MODE_PROP_BITMASK); - data.set_values_ptr( - &bitmask_flags - .iter() - .map(|&(_, value)| value) - .collect::>(), - ); - data.set_enum_blob_ptr( - &bitmask_flags - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Object { type_ } => { - data.set_flags(flags | DRM_MODE_PROP_OBJECT); - data.set_values_ptr(&[u64::from(*type_)]); - data.set_enum_blob_ptr(&[]); - } - &KmsPropertyKind::SignedRange(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); - data.set_values_ptr(&[start as u64, end as u64]); - data.set_enum_blob_ptr(&[]); - } - } - Ok(0) - }), - ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { - let blob = self.objects.get_blob(KmsObjectId(data.blob_id()))?; - data.set_data(&blob); - Ok(0) - }), - ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let (bpp, depth) = match fb.pixel_format { - DrmFourcc::Xrgb8888 => (32, 24), - DrmFourcc::Argb8888 => (32, 32), - _ => todo!(), - }; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pitch(fb.pitch); - data.set_bpp(bpp); - data.set_depth(depth); - data.set_handle(handle.next_id); - Ok(0) - }), - ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let buffer = handle - .buffers - .get(&data.handle()) - .ok_or(Error::new(EINVAL))?; - - if data.bpp() != 32 { - return Err(Error::new(EINVAL)); - } - let pixel_format = match data.depth() { - 24 => DrmFourcc::Xrgb8888, - 32 => DrmFourcc::Argb8888, - _ => return Err(Error::new(EINVAL)), - }; - - let fb = self.adapter.create_framebuffer(buffer); - - let id = self.objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format, - pitch: data.pitch(), - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) - }), - ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { - let fb_id = KmsObjectId(data.inner()); - self.objects.remove_framebuffer(fb_id)?; - - // Disable planes that use this framebuffer. - for (vt, vt_data) in &mut self.vts { - for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { - if plane_state.fb_id != Some(fb_id) { - continue; - } - plane_state.fb_id = None; - - if *vt != self.active_vt { - continue; - } - let plane = self.objects.planes().nth(plane_idx).unwrap(); - self.adapter - .set_plane( - &self.objects, - plane, - plane_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - ) - .unwrap(); - } - } - - Ok(0) - }), - ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let damage = data - .clips_ptr() - .iter() - .map(|rect| Damage { - x: u32::from(rect.x1), - y: u32::from(rect.y1), - width: u32::from(rect.x2 - rect.x1), - height: u32::from(rect.y2 - rect.y1), - }) - .reduce(Damage::merge) - .unwrap_or(Damage { - x: 0, - y: 0, - width: fb.width, - height: fb.height, - }); - - if handle.vt == self.active_vt { - for plane in self.objects.planes() { - let state = plane.lock().unwrap().state.clone(); - if state.fb_id == Some(KmsObjectId(data.fb_id())) { - self.adapter - .set_plane(&self.objects, plane, state, damage)?; - } - } - } - - Ok(0) - }), - ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { - if data.bpp() != 32 || data.flags() != 0 { - return Err(Error::new(EINVAL)); - } - - let (buffer, pitch) = - self.adapter.create_dumb_buffer(data.width(), data.height()); - - data.set_pitch(pitch); - data.set_size(buffer.size() as u64); - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, Arc::new(buffer)); - data.set_handle(handle.next_id as u32); - Ok(0) - }), - ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { - if data.offset() != 0 { - return Err(Error::new(EINVAL)); - } - - let buffer_id = data.handle(); - - if !handle.buffers.contains_key(&buffer_id) { - return Err(Error::new(ENOENT)); - } - - // FIXME use a better scheme for creating map offsets - assert!(handle.buffers[&buffer_id].size() < MAP_FAKE_OFFSET_MULTIPLIER); - - data.set_offset((buffer_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); - - Ok(0) - }), - ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { - if handle.buffers.remove(&data.handle()).is_none() { - return Err(Error::new(ENOENT)); - } - Ok(0) - }), - ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { - let ids = self - .objects - .plane_ids() - .iter() - .map(|id| id.0) - .collect::>(); - data.set_plane_id_ptr(&ids); - Ok(0) - }), - ipc::MODE_SET_PLANE => ipc::DrmModeSetPlane::with(payload, |data| { - let plane_id = KmsObjectId(data.plane_id()); - let plane = self.objects.get_plane(plane_id)?; - - let crtc_id = KmsObjectId(data.crtc_id()); - let crtc_index = self.objects.get_crtc(crtc_id)?.lock().unwrap().crtc_index; - - let mut new_state = { - let plane = plane.lock().unwrap(); - if plane.possible_crtcs & (1 << crtc_index) == 0 { - return Err(Error::new(EINVAL)); - } - plane.state.clone() - }; - let fb_id = if data.fb_id() != 0 { - KmsObjectId(data.fb_id()) - } else { - KmsObjectId::INVALID - }; - new_state.fb_id = Some(fb_id); - new_state.crtc_id = Some(crtc_id); - new_state.src_rect = KmsRect { - x: data.src_x(), - y: data.src_y(), - width: data.src_w(), - height: data.src_h(), - }; - new_state.crtc_rect = KmsRect { - x: data.crtc_x() as i32, - y: data.crtc_y() as i32, - width: data.crtc_w(), - height: data.crtc_h(), - }; - - if handle.vt == self.active_vt { - self.adapter.set_plane( - &self.objects, - plane, - new_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - )?; - } - self.vts.get_mut(&handle.vt).unwrap().plane_state - [plane.lock().unwrap().plane_index as usize] = new_state; - Ok(0) - }), - ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| { - let plane = self - .objects - .get_plane(KmsObjectId(data.plane_id())) - .unwrap() - .lock() - .unwrap(); - data.set_crtc_id(plane.state.crtc_id.map_or(0, |id| id.0)); - data.set_fb_id(plane.state.fb_id.unwrap_or(KmsObjectId::INVALID).0); - data.set_possible_crtcs(plane.possible_crtcs); - data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); - Ok(0) - }), - ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - // FIXME handle multi-plane framebuffers - - let buffer = handle - .buffers - .get(&data.handles()[0]) - .ok_or(Error::new(EINVAL))?; - - let fb = self.adapter.create_framebuffer(buffer); - - let id = self.objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format: DrmFourcc::try_from(data.pixel_format()) - .map_err(|_| Error::new(EINVAL))?, - pitch: data.pitches()[0], - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) - }), - ipc::MODE_OBJ_GET_PROPERTIES => { - ipc::DrmModeObjGetProperties::with(payload, |mut data| { - let (props, prop_vals) = self - .objects - .get_object_properties_data(KmsObjectId(data.obj_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - data.set_obj_type(self.objects.object_type(KmsObjectId(data.obj_id()))?); - Ok(0) - }) - } - ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { - let vt_state = self.vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - cursor_plane.hot_x = data.hot_x(); - cursor_plane.hot_y = data.hot_y(); - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - self.adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pixel_format(fb.pixel_format as u32); - data.set_handles([handle.next_id, 0, 0, 0]); - data.set_pitches([fb.pitch, 0, 0, 0]); - data.set_offsets([0; 4]); - data.set_modifier([0; 4]); - Ok(0) - }), - _ => return Err(Error::new(EINVAL)), - }, + Handle::V2(handle) => call_ioctl( + &mut self.adapter, + &mut self.objects, + self.active_vt, + &mut self.vts, + handle, + metadata[0], + payload, + ), } } @@ -1149,3 +531,616 @@ impl SchemeSync for GraphicsSchemeInner { self.handles.remove(id); } } + +fn call_ioctl( + adapter: &mut T, + objects: &mut KmsObjects, + active_vt: usize, + vts: &mut HashMap>, + + handle: &mut DrmHandle, + cmd: u64, + payload: &mut [u8], +) -> syscall::Result { + use redox_ioctl::drm as ipc; + + match cmd { + ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| { + data.set_version_major(1); + data.set_version_minor(4); + data.set_version_patchlevel(0); + + data.set_name(unsafe { mem::transmute(adapter.name()) }); + data.set_date(unsafe { mem::transmute(&b"0"[..]) }); + data.set_desc(unsafe { mem::transmute(adapter.desc()) }); + + Ok(0) + }), + ipc::GET_UNIQUE => ipc::DrmUnique::with(payload, |mut data| { + if let Some(unique) = &handle.unique { + data.set_unique(unsafe { mem::transmute::<&[u8], &[c_char]>(unique.as_bytes()) }); + } else { + data.set_unique_len(0); + } + Ok(0) + }), + ipc::SET_VERSION => ipc::DrmSetVersion::with(payload, |mut data| { + // We only support version 1.4 currently + if data.drm_di_major() != 0 || data.drm_di_minor() != 4 { + return Err(Error::new(EINVAL)); + } + if data.drm_dd_major() != 0 || data.drm_dd_minor() != 4 { + return Err(Error::new(EINVAL)); + } + data.set_drm_di_major(1); + data.set_drm_di_minor(4); + data.set_drm_dd_major(1); + data.set_drm_dd_minor(4); + + handle.unique = Some(adapter.get_unique()); + + Ok(0) + }), + ipc::GET_CAP => ipc::DrmGetCap::with(payload, |mut data| { + data.set_value( + adapter.get_cap( + data.capability() + .try_into() + .map_err(|_| Error::new(EINVAL))?, + )?, + ); + Ok(0) + }), + ipc::SET_CLIENT_CAP => ipc::DrmSetClientCap::with(payload, |data| { + adapter.set_client_cap( + data.capability() + .try_into() + .map_err(|_| Error::new(EINVAL))?, + data.value(), + )?; + Ok(0) + }), + ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| { + let conn_ids = objects + .connector_ids() + .iter() + .map(|id| id.0) + .collect::>(); + let crtc_ids = objects.crtc_ids().iter().map(|id| id.0).collect::>(); + let enc_ids = objects + .encoder_ids() + .iter() + .map(|id| id.0) + .collect::>(); + let fb_ids = objects.fb_ids().iter().map(|id| id.0).collect::>(); + data.set_fb_id_ptr(&fb_ids); + data.set_crtc_id_ptr(&crtc_ids); + data.set_connector_id_ptr(&conn_ids); + data.set_encoder_id_ptr(&enc_ids); + data.set_min_width(0); + data.set_max_width(16384); + data.set_min_height(0); + data.set_max_height(16384); + Ok(0) + }), + ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| { + let crtc = objects + .get_crtc(KmsObjectId(data.crtc_id()))? + .lock() + .unwrap(); + // Don't touch set_connectors, that is only used by MODE_SET_CRTC + data.set_fb_id( + objects + .get_plane(crtc.primary_plane) + .unwrap() + .lock() + .unwrap() + .state + .fb_id + .unwrap_or(KmsObjectId::INVALID) + .0, + ); + // FIXME fill x and y with the data from the primary plane + data.set_x(0); + data.set_y(0); + data.set_gamma_size(crtc.gamma_size); + if let Some(mode) = crtc.state.mode { + data.set_mode_valid(1); + data.set_mode(mode); + } else { + data.set_mode_valid(0); + data.set_mode(Default::default()); + } + Ok(0) + }), + ipc::MODE_SET_CRTC => ipc::DrmModeCrtc::with(payload, |data| { + let crtc_id = KmsObjectId(data.crtc_id()); + let crtc = objects.get_crtc(crtc_id)?; + let connector_ids: Vec = data + .set_connectors_ptr() + .iter() + .take(data.count_connectors() as usize) + .map(|&id| KmsObjectId(id)) + .collect(); + let fb_id = if data.fb_id() != 0 { + Some(KmsObjectId(data.fb_id())) + } else { + None + }; + let mode = if data.mode_valid() != 0 { + Some(data.mode()) + } else { + None + }; + + let primary_plane_id = crtc.lock().unwrap().primary_plane; + let plane = objects.get_plane(primary_plane_id)?; + let mut new_crtc_state = crtc.lock().unwrap().state.clone(); + new_crtc_state.mode = mode; + let mut new_plane_state = plane.lock().unwrap().state.clone(); + new_plane_state.fb_id = fb_id; + new_plane_state.crtc_id = Some(crtc_id); + if handle.vt == active_vt { + adapter.set_crtc(&objects, crtc, new_crtc_state.clone())?; + adapter.set_plane( + &objects, + plane, + new_plane_state.clone(), + Damage { + x: data.x(), + y: data.y(), + width: mode.map_or(0, |m| m.hdisplay as u32), + height: mode.map_or(0, |m| m.vdisplay as u32), + }, + )?; + for connector in connector_ids { + objects + .get_connector(connector)? + .lock() + .unwrap() + .state + .crtc_id = crtc_id + } + } + crtc.lock().unwrap().state = new_crtc_state.clone(); + plane.lock().unwrap().state = new_plane_state.clone(); + vts.get_mut(&handle.vt).unwrap().crtc_state[crtc.lock().unwrap().crtc_index as usize] = + new_crtc_state; + vts.get_mut(&handle.vt).unwrap().plane_state + [plane.lock().unwrap().plane_index as usize] = new_plane_state; + Ok(0) + }), + ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) + }), + ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { + let encoder = objects.get_encoder(KmsObjectId(data.encoder_id()))?; + data.set_crtc_id(encoder.crtc_id.0); + data.set_possible_crtcs(encoder.possible_crtcs); + data.set_possible_clones(encoder.possible_clones); + Ok(0) + }), + ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { + if data.count_modes() == 0 { + adapter.probe_connector(objects, KmsObjectId(data.connector_id())); + } + let connector = objects + .get_connector(KmsObjectId(data.connector_id()))? + .lock() + .unwrap(); + data.set_encoders_ptr(&[connector.encoder_id.0]); + data.set_modes_ptr(&connector.modes); + data.set_connector_type(data.connector_type()); + data.set_connector_type_id(data.connector_type_id()); + data.set_connection(connector.connection as u32); + data.set_mm_width(connector.mm_width); + data.set_mm_height(connector.mm_width); + data.set_subpixel(connector.subpixel as u32); + drop(connector); + let (props, prop_vals) = + objects.get_object_properties_data(KmsObjectId(data.connector_id()))?; + data.set_props_ptr(&props); + data.set_prop_values_ptr(&prop_vals); + Ok(0) + }), + ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { + let property = objects.get_property(KmsObjectId(data.prop_id()))?; + data.set_name(property.name.0); + let mut flags = 0; + if property.immutable { + flags |= DRM_MODE_PROP_IMMUTABLE; + } + if property.atomic { + flags |= DRM_MODE_PROP_ATOMIC; + } + match &property.kind { + &KmsPropertyKind::Range(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_RANGE); + data.set_values_ptr(&[start, end]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Enum(variants) => { + data.set_flags(flags | DRM_MODE_PROP_ENUM); + data.set_values_ptr( + &variants.iter().map(|&(_, value)| value).collect::>(), + ); + data.set_enum_blob_ptr( + &variants + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Blob => { + data.set_flags(flags | DRM_MODE_PROP_BLOB); + data.set_values_ptr(&[]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Bitmask(bitmask_flags) => { + data.set_flags(flags | DRM_MODE_PROP_BITMASK); + data.set_values_ptr( + &bitmask_flags + .iter() + .map(|&(_, value)| value) + .collect::>(), + ); + data.set_enum_blob_ptr( + &bitmask_flags + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Object { type_ } => { + data.set_flags(flags | DRM_MODE_PROP_OBJECT); + data.set_values_ptr(&[u64::from(*type_)]); + data.set_enum_blob_ptr(&[]); + } + &KmsPropertyKind::SignedRange(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); + data.set_values_ptr(&[start as u64, end as u64]); + data.set_enum_blob_ptr(&[]); + } + } + Ok(0) + }), + ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { + let blob = objects.get_blob(KmsObjectId(data.blob_id()))?; + data.set_data(&blob); + Ok(0) + }), + ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let (bpp, depth) = match fb.pixel_format { + DrmFourcc::Xrgb8888 => (32, 24), + DrmFourcc::Argb8888 => (32, 32), + _ => todo!(), + }; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pitch(fb.pitch); + data.set_bpp(bpp); + data.set_depth(depth); + data.set_handle(handle.next_id); + Ok(0) + }), + ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { + let buffer = handle + .buffers + .get(&data.handle()) + .ok_or(Error::new(EINVAL))?; + + if data.bpp() != 32 { + return Err(Error::new(EINVAL)); + } + let pixel_format = match data.depth() { + 24 => DrmFourcc::Xrgb8888, + 32 => DrmFourcc::Argb8888, + _ => return Err(Error::new(EINVAL)), + }; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(objects::KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format, + pitch: data.pitch(), + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) + }), + ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { + let fb_id = KmsObjectId(data.inner()); + objects.remove_framebuffer(fb_id)?; + + // Disable planes that use this framebuffer. + for (vt, vt_data) in vts { + for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { + if plane_state.fb_id != Some(fb_id) { + continue; + } + plane_state.fb_id = None; + + if *vt != active_vt { + continue; + } + let plane = objects.planes().nth(plane_idx).unwrap(); + adapter + .set_plane( + &objects, + plane, + plane_state.clone(), + Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }, + ) + .unwrap(); + } + } + + Ok(0) + }), + ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let damage = data + .clips_ptr() + .iter() + .map(|rect| Damage { + x: u32::from(rect.x1), + y: u32::from(rect.y1), + width: u32::from(rect.x2 - rect.x1), + height: u32::from(rect.y2 - rect.y1), + }) + .reduce(Damage::merge) + .unwrap_or(Damage { + x: 0, + y: 0, + width: fb.width, + height: fb.height, + }); + + if handle.vt == active_vt { + for plane in objects.planes() { + let state = plane.lock().unwrap().state.clone(); + if state.fb_id == Some(KmsObjectId(data.fb_id())) { + adapter.set_plane(&objects, plane, state, damage)?; + } + } + } + + Ok(0) + }), + ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { + if data.bpp() != 32 || data.flags() != 0 { + return Err(Error::new(EINVAL)); + } + + let (buffer, pitch) = adapter.create_dumb_buffer(data.width(), data.height()); + + data.set_pitch(pitch); + data.set_size(buffer.size() as u64); + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, Arc::new(buffer)); + data.set_handle(handle.next_id as u32); + Ok(0) + }), + ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { + if data.offset() != 0 { + return Err(Error::new(EINVAL)); + } + + let buffer_id = data.handle(); + + if !handle.buffers.contains_key(&buffer_id) { + return Err(Error::new(ENOENT)); + } + + // FIXME use a better scheme for creating map offsets + assert!(handle.buffers[&buffer_id].size() < MAP_FAKE_OFFSET_MULTIPLIER); + + data.set_offset((buffer_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); + + Ok(0) + }), + ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { + if handle.buffers.remove(&data.handle()).is_none() { + return Err(Error::new(ENOENT)); + } + Ok(0) + }), + ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { + let ids = objects + .plane_ids() + .iter() + .map(|id| id.0) + .collect::>(); + data.set_plane_id_ptr(&ids); + Ok(0) + }), + ipc::MODE_SET_PLANE => ipc::DrmModeSetPlane::with(payload, |data| { + let plane_id = KmsObjectId(data.plane_id()); + let plane = objects.get_plane(plane_id)?; + + let crtc_id = KmsObjectId(data.crtc_id()); + let crtc_index = objects.get_crtc(crtc_id)?.lock().unwrap().crtc_index; + + let mut new_state = { + let plane = plane.lock().unwrap(); + if plane.possible_crtcs & (1 << crtc_index) == 0 { + return Err(Error::new(EINVAL)); + } + plane.state.clone() + }; + let fb_id = if data.fb_id() != 0 { + KmsObjectId(data.fb_id()) + } else { + KmsObjectId::INVALID + }; + new_state.fb_id = Some(fb_id); + new_state.crtc_id = Some(crtc_id); + new_state.src_rect = KmsRect { + x: data.src_x(), + y: data.src_y(), + width: data.src_w(), + height: data.src_h(), + }; + new_state.crtc_rect = KmsRect { + x: data.crtc_x() as i32, + y: data.crtc_y() as i32, + width: data.crtc_w(), + height: data.crtc_h(), + }; + + if handle.vt == active_vt { + adapter.set_plane( + &objects, + plane, + new_state.clone(), + Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }, + )?; + } + vts.get_mut(&handle.vt).unwrap().plane_state + [plane.lock().unwrap().plane_index as usize] = new_state; + Ok(0) + }), + ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| { + let plane = objects + .get_plane(KmsObjectId(data.plane_id())) + .unwrap() + .lock() + .unwrap(); + data.set_crtc_id(plane.state.crtc_id.map_or(0, |id| id.0)); + data.set_fb_id(plane.state.fb_id.unwrap_or(KmsObjectId::INVALID).0); + data.set_possible_crtcs(plane.possible_crtcs); + data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); + Ok(0) + }), + ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { + // FIXME handle multi-plane framebuffers + + let buffer = handle + .buffers + .get(&data.handles()[0]) + .ok_or(Error::new(EINVAL))?; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(objects::KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format: DrmFourcc::try_from(data.pixel_format()) + .map_err(|_| Error::new(EINVAL))?, + pitch: data.pitches()[0], + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) + }), + ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |mut data| { + let (props, prop_vals) = + objects.get_object_properties_data(KmsObjectId(data.obj_id()))?; + data.set_props_ptr(&props); + data.set_prop_values_ptr(&prop_vals); + data.set_obj_type(objects.object_type(KmsObjectId(data.obj_id()))?); + Ok(0) + }), + ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + cursor_plane.hot_x = data.hot_x(); + cursor_plane.hot_y = data.hot_y(); + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) + }), + ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pixel_format(fb.pixel_format as u32); + data.set_handles([handle.next_id, 0, 0, 0]); + data.set_pitches([fb.pitch, 0, 0, 0]); + data.set_offsets([0; 4]); + data.set_modifier([0; 4]); + Ok(0) + }), + _ => return Err(Error::new(EINVAL)), + } +} From 2ac2182caa8f46b7ddf53b93c34ad3929536085d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 17:25:02 +0200 Subject: [PATCH 2/6] drivers/graphics/driver-graphics: Move ioctl impls to a new module --- .../graphics/driver-graphics/src/ioctl/mod.rs | 629 +++++++++++++++++ drivers/graphics/driver-graphics/src/lib.rs | 632 +----------------- 2 files changed, 635 insertions(+), 626 deletions(-) create mode 100644 drivers/graphics/driver-graphics/src/ioctl/mod.rs diff --git a/drivers/graphics/driver-graphics/src/ioctl/mod.rs b/drivers/graphics/driver-graphics/src/ioctl/mod.rs new file mode 100644 index 0000000000..20b8732119 --- /dev/null +++ b/drivers/graphics/driver-graphics/src/ioctl/mod.rs @@ -0,0 +1,629 @@ +use std::collections::HashMap; +use std::ffi::c_char; +use std::mem; +use std::sync::Arc; + +use drm_fourcc::DrmFourcc; +use drm_sys::{ + drm_mode_property_enum, DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE, DRM_MODE_PROP_ATOMIC, + DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, + DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, +}; +use syscall::{Error, EINVAL, ENOENT, ENXIO}; + +use crate::kms::objects::{self, KmsObjectId, KmsObjects, KmsRect}; +use crate::kms::properties::KmsPropertyKind; +use crate::{Buffer, Damage, DrmHandle, GraphicsAdapter, VtState, MAP_FAKE_OFFSET_MULTIPLIER}; + +pub(crate) fn call_ioctl( + adapter: &mut T, + objects: &mut KmsObjects, + active_vt: usize, + vts: &mut HashMap>, + + handle: &mut DrmHandle, + cmd: u64, + payload: &mut [u8], +) -> syscall::Result { + use redox_ioctl::drm as ipc; + + match cmd { + ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| { + data.set_version_major(1); + data.set_version_minor(4); + data.set_version_patchlevel(0); + + data.set_name(unsafe { mem::transmute(adapter.name()) }); + data.set_date(unsafe { mem::transmute(&b"0"[..]) }); + data.set_desc(unsafe { mem::transmute(adapter.desc()) }); + + Ok(0) + }), + ipc::GET_UNIQUE => ipc::DrmUnique::with(payload, |mut data| { + if let Some(unique) = &handle.unique { + data.set_unique(unsafe { mem::transmute::<&[u8], &[c_char]>(unique.as_bytes()) }); + } else { + data.set_unique_len(0); + } + Ok(0) + }), + ipc::SET_VERSION => ipc::DrmSetVersion::with(payload, |mut data| { + // We only support version 1.4 currently + if data.drm_di_major() != 0 || data.drm_di_minor() != 4 { + return Err(Error::new(EINVAL)); + } + if data.drm_dd_major() != 0 || data.drm_dd_minor() != 4 { + return Err(Error::new(EINVAL)); + } + data.set_drm_di_major(1); + data.set_drm_di_minor(4); + data.set_drm_dd_major(1); + data.set_drm_dd_minor(4); + + handle.unique = Some(adapter.get_unique()); + + Ok(0) + }), + ipc::GET_CAP => ipc::DrmGetCap::with(payload, |mut data| { + data.set_value( + adapter.get_cap( + data.capability() + .try_into() + .map_err(|_| Error::new(EINVAL))?, + )?, + ); + Ok(0) + }), + ipc::SET_CLIENT_CAP => ipc::DrmSetClientCap::with(payload, |data| { + adapter.set_client_cap( + data.capability() + .try_into() + .map_err(|_| Error::new(EINVAL))?, + data.value(), + )?; + Ok(0) + }), + ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| { + let conn_ids = objects + .connector_ids() + .iter() + .map(|id| id.0) + .collect::>(); + let crtc_ids = objects.crtc_ids().iter().map(|id| id.0).collect::>(); + let enc_ids = objects + .encoder_ids() + .iter() + .map(|id| id.0) + .collect::>(); + let fb_ids = objects.fb_ids().iter().map(|id| id.0).collect::>(); + data.set_fb_id_ptr(&fb_ids); + data.set_crtc_id_ptr(&crtc_ids); + data.set_connector_id_ptr(&conn_ids); + data.set_encoder_id_ptr(&enc_ids); + data.set_min_width(0); + data.set_max_width(16384); + data.set_min_height(0); + data.set_max_height(16384); + Ok(0) + }), + ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| { + let crtc = objects + .get_crtc(KmsObjectId(data.crtc_id()))? + .lock() + .unwrap(); + // Don't touch set_connectors, that is only used by MODE_SET_CRTC + data.set_fb_id( + objects + .get_plane(crtc.primary_plane) + .unwrap() + .lock() + .unwrap() + .state + .fb_id + .unwrap_or(KmsObjectId::INVALID) + .0, + ); + // FIXME fill x and y with the data from the primary plane + data.set_x(0); + data.set_y(0); + data.set_gamma_size(crtc.gamma_size); + if let Some(mode) = crtc.state.mode { + data.set_mode_valid(1); + data.set_mode(mode); + } else { + data.set_mode_valid(0); + data.set_mode(Default::default()); + } + Ok(0) + }), + ipc::MODE_SET_CRTC => ipc::DrmModeCrtc::with(payload, |data| { + let crtc_id = KmsObjectId(data.crtc_id()); + let crtc = objects.get_crtc(crtc_id)?; + let connector_ids: Vec = data + .set_connectors_ptr() + .iter() + .take(data.count_connectors() as usize) + .map(|&id| KmsObjectId(id)) + .collect(); + let fb_id = if data.fb_id() != 0 { + Some(KmsObjectId(data.fb_id())) + } else { + None + }; + let mode = if data.mode_valid() != 0 { + Some(data.mode()) + } else { + None + }; + + let primary_plane_id = crtc.lock().unwrap().primary_plane; + let plane = objects.get_plane(primary_plane_id)?; + let mut new_crtc_state = crtc.lock().unwrap().state.clone(); + new_crtc_state.mode = mode; + let mut new_plane_state = plane.lock().unwrap().state.clone(); + new_plane_state.fb_id = fb_id; + new_plane_state.crtc_id = Some(crtc_id); + if handle.vt == active_vt { + adapter.set_crtc(&objects, crtc, new_crtc_state.clone())?; + adapter.set_plane( + &objects, + plane, + new_plane_state.clone(), + Damage { + x: data.x(), + y: data.y(), + width: mode.map_or(0, |m| m.hdisplay as u32), + height: mode.map_or(0, |m| m.vdisplay as u32), + }, + )?; + for connector in connector_ids { + objects + .get_connector(connector)? + .lock() + .unwrap() + .state + .crtc_id = crtc_id + } + } + crtc.lock().unwrap().state = new_crtc_state.clone(); + plane.lock().unwrap().state = new_plane_state.clone(); + vts.get_mut(&handle.vt).unwrap().crtc_state[crtc.lock().unwrap().crtc_index as usize] = + new_crtc_state; + vts.get_mut(&handle.vt).unwrap().plane_state + [plane.lock().unwrap().plane_index as usize] = new_plane_state; + Ok(0) + }), + ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) + }), + ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { + let encoder = objects.get_encoder(KmsObjectId(data.encoder_id()))?; + data.set_crtc_id(encoder.crtc_id.0); + data.set_possible_crtcs(encoder.possible_crtcs); + data.set_possible_clones(encoder.possible_clones); + Ok(0) + }), + ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { + if data.count_modes() == 0 { + adapter.probe_connector(objects, KmsObjectId(data.connector_id())); + } + let connector = objects + .get_connector(KmsObjectId(data.connector_id()))? + .lock() + .unwrap(); + data.set_encoders_ptr(&[connector.encoder_id.0]); + data.set_modes_ptr(&connector.modes); + data.set_connector_type(data.connector_type()); + data.set_connector_type_id(data.connector_type_id()); + data.set_connection(connector.connection as u32); + data.set_mm_width(connector.mm_width); + data.set_mm_height(connector.mm_width); + data.set_subpixel(connector.subpixel as u32); + drop(connector); + let (props, prop_vals) = + objects.get_object_properties_data(KmsObjectId(data.connector_id()))?; + data.set_props_ptr(&props); + data.set_prop_values_ptr(&prop_vals); + Ok(0) + }), + ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { + let property = objects.get_property(KmsObjectId(data.prop_id()))?; + data.set_name(property.name.0); + let mut flags = 0; + if property.immutable { + flags |= DRM_MODE_PROP_IMMUTABLE; + } + if property.atomic { + flags |= DRM_MODE_PROP_ATOMIC; + } + match &property.kind { + &KmsPropertyKind::Range(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_RANGE); + data.set_values_ptr(&[start, end]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Enum(variants) => { + data.set_flags(flags | DRM_MODE_PROP_ENUM); + data.set_values_ptr( + &variants.iter().map(|&(_, value)| value).collect::>(), + ); + data.set_enum_blob_ptr( + &variants + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Blob => { + data.set_flags(flags | DRM_MODE_PROP_BLOB); + data.set_values_ptr(&[]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Bitmask(bitmask_flags) => { + data.set_flags(flags | DRM_MODE_PROP_BITMASK); + data.set_values_ptr( + &bitmask_flags + .iter() + .map(|&(_, value)| value) + .collect::>(), + ); + data.set_enum_blob_ptr( + &bitmask_flags + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Object { type_ } => { + data.set_flags(flags | DRM_MODE_PROP_OBJECT); + data.set_values_ptr(&[u64::from(*type_)]); + data.set_enum_blob_ptr(&[]); + } + &KmsPropertyKind::SignedRange(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); + data.set_values_ptr(&[start as u64, end as u64]); + data.set_enum_blob_ptr(&[]); + } + } + Ok(0) + }), + ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { + let blob = objects.get_blob(KmsObjectId(data.blob_id()))?; + data.set_data(&blob); + Ok(0) + }), + ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let (bpp, depth) = match fb.pixel_format { + DrmFourcc::Xrgb8888 => (32, 24), + DrmFourcc::Argb8888 => (32, 32), + _ => todo!(), + }; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pitch(fb.pitch); + data.set_bpp(bpp); + data.set_depth(depth); + data.set_handle(handle.next_id); + Ok(0) + }), + ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { + let buffer = handle + .buffers + .get(&data.handle()) + .ok_or(Error::new(EINVAL))?; + + if data.bpp() != 32 { + return Err(Error::new(EINVAL)); + } + let pixel_format = match data.depth() { + 24 => DrmFourcc::Xrgb8888, + 32 => DrmFourcc::Argb8888, + _ => return Err(Error::new(EINVAL)), + }; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(objects::KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format, + pitch: data.pitch(), + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) + }), + ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { + let fb_id = KmsObjectId(data.inner()); + objects.remove_framebuffer(fb_id)?; + + // Disable planes that use this framebuffer. + for (vt, vt_data) in vts { + for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { + if plane_state.fb_id != Some(fb_id) { + continue; + } + plane_state.fb_id = None; + + if *vt != active_vt { + continue; + } + let plane = objects.planes().nth(plane_idx).unwrap(); + adapter + .set_plane( + &objects, + plane, + plane_state.clone(), + Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }, + ) + .unwrap(); + } + } + + Ok(0) + }), + ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let damage = data + .clips_ptr() + .iter() + .map(|rect| Damage { + x: u32::from(rect.x1), + y: u32::from(rect.y1), + width: u32::from(rect.x2 - rect.x1), + height: u32::from(rect.y2 - rect.y1), + }) + .reduce(Damage::merge) + .unwrap_or(Damage { + x: 0, + y: 0, + width: fb.width, + height: fb.height, + }); + + if handle.vt == active_vt { + for plane in objects.planes() { + let state = plane.lock().unwrap().state.clone(); + if state.fb_id == Some(KmsObjectId(data.fb_id())) { + adapter.set_plane(&objects, plane, state, damage)?; + } + } + } + + Ok(0) + }), + ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { + if data.bpp() != 32 || data.flags() != 0 { + return Err(Error::new(EINVAL)); + } + + let (buffer, pitch) = adapter.create_dumb_buffer(data.width(), data.height()); + + data.set_pitch(pitch); + data.set_size(buffer.size() as u64); + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, Arc::new(buffer)); + data.set_handle(handle.next_id as u32); + Ok(0) + }), + ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { + if data.offset() != 0 { + return Err(Error::new(EINVAL)); + } + + let buffer_id = data.handle(); + + if !handle.buffers.contains_key(&buffer_id) { + return Err(Error::new(ENOENT)); + } + + // FIXME use a better scheme for creating map offsets + assert!(handle.buffers[&buffer_id].size() < MAP_FAKE_OFFSET_MULTIPLIER); + + data.set_offset((buffer_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); + + Ok(0) + }), + ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { + if handle.buffers.remove(&data.handle()).is_none() { + return Err(Error::new(ENOENT)); + } + Ok(0) + }), + ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { + let ids = objects + .plane_ids() + .iter() + .map(|id| id.0) + .collect::>(); + data.set_plane_id_ptr(&ids); + Ok(0) + }), + ipc::MODE_SET_PLANE => ipc::DrmModeSetPlane::with(payload, |data| { + let plane_id = KmsObjectId(data.plane_id()); + let plane = objects.get_plane(plane_id)?; + + let crtc_id = KmsObjectId(data.crtc_id()); + let crtc_index = objects.get_crtc(crtc_id)?.lock().unwrap().crtc_index; + + let mut new_state = { + let plane = plane.lock().unwrap(); + if plane.possible_crtcs & (1 << crtc_index) == 0 { + return Err(Error::new(EINVAL)); + } + plane.state.clone() + }; + let fb_id = if data.fb_id() != 0 { + KmsObjectId(data.fb_id()) + } else { + KmsObjectId::INVALID + }; + new_state.fb_id = Some(fb_id); + new_state.crtc_id = Some(crtc_id); + new_state.src_rect = KmsRect { + x: data.src_x(), + y: data.src_y(), + width: data.src_w(), + height: data.src_h(), + }; + new_state.crtc_rect = KmsRect { + x: data.crtc_x() as i32, + y: data.crtc_y() as i32, + width: data.crtc_w(), + height: data.crtc_h(), + }; + + if handle.vt == active_vt { + adapter.set_plane( + &objects, + plane, + new_state.clone(), + Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }, + )?; + } + vts.get_mut(&handle.vt).unwrap().plane_state + [plane.lock().unwrap().plane_index as usize] = new_state; + Ok(0) + }), + ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| { + let plane = objects + .get_plane(KmsObjectId(data.plane_id())) + .unwrap() + .lock() + .unwrap(); + data.set_crtc_id(plane.state.crtc_id.map_or(0, |id| id.0)); + data.set_fb_id(plane.state.fb_id.unwrap_or(KmsObjectId::INVALID).0); + data.set_possible_crtcs(plane.possible_crtcs); + data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); + Ok(0) + }), + ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { + // FIXME handle multi-plane framebuffers + + let buffer = handle + .buffers + .get(&data.handles()[0]) + .ok_or(Error::new(EINVAL))?; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(objects::KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format: DrmFourcc::try_from(data.pixel_format()) + .map_err(|_| Error::new(EINVAL))?, + pitch: data.pitches()[0], + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) + }), + ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |mut data| { + let (props, prop_vals) = + objects.get_object_properties_data(KmsObjectId(data.obj_id()))?; + data.set_props_ptr(&props); + data.set_prop_values_ptr(&prop_vals); + data.set_obj_type(objects.object_type(KmsObjectId(data.obj_id()))?); + Ok(0) + }), + ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + cursor_plane.hot_x = data.hot_x(); + cursor_plane.hot_y = data.hot_y(); + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) + }), + ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pixel_format(fb.pixel_format as u32); + data.set_handles([handle.next_id, 0, 0, 0]); + data.set_pitches([fb.pitch, 0, 0, 0]); + data.set_offsets([0; 4]); + data.set_modifier([0; 4]); + Ok(0) + }), + _ => return Err(Error::new(EINVAL)), + } +} diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index af1ec4dd34..f76b31ebe1 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -1,35 +1,28 @@ #![feature(macro_metavar_expr)] +use std::cmp; use std::collections::HashMap; -use std::ffi::c_char; use std::fmt::Debug; use std::fs::File; use std::io::{self, Write}; use std::os::fd::BorrowedFd; use std::sync::{Arc, Mutex}; -use std::{cmp, mem}; -use drm_fourcc::DrmFourcc; -use drm_sys::{ - drm_mode_property_enum, DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE, DRM_MODE_PROP_ATOMIC, - DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, - DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, -}; use inputd::{DisplayHandle, VtEventKind}; use libredox::Fd; use redox_scheme::scheme::{register_scheme_inner, SchemeState, SchemeSync}; use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket}; use scheme_utils::{FpathWriter, HandleMap}; use syscall::schemev2::NewFdFlags; -use syscall::{Error, MapFlags, Result, EACCES, EAGAIN, EINVAL, ENOENT, ENXIO, EOPNOTSUPP}; +use syscall::{Error, MapFlags, Result, EACCES, EAGAIN, EINVAL, ENOENT, EOPNOTSUPP}; use crate::kms::connector::{KmsConnectorDriver, KmsConnectorState}; use crate::kms::objects::{ - self, KmsCrtc, KmsCrtcDriver, KmsCrtcState, KmsObjectId, KmsObjects, KmsPlane, KmsPlaneDriver, - KmsPlaneState, KmsRect, + KmsCrtc, KmsCrtcDriver, KmsCrtcState, KmsObjectId, KmsObjects, KmsPlane, KmsPlaneDriver, + KmsPlaneState, }; -use crate::kms::properties::KmsPropertyKind; +mod ioctl; pub mod kms; #[derive(Debug, Copy, Clone)] @@ -487,7 +480,7 @@ impl SchemeSync for GraphicsSchemeInner { ) -> Result { match self.handles.get_mut(id)? { Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), - Handle::V2(handle) => call_ioctl( + Handle::V2(handle) => ioctl::call_ioctl( &mut self.adapter, &mut self.objects, self.active_vt, @@ -531,616 +524,3 @@ impl SchemeSync for GraphicsSchemeInner { self.handles.remove(id); } } - -fn call_ioctl( - adapter: &mut T, - objects: &mut KmsObjects, - active_vt: usize, - vts: &mut HashMap>, - - handle: &mut DrmHandle, - cmd: u64, - payload: &mut [u8], -) -> syscall::Result { - use redox_ioctl::drm as ipc; - - match cmd { - ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| { - data.set_version_major(1); - data.set_version_minor(4); - data.set_version_patchlevel(0); - - data.set_name(unsafe { mem::transmute(adapter.name()) }); - data.set_date(unsafe { mem::transmute(&b"0"[..]) }); - data.set_desc(unsafe { mem::transmute(adapter.desc()) }); - - Ok(0) - }), - ipc::GET_UNIQUE => ipc::DrmUnique::with(payload, |mut data| { - if let Some(unique) = &handle.unique { - data.set_unique(unsafe { mem::transmute::<&[u8], &[c_char]>(unique.as_bytes()) }); - } else { - data.set_unique_len(0); - } - Ok(0) - }), - ipc::SET_VERSION => ipc::DrmSetVersion::with(payload, |mut data| { - // We only support version 1.4 currently - if data.drm_di_major() != 0 || data.drm_di_minor() != 4 { - return Err(Error::new(EINVAL)); - } - if data.drm_dd_major() != 0 || data.drm_dd_minor() != 4 { - return Err(Error::new(EINVAL)); - } - data.set_drm_di_major(1); - data.set_drm_di_minor(4); - data.set_drm_dd_major(1); - data.set_drm_dd_minor(4); - - handle.unique = Some(adapter.get_unique()); - - Ok(0) - }), - ipc::GET_CAP => ipc::DrmGetCap::with(payload, |mut data| { - data.set_value( - adapter.get_cap( - data.capability() - .try_into() - .map_err(|_| Error::new(EINVAL))?, - )?, - ); - Ok(0) - }), - ipc::SET_CLIENT_CAP => ipc::DrmSetClientCap::with(payload, |data| { - adapter.set_client_cap( - data.capability() - .try_into() - .map_err(|_| Error::new(EINVAL))?, - data.value(), - )?; - Ok(0) - }), - ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| { - let conn_ids = objects - .connector_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let crtc_ids = objects.crtc_ids().iter().map(|id| id.0).collect::>(); - let enc_ids = objects - .encoder_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let fb_ids = objects.fb_ids().iter().map(|id| id.0).collect::>(); - data.set_fb_id_ptr(&fb_ids); - data.set_crtc_id_ptr(&crtc_ids); - data.set_connector_id_ptr(&conn_ids); - data.set_encoder_id_ptr(&enc_ids); - data.set_min_width(0); - data.set_max_width(16384); - data.set_min_height(0); - data.set_max_height(16384); - Ok(0) - }), - ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| { - let crtc = objects - .get_crtc(KmsObjectId(data.crtc_id()))? - .lock() - .unwrap(); - // Don't touch set_connectors, that is only used by MODE_SET_CRTC - data.set_fb_id( - objects - .get_plane(crtc.primary_plane) - .unwrap() - .lock() - .unwrap() - .state - .fb_id - .unwrap_or(KmsObjectId::INVALID) - .0, - ); - // FIXME fill x and y with the data from the primary plane - data.set_x(0); - data.set_y(0); - data.set_gamma_size(crtc.gamma_size); - if let Some(mode) = crtc.state.mode { - data.set_mode_valid(1); - data.set_mode(mode); - } else { - data.set_mode_valid(0); - data.set_mode(Default::default()); - } - Ok(0) - }), - ipc::MODE_SET_CRTC => ipc::DrmModeCrtc::with(payload, |data| { - let crtc_id = KmsObjectId(data.crtc_id()); - let crtc = objects.get_crtc(crtc_id)?; - let connector_ids: Vec = data - .set_connectors_ptr() - .iter() - .take(data.count_connectors() as usize) - .map(|&id| KmsObjectId(id)) - .collect(); - let fb_id = if data.fb_id() != 0 { - Some(KmsObjectId(data.fb_id())) - } else { - None - }; - let mode = if data.mode_valid() != 0 { - Some(data.mode()) - } else { - None - }; - - let primary_plane_id = crtc.lock().unwrap().primary_plane; - let plane = objects.get_plane(primary_plane_id)?; - let mut new_crtc_state = crtc.lock().unwrap().state.clone(); - new_crtc_state.mode = mode; - let mut new_plane_state = plane.lock().unwrap().state.clone(); - new_plane_state.fb_id = fb_id; - new_plane_state.crtc_id = Some(crtc_id); - if handle.vt == active_vt { - adapter.set_crtc(&objects, crtc, new_crtc_state.clone())?; - adapter.set_plane( - &objects, - plane, - new_plane_state.clone(), - Damage { - x: data.x(), - y: data.y(), - width: mode.map_or(0, |m| m.hdisplay as u32), - height: mode.map_or(0, |m| m.vdisplay as u32), - }, - )?; - for connector in connector_ids { - objects - .get_connector(connector)? - .lock() - .unwrap() - .state - .crtc_id = crtc_id - } - } - crtc.lock().unwrap().state = new_crtc_state.clone(); - plane.lock().unwrap().state = new_plane_state.clone(); - vts.get_mut(&handle.vt).unwrap().crtc_state[crtc.lock().unwrap().crtc_index as usize] = - new_crtc_state; - vts.get_mut(&handle.vt).unwrap().plane_state - [plane.lock().unwrap().plane_index as usize] = new_plane_state; - Ok(0) - }), - ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { - let vt_state = vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { - let encoder = objects.get_encoder(KmsObjectId(data.encoder_id()))?; - data.set_crtc_id(encoder.crtc_id.0); - data.set_possible_crtcs(encoder.possible_crtcs); - data.set_possible_clones(encoder.possible_clones); - Ok(0) - }), - ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { - if data.count_modes() == 0 { - adapter.probe_connector(objects, KmsObjectId(data.connector_id())); - } - let connector = objects - .get_connector(KmsObjectId(data.connector_id()))? - .lock() - .unwrap(); - data.set_encoders_ptr(&[connector.encoder_id.0]); - data.set_modes_ptr(&connector.modes); - data.set_connector_type(data.connector_type()); - data.set_connector_type_id(data.connector_type_id()); - data.set_connection(connector.connection as u32); - data.set_mm_width(connector.mm_width); - data.set_mm_height(connector.mm_width); - data.set_subpixel(connector.subpixel as u32); - drop(connector); - let (props, prop_vals) = - objects.get_object_properties_data(KmsObjectId(data.connector_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - Ok(0) - }), - ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { - let property = objects.get_property(KmsObjectId(data.prop_id()))?; - data.set_name(property.name.0); - let mut flags = 0; - if property.immutable { - flags |= DRM_MODE_PROP_IMMUTABLE; - } - if property.atomic { - flags |= DRM_MODE_PROP_ATOMIC; - } - match &property.kind { - &KmsPropertyKind::Range(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_RANGE); - data.set_values_ptr(&[start, end]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Enum(variants) => { - data.set_flags(flags | DRM_MODE_PROP_ENUM); - data.set_values_ptr( - &variants.iter().map(|&(_, value)| value).collect::>(), - ); - data.set_enum_blob_ptr( - &variants - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Blob => { - data.set_flags(flags | DRM_MODE_PROP_BLOB); - data.set_values_ptr(&[]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Bitmask(bitmask_flags) => { - data.set_flags(flags | DRM_MODE_PROP_BITMASK); - data.set_values_ptr( - &bitmask_flags - .iter() - .map(|&(_, value)| value) - .collect::>(), - ); - data.set_enum_blob_ptr( - &bitmask_flags - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Object { type_ } => { - data.set_flags(flags | DRM_MODE_PROP_OBJECT); - data.set_values_ptr(&[u64::from(*type_)]); - data.set_enum_blob_ptr(&[]); - } - &KmsPropertyKind::SignedRange(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); - data.set_values_ptr(&[start as u64, end as u64]); - data.set_enum_blob_ptr(&[]); - } - } - Ok(0) - }), - ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { - let blob = objects.get_blob(KmsObjectId(data.blob_id()))?; - data.set_data(&blob); - Ok(0) - }), - ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let (bpp, depth) = match fb.pixel_format { - DrmFourcc::Xrgb8888 => (32, 24), - DrmFourcc::Argb8888 => (32, 32), - _ => todo!(), - }; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pitch(fb.pitch); - data.set_bpp(bpp); - data.set_depth(depth); - data.set_handle(handle.next_id); - Ok(0) - }), - ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let buffer = handle - .buffers - .get(&data.handle()) - .ok_or(Error::new(EINVAL))?; - - if data.bpp() != 32 { - return Err(Error::new(EINVAL)); - } - let pixel_format = match data.depth() { - 24 => DrmFourcc::Xrgb8888, - 32 => DrmFourcc::Argb8888, - _ => return Err(Error::new(EINVAL)), - }; - - let fb = adapter.create_framebuffer(buffer); - - let id = objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format, - pitch: data.pitch(), - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) - }), - ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { - let fb_id = KmsObjectId(data.inner()); - objects.remove_framebuffer(fb_id)?; - - // Disable planes that use this framebuffer. - for (vt, vt_data) in vts { - for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { - if plane_state.fb_id != Some(fb_id) { - continue; - } - plane_state.fb_id = None; - - if *vt != active_vt { - continue; - } - let plane = objects.planes().nth(plane_idx).unwrap(); - adapter - .set_plane( - &objects, - plane, - plane_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - ) - .unwrap(); - } - } - - Ok(0) - }), - ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let damage = data - .clips_ptr() - .iter() - .map(|rect| Damage { - x: u32::from(rect.x1), - y: u32::from(rect.y1), - width: u32::from(rect.x2 - rect.x1), - height: u32::from(rect.y2 - rect.y1), - }) - .reduce(Damage::merge) - .unwrap_or(Damage { - x: 0, - y: 0, - width: fb.width, - height: fb.height, - }); - - if handle.vt == active_vt { - for plane in objects.planes() { - let state = plane.lock().unwrap().state.clone(); - if state.fb_id == Some(KmsObjectId(data.fb_id())) { - adapter.set_plane(&objects, plane, state, damage)?; - } - } - } - - Ok(0) - }), - ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { - if data.bpp() != 32 || data.flags() != 0 { - return Err(Error::new(EINVAL)); - } - - let (buffer, pitch) = adapter.create_dumb_buffer(data.width(), data.height()); - - data.set_pitch(pitch); - data.set_size(buffer.size() as u64); - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, Arc::new(buffer)); - data.set_handle(handle.next_id as u32); - Ok(0) - }), - ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { - if data.offset() != 0 { - return Err(Error::new(EINVAL)); - } - - let buffer_id = data.handle(); - - if !handle.buffers.contains_key(&buffer_id) { - return Err(Error::new(ENOENT)); - } - - // FIXME use a better scheme for creating map offsets - assert!(handle.buffers[&buffer_id].size() < MAP_FAKE_OFFSET_MULTIPLIER); - - data.set_offset((buffer_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); - - Ok(0) - }), - ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { - if handle.buffers.remove(&data.handle()).is_none() { - return Err(Error::new(ENOENT)); - } - Ok(0) - }), - ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { - let ids = objects - .plane_ids() - .iter() - .map(|id| id.0) - .collect::>(); - data.set_plane_id_ptr(&ids); - Ok(0) - }), - ipc::MODE_SET_PLANE => ipc::DrmModeSetPlane::with(payload, |data| { - let plane_id = KmsObjectId(data.plane_id()); - let plane = objects.get_plane(plane_id)?; - - let crtc_id = KmsObjectId(data.crtc_id()); - let crtc_index = objects.get_crtc(crtc_id)?.lock().unwrap().crtc_index; - - let mut new_state = { - let plane = plane.lock().unwrap(); - if plane.possible_crtcs & (1 << crtc_index) == 0 { - return Err(Error::new(EINVAL)); - } - plane.state.clone() - }; - let fb_id = if data.fb_id() != 0 { - KmsObjectId(data.fb_id()) - } else { - KmsObjectId::INVALID - }; - new_state.fb_id = Some(fb_id); - new_state.crtc_id = Some(crtc_id); - new_state.src_rect = KmsRect { - x: data.src_x(), - y: data.src_y(), - width: data.src_w(), - height: data.src_h(), - }; - new_state.crtc_rect = KmsRect { - x: data.crtc_x() as i32, - y: data.crtc_y() as i32, - width: data.crtc_w(), - height: data.crtc_h(), - }; - - if handle.vt == active_vt { - adapter.set_plane( - &objects, - plane, - new_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - )?; - } - vts.get_mut(&handle.vt).unwrap().plane_state - [plane.lock().unwrap().plane_index as usize] = new_state; - Ok(0) - }), - ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| { - let plane = objects - .get_plane(KmsObjectId(data.plane_id())) - .unwrap() - .lock() - .unwrap(); - data.set_crtc_id(plane.state.crtc_id.map_or(0, |id| id.0)); - data.set_fb_id(plane.state.fb_id.unwrap_or(KmsObjectId::INVALID).0); - data.set_possible_crtcs(plane.possible_crtcs); - data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); - Ok(0) - }), - ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - // FIXME handle multi-plane framebuffers - - let buffer = handle - .buffers - .get(&data.handles()[0]) - .ok_or(Error::new(EINVAL))?; - - let fb = adapter.create_framebuffer(buffer); - - let id = objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format: DrmFourcc::try_from(data.pixel_format()) - .map_err(|_| Error::new(EINVAL))?, - pitch: data.pitches()[0], - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) - }), - ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |mut data| { - let (props, prop_vals) = - objects.get_object_properties_data(KmsObjectId(data.obj_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - data.set_obj_type(objects.object_type(KmsObjectId(data.obj_id()))?); - Ok(0) - }), - ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { - let vt_state = vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - cursor_plane.hot_x = data.hot_x(); - cursor_plane.hot_y = data.hot_y(); - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pixel_format(fb.pixel_format as u32); - data.set_handles([handle.next_id, 0, 0, 0]); - data.set_pitches([fb.pitch, 0, 0, 0]); - data.set_offsets([0; 4]); - data.set_modifier([0; 4]); - Ok(0) - }), - _ => return Err(Error::new(EINVAL)), - } -} From df845d6566c3e511fc500bab81bba7822fe8d840 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 17:32:39 +0200 Subject: [PATCH 3/6] drivers/graphics/driver-graphics: Move framebuffer ioctls to a separate module --- .../driver-graphics/src/ioctl/framebuffer.rs | 196 ++++++++++++++++++ .../graphics/driver-graphics/src/ioctl/mod.rs | 160 ++------------ 2 files changed, 209 insertions(+), 147 deletions(-) create mode 100644 drivers/graphics/driver-graphics/src/ioctl/framebuffer.rs diff --git a/drivers/graphics/driver-graphics/src/ioctl/framebuffer.rs b/drivers/graphics/driver-graphics/src/ioctl/framebuffer.rs new file mode 100644 index 0000000000..d6ccdd645e --- /dev/null +++ b/drivers/graphics/driver-graphics/src/ioctl/framebuffer.rs @@ -0,0 +1,196 @@ +use std::collections::HashMap; + +use drm_fourcc::DrmFourcc; +use syscall::{Error, EINVAL}; + +use crate::kms::objects::{KmsFramebuffer, KmsObjectId, KmsObjects}; +use crate::{Damage, DrmHandle, GraphicsAdapter, VtState}; + +pub(super) fn mode_get_fb( + objects: &mut KmsObjects, + handle: &mut DrmHandle, + mut data: redox_ioctl::drm::DrmModeFbCmd<'_>, +) -> Result { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let (bpp, depth) = match fb.pixel_format { + DrmFourcc::Xrgb8888 => (32, 24), + DrmFourcc::Argb8888 => (32, 32), + _ => todo!(), + }; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pitch(fb.pitch); + data.set_bpp(bpp); + data.set_depth(depth); + data.set_handle(handle.next_id); + Ok(0) +} + +pub(super) fn mode_add_fb( + adapter: &mut T, + objects: &mut KmsObjects, + handle: &mut DrmHandle, + mut data: redox_ioctl::drm::DrmModeFbCmd<'_>, +) -> Result { + let buffer = handle + .buffers + .get(&data.handle()) + .ok_or(Error::new(EINVAL))?; + + if data.bpp() != 32 { + return Err(Error::new(EINVAL)); + } + let pixel_format = match data.depth() { + 24 => DrmFourcc::Xrgb8888, + 32 => DrmFourcc::Argb8888, + _ => return Err(Error::new(EINVAL)), + }; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format, + pitch: data.pitch(), + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) +} + +pub(super) fn mode_rm_fb( + adapter: &mut T, + objects: &mut KmsObjects, + active_vt: usize, + vts: &mut HashMap>, + data: redox_ioctl::drm::StandinForUint<'_>, +) -> Result { + let fb_id = KmsObjectId(data.inner()); + objects.remove_framebuffer(fb_id)?; + + // Disable planes that use this framebuffer. + for (vt, vt_data) in vts { + for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { + if plane_state.fb_id != Some(fb_id) { + continue; + } + plane_state.fb_id = None; + + if *vt != active_vt { + continue; + } + let plane = objects.planes().nth(plane_idx).unwrap(); + adapter + .set_plane( + &objects, + plane, + plane_state.clone(), + Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }, + ) + .unwrap(); + } + } + + Ok(0) +} + +pub(super) fn mode_dirtyfb( + adapter: &mut T, + objects: &mut KmsObjects, + active_vt: usize, + handle: &mut DrmHandle, + data: redox_ioctl::drm::DrmModeFbDirtyCmd<'_>, +) -> Result { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + let damage = data + .clips_ptr() + .iter() + .map(|rect| Damage { + x: u32::from(rect.x1), + y: u32::from(rect.y1), + width: u32::from(rect.x2 - rect.x1), + height: u32::from(rect.y2 - rect.y1), + }) + .reduce(Damage::merge) + .unwrap_or(Damage { + x: 0, + y: 0, + width: fb.width, + height: fb.height, + }); + + if handle.vt == active_vt { + for plane in objects.planes() { + let state = plane.lock().unwrap().state.clone(); + if state.fb_id == Some(KmsObjectId(data.fb_id())) { + adapter.set_plane(&objects, plane, state, damage)?; + } + } + } + + Ok(0) +} + +pub(super) fn mode_add_fb2( + adapter: &mut T, + objects: &mut KmsObjects, + handle: &mut DrmHandle, + mut data: redox_ioctl::drm::DrmModeFbCmd2<'_>, +) -> Result { + // FIXME handle multi-plane framebuffers + + let buffer = handle + .buffers + .get(&data.handles()[0]) + .ok_or(Error::new(EINVAL))?; + + let fb = adapter.create_framebuffer(buffer); + + let id = objects.add_framebuffer(KmsFramebuffer { + width: data.width(), + height: data.height(), + pixel_format: DrmFourcc::try_from(data.pixel_format()).map_err(|_| Error::new(EINVAL))?, + pitch: data.pitches()[0], + buffer: buffer.clone(), + driver_data: fb, + }); + + data.set_fb_id(id.0); + + Ok(0) +} + +pub(super) fn mode_get_fb2( + objects: &mut KmsObjects, + handle: &mut DrmHandle, + mut data: redox_ioctl::drm::DrmModeFbCmd2<'_>, +) -> Result { + let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; + + handle.next_id += 1; + handle.buffers.insert(handle.next_id, fb.buffer.clone()); + + data.set_width(fb.width); + data.set_height(fb.height); + data.set_pixel_format(fb.pixel_format as u32); + data.set_handles([handle.next_id, 0, 0, 0]); + data.set_pitches([fb.pitch, 0, 0, 0]); + data.set_offsets([0; 4]); + data.set_modifier([0; 4]); + Ok(0) +} diff --git a/drivers/graphics/driver-graphics/src/ioctl/mod.rs b/drivers/graphics/driver-graphics/src/ioctl/mod.rs index 20b8732119..eb67e9452d 100644 --- a/drivers/graphics/driver-graphics/src/ioctl/mod.rs +++ b/drivers/graphics/driver-graphics/src/ioctl/mod.rs @@ -11,10 +11,12 @@ use drm_sys::{ }; use syscall::{Error, EINVAL, ENOENT, ENXIO}; -use crate::kms::objects::{self, KmsObjectId, KmsObjects, KmsRect}; +use crate::kms::objects::{KmsObjectId, KmsObjects, KmsRect}; use crate::kms::properties::KmsPropertyKind; use crate::{Buffer, Damage, DrmHandle, GraphicsAdapter, VtState, MAP_FAKE_OFFSET_MULTIPLIER}; +mod framebuffer; + pub(crate) fn call_ioctl( adapter: &mut T, objects: &mut KmsObjects, @@ -322,120 +324,17 @@ pub(crate) fn call_ioctl( data.set_data(&blob); Ok(0) }), - ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let (bpp, depth) = match fb.pixel_format { - DrmFourcc::Xrgb8888 => (32, 24), - DrmFourcc::Argb8888 => (32, 32), - _ => todo!(), - }; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pitch(fb.pitch); - data.set_bpp(bpp); - data.set_depth(depth); - data.set_handle(handle.next_id); - Ok(0) + ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |data| { + framebuffer::mode_get_fb(objects, handle, data) }), - ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let buffer = handle - .buffers - .get(&data.handle()) - .ok_or(Error::new(EINVAL))?; - - if data.bpp() != 32 { - return Err(Error::new(EINVAL)); - } - let pixel_format = match data.depth() { - 24 => DrmFourcc::Xrgb8888, - 32 => DrmFourcc::Argb8888, - _ => return Err(Error::new(EINVAL)), - }; - - let fb = adapter.create_framebuffer(buffer); - - let id = objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format, - pitch: data.pitch(), - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) + ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |data| { + framebuffer::mode_add_fb(adapter, objects, handle, data) }), ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { - let fb_id = KmsObjectId(data.inner()); - objects.remove_framebuffer(fb_id)?; - - // Disable planes that use this framebuffer. - for (vt, vt_data) in vts { - for (plane_idx, plane_state) in vt_data.plane_state.iter_mut().enumerate() { - if plane_state.fb_id != Some(fb_id) { - continue; - } - plane_state.fb_id = None; - - if *vt != active_vt { - continue; - } - let plane = objects.planes().nth(plane_idx).unwrap(); - adapter - .set_plane( - &objects, - plane, - plane_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - ) - .unwrap(); - } - } - - Ok(0) + framebuffer::mode_rm_fb(adapter, objects, active_vt, vts, data) }), ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let damage = data - .clips_ptr() - .iter() - .map(|rect| Damage { - x: u32::from(rect.x1), - y: u32::from(rect.y1), - width: u32::from(rect.x2 - rect.x1), - height: u32::from(rect.y2 - rect.y1), - }) - .reduce(Damage::merge) - .unwrap_or(Damage { - x: 0, - y: 0, - width: fb.width, - height: fb.height, - }); - - if handle.vt == active_vt { - for plane in objects.planes() { - let state = plane.lock().unwrap().state.clone(); - if state.fb_id == Some(KmsObjectId(data.fb_id())) { - adapter.set_plane(&objects, plane, state, damage)?; - } - } - } - - Ok(0) + framebuffer::mode_dirtyfb(adapter, objects, active_vt, handle, data) }), ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { if data.bpp() != 32 || data.flags() != 0 { @@ -548,29 +447,8 @@ pub(crate) fn call_ioctl( data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); Ok(0) }), - ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - // FIXME handle multi-plane framebuffers - - let buffer = handle - .buffers - .get(&data.handles()[0]) - .ok_or(Error::new(EINVAL))?; - - let fb = adapter.create_framebuffer(buffer); - - let id = objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pixel_format: DrmFourcc::try_from(data.pixel_format()) - .map_err(|_| Error::new(EINVAL))?, - pitch: data.pitches()[0], - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) + ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |data| { + framebuffer::mode_add_fb2(adapter, objects, handle, data) }), ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |mut data| { let (props, prop_vals) = @@ -609,20 +487,8 @@ pub(crate) fn call_ioctl( Ok(0) }), - ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - let fb = objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - handle.next_id += 1; - handle.buffers.insert(handle.next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pixel_format(fb.pixel_format as u32); - data.set_handles([handle.next_id, 0, 0, 0]); - data.set_pitches([fb.pitch, 0, 0, 0]); - data.set_offsets([0; 4]); - data.set_modifier([0; 4]); - Ok(0) + ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |data| { + framebuffer::mode_get_fb2(objects, handle, data) }), _ => return Err(Error::new(EINVAL)), } From 798ef0738e0d4231c1569061238d0eb937099255 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 17:36:55 +0200 Subject: [PATCH 4/6] drivers/graphics/driver-graphics: Move cursor ioctls to a separate module --- .../driver-graphics/src/ioctl/cursor.rs | 74 +++++++++++++++++++ .../graphics/driver-graphics/src/ioctl/mod.rs | 63 ++-------------- 2 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 drivers/graphics/driver-graphics/src/ioctl/cursor.rs diff --git a/drivers/graphics/driver-graphics/src/ioctl/cursor.rs b/drivers/graphics/driver-graphics/src/ioctl/cursor.rs new file mode 100644 index 0000000000..a60c17f72b --- /dev/null +++ b/drivers/graphics/driver-graphics/src/ioctl/cursor.rs @@ -0,0 +1,74 @@ +use std::collections::HashMap; + +use drm_sys::{DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE}; +use syscall::{Error, ENOENT, ENXIO}; + +use crate::{DrmHandle, GraphicsAdapter, VtState}; + +pub(super) fn mode_cursor( + adapter: &mut T, + vts: &mut HashMap>, + handle: &mut DrmHandle, + data: redox_ioctl::drm::DrmModeCursor<'_>, +) -> Result { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) +} + +pub(super) fn mode_cursor2( + adapter: &mut T, + vts: &mut HashMap>, + handle: &mut DrmHandle, + data: redox_ioctl::drm::DrmModeCursor2<'_>, +) -> Result { + let vt_state = vts.get_mut(&handle.vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + return Err(Error::new(ENXIO)); + }; + + let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + if update_buffer { + cursor_plane.buffer = if data.handle() == 0 { + None + } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + Some(buffer.clone()) + } else { + return Err(Error::new(ENOENT)); + }; + cursor_plane.hot_x = data.hot_x(); + cursor_plane.hot_y = data.hot_y(); + } + + if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = data.x(); + cursor_plane.y = data.y(); + } + + adapter.handle_cursor(cursor_plane, update_buffer); + + Ok(0) +} diff --git a/drivers/graphics/driver-graphics/src/ioctl/mod.rs b/drivers/graphics/driver-graphics/src/ioctl/mod.rs index eb67e9452d..6731c43246 100644 --- a/drivers/graphics/driver-graphics/src/ioctl/mod.rs +++ b/drivers/graphics/driver-graphics/src/ioctl/mod.rs @@ -5,16 +5,17 @@ use std::sync::Arc; use drm_fourcc::DrmFourcc; use drm_sys::{ - drm_mode_property_enum, DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE, DRM_MODE_PROP_ATOMIC, - DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, - DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, + drm_mode_property_enum, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, + DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, + DRM_MODE_PROP_SIGNED_RANGE, }; -use syscall::{Error, EINVAL, ENOENT, ENXIO}; +use syscall::{Error, EINVAL, ENOENT}; use crate::kms::objects::{KmsObjectId, KmsObjects, KmsRect}; use crate::kms::properties::KmsPropertyKind; use crate::{Buffer, Damage, DrmHandle, GraphicsAdapter, VtState, MAP_FAKE_OFFSET_MULTIPLIER}; +mod cursor; mod framebuffer; pub(crate) fn call_ioctl( @@ -196,31 +197,7 @@ pub(crate) fn call_ioctl( Ok(0) }), ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { - let vt_state = vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) + cursor::mode_cursor(adapter, vts, handle, data) }), ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { let encoder = objects.get_encoder(KmsObjectId(data.encoder_id()))?; @@ -459,33 +436,7 @@ pub(crate) fn call_ioctl( Ok(0) }), ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { - let vt_state = vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - cursor_plane.hot_x = data.hot_x(); - cursor_plane.hot_y = data.hot_y(); - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) + cursor::mode_cursor2(adapter, vts, handle, data) }), ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |data| { framebuffer::mode_get_fb2(objects, handle, data) From 3e7b757f0bb622e3231c58c60cfb4c5f8719e31c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 17:40:43 +0200 Subject: [PATCH 5/6] drivers/graphics/driver-graphics: Deduplicate code between MODE_CURSOR and MODE_CURSOR2 --- .../driver-graphics/src/ioctl/cursor.rs | 86 ++++++++++++------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/drivers/graphics/driver-graphics/src/ioctl/cursor.rs b/drivers/graphics/driver-graphics/src/ioctl/cursor.rs index a60c17f72b..5781fc69bb 100644 --- a/drivers/graphics/driver-graphics/src/ioctl/cursor.rs +++ b/drivers/graphics/driver-graphics/src/ioctl/cursor.rs @@ -11,31 +11,20 @@ pub(super) fn mode_cursor( handle: &mut DrmHandle, data: redox_ioctl::drm::DrmModeCursor<'_>, ) -> Result { - let vt_state = vts.get_mut(&handle.vt).unwrap(); - - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - return Err(Error::new(ENXIO)); - }; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(ENOENT)); - }; - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) + cursor_inner( + adapter, + vts, + handle, + data.flags(), + data.crtc_id(), + data.x(), + data.y(), + data.width(), + data.height(), + data.handle(), + 0, + 0, + ) } pub(super) fn mode_cursor2( @@ -43,6 +32,37 @@ pub(super) fn mode_cursor2( vts: &mut HashMap>, handle: &mut DrmHandle, data: redox_ioctl::drm::DrmModeCursor2<'_>, +) -> Result { + cursor_inner( + adapter, + vts, + handle, + data.flags(), + data.crtc_id(), + data.x(), + data.y(), + data.width(), + data.height(), + data.handle(), + data.hot_x(), + data.hot_y(), + ) +} + +fn cursor_inner( + adapter: &mut T, + vts: &mut HashMap>, + handle: &mut DrmHandle, + + flags: u32, + _crtc_id: u32, + x: i32, + y: i32, + _width: u32, + _height: u32, + handle_id: u32, + hot_x: i32, + hot_y: i32, ) -> Result { let vt_state = vts.get_mut(&handle.vt).unwrap(); @@ -50,22 +70,22 @@ pub(super) fn mode_cursor2( return Err(Error::new(ENXIO)); }; - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; + let update_buffer = flags & DRM_MODE_CURSOR_BO != 0; if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { + cursor_plane.buffer = if handle_id == 0 { None - } else if let Some(buffer) = handle.buffers.get(&data.handle()) { + } else if let Some(buffer) = handle.buffers.get(&handle_id) { Some(buffer.clone()) } else { return Err(Error::new(ENOENT)); }; - cursor_plane.hot_x = data.hot_x(); - cursor_plane.hot_y = data.hot_y(); + cursor_plane.hot_x = hot_x; + cursor_plane.hot_y = hot_y; } - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); + if flags & DRM_MODE_CURSOR_MOVE != 0 { + cursor_plane.x = x; + cursor_plane.y = y; } adapter.handle_cursor(cursor_plane, update_buffer); From fc2d098f70adef6ba820f7ae97e4113865c5843e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 14 May 2026 18:37:55 +0200 Subject: [PATCH 6/6] drivers/graphics/driver-graphics: Move property ioctls to a separate module --- .../graphics/driver-graphics/src/ioctl/mod.rs | 92 ++--------------- .../driver-graphics/src/ioctl/property.rs | 99 +++++++++++++++++++ 2 files changed, 107 insertions(+), 84 deletions(-) create mode 100644 drivers/graphics/driver-graphics/src/ioctl/property.rs diff --git a/drivers/graphics/driver-graphics/src/ioctl/mod.rs b/drivers/graphics/driver-graphics/src/ioctl/mod.rs index 6731c43246..1c050d9b42 100644 --- a/drivers/graphics/driver-graphics/src/ioctl/mod.rs +++ b/drivers/graphics/driver-graphics/src/ioctl/mod.rs @@ -4,19 +4,14 @@ use std::mem; use std::sync::Arc; use drm_fourcc::DrmFourcc; -use drm_sys::{ - drm_mode_property_enum, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, - DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, - DRM_MODE_PROP_SIGNED_RANGE, -}; use syscall::{Error, EINVAL, ENOENT}; use crate::kms::objects::{KmsObjectId, KmsObjects, KmsRect}; -use crate::kms::properties::KmsPropertyKind; use crate::{Buffer, Damage, DrmHandle, GraphicsAdapter, VtState, MAP_FAKE_OFFSET_MULTIPLIER}; mod cursor; mod framebuffer; +mod property; pub(crate) fn call_ioctl( adapter: &mut T, @@ -229,78 +224,12 @@ pub(crate) fn call_ioctl( data.set_prop_values_ptr(&prop_vals); Ok(0) }), - ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { - let property = objects.get_property(KmsObjectId(data.prop_id()))?; - data.set_name(property.name.0); - let mut flags = 0; - if property.immutable { - flags |= DRM_MODE_PROP_IMMUTABLE; - } - if property.atomic { - flags |= DRM_MODE_PROP_ATOMIC; - } - match &property.kind { - &KmsPropertyKind::Range(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_RANGE); - data.set_values_ptr(&[start, end]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Enum(variants) => { - data.set_flags(flags | DRM_MODE_PROP_ENUM); - data.set_values_ptr( - &variants.iter().map(|&(_, value)| value).collect::>(), - ); - data.set_enum_blob_ptr( - &variants - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Blob => { - data.set_flags(flags | DRM_MODE_PROP_BLOB); - data.set_values_ptr(&[]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Bitmask(bitmask_flags) => { - data.set_flags(flags | DRM_MODE_PROP_BITMASK); - data.set_values_ptr( - &bitmask_flags - .iter() - .map(|&(_, value)| value) - .collect::>(), - ); - data.set_enum_blob_ptr( - &bitmask_flags - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Object { type_ } => { - data.set_flags(flags | DRM_MODE_PROP_OBJECT); - data.set_values_ptr(&[u64::from(*type_)]); - data.set_enum_blob_ptr(&[]); - } - &KmsPropertyKind::SignedRange(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); - data.set_values_ptr(&[start as u64, end as u64]); - data.set_enum_blob_ptr(&[]); - } - } - Ok(0) - }), - ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { - let blob = objects.get_blob(KmsObjectId(data.blob_id()))?; - data.set_data(&blob); - Ok(0) + ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |data| { + property::mode_get_property(objects, data) }), + ipc::MODE_GET_PROP_BLOB => { + ipc::DrmModeGetBlob::with(payload, |data| property::mode_get_prop_blob(objects, data)) + } ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |data| { framebuffer::mode_get_fb(objects, handle, data) }), @@ -427,13 +356,8 @@ pub(crate) fn call_ioctl( ipc::MODE_ADD_FB2 => ipc::DrmModeFbCmd2::with(payload, |data| { framebuffer::mode_add_fb2(adapter, objects, handle, data) }), - ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |mut data| { - let (props, prop_vals) = - objects.get_object_properties_data(KmsObjectId(data.obj_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - data.set_obj_type(objects.object_type(KmsObjectId(data.obj_id()))?); - Ok(0) + ipc::MODE_OBJ_GET_PROPERTIES => ipc::DrmModeObjGetProperties::with(payload, |data| { + property::mode_obj_get_properties(objects, data) }), ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { cursor::mode_cursor2(adapter, vts, handle, data) diff --git a/drivers/graphics/driver-graphics/src/ioctl/property.rs b/drivers/graphics/driver-graphics/src/ioctl/property.rs new file mode 100644 index 0000000000..b79d782e96 --- /dev/null +++ b/drivers/graphics/driver-graphics/src/ioctl/property.rs @@ -0,0 +1,99 @@ +use drm_sys::{ + drm_mode_property_enum, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, + DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, + DRM_MODE_PROP_SIGNED_RANGE, +}; +use syscall::Error; + +use crate::kms::objects::{KmsObjectId, KmsObjects}; +use crate::kms::properties::KmsPropertyKind; +use crate::GraphicsAdapter; + +pub(super) fn mode_get_property( + objects: &mut KmsObjects, + mut data: redox_ioctl::drm::DrmModeGetProperty<'_>, +) -> Result { + let property = objects.get_property(KmsObjectId(data.prop_id()))?; + data.set_name(property.name.0); + let mut flags = 0; + if property.immutable { + flags |= DRM_MODE_PROP_IMMUTABLE; + } + if property.atomic { + flags |= DRM_MODE_PROP_ATOMIC; + } + match &property.kind { + &KmsPropertyKind::Range(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_RANGE); + data.set_values_ptr(&[start, end]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Enum(variants) => { + data.set_flags(flags | DRM_MODE_PROP_ENUM); + data.set_values_ptr(&variants.iter().map(|&(_, value)| value).collect::>()); + data.set_enum_blob_ptr( + &variants + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Blob => { + data.set_flags(flags | DRM_MODE_PROP_BLOB); + data.set_values_ptr(&[]); + data.set_enum_blob_ptr(&[]); + } + KmsPropertyKind::Bitmask(bitmask_flags) => { + data.set_flags(flags | DRM_MODE_PROP_BITMASK); + data.set_values_ptr( + &bitmask_flags + .iter() + .map(|&(_, value)| value) + .collect::>(), + ); + data.set_enum_blob_ptr( + &bitmask_flags + .iter() + .map(|&(name, value)| drm_mode_property_enum { + name: name.0, + value, + }) + .collect::>(), + ); + } + KmsPropertyKind::Object { type_ } => { + data.set_flags(flags | DRM_MODE_PROP_OBJECT); + data.set_values_ptr(&[u64::from(*type_)]); + data.set_enum_blob_ptr(&[]); + } + &KmsPropertyKind::SignedRange(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); + data.set_values_ptr(&[start as u64, end as u64]); + data.set_enum_blob_ptr(&[]); + } + } + Ok(0) +} + +pub(super) fn mode_get_prop_blob( + objects: &mut KmsObjects, + mut data: redox_ioctl::drm::DrmModeGetBlob<'_>, +) -> Result { + let blob = objects.get_blob(KmsObjectId(data.blob_id()))?; + data.set_data(&blob); + Ok(0) +} + +pub(super) fn mode_obj_get_properties( + objects: &mut KmsObjects, + mut data: redox_ioctl::drm::DrmModeObjGetProperties<'_>, +) -> Result { + let (props, prop_vals) = objects.get_object_properties_data(KmsObjectId(data.obj_id()))?; + data.set_props_ptr(&props); + data.set_prop_values_ptr(&prop_vals); + data.set_obj_type(objects.object_type(KmsObjectId(data.obj_id()))?); + Ok(0) +}