選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

fbcon.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*
  2. * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. /** @file
  21. *
  22. * Frame buffer console
  23. *
  24. */
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <assert.h>
  28. #include <byteswap.h>
  29. #include <ipxe/ansiesc.h>
  30. #include <ipxe/image.h>
  31. #include <ipxe/pixbuf.h>
  32. #include <ipxe/umalloc.h>
  33. #include <ipxe/console.h>
  34. #include <ipxe/fbcon.h>
  35. /**
  36. * Calculate raw colour value
  37. *
  38. * @v fbcon Frame buffer console
  39. * @v rgb 24-bit RGB value
  40. * @ret raw Raw colour
  41. */
  42. static uint32_t fbcon_colour ( struct fbcon *fbcon, uint32_t rgb ) {
  43. struct fbcon_colour_map *map = fbcon->map;
  44. uint8_t red = ( rgb >> 16 );
  45. uint8_t green = ( rgb >> 8 );
  46. uint8_t blue = ( rgb >> 0 );
  47. uint32_t mapped;
  48. mapped = ( ( ( red >> map->red_scale ) << map->red_lsb ) |
  49. ( ( green >> map->green_scale ) << map->green_lsb ) |
  50. ( ( blue >> map->blue_scale ) << map->blue_lsb ) );
  51. return cpu_to_le32 ( mapped );
  52. }
  53. /**
  54. * Calculate ANSI font colour
  55. *
  56. * @v fbcon Frame buffer console
  57. * @v ansicol ANSI colour value (0-based)
  58. * @ret colour Raw colour
  59. */
  60. static uint32_t fbcon_ansi_colour ( struct fbcon *fbcon,
  61. unsigned int ansicol ) {
  62. uint32_t rgb;
  63. /* Treat ansicol as 3-bit BGR with intensity 0xaa */
  64. rgb = ( ( ( ansicol & ( 1 << 0 ) ) ? 0xaa0000 : 0 ) |
  65. ( ( ansicol & ( 1 << 1 ) ) ? 0x00aa00 : 0 ) |
  66. ( ( ansicol & ( 1 << 2 ) ) ? 0x0000aa : 0 ) );
  67. return fbcon_colour ( fbcon, rgb );
  68. }
  69. /**
  70. * Set default foreground colour
  71. *
  72. * @v fbcon Frame buffer console
  73. */
  74. static void fbcon_set_default_foreground ( struct fbcon *fbcon ) {
  75. /* Default to non-bold white foreground */
  76. fbcon->foreground = fbcon_ansi_colour ( fbcon, 0x7 );
  77. fbcon->bold = 0;
  78. }
  79. /**
  80. * Set default background colour
  81. *
  82. * @v fbcon Frame buffer console
  83. */
  84. static void fbcon_set_default_background ( struct fbcon *fbcon ) {
  85. /* Default to transparent background */
  86. fbcon->background = FBCON_TRANSPARENT;
  87. }
  88. /**
  89. * Clear rows of characters
  90. *
  91. * @v fbcon Frame buffer console
  92. * @v ypos Starting Y position
  93. */
  94. static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) {
  95. struct fbcon_text_cell cell = {
  96. .foreground = fbcon->foreground,
  97. .background = fbcon->background,
  98. .character = ' ',
  99. };
  100. size_t offset;
  101. unsigned int xpos;
  102. /* Clear stored character array */
  103. for ( ; ypos < fbcon->character.height ; ypos++ ) {
  104. offset = ( ypos * fbcon->character.width * sizeof ( cell ) );
  105. for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) {
  106. copy_to_user ( fbcon->text.start, offset, &cell,
  107. sizeof ( cell ) );
  108. offset += sizeof ( cell );
  109. }
  110. }
  111. }
  112. /**
  113. * Store character at specified position
  114. *
  115. * @v fbcon Frame buffer console
  116. * @v cell Text cell
  117. * @v xpos X position
  118. * @v ypos Y position
  119. */
  120. static void fbcon_store ( struct fbcon *fbcon, struct fbcon_text_cell *cell,
  121. unsigned int xpos, unsigned int ypos ) {
  122. size_t offset;
  123. /* Store cell */
  124. offset = ( ( ( ypos * fbcon->character.width ) + xpos ) *
  125. sizeof ( *cell ) );
  126. copy_to_user ( fbcon->text.start, offset, cell, sizeof ( *cell ) );
  127. }
  128. /**
  129. * Draw character at specified position
  130. *
  131. * @v fbcon Frame buffer console
  132. * @v cell Text cell
  133. * @v xpos X position
  134. * @v ypos Y position
  135. */
  136. static void fbcon_draw ( struct fbcon *fbcon, struct fbcon_text_cell *cell,
  137. unsigned int xpos, unsigned int ypos ) {
  138. struct fbcon_font_glyph glyph;
  139. size_t offset;
  140. size_t pixel_len;
  141. size_t skip_len;
  142. unsigned int row;
  143. unsigned int column;
  144. uint8_t bitmask;
  145. int transparent;
  146. void *src;
  147. /* Get font character */
  148. copy_from_user ( &glyph, fbcon->font->start,
  149. ( cell->character * sizeof ( glyph ) ),
  150. sizeof ( glyph ) );
  151. /* Calculate pixel geometry */
  152. offset = ( fbcon->indent +
  153. ( ypos * fbcon->character.stride ) +
  154. ( xpos * fbcon->character.len ) );
  155. pixel_len = fbcon->pixel->len;
  156. skip_len = ( fbcon->pixel->stride - fbcon->character.len );
  157. /* Check for transparent background colour */
  158. transparent = ( cell->background == FBCON_TRANSPARENT );
  159. /* Draw character rows */
  160. for ( row = 0 ; row < FBCON_CHAR_HEIGHT ; row++ ) {
  161. /* Draw background picture, if applicable */
  162. if ( transparent ) {
  163. if ( fbcon->picture.start ) {
  164. memcpy_user ( fbcon->start, offset,
  165. fbcon->picture.start, offset,
  166. fbcon->character.len );
  167. } else {
  168. memset_user ( fbcon->start, offset, 0,
  169. fbcon->character.len );
  170. }
  171. }
  172. /* Draw character row */
  173. for ( column = FBCON_CHAR_WIDTH, bitmask = glyph.bitmask[row] ;
  174. column ; column--, bitmask <<= 1, offset += pixel_len ) {
  175. if ( bitmask & 0x80 ) {
  176. src = &cell->foreground;
  177. } else if ( ! transparent ) {
  178. src = &cell->background;
  179. } else {
  180. continue;
  181. }
  182. copy_to_user ( fbcon->start, offset, src, pixel_len );
  183. }
  184. /* Move to next row */
  185. offset += skip_len;
  186. }
  187. }
  188. /**
  189. * Redraw all characters
  190. *
  191. * @v fbcon Frame buffer console
  192. */
  193. static void fbcon_redraw ( struct fbcon *fbcon ) {
  194. struct fbcon_text_cell cell;
  195. size_t offset = 0;
  196. unsigned int xpos;
  197. unsigned int ypos;
  198. /* Redraw characters */
  199. for ( ypos = 0 ; ypos < fbcon->character.height ; ypos++ ) {
  200. for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) {
  201. copy_from_user ( &cell, fbcon->text.start, offset,
  202. sizeof ( cell ) );
  203. fbcon_draw ( fbcon, &cell, xpos, ypos );
  204. offset += sizeof ( cell );
  205. }
  206. }
  207. }
  208. /**
  209. * Scroll screen
  210. *
  211. * @v fbcon Frame buffer console
  212. */
  213. static void fbcon_scroll ( struct fbcon *fbcon ) {
  214. size_t row_len;
  215. /* Sanity check */
  216. assert ( fbcon->ypos == fbcon->character.height );
  217. /* Scroll up character array */
  218. row_len = ( fbcon->character.width * sizeof ( struct fbcon_text_cell ));
  219. memmove_user ( fbcon->text.start, 0, fbcon->text.start, row_len,
  220. ( row_len * ( fbcon->character.height - 1 ) ) );
  221. fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) );
  222. /* Update cursor position */
  223. fbcon->ypos--;
  224. /* Redraw all characters */
  225. fbcon_redraw ( fbcon );
  226. }
  227. /**
  228. * Draw character at cursor position
  229. *
  230. * @v fbcon Frame buffer console
  231. * @v show_cursor Show cursor
  232. */
  233. static void fbcon_draw_cursor ( struct fbcon *fbcon, int show_cursor ) {
  234. struct fbcon_text_cell cell;
  235. size_t offset;
  236. offset = ( ( ( fbcon->ypos * fbcon->character.width ) + fbcon->xpos ) *
  237. sizeof ( cell ) );
  238. copy_from_user ( &cell, fbcon->text.start, offset, sizeof ( cell ) );
  239. if ( show_cursor ) {
  240. cell.background = fbcon->foreground;
  241. cell.foreground = ( ( fbcon->background == FBCON_TRANSPARENT ) ?
  242. 0 : fbcon->background );
  243. }
  244. fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
  245. }
  246. /**
  247. * Handle ANSI CUP (cursor position)
  248. *
  249. * @v ctx ANSI escape sequence context
  250. * @v count Parameter count
  251. * @v params[0] Row (1 is top)
  252. * @v params[1] Column (1 is left)
  253. */
  254. static void fbcon_handle_cup ( struct ansiesc_context *ctx,
  255. unsigned int count __unused, int params[] ) {
  256. struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
  257. int cx = ( params[1] - 1 );
  258. int cy = ( params[0] - 1 );
  259. fbcon_draw_cursor ( fbcon, 0 );
  260. fbcon->xpos = cx;
  261. if ( fbcon->xpos >= fbcon->character.width )
  262. fbcon->xpos = 0;
  263. fbcon->ypos = cy;
  264. if ( fbcon->ypos >= fbcon->character.height )
  265. fbcon->ypos = 0;
  266. fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
  267. }
  268. /**
  269. * Handle ANSI ED (erase in page)
  270. *
  271. * @v ctx ANSI escape sequence context
  272. * @v count Parameter count
  273. * @v params[0] Region to erase
  274. */
  275. static void fbcon_handle_ed ( struct ansiesc_context *ctx,
  276. unsigned int count __unused,
  277. int params[] __unused ) {
  278. struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
  279. /* We assume that we always clear the whole screen */
  280. assert ( params[0] == ANSIESC_ED_ALL );
  281. /* Clear character array */
  282. fbcon_clear ( fbcon, 0 );
  283. /* Redraw all characters */
  284. fbcon_redraw ( fbcon );
  285. /* Reset cursor position */
  286. fbcon->xpos = 0;
  287. fbcon->ypos = 0;
  288. fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
  289. }
  290. /**
  291. * Handle ANSI SGR (set graphics rendition)
  292. *
  293. * @v ctx ANSI escape sequence context
  294. * @v count Parameter count
  295. * @v params List of graphic rendition aspects
  296. */
  297. static void fbcon_handle_sgr ( struct ansiesc_context *ctx, unsigned int count,
  298. int params[] ) {
  299. struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
  300. uint32_t *custom = NULL;
  301. uint32_t rgb;
  302. unsigned int end;
  303. unsigned int i;
  304. int aspect;
  305. for ( i = 0 ; i < count ; i++ ) {
  306. /* Process aspect */
  307. aspect = params[i];
  308. if ( aspect == 0 ) {
  309. fbcon_set_default_foreground ( fbcon );
  310. fbcon_set_default_background ( fbcon );
  311. } else if ( aspect == 1 ) {
  312. fbcon->bold = fbcon_colour ( fbcon, FBCON_BOLD );
  313. } else if ( aspect == 22 ) {
  314. fbcon->bold = 0;
  315. } else if ( ( aspect >= 30 ) && ( aspect <= 37 ) ) {
  316. fbcon->foreground =
  317. fbcon_ansi_colour ( fbcon, aspect - 30 );
  318. } else if ( aspect == 38 ) {
  319. custom = &fbcon->foreground;
  320. } else if ( aspect == 39 ) {
  321. fbcon_set_default_foreground ( fbcon );
  322. } else if ( ( aspect >= 40 ) && ( aspect <= 47 ) ) {
  323. fbcon->background =
  324. fbcon_ansi_colour ( fbcon, aspect - 40 );
  325. } else if ( aspect == 48 ) {
  326. custom = &fbcon->background;
  327. } else if ( aspect == 49 ) {
  328. fbcon_set_default_background ( fbcon );
  329. }
  330. /* Process custom RGB colour, if applicable
  331. *
  332. * We support the xterm-compatible
  333. * "<ESC>[38;2;<red>;<green>;<blue>m" and
  334. * "<ESC>[48;2;<red>;<green>;<blue>m" sequences.
  335. */
  336. if ( custom ) {
  337. rgb = 0;
  338. end = ( i + 5 );
  339. for ( ; ( i < count ) && ( i < end ) ; i++ )
  340. rgb = ( ( rgb << 8 ) | params[i] );
  341. *custom = fbcon_colour ( fbcon, rgb );
  342. custom = NULL;
  343. }
  344. }
  345. }
  346. /**
  347. * Handle ANSI DECTCEM set (show cursor)
  348. *
  349. * @v ctx ANSI escape sequence context
  350. * @v count Parameter count
  351. * @v params List of graphic rendition aspects
  352. */
  353. static void fbcon_handle_dectcem_set ( struct ansiesc_context *ctx,
  354. unsigned int count __unused,
  355. int params[] __unused ) {
  356. struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
  357. fbcon->show_cursor = 1;
  358. fbcon_draw_cursor ( fbcon, 1 );
  359. }
  360. /**
  361. * Handle ANSI DECTCEM reset (hide cursor)
  362. *
  363. * @v ctx ANSI escape sequence context
  364. * @v count Parameter count
  365. * @v params List of graphic rendition aspects
  366. */
  367. static void fbcon_handle_dectcem_reset ( struct ansiesc_context *ctx,
  368. unsigned int count __unused,
  369. int params[] __unused ) {
  370. struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
  371. fbcon->show_cursor = 0;
  372. fbcon_draw_cursor ( fbcon, 0 );
  373. }
  374. /** ANSI escape sequence handlers */
  375. static struct ansiesc_handler fbcon_ansiesc_handlers[] = {
  376. { ANSIESC_CUP, fbcon_handle_cup },
  377. { ANSIESC_ED, fbcon_handle_ed },
  378. { ANSIESC_SGR, fbcon_handle_sgr },
  379. { ANSIESC_DECTCEM_SET, fbcon_handle_dectcem_set },
  380. { ANSIESC_DECTCEM_RESET, fbcon_handle_dectcem_reset },
  381. { 0, NULL }
  382. };
  383. /**
  384. * Print a character to current cursor position
  385. *
  386. * @v fbcon Frame buffer console
  387. * @v character Character
  388. */
  389. void fbcon_putchar ( struct fbcon *fbcon, int character ) {
  390. struct fbcon_text_cell cell;
  391. /* Intercept ANSI escape sequences */
  392. character = ansiesc_process ( &fbcon->ctx, character );
  393. if ( character < 0 )
  394. return;
  395. /* Handle control characters */
  396. switch ( character ) {
  397. case '\r':
  398. fbcon_draw_cursor ( fbcon, 0 );
  399. fbcon->xpos = 0;
  400. break;
  401. case '\n':
  402. fbcon_draw_cursor ( fbcon, 0 );
  403. fbcon->xpos = 0;
  404. fbcon->ypos++;
  405. break;
  406. case '\b':
  407. fbcon_draw_cursor ( fbcon, 0 );
  408. if ( fbcon->xpos ) {
  409. fbcon->xpos--;
  410. } else if ( fbcon->ypos ) {
  411. fbcon->xpos = ( fbcon->character.width - 1 );
  412. fbcon->ypos--;
  413. }
  414. break;
  415. default:
  416. /* Print character at current cursor position */
  417. cell.foreground = ( fbcon->foreground | fbcon->bold );
  418. cell.background = fbcon->background;
  419. cell.character = character;
  420. fbcon_store ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
  421. fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
  422. /* Advance cursor */
  423. fbcon->xpos++;
  424. if ( fbcon->xpos >= fbcon->character.width ) {
  425. fbcon->xpos = 0;
  426. fbcon->ypos++;
  427. }
  428. break;
  429. }
  430. /* Scroll screen if necessary */
  431. if ( fbcon->ypos >= fbcon->character.height )
  432. fbcon_scroll ( fbcon );
  433. /* Show cursor */
  434. fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
  435. }
  436. /**
  437. * Initialise background picture
  438. *
  439. * @v fbcon Frame buffer console
  440. * @v pixbuf Background picture
  441. * @ret rc Return status code
  442. */
  443. static int fbcon_picture_init ( struct fbcon *fbcon,
  444. struct pixel_buffer *pixbuf ) {
  445. struct fbcon_geometry *pixel = fbcon->pixel;
  446. struct fbcon_picture *picture = &fbcon->picture;
  447. size_t len;
  448. size_t pixbuf_stride;
  449. size_t indent;
  450. size_t pixbuf_indent;
  451. size_t offset;
  452. size_t pixbuf_offset;
  453. uint32_t rgb;
  454. uint32_t raw;
  455. unsigned int x;
  456. unsigned int y;
  457. unsigned int width;
  458. unsigned int height;
  459. int xgap;
  460. int ygap;
  461. int rc;
  462. /* Allocate buffer */
  463. len = ( pixel->height * pixel->stride );
  464. picture->start = umalloc ( len );
  465. if ( ! picture->start ) {
  466. DBGC ( fbcon, "FBCON %p could not allocate %zd bytes for "
  467. "picture\n", fbcon, len );
  468. rc = -ENOMEM;
  469. goto err_umalloc;
  470. }
  471. /* Centre picture on console */
  472. pixbuf_stride = ( pixbuf->width * sizeof ( rgb ) );
  473. xgap = ( ( ( int ) ( pixel->width - pixbuf->width ) ) / 2 );
  474. ygap = ( ( ( int ) ( pixel->height - pixbuf->height ) ) / 2 );
  475. indent = ( ( ( ( ygap >= 0 ) ? ygap : 0 ) * pixel->stride ) +
  476. ( ( ( xgap >= 0 ) ? xgap : 0 ) * pixel->len ) );
  477. pixbuf_indent = ( ( ( ( ygap < 0 ) ? -ygap : 0 ) * pixbuf_stride ) +
  478. ( ( ( xgap < 0 ) ? -xgap : 0 ) * sizeof ( rgb ) ) );
  479. width = pixbuf->width;
  480. if ( width > pixel->width )
  481. width = pixel->width;
  482. height = pixbuf->height;
  483. if ( height > pixel->height )
  484. height = pixel->height;
  485. DBGC ( fbcon, "FBCON %p picture is pixel %dx%d at [%d,%d),[%d,%d)\n",
  486. fbcon, width, height, xgap, ( xgap + pixbuf->width ), ygap,
  487. ( ygap + pixbuf->height ) );
  488. /* Convert to frame buffer raw format */
  489. memset_user ( picture->start, 0, 0, len );
  490. for ( y = 0 ; y < height ; y++ ) {
  491. offset = ( indent + ( y * pixel->stride ) );
  492. pixbuf_offset = ( pixbuf_indent + ( y * pixbuf_stride ) );
  493. for ( x = 0 ; x < width ; x++ ) {
  494. copy_from_user ( &rgb, pixbuf->data, pixbuf_offset,
  495. sizeof ( rgb ) );
  496. raw = fbcon_colour ( fbcon, rgb );
  497. copy_to_user ( picture->start, offset, &raw,
  498. pixel->len );
  499. offset += pixel->len;
  500. pixbuf_offset += sizeof ( rgb );
  501. }
  502. }
  503. return 0;
  504. ufree ( picture->start );
  505. err_umalloc:
  506. return rc;
  507. }
  508. /**
  509. * Initialise frame buffer console
  510. *
  511. * @v fbcon Frame buffer console
  512. * @v start Start address
  513. * @v pixel Pixel geometry
  514. * @v margin Minimum margin
  515. * @v map Colour mapping
  516. * @v font Font definition
  517. * @v pixbuf Background picture (if any)
  518. * @ret rc Return status code
  519. */
  520. int fbcon_init ( struct fbcon *fbcon, userptr_t start,
  521. struct fbcon_geometry *pixel,
  522. struct fbcon_margin *margin,
  523. struct fbcon_colour_map *map,
  524. struct fbcon_font *font,
  525. struct pixel_buffer *pixbuf ) {
  526. int width;
  527. int height;
  528. unsigned int xgap;
  529. unsigned int ygap;
  530. int rc;
  531. /* Initialise data structure */
  532. memset ( fbcon, 0, sizeof ( *fbcon ) );
  533. fbcon->start = start;
  534. fbcon->pixel = pixel;
  535. assert ( pixel->len <= sizeof ( uint32_t ) );
  536. fbcon->map = map;
  537. fbcon->font = font;
  538. fbcon->ctx.handlers = fbcon_ansiesc_handlers;
  539. fbcon->show_cursor = 1;
  540. /* Derive overall length */
  541. fbcon->len = ( pixel->height * pixel->stride );
  542. DBGC ( fbcon, "FBCON %p at [%08lx,%08lx)\n", fbcon,
  543. user_to_phys ( fbcon->start, 0 ),
  544. user_to_phys ( fbcon->start, fbcon->len ) );
  545. /* Expand margin to accommodate whole characters */
  546. width = ( pixel->width - margin->left - margin->right );
  547. height = ( pixel->height - margin->top - margin->bottom );
  548. if ( ( width < FBCON_CHAR_WIDTH ) || ( height < FBCON_CHAR_HEIGHT ) ) {
  549. DBGC ( fbcon, "FBCON %p has unusable character area "
  550. "[%d-%d),[%d-%d)\n", fbcon,
  551. margin->left, ( pixel->width - margin->right ),
  552. margin->top, ( pixel->height - margin->bottom ) );
  553. rc = -EINVAL;
  554. goto err_margin;
  555. }
  556. xgap = ( width % FBCON_CHAR_WIDTH );
  557. ygap = ( height % FBCON_CHAR_HEIGHT );
  558. fbcon->margin.left = ( margin->left + ( xgap / 2 ) );
  559. fbcon->margin.top = ( margin->top + ( ygap / 2 ) );
  560. fbcon->margin.right = ( margin->right + ( xgap - ( xgap / 2 ) ) );
  561. fbcon->margin.bottom = ( margin->bottom + ( ygap - ( ygap / 2 ) ) );
  562. fbcon->indent = ( ( fbcon->margin.top * pixel->stride ) +
  563. ( fbcon->margin.left * pixel->len ) );
  564. /* Derive character geometry from pixel geometry */
  565. fbcon->character.width = ( width / FBCON_CHAR_WIDTH );
  566. fbcon->character.height = ( height / FBCON_CHAR_HEIGHT );
  567. fbcon->character.len = ( pixel->len * FBCON_CHAR_WIDTH );
  568. fbcon->character.stride = ( pixel->stride * FBCON_CHAR_HEIGHT );
  569. DBGC ( fbcon, "FBCON %p is pixel %dx%d, char %dx%d at "
  570. "[%d-%d),[%d-%d)\n", fbcon, fbcon->pixel->width,
  571. fbcon->pixel->height, fbcon->character.width,
  572. fbcon->character.height, fbcon->margin.left,
  573. ( fbcon->pixel->width - fbcon->margin.right ),
  574. fbcon->margin.top,
  575. ( fbcon->pixel->height - fbcon->margin.bottom ) );
  576. /* Set default colours */
  577. fbcon_set_default_foreground ( fbcon );
  578. fbcon_set_default_background ( fbcon );
  579. /* Allocate and initialise stored character array */
  580. fbcon->text.start = umalloc ( fbcon->character.width *
  581. fbcon->character.height *
  582. sizeof ( struct fbcon_text_cell ) );
  583. if ( ! fbcon->text.start ) {
  584. rc = -ENOMEM;
  585. goto err_text;
  586. }
  587. fbcon_clear ( fbcon, 0 );
  588. /* Set framebuffer to all black (including margins) */
  589. memset_user ( fbcon->start, 0, 0, fbcon->len );
  590. /* Generate pixel buffer from background image, if applicable */
  591. if ( pixbuf && ( ( rc = fbcon_picture_init ( fbcon, pixbuf ) ) != 0 ) )
  592. goto err_picture;
  593. /* Draw background picture (including margins), if applicable */
  594. if ( fbcon->picture.start ) {
  595. memcpy_user ( fbcon->start, 0, fbcon->picture.start, 0,
  596. fbcon->len );
  597. }
  598. /* Update console width and height */
  599. console_set_size ( fbcon->character.width, fbcon->character.height );
  600. return 0;
  601. ufree ( fbcon->picture.start );
  602. err_picture:
  603. ufree ( fbcon->text.start );
  604. err_text:
  605. err_margin:
  606. return rc;
  607. }
  608. /**
  609. * Finalise frame buffer console
  610. *
  611. * @v fbcon Frame buffer console
  612. */
  613. void fbcon_fini ( struct fbcon *fbcon ) {
  614. ufree ( fbcon->text.start );
  615. ufree ( fbcon->picture.start );
  616. }