vidconsole-uclass.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright (c) 2015 Google, Inc
  3. * (C) Copyright 2001-2015
  4. * DENX Software Engineering -- wd@denx.de
  5. * Compulab Ltd - http://compulab.co.il/
  6. * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
  7. *
  8. * SPDX-License-Identifier: GPL-2.0+
  9. */
  10. #include <common.h>
  11. #include <dm.h>
  12. #include <video.h>
  13. #include <video_console.h>
  14. #include <video_font.h> /* Get font data, width and height */
  15. /* By default we scroll by a single line */
  16. #ifndef CONFIG_CONSOLE_SCROLL_LINES
  17. #define CONFIG_CONSOLE_SCROLL_LINES 1
  18. #endif
  19. int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
  20. {
  21. struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  22. if (!ops->putc_xy)
  23. return -ENOSYS;
  24. return ops->putc_xy(dev, x, y, ch);
  25. }
  26. int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
  27. uint count)
  28. {
  29. struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  30. if (!ops->move_rows)
  31. return -ENOSYS;
  32. return ops->move_rows(dev, rowdst, rowsrc, count);
  33. }
  34. int vidconsole_set_row(struct udevice *dev, uint row, int clr)
  35. {
  36. struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  37. if (!ops->set_row)
  38. return -ENOSYS;
  39. return ops->set_row(dev, row, clr);
  40. }
  41. static int vidconsole_entry_start(struct udevice *dev)
  42. {
  43. struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  44. if (!ops->entry_start)
  45. return -ENOSYS;
  46. return ops->entry_start(dev);
  47. }
  48. /* Move backwards one space */
  49. static int vidconsole_back(struct udevice *dev)
  50. {
  51. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  52. struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  53. int ret;
  54. if (ops->backspace) {
  55. ret = ops->backspace(dev);
  56. if (ret != -ENOSYS)
  57. return ret;
  58. }
  59. priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
  60. if (priv->xcur_frac < priv->xstart_frac) {
  61. priv->xcur_frac = (priv->cols - 1) *
  62. VID_TO_POS(priv->x_charsize);
  63. priv->ycur -= priv->y_charsize;
  64. if (priv->ycur < 0)
  65. priv->ycur = 0;
  66. }
  67. video_sync(dev->parent);
  68. return 0;
  69. }
  70. /* Move to a newline, scrolling the display if necessary */
  71. static void vidconsole_newline(struct udevice *dev)
  72. {
  73. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  74. struct udevice *vid_dev = dev->parent;
  75. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  76. const int rows = CONFIG_CONSOLE_SCROLL_LINES;
  77. int i;
  78. priv->xcur_frac = priv->xstart_frac;
  79. priv->ycur += priv->y_charsize;
  80. /* Check if we need to scroll the terminal */
  81. if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
  82. vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
  83. for (i = 0; i < rows; i++)
  84. vidconsole_set_row(dev, priv->rows - i - 1,
  85. vid_priv->colour_bg);
  86. priv->ycur -= rows * priv->y_charsize;
  87. }
  88. priv->last_ch = 0;
  89. video_sync(dev->parent);
  90. }
  91. int vidconsole_put_char(struct udevice *dev, char ch)
  92. {
  93. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  94. int ret;
  95. switch (ch) {
  96. case '\a':
  97. /* beep */
  98. break;
  99. case '\r':
  100. priv->xcur_frac = priv->xstart_frac;
  101. break;
  102. case '\n':
  103. vidconsole_newline(dev);
  104. vidconsole_entry_start(dev);
  105. break;
  106. case '\t': /* Tab (8 chars alignment) */
  107. priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
  108. + 1) * priv->tab_width_frac;
  109. if (priv->xcur_frac >= priv->xsize_frac)
  110. vidconsole_newline(dev);
  111. break;
  112. case '\b':
  113. vidconsole_back(dev);
  114. priv->last_ch = 0;
  115. break;
  116. default:
  117. /*
  118. * Failure of this function normally indicates an unsupported
  119. * colour depth. Check this and return an error to help with
  120. * diagnosis.
  121. */
  122. ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
  123. if (ret == -EAGAIN) {
  124. vidconsole_newline(dev);
  125. ret = vidconsole_putc_xy(dev, priv->xcur_frac,
  126. priv->ycur, ch);
  127. }
  128. if (ret < 0)
  129. return ret;
  130. priv->xcur_frac += ret;
  131. priv->last_ch = ch;
  132. if (priv->xcur_frac >= priv->xsize_frac)
  133. vidconsole_newline(dev);
  134. break;
  135. }
  136. return 0;
  137. }
  138. static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
  139. {
  140. struct udevice *dev = sdev->priv;
  141. vidconsole_put_char(dev, ch);
  142. }
  143. static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
  144. {
  145. struct udevice *dev = sdev->priv;
  146. while (*s)
  147. vidconsole_put_char(dev, *s++);
  148. video_sync(dev->parent);
  149. }
  150. /* Set up the number of rows and colours (rotated drivers override this) */
  151. static int vidconsole_pre_probe(struct udevice *dev)
  152. {
  153. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  154. struct udevice *vid = dev->parent;
  155. struct video_priv *vid_priv = dev_get_uclass_priv(vid);
  156. priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
  157. return 0;
  158. }
  159. /* Register the device with stdio */
  160. static int vidconsole_post_probe(struct udevice *dev)
  161. {
  162. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  163. struct stdio_dev *sdev = &priv->sdev;
  164. if (!priv->tab_width_frac)
  165. priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
  166. if (dev->seq) {
  167. snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
  168. dev->seq);
  169. } else {
  170. strcpy(sdev->name, "vidconsole");
  171. }
  172. sdev->flags = DEV_FLAGS_OUTPUT;
  173. sdev->putc = vidconsole_putc;
  174. sdev->puts = vidconsole_puts;
  175. sdev->priv = dev;
  176. return stdio_register(sdev);
  177. }
  178. UCLASS_DRIVER(vidconsole) = {
  179. .id = UCLASS_VIDEO_CONSOLE,
  180. .name = "vidconsole0",
  181. .pre_probe = vidconsole_pre_probe,
  182. .post_probe = vidconsole_post_probe,
  183. .per_device_auto_alloc_size = sizeof(struct vidconsole_priv),
  184. };
  185. void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
  186. {
  187. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  188. struct udevice *vid_dev = dev->parent;
  189. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  190. priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1));
  191. priv->ycur = min_t(short, row, vid_priv->ysize - 1);
  192. }
  193. static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
  194. char *const argv[])
  195. {
  196. unsigned int col, row;
  197. struct udevice *dev;
  198. if (argc != 3)
  199. return CMD_RET_USAGE;
  200. if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
  201. return CMD_RET_FAILURE;
  202. col = simple_strtoul(argv[1], NULL, 10);
  203. row = simple_strtoul(argv[2], NULL, 10);
  204. vidconsole_position_cursor(dev, col, row);
  205. return 0;
  206. }
  207. static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
  208. char *const argv[])
  209. {
  210. struct udevice *dev;
  211. const char *s;
  212. if (argc != 2)
  213. return CMD_RET_USAGE;
  214. if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
  215. return CMD_RET_FAILURE;
  216. for (s = argv[1]; *s; s++)
  217. vidconsole_put_char(dev, *s);
  218. return 0;
  219. }
  220. U_BOOT_CMD(
  221. setcurs, 3, 1, do_video_setcursor,
  222. "set cursor position within screen",
  223. " <col> <row> in character"
  224. );
  225. U_BOOT_CMD(
  226. lcdputs, 2, 1, do_video_puts,
  227. "print string on video framebuffer",
  228. " <string>"
  229. );