1 /// Check the `util` module to see how the `Card` structure is implemented.
2 pub mod utils;
3 use crate::utils::*;
4 use drm::control::{from_u32, RawResourceHandle};
5 
main()6 pub fn main() {
7     let card = Card::open_global();
8 
9     // Enable all possible client capabilities
10     for &cap in capabilities::CLIENT_CAP_ENUMS {
11         if let Err(e) = card.set_client_capability(cap, true) {
12             eprintln!("Unable to activate capability {:?}: {}", cap, e);
13             return;
14         }
15     }
16 
17     run_repl(&card);
18 }
19 
run_repl(card: &Card)20 fn run_repl(card: &Card) {
21     // Load a set of numbered images
22     let images = [
23         images::load_image("1.png"),
24         images::load_image("2.png"),
25         images::load_image("3.png"),
26         images::load_image("4.png"),
27     ];
28 
29     for image in &images {
30         // Create the Dumbbuffer
31         let fmt = drm::buffer::DrmFourcc::Xrgb8888;
32         let mut db = card
33             .create_dumb_buffer(image.dimensions(), fmt, 32)
34             .unwrap();
35 
36         // Create a Framebuffer to represent it
37         let _fb = card.add_framebuffer(&db, 24, 32).unwrap();
38 
39         // Load the image into the buffer
40         {
41             let mut mapping = card.map_dumb_buffer(&mut db).unwrap();
42             let buffer = mapping.as_mut();
43             for (img_px, map_px) in image.pixels().zip(buffer.chunks_exact_mut(4)) {
44                 // Assuming little endian, it's BGRA
45                 map_px[0] = img_px[0]; // Blue
46                 map_px[1] = img_px[1]; // Green
47                 map_px[2] = img_px[2]; // Red
48                 map_px[3] = img_px[3]; // Alpha
49             }
50         };
51     }
52 
53     // Using rustyline to create the interactive prompt.
54     let editor_config = rustyline::config::Builder::new()
55         .max_history_size(256)
56         .unwrap()
57         .completion_type(rustyline::config::CompletionType::List)
58         .edit_mode(rustyline::config::EditMode::Vi)
59         .auto_add_history(true)
60         .build();
61     let mut kms_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap();
62     let mut atomic_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap();
63 
64     for line in kms_editor.iter("KMS>> ").map(|x| x.unwrap()) {
65         let args: Vec<_> = line.split_whitespace().collect();
66         match &args[..] {
67             ["CreateAtomicSet"] => {
68                 for line in atomic_editor.iter("Atomic>> ").map(|x| x.unwrap()) {
69                     let args: Vec<_> = line.split_whitespace().collect();
70                     match &args[..] {
71                         ["Quit"] => break,
72                         args => println!("{:?}", args),
73                     }
74                 }
75             }
76             // Destroying a framebuffer
77             ["DestroyFramebuffer", handle] => {
78                 let handle: u32 = str::parse(handle).unwrap();
79                 let handle: drm::control::framebuffer::Handle = from_u32(handle).unwrap();
80                 if let Err(err) = card.destroy_framebuffer(handle) {
81                     println!("Unable to destroy framebuffer ({:?}): {}", handle, err);
82                 }
83             }
84             // Print out all resources
85             ["GetResources"] => {
86                 let resources = card.resource_handles().unwrap();
87                 println!("\tConnectors: {:?}", resources.connectors());
88                 println!("\tEncoders: {:?}", resources.encoders());
89                 println!("\tCRTCS: {:?}", resources.crtcs());
90                 println!("\tFramebuffers: {:?}", resources.framebuffers());
91                 let planes = card.plane_handles().unwrap();
92                 println!("\tPlanes: {:?}", planes);
93             }
94             // Print out the values of a specific property
95             ["GetProperty", handle] => {
96                 let handle: u32 = str::parse(handle).unwrap();
97                 let handle: drm::control::property::Handle = from_u32(handle).unwrap();
98                 let property = card.get_property(handle).unwrap();
99                 println!("\tName: {:?}", property.name());
100                 println!("\tMutable: {:?}", property.mutable());
101                 println!("\tAtomic: {:?}", property.atomic());
102                 println!("\tValue: {:#?}", property.value_type());
103             }
104             // Get the property-value pairs of a single resource
105             ["GetProperties", handle] => match HandleWithProperties::from_str(card, handle) {
106                 Ok(handle) => {
107                     let props = match handle {
108                         HandleWithProperties::Connector(handle) => {
109                             card.get_properties(handle).unwrap()
110                         }
111                         HandleWithProperties::CRTC(handle) => card.get_properties(handle).unwrap(),
112                         HandleWithProperties::Plane(handle) => card.get_properties(handle).unwrap(),
113                     };
114                     for (id, val) in props.iter() {
115                         println!("\tProperty: {:?}\tValue: {:?}", id, val);
116                     }
117                 }
118                 Err(_) => println!("Unknown handle or handle has no properties"),
119             },
120             // Set a property's value on a resource
121             ["SetProperty", handle, property, value] => {
122                 let property: u32 = str::parse(property).unwrap();
123                 let property: drm::control::property::Handle = from_u32(property).unwrap();
124                 let value: u64 = str::parse(value).unwrap();
125 
126                 match HandleWithProperties::from_str(card, handle) {
127                     Ok(handle) => {
128                         match handle {
129                             HandleWithProperties::Connector(handle) => {
130                                 println!("\t{:?}", card.set_property(handle, property, value));
131                             }
132                             HandleWithProperties::CRTC(handle) => {
133                                 println!("\t{:?}", card.set_property(handle, property, value));
134                             }
135                             HandleWithProperties::Plane(handle) => {
136                                 println!("\t{:?}", card.set_property(handle, property, value));
137                             }
138                         };
139                     }
140                     Err(_) => println!("Unknown handle or handle has no properties"),
141                 };
142             }
143             ["GetModes", handle] => match HandleWithProperties::from_str(card, handle) {
144                 Ok(HandleWithProperties::Connector(handle)) => {
145                     let modes = card.get_modes(handle).unwrap();
146                     for mode in modes {
147                         println!("\tName:\t{:?}", mode.name());
148                         println!("\t\tSize:\t{:?}", mode.size());
149                         println!("\t\tRefresh:\t{:?}", mode.vrefresh());
150                     }
151                 }
152                 _ => println!("Unknown handle or handle is not a connector"),
153             },
154             ["help"] => {
155                 println!("CreateAtomicSet");
156                 println!("DestroyFramebuffer <handle>");
157                 println!("GetResources");
158                 println!("GetProperty <handle>");
159                 println!("GetProperties <handle>");
160                 println!("SetProperty <handle> <poperty> <value>");
161                 println!("GetModes <handle>");
162             }
163             ["quit"] => break,
164             [] => (),
165             _ => {
166                 println!("Unknown command");
167             }
168         }
169     }
170 }
171 
172 #[allow(clippy::upper_case_acronyms)]
173 enum HandleWithProperties {
174     Connector(drm::control::connector::Handle),
175     CRTC(drm::control::crtc::Handle),
176     Plane(drm::control::plane::Handle),
177 }
178 
179 impl HandleWithProperties {
180     // This is a helper command that will take a string of a number and lookup
181     // the corresponding resource.
from_str(card: &Card, handle: &str) -> Result<Self, ()>182     fn from_str(card: &Card, handle: &str) -> Result<Self, ()> {
183         let handle: u32 = str::parse(handle).unwrap();
184         let handle = RawResourceHandle::new(handle).unwrap();
185 
186         let rhandles = card.resource_handles().unwrap();
187         for connector in rhandles.connectors().iter().map(|h| (*h).into()) {
188             if handle == connector {
189                 return Ok(HandleWithProperties::Connector(handle.into()));
190             }
191         }
192 
193         for crtc in rhandles.crtcs().iter().map(|h| (*h).into()) {
194             if handle == crtc {
195                 return Ok(HandleWithProperties::CRTC(handle.into()));
196             }
197         }
198 
199         let phandles = card.plane_handles().unwrap();
200         for plane in phandles.iter().map(|h| (*h).into()) {
201             if handle == plane {
202                 return Ok(HandleWithProperties::Plane(handle.into()));
203             }
204         }
205 
206         Err(())
207     }
208 }
209