vidconsole-uclass.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. return 0;
  68. }
  69. /* Move to a newline, scrolling the display if necessary */
  70. static void vidconsole_newline(struct udevice *dev)
  71. {
  72. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  73. struct udevice *vid_dev = dev->parent;
  74. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  75. const int rows = CONFIG_CONSOLE_SCROLL_LINES;
  76. int i;
  77. priv->xcur_frac = priv->xstart_frac;
  78. priv->ycur += priv->y_charsize;
  79. /* Check if we need to scroll the terminal */
  80. if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
  81. vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
  82. for (i = 0; i < rows; i++)
  83. vidconsole_set_row(dev, priv->rows - i - 1,
  84. vid_priv->colour_bg);
  85. priv->ycur -= rows * priv->y_charsize;
  86. }
  87. priv->last_ch = 0;
  88. video_sync(dev->parent);
  89. }
  90. int vidconsole_put_char(struct udevice *dev, char ch)
  91. {
  92. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  93. int ret;
  94. switch (ch) {
  95. case '\a':
  96. /* beep */
  97. break;
  98. case '\r':
  99. priv->xcur_frac = priv->xstart_frac;
  100. break;
  101. case '\n':
  102. vidconsole_newline(dev);
  103. vidconsole_entry_start(dev);
  104. break;
  105. case '\t': /* Tab (8 chars alignment) */
  106. priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
  107. + 1) * priv->tab_width_frac;
  108. if (priv->xcur_frac >= priv->xsize_frac)
  109. vidconsole_newline(dev);
  110. break;
  111. case '\b':
  112. vidconsole_back(dev);
  113. priv->last_ch = 0;
  114. break;
  115. default:
  116. /*
  117. * Failure of this function normally indicates an unsupported
  118. * colour depth. Check this and return an error to help with
  119. * diagnosis.
  120. */
  121. ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
  122. if (ret == -EAGAIN) {
  123. vidconsole_newline(dev);
  124. ret = vidconsole_putc_xy(dev, priv->xcur_frac,
  125. priv->ycur, ch);
  126. }
  127. if (ret < 0)
  128. return ret;
  129. priv->xcur_frac += ret;
  130. priv->last_ch = ch;
  131. if (priv->xcur_frac >= priv->xsize_frac)
  132. vidconsole_newline(dev);
  133. break;
  134. }
  135. return 0;
  136. }
  137. static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
  138. {
  139. struct udevice *dev = sdev->priv;
  140. vidconsole_put_char(dev, ch);
  141. }
  142. static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
  143. {
  144. struct udevice *dev = sdev->priv;
  145. while (*s)
  146. vidconsole_put_char(dev, *s++);
  147. video_sync(dev->parent);
  148. }
  149. /* Set up the number of rows and colours (rotated drivers override this) */
  150. static int vidconsole_pre_probe(struct udevice *dev)
  151. {
  152. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  153. struct udevice *vid = dev->parent;
  154. struct video_priv *vid_priv = dev_get_uclass_priv(vid);
  155. priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
  156. return 0;
  157. }
  158. /* Register the device with stdio */
  159. static int vidconsole_post_probe(struct udevice *dev)
  160. {
  161. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  162. struct stdio_dev *sdev = &priv->sdev;
  163. if (!priv->tab_width_frac)
  164. priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
  165. if (dev->seq) {
  166. snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
  167. dev->seq);
  168. } else {
  169. strcpy(sdev->name, "vidconsole");
  170. }
  171. sdev->flags = DEV_FLAGS_OUTPUT;
  172. sdev->putc = vidconsole_putc;
  173. sdev->puts = vidconsole_puts;
  174. sdev->priv = dev;
  175. return stdio_register(sdev);
  176. }
  177. UCLASS_DRIVER(vidconsole) = {
  178. .id = UCLASS_VIDEO_CONSOLE,
  179. .name = "vidconsole0",
  180. .pre_probe = vidconsole_pre_probe,
  181. .post_probe = vidconsole_post_probe,
  182. .per_device_auto_alloc_size = sizeof(struct vidconsole_priv),
  183. };
  184. void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
  185. {
  186. struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  187. struct udevice *vid_dev = dev->parent;
  188. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  189. priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1));
  190. priv->ycur = min_t(short, row, vid_priv->ysize - 1);
  191. }
  192. static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
  193. char *const argv[])
  194. {
  195. unsigned int col, row;
  196. struct udevice *dev;
  197. if (argc != 3)
  198. return CMD_RET_USAGE;
  199. if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
  200. return CMD_RET_FAILURE;
  201. col = simple_strtoul(argv[1], NULL, 10);
  202. row = simple_strtoul(argv[2], NULL, 10);
  203. vidconsole_position_cursor(dev, col, row);
  204. return 0;
  205. }
  206. static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
  207. char *const argv[])
  208. {
  209. struct udevice *dev;
  210. const char *s;
  211. if (argc != 2)
  212. return CMD_RET_USAGE;
  213. if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
  214. return CMD_RET_FAILURE;
  215. for (s = argv[1]; *s; s++)
  216. vidconsole_put_char(dev, *s);
  217. return 0;
  218. }
  219. U_BOOT_CMD(
  220. setcurs, 3, 1, do_video_setcursor,
  221. "set cursor position within screen",
  222. " <col> <row> in character"
  223. );
  224. U_BOOT_CMD(
  225. lcdputs, 2, 1, do_video_puts,
  226. "print string on video framebuffer",
  227. " <string>"
  228. );