1use core::cell::Cell;
18
19use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
20use kernel::hil;
21use kernel::hil::screen::{ScreenPixelFormat, ScreenRotation};
22use kernel::processbuffer::ReadableProcessBuffer;
23use kernel::syscall::{CommandReturn, SyscallDriver};
24use kernel::utilities::cells::{OptionalCell, TakeCell};
25use kernel::utilities::leasable_buffer::SubSliceMut;
26use kernel::{ErrorCode, ProcessId};
27
28use capsules_core::driver;
30pub const DRIVER_NUM: usize = driver::NUM::Screen as usize;
31
32mod ro_allow {
34 pub const SHARED: usize = 0;
35 pub const COUNT: u8 = 1;
37}
38
39fn screen_rotation_from(screen_rotation: usize) -> Option<ScreenRotation> {
40 match screen_rotation {
41 0 => Some(ScreenRotation::Normal),
42 1 => Some(ScreenRotation::Rotated90),
43 2 => Some(ScreenRotation::Rotated180),
44 3 => Some(ScreenRotation::Rotated270),
45 _ => None,
46 }
47}
48
49fn screen_pixel_format_from(screen_pixel_format: usize) -> Option<ScreenPixelFormat> {
50 match screen_pixel_format {
51 0 => Some(ScreenPixelFormat::Mono),
52 1 => Some(ScreenPixelFormat::RGB_332),
53 2 => Some(ScreenPixelFormat::RGB_565),
54 3 => Some(ScreenPixelFormat::RGB_888),
55 4 => Some(ScreenPixelFormat::ARGB_8888),
56 _ => None,
57 }
58}
59
60#[derive(Clone, Copy, PartialEq)]
61enum ScreenCommand {
62 Nop,
63 SetBrightness(u16),
64 SetPower(bool),
65 SetInvert(bool),
66 SetRotation(ScreenRotation),
67 SetResolution {
68 width: usize,
69 height: usize,
70 },
71 SetPixelFormat(ScreenPixelFormat),
72 SetWriteFrame {
73 x: usize,
74 y: usize,
75 width: usize,
76 height: usize,
77 },
78 Write(usize),
79 Fill,
80}
81
82fn pixels_in_bytes(pixels: usize, bits_per_pixel: usize) -> usize {
83 let bytes = pixels * bits_per_pixel / 8;
84 if pixels * bits_per_pixel % 8 != 0 {
85 bytes + 1
86 } else {
87 bytes
88 }
89}
90
91pub struct App {
92 pending_command: bool,
93 write_position: usize,
94 write_len: usize,
95 command: ScreenCommand,
96 width: usize,
97 height: usize,
98}
99
100impl Default for App {
101 fn default() -> App {
102 App {
103 pending_command: false,
104 command: ScreenCommand::Nop,
105 width: 0,
106 height: 0,
107 write_len: 0,
108 write_position: 0,
109 }
110 }
111}
112
113pub struct Screen<'a> {
114 screen: &'a dyn hil::screen::Screen<'a>,
115 screen_setup: Option<&'a dyn hil::screen::ScreenSetup<'a>>,
116 apps: Grant<App, UpcallCount<1>, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>,
117 current_process: OptionalCell<ProcessId>,
118 pixel_format: Cell<ScreenPixelFormat>,
119 buffer: TakeCell<'static, [u8]>,
120}
121
122impl<'a> Screen<'a> {
123 pub fn new(
124 screen: &'a dyn hil::screen::Screen<'a>,
125 screen_setup: Option<&'a dyn hil::screen::ScreenSetup<'a>>,
126 buffer: &'static mut [u8],
127 grant: Grant<App, UpcallCount<1>, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>,
128 ) -> Screen<'a> {
129 Screen {
130 screen,
131 screen_setup,
132 apps: grant,
133 current_process: OptionalCell::empty(),
134 pixel_format: Cell::new(screen.get_pixel_format()),
135 buffer: TakeCell::new(buffer),
136 }
137 }
138
139 fn enqueue_command(&self, command: ScreenCommand, process_id: ProcessId) -> CommandReturn {
143 match self
144 .apps
145 .enter(process_id, |app, _| {
146 if app.pending_command {
147 CommandReturn::failure(ErrorCode::BUSY)
148 } else {
149 app.pending_command = true;
150 app.command = command;
151 app.write_position = 0;
152 CommandReturn::success()
153 }
154 })
155 .map_err(ErrorCode::from)
156 {
157 Err(e) => CommandReturn::failure(e),
158 Ok(r) => {
159 if self.current_process.is_none() {
160 self.current_process.set(process_id);
161 let r = self.call_screen(command, process_id);
162 if r != Ok(()) {
163 self.current_process.clear();
164 }
165 CommandReturn::from(r)
166 } else {
167 r
168 }
169 }
170 }
171 }
172
173 fn is_len_multiple_color_depth(&self, len: usize) -> bool {
174 let depth = pixels_in_bytes(1, self.screen.get_pixel_format().get_bits_per_pixel());
175 (len % depth) == 0
176 }
177
178 fn call_screen(&self, command: ScreenCommand, process_id: ProcessId) -> Result<(), ErrorCode> {
179 match command {
180 ScreenCommand::SetBrightness(brighness) => self.screen.set_brightness(brighness),
181 ScreenCommand::SetPower(enabled) => self.screen.set_power(enabled),
182 ScreenCommand::SetInvert(enabled) => self.screen.set_invert(enabled),
183 ScreenCommand::SetRotation(rotation) => {
184 if let Some(screen) = self.screen_setup {
185 screen.set_rotation(rotation)
186 } else {
187 Err(ErrorCode::NOSUPPORT)
188 }
189 }
190 ScreenCommand::SetResolution { width, height } => {
191 if let Some(screen) = self.screen_setup {
192 screen.set_resolution((width, height))
193 } else {
194 Err(ErrorCode::NOSUPPORT)
195 }
196 }
197 ScreenCommand::SetPixelFormat(pixel_format) => {
198 if let Some(screen) = self.screen_setup {
199 screen.set_pixel_format(pixel_format)
200 } else {
201 Err(ErrorCode::NOSUPPORT)
202 }
203 }
204 ScreenCommand::Fill => {
205 match self
206 .apps
207 .enter(process_id, |app, kernel_data| {
208 let len = kernel_data
209 .get_readonly_processbuffer(ro_allow::SHARED)
210 .map_or(0, |shared| shared.len());
211 if len == 0 {
213 Err(ErrorCode::NOMEM)
214 } else if !self.is_len_multiple_color_depth(len) {
215 Err(ErrorCode::INVAL)
216 } else {
217 app.write_position = 0;
218 app.write_len = pixels_in_bytes(
219 app.width * app.height,
220 self.pixel_format.get().get_bits_per_pixel(),
221 );
222 Ok(())
223 }
224 })
225 .unwrap_or_else(|err| err.into())
226 {
227 Err(e) => Err(e),
228 Ok(()) => self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
229 let len = self.fill_next_buffer_for_write(buffer);
230 if len > 0 {
231 let mut data = SubSliceMut::new(buffer);
232 data.slice(..len);
233 self.screen.write(data, false)
234 } else {
235 self.buffer.replace(buffer);
236 self.run_next_command(kernel::errorcode::into_statuscode(Ok(())), 0, 0);
237 Ok(())
238 }
239 }),
240 }
241 }
242
243 ScreenCommand::Write(data_len) => {
244 match self
245 .apps
246 .enter(process_id, |app, kernel_data| {
247 let len = kernel_data
248 .get_readonly_processbuffer(ro_allow::SHARED)
249 .map_or(0, |shared| shared.len())
250 .min(data_len);
251 if len == 0 {
253 Err(ErrorCode::NOMEM)
254 } else if !self.is_len_multiple_color_depth(len) {
255 Err(ErrorCode::INVAL)
256 } else {
257 app.write_position = 0;
258 app.write_len = len;
259 Ok(())
260 }
261 })
262 .unwrap_or_else(|err| err.into())
263 {
264 Ok(()) => self.buffer.take().map_or(Err(ErrorCode::FAIL), |buffer| {
265 let len = self.fill_next_buffer_for_write(buffer);
266 if len > 0 {
267 let mut data = SubSliceMut::new(buffer);
268 data.slice(..len);
269 self.screen.write(data, false)
270 } else {
271 self.buffer.replace(buffer);
272 self.run_next_command(kernel::errorcode::into_statuscode(Ok(())), 0, 0);
273 Ok(())
274 }
275 }),
276 Err(e) => Err(e),
277 }
278 }
279 ScreenCommand::SetWriteFrame {
280 x,
281 y,
282 width,
283 height,
284 } => self
285 .apps
286 .enter(process_id, |app, _| {
287 app.write_position = 0;
288 app.width = width;
289 app.height = height;
290
291 self.screen.set_write_frame(x, y, width, height)
292 })
293 .unwrap_or_else(|err| err.into()),
294 _ => Err(ErrorCode::NOSUPPORT),
295 }
296 }
297
298 fn schedule_callback(&self, data1: usize, data2: usize, data3: usize) {
299 self.current_process.take().map(|process_id| {
300 let _ = self.apps.enter(process_id, |app, upcalls| {
301 app.pending_command = false;
302 upcalls.schedule_upcall(0, (data1, data2, data3)).ok();
303 });
304 });
305 }
306
307 fn run_next_command(&self, data1: usize, data2: usize, data3: usize) {
308 self.schedule_callback(data1, data2, data3);
309
310 let mut command = ScreenCommand::Nop;
311
312 for app in self.apps.iter() {
314 let process_id = app.processid();
315 let start_command = app.enter(|app, _| {
316 if app.pending_command {
317 app.pending_command = false;
318 command = app.command;
319 self.current_process.set(process_id);
320 true
321 } else {
322 false
323 }
324 });
325 if start_command {
326 match self.call_screen(command, process_id) {
327 Err(err) => {
328 self.current_process.clear();
329 self.schedule_callback(kernel::errorcode::into_statuscode(Err(err)), 0, 0);
330 }
331 Ok(()) => {
332 break;
333 }
334 }
335 }
336 }
337 }
338
339 fn fill_next_buffer_for_write(&self, buffer: &mut [u8]) -> usize {
340 self.current_process.map_or(0, |process_id| {
341 self.apps
342 .enter(process_id, |app, kernel_data| {
343 let position = app.write_position;
344 let mut len = app.write_len;
345 if position < len {
346 let buffer_size = buffer.len();
347 let chunk_number = position / buffer_size;
348 let initial_pos = chunk_number * buffer_size;
349 let mut pos = initial_pos;
350 match app.command {
351 ScreenCommand::Write(_) => {
352 let res = kernel_data
353 .get_readonly_processbuffer(ro_allow::SHARED)
354 .and_then(|shared| {
355 shared.enter(|s| {
356 let mut count = 0;
357 let mut chunks = s.chunks(buffer_size);
358 if let Some(chunk) = chunks.nth(chunk_number) {
359 for (i, byte) in chunk.iter().enumerate() {
360 if pos < len {
361 buffer[i] = byte.get();
362 count += 1;
363 pos += 1;
364 } else {
365 break;
366 }
367 }
368 count
369 } else {
370 0
372 }
373 })
374 })
375 .unwrap_or(0);
376 if res > 0 {
377 app.write_position = pos;
378 }
379 res
380 }
381 ScreenCommand::Fill => {
382 len -= position;
384 let bytes_per_pixel = pixels_in_bytes(
385 1,
386 self.pixel_format.get().get_bits_per_pixel(),
387 );
388 let mut write_len = buffer_size / bytes_per_pixel;
389 if write_len > len {
390 write_len = len
391 }
392 app.write_position += write_len * bytes_per_pixel;
393 kernel_data
394 .get_readonly_processbuffer(ro_allow::SHARED)
395 .and_then(|shared| {
396 shared.enter(|data| {
397 let mut bytes = data.iter();
398 for i in 0..bytes_per_pixel {
400 if let Some(byte) = bytes.next() {
401 buffer[i] = byte.get();
402 }
403 }
404 for i in 1..write_len {
405 for j in 0..bytes_per_pixel {
407 buffer[bytes_per_pixel * i + j] = buffer[j]
408 }
409 }
410 write_len * bytes_per_pixel
411 })
412 })
413 .unwrap_or(0)
414 }
415 _ => 0,
416 }
417 } else {
418 0
419 }
420 })
421 .unwrap_or(0)
422 })
423 }
424}
425
426impl hil::screen::ScreenClient for Screen<'_> {
427 fn command_complete(&self, r: Result<(), ErrorCode>) {
428 self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0);
429 }
430
431 fn write_complete(&self, data: SubSliceMut<'static, u8>, r: Result<(), ErrorCode>) {
432 let buffer = data.take();
433 let len = self.fill_next_buffer_for_write(buffer);
434
435 if r == Ok(()) && len > 0 {
436 let mut data = SubSliceMut::new(buffer);
437 data.slice(..len);
438 let _ = self.screen.write(data, true);
439 } else {
440 self.buffer.replace(buffer);
441 self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0);
442 }
443 }
444
445 fn screen_is_ready(&self) {
446 self.run_next_command(kernel::errorcode::into_statuscode(Ok(())), 0, 0);
447 }
448}
449
450impl hil::screen::ScreenSetupClient for Screen<'_> {
451 fn command_complete(&self, r: Result<(), ErrorCode>) {
452 self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0);
453 }
454}
455
456impl SyscallDriver for Screen<'_> {
457 fn command(
458 &self,
459 command_num: usize,
460 data1: usize,
461 data2: usize,
462 process_id: ProcessId,
463 ) -> CommandReturn {
464 match command_num {
465 0 => CommandReturn::success(),
467 1 => CommandReturn::success_u32(self.screen_setup.is_some() as u32),
469 2 => self.enqueue_command(ScreenCommand::SetPower(data1 != 0), process_id),
471 3 => self.enqueue_command(ScreenCommand::SetBrightness(data1 as u16), process_id),
473 4 => self.enqueue_command(ScreenCommand::SetInvert(true), process_id),
475 5 => self.enqueue_command(ScreenCommand::SetInvert(false), process_id),
477 6 => self.enqueue_command(ScreenCommand::SetInvert(data1 != 0), process_id),
479
480 11 => {
482 if let Some(screen) = self.screen_setup {
483 CommandReturn::success_u32(screen.get_num_supported_resolutions() as u32)
484 } else {
485 CommandReturn::failure(ErrorCode::NOSUPPORT)
486 }
487 }
488 12 => {
490 if let Some(screen) = self.screen_setup {
491 match screen.get_supported_resolution(data1) {
492 Some((width, height)) if width > 0 && height > 0 => {
493 CommandReturn::success_u32_u32(width as u32, height as u32)
494 }
495 _ => CommandReturn::failure(ErrorCode::INVAL),
496 }
497 } else {
498 CommandReturn::failure(ErrorCode::NOSUPPORT)
499 }
500 }
501
502 13 => {
504 if let Some(screen) = self.screen_setup {
505 CommandReturn::success_u32(screen.get_num_supported_pixel_formats() as u32)
506 } else {
507 CommandReturn::failure(ErrorCode::NOSUPPORT)
508 }
509 }
510 14 => {
512 if let Some(screen) = self.screen_setup {
513 match screen.get_supported_pixel_format(data1) {
514 Some(pixel_format) => CommandReturn::success_u32(pixel_format as u32),
515 _ => CommandReturn::failure(ErrorCode::INVAL),
516 }
517 } else {
518 CommandReturn::failure(ErrorCode::NOSUPPORT)
519 }
520 }
521
522 21 => CommandReturn::success_u32(self.screen.get_rotation() as u32),
524 22 => self.enqueue_command(
526 ScreenCommand::SetRotation(
527 screen_rotation_from(data1).unwrap_or(ScreenRotation::Normal),
528 ),
529 process_id,
530 ),
531
532 23 => {
534 let (width, height) = self.screen.get_resolution();
535 CommandReturn::success_u32_u32(width as u32, height as u32)
536 }
537 24 => self.enqueue_command(
539 ScreenCommand::SetResolution {
540 width: data1,
541 height: data2,
542 },
543 process_id,
544 ),
545
546 25 => CommandReturn::success_u32(self.screen.get_pixel_format() as u32),
548 26 => {
550 if let Some(pixel_format) = screen_pixel_format_from(data1) {
551 self.enqueue_command(ScreenCommand::SetPixelFormat(pixel_format), process_id)
552 } else {
553 CommandReturn::failure(ErrorCode::INVAL)
554 }
555 }
556
557 100 => self.enqueue_command(
559 ScreenCommand::SetWriteFrame {
560 x: (data1 >> 16) & 0xFFFF,
561 y: data1 & 0xFFFF,
562 width: (data2 >> 16) & 0xFFFF,
563 height: data2 & 0xFFFF,
564 },
565 process_id,
566 ),
567 200 => self.enqueue_command(ScreenCommand::Write(data1), process_id),
569 300 => self.enqueue_command(ScreenCommand::Fill, process_id),
571
572 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
573 }
574 }
575
576 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
577 self.apps.enter(processid, |_, _| {})
578 }
579}