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