2009-08-17 Robert Millan <rmh.grub@aybabtu.com>
[grub2/phcoder/solaris.git] / video / video.c
blob36ebfd1b81366f086b1f279141fd6c5fce38c5c9
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/video.h>
20 #include <grub/types.h>
21 #include <grub/dl.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
25 /* The list of video adapters registered to system. */
26 static grub_video_adapter_t grub_video_adapter_list;
28 /* Active video adapter. */
29 static grub_video_adapter_t grub_video_adapter_active;
31 /* Register video driver. */
32 void
33 grub_video_register (grub_video_adapter_t adapter)
35 adapter->next = grub_video_adapter_list;
36 grub_video_adapter_list = adapter;
39 /* Unregister video driver. */
40 void
41 grub_video_unregister (grub_video_adapter_t adapter)
43 grub_video_adapter_t *p, q;
45 for (p = &grub_video_adapter_list, q = *p; q; p = &(q->next), q = q->next)
46 if (q == adapter)
48 *p = q->next;
49 break;
53 /* Iterate thru all registered video drivers. */
54 void
55 grub_video_iterate (int (*hook) (grub_video_adapter_t adapter))
57 grub_video_adapter_t p;
59 for (p = grub_video_adapter_list; p; p = p->next)
60 if (hook (p))
61 break;
64 /* Restore back to initial mode (where applicable). */
65 grub_err_t
66 grub_video_restore (void)
68 if (grub_video_adapter_active)
70 grub_video_adapter_active->fini ();
71 if (grub_errno != GRUB_ERR_NONE)
72 return grub_errno;
74 grub_video_adapter_active = 0;
76 return GRUB_ERR_NONE;
79 /* Get information about active video mode. */
80 grub_err_t
81 grub_video_get_info (struct grub_video_mode_info *mode_info)
83 if (! grub_video_adapter_active)
84 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
86 /* If mode_info is NULL just report that video adapter is active. */
87 if (! mode_info)
89 grub_errno = GRUB_ERR_NONE;
90 return grub_errno;
93 return grub_video_adapter_active->get_info (mode_info);
96 /* Get information about active video mode. */
97 grub_err_t
98 grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info,
99 void **framebuffer)
101 grub_err_t err;
103 if (! grub_video_adapter_active)
104 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
106 err = grub_video_adapter_active->get_info_and_fini (mode_info, framebuffer);
107 if (err)
108 return err;
110 grub_video_adapter_active = 0;
111 return GRUB_ERR_NONE;
114 /* Determine optimized blitting formation for specified video mode info. */
115 enum grub_video_blit_format
116 grub_video_get_blit_format (struct grub_video_mode_info *mode_info)
118 /* Check if we have any known 32 bit modes. */
119 if (mode_info->bpp == 32)
121 if ((mode_info->red_mask_size == 8)
122 && (mode_info->red_field_pos == 16)
123 && (mode_info->green_mask_size == 8)
124 && (mode_info->green_field_pos == 8)
125 && (mode_info->blue_mask_size == 8)
126 && (mode_info->blue_field_pos == 0))
128 return GRUB_VIDEO_BLIT_FORMAT_BGRA_8888;
130 else if ((mode_info->red_mask_size == 8)
131 && (mode_info->red_field_pos == 0)
132 && (mode_info->green_mask_size == 8)
133 && (mode_info->green_field_pos == 8)
134 && (mode_info->blue_mask_size == 8)
135 && (mode_info->blue_field_pos == 16))
137 return GRUB_VIDEO_BLIT_FORMAT_RGBA_8888;
140 /* Check if we have any known 24 bit modes. */
141 else if (mode_info->bpp == 24)
143 if ((mode_info->red_mask_size == 8)
144 && (mode_info->red_field_pos == 16)
145 && (mode_info->green_mask_size == 8)
146 && (mode_info->green_field_pos == 8)
147 && (mode_info->blue_mask_size == 8)
148 && (mode_info->blue_field_pos == 0))
150 return GRUB_VIDEO_BLIT_FORMAT_BGR_888;
152 else if ((mode_info->red_mask_size == 8)
153 && (mode_info->red_field_pos == 0)
154 && (mode_info->green_mask_size == 8)
155 && (mode_info->green_field_pos == 8)
156 && (mode_info->blue_mask_size == 8)
157 && (mode_info->blue_field_pos == 16))
159 return GRUB_VIDEO_BLIT_FORMAT_RGB_888;
162 /* Check if we have any known 16 bit modes. */
163 else if (mode_info->bpp == 16)
165 if ((mode_info->red_mask_size == 5)
166 && (mode_info->red_field_pos == 11)
167 && (mode_info->green_mask_size == 6)
168 && (mode_info->green_field_pos == 5)
169 && (mode_info->blue_mask_size == 5)
170 && (mode_info->blue_field_pos == 0))
172 return GRUB_VIDEO_BLIT_FORMAT_BGR_565;
174 else if ((mode_info->red_mask_size == 5)
175 && (mode_info->red_field_pos == 0)
176 && (mode_info->green_mask_size == 6)
177 && (mode_info->green_field_pos == 5)
178 && (mode_info->blue_mask_size == 5)
179 && (mode_info->blue_field_pos == 11))
181 return GRUB_VIDEO_BLIT_FORMAT_RGB_565;
185 /* Backup route. Unknown format. */
187 /* If there are more than 8 bits per color, assume RGB(A) mode. */
188 if (mode_info->bpp > 8)
190 if (mode_info->reserved_mask_size > 0)
192 return GRUB_VIDEO_BLIT_FORMAT_RGBA;
194 else
196 return GRUB_VIDEO_BLIT_FORMAT_RGB;
200 /* Assume as indexcolor mode. */
201 return GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR;
204 /* Set new indexed color palette entries. */
205 grub_err_t
206 grub_video_set_palette (unsigned int start, unsigned int count,
207 struct grub_video_palette_data *palette_data)
209 if (! grub_video_adapter_active)
210 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
212 return grub_video_adapter_active->set_palette (start, count, palette_data);
215 /* Get indexed color palette entries. */
216 grub_err_t
217 grub_video_get_palette (unsigned int start, unsigned int count,
218 struct grub_video_palette_data *palette_data)
220 if (! grub_video_adapter_active)
221 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
223 return grub_video_adapter_active->get_palette (start, count, palette_data);
226 /* Set viewport dimensions. */
227 grub_err_t
228 grub_video_set_viewport (unsigned int x, unsigned int y,
229 unsigned int width, unsigned int height)
231 if (! grub_video_adapter_active)
232 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
234 return grub_video_adapter_active->set_viewport (x, y, width, height);
237 /* Get viewport dimensions. */
238 grub_err_t
239 grub_video_get_viewport (unsigned int *x, unsigned int *y,
240 unsigned int *width, unsigned int *height)
242 if (! grub_video_adapter_active)
243 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
245 return grub_video_adapter_active->get_viewport (x, y, width, height);
248 /* Map color name to adapter specific color. */
249 grub_video_color_t
250 grub_video_map_color (grub_uint32_t color_name)
252 if (! grub_video_adapter_active)
253 return 0;
255 return grub_video_adapter_active->map_color (color_name);
258 /* Map RGB value to adapter specific color. */
259 grub_video_color_t
260 grub_video_map_rgb (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue)
262 if (! grub_video_adapter_active)
263 return 0;
265 return grub_video_adapter_active->map_rgb (red, green, blue);
268 /* Map RGBA value to adapter specific color. */
269 grub_video_color_t
270 grub_video_map_rgba (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue,
271 grub_uint8_t alpha)
273 if (! grub_video_adapter_active)
274 return 0;
276 return grub_video_adapter_active->map_rgba (red, green, blue, alpha);
279 /* Unmap video color back to RGBA components. */
280 grub_err_t
281 grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *red,
282 grub_uint8_t *green, grub_uint8_t *blue,
283 grub_uint8_t *alpha)
285 if (! grub_video_adapter_active)
286 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
288 return grub_video_adapter_active->unmap_color (color,
289 red,
290 green,
291 blue,
292 alpha);
295 /* Fill rectangle using specified color. */
296 grub_err_t
297 grub_video_fill_rect (grub_video_color_t color, int x, int y,
298 unsigned int width, unsigned int height)
300 if (! grub_video_adapter_active)
301 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
303 return grub_video_adapter_active->fill_rect (color, x, y, width, height);
306 /* Blit bitmap to screen. */
307 grub_err_t
308 grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,
309 enum grub_video_blit_operators oper,
310 int x, int y, int offset_x, int offset_y,
311 unsigned int width, unsigned int height)
313 if (! grub_video_adapter_active)
314 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
316 return grub_video_adapter_active->blit_bitmap (bitmap, oper, x, y,
317 offset_x, offset_y,
318 width, height);
321 /* Blit render target to active render target. */
322 grub_err_t
323 grub_video_blit_render_target (struct grub_video_render_target *target,
324 enum grub_video_blit_operators oper,
325 int x, int y, int offset_x, int offset_y,
326 unsigned int width, unsigned int height)
328 if (! grub_video_adapter_active)
329 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
331 return grub_video_adapter_active->blit_render_target (target, oper, x, y,
332 offset_x, offset_y,
333 width, height);
336 /* Scroll viewport and fill new areas with specified color. */
337 grub_err_t
338 grub_video_scroll (grub_video_color_t color, int dx, int dy)
340 if (! grub_video_adapter_active)
341 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
343 return grub_video_adapter_active->scroll (color, dx, dy);
346 /* Swap buffers (swap active render target). */
347 grub_err_t
348 grub_video_swap_buffers (void)
350 if (! grub_video_adapter_active)
351 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
353 return grub_video_adapter_active->swap_buffers ();
356 /* Create new render target. */
357 grub_err_t
358 grub_video_create_render_target (struct grub_video_render_target **result,
359 unsigned int width, unsigned int height,
360 unsigned int mode_type)
362 if (! grub_video_adapter_active)
363 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
365 return grub_video_adapter_active->create_render_target (result,
366 width, height,
367 mode_type);
370 /* Delete render target. */
371 grub_err_t
372 grub_video_delete_render_target (struct grub_video_render_target *target)
374 if (! grub_video_adapter_active)
375 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
377 return grub_video_adapter_active->delete_render_target (target);
380 /* Set active render target. */
381 grub_err_t
382 grub_video_set_active_render_target (struct grub_video_render_target *target)
384 if (! grub_video_adapter_active)
385 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
387 return grub_video_adapter_active->set_active_render_target (target);
390 /* Get active render target. */
391 grub_err_t
392 grub_video_get_active_render_target (struct grub_video_render_target **target)
394 if (! grub_video_adapter_active)
395 return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
397 return grub_video_adapter_active->get_active_render_target (target);
400 grub_err_t
401 grub_video_set_mode (const char *modestring,
402 int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p,
403 struct grub_video_mode_info *mode_info))
405 char *tmp;
406 char *next_mode;
407 char *current_mode;
408 char *param;
409 char *value;
410 char *modevar;
411 int width = -1;
412 int height = -1;
413 int depth = -1;
414 int flags = 0;
416 /* Take copy of env.var. as we don't want to modify that. */
417 modevar = grub_strdup (modestring);
419 /* Initialize next mode. */
420 next_mode = modevar;
422 if (! modevar)
423 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
424 "couldn't allocate space for local modevar copy");
426 if (grub_memcmp (next_mode, "keep", sizeof ("keep")) == 0
427 || grub_memcmp (next_mode, "keep,", sizeof ("keep,") - 1) == 0
428 || grub_memcmp (next_mode, "keep;", sizeof ("keep;") - 1) == 0)
430 struct grub_video_mode_info mode_info;
431 int suitable = 1;
432 grub_err_t err;
434 grub_memset (&mode_info, 0, sizeof (mode_info));
436 if (grub_video_adapter_active)
438 err = grub_video_get_info (&mode_info);
439 if (err)
441 suitable = 0;
442 grub_errno = GRUB_ERR_NONE;
445 else
446 mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT;
448 if (suitable && hook)
449 suitable = hook (grub_video_adapter_active, &mode_info);
450 if (suitable)
452 grub_free (modevar);
453 return GRUB_ERR_NONE;
455 next_mode += sizeof ("keep") - 1;
456 if (! *next_mode)
458 grub_free (modevar);
460 return grub_error (GRUB_ERR_BAD_ARGUMENT,
461 "No suitable mode found.");
464 /* Skip separator. */
465 next_mode++;
468 /* De-activate last set video adapter. */
469 if (grub_video_adapter_active)
471 /* Finalize adapter. */
472 grub_video_adapter_active->fini ();
473 if (grub_errno != GRUB_ERR_NONE)
474 grub_errno = GRUB_ERR_NONE;
476 /* Mark active adapter as not set. */
477 grub_video_adapter_active = 0;
480 /* Loop until all modes has been tested out. */
481 while (next_mode != NULL)
483 /* Use last next_mode as current mode. */
484 tmp = next_mode;
486 /* Reset video mode settings. */
487 width = -1;
488 height = -1;
489 depth = -1;
490 flags = 0;
492 /* Save position of next mode and separate modes. */
493 for (; *next_mode; next_mode++)
494 if (*next_mode == ',' || *next_mode == ';')
495 break;
496 if (*next_mode)
498 *next_mode = 0;
499 next_mode++;
501 else
502 next_mode = 0;
504 /* Skip whitespace. */
505 while (grub_isspace (*tmp))
506 tmp++;
508 /* Initialize token holders. */
509 current_mode = tmp;
510 param = tmp;
511 value = NULL;
513 /* XXX: we assume that we're in pure text mode if
514 no video mode is initialized. Is it always true? */
515 if (grub_strcmp (param, "text") == 0)
517 struct grub_video_mode_info mode_info;
519 grub_memset (&mode_info, 0, sizeof (mode_info));
520 mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT;
522 if (! hook || hook (0, &mode_info))
524 /* Valid mode found from adapter, and it has been activated.
525 Specify it as active adapter. */
526 grub_video_adapter_active = NULL;
528 /* Free memory. */
529 grub_free (modevar);
531 return GRUB_ERR_NONE;
535 /* Parse <width>x<height>[x<depth>]*/
537 /* Find width value. */
538 value = param;
539 param = grub_strchr(param, 'x');
540 if (param == NULL)
542 grub_err_t rc;
544 /* First setup error message. */
545 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
546 "Invalid mode: %s\n",
547 current_mode);
549 /* Free memory before returning. */
550 grub_free (modevar);
552 return rc;
555 *param = 0;
556 param++;
558 width = grub_strtoul (value, 0, 0);
559 if (grub_errno != GRUB_ERR_NONE)
561 grub_err_t rc;
563 /* First setup error message. */
564 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
565 "Invalid mode: %s\n",
566 current_mode);
568 /* Free memory before returning. */
569 grub_free (modevar);
571 return rc;
574 /* Find height value. */
575 value = param;
576 param = grub_strchr(param, 'x');
577 if (param == NULL)
579 height = grub_strtoul (value, 0, 0);
580 if (grub_errno != GRUB_ERR_NONE)
582 grub_err_t rc;
584 /* First setup error message. */
585 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
586 "Invalid mode: %s\n",
587 current_mode);
589 /* Free memory before returning. */
590 grub_free (modevar);
592 return rc;
595 else
597 /* We have optional color depth value. */
598 *param = 0;
599 param++;
601 height = grub_strtoul (value, 0, 0);
602 if (grub_errno != GRUB_ERR_NONE)
604 grub_err_t rc;
606 /* First setup error message. */
607 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
608 "Invalid mode: %s\n",
609 current_mode);
611 /* Free memory before returning. */
612 grub_free (modevar);
614 return rc;
617 /* Convert color depth value. */
618 value = param;
619 depth = grub_strtoul (value, 0, 0);
620 if (grub_errno != GRUB_ERR_NONE)
622 grub_err_t rc;
624 /* First setup error message. */
625 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
626 "Invalid mode: %s\n",
627 current_mode);
629 /* Free memory before returning. */
630 grub_free (modevar);
632 return rc;
636 /* Try out video mode. */
638 /* If we have 8 or less bits, then assume that it is indexed color mode. */
639 if ((depth <= 8) && (depth != -1))
640 flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
642 /* We have more than 8 bits, then assume that it is RGB color mode. */
643 if (depth > 8)
644 flags |= GRUB_VIDEO_MODE_TYPE_RGB;
646 /* If user requested specific depth, forward that information to driver. */
647 if (depth != -1)
648 flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
649 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
651 /* Try to initialize requested mode. Ignore any errors. */
652 grub_video_adapter_t p;
654 /* Loop thru all possible video adapter trying to find requested mode. */
655 for (p = grub_video_adapter_list; p; p = p->next)
657 grub_err_t err;
658 struct grub_video_mode_info mode_info;
660 grub_memset (&mode_info, 0, sizeof (mode_info));
662 /* Try to initialize adapter, if it fails, skip to next adapter. */
663 err = p->init ();
664 if (err != GRUB_ERR_NONE)
666 grub_errno = GRUB_ERR_NONE;
667 continue;
670 /* Try to initialize video mode. */
671 err = p->setup (width, height, flags);
672 if (err != GRUB_ERR_NONE)
674 p->fini ();
675 grub_errno = GRUB_ERR_NONE;
676 continue;
679 err = p->get_info (&mode_info);
680 if (err != GRUB_ERR_NONE)
682 p->fini ();
683 grub_errno = GRUB_ERR_NONE;
684 continue;
687 if (hook && ! hook (p, &mode_info))
689 p->fini ();
690 grub_errno = GRUB_ERR_NONE;
691 continue;
694 /* Valid mode found from adapter, and it has been activated.
695 Specify it as active adapter. */
696 grub_video_adapter_active = p;
698 /* Free memory. */
699 grub_free (modevar);
701 return GRUB_ERR_NONE;
706 /* Free memory. */
707 grub_free (modevar);
709 return grub_error (GRUB_ERR_BAD_ARGUMENT,
710 "No suitable mode found.");
713 /* Initialize Video API module. */
714 GRUB_MOD_INIT(video_video)
718 /* Finalize Video API module. */
719 GRUB_MOD_FINI(video_video)