@@ -1,4 +1,5 @@
drm-text-y := drm-text-console.o drm-text-buffer.o
+drm-text-$(CONFIG_VT) += drm-text-vt.o
drm-text-$(CONFIG_DEBUG_FS) += drm-text-debugfs.o
obj-m += drm-text.o
@@ -317,6 +317,7 @@ static int __init drm_text_init(void)
drm_text_scan_fbdev();
ret = drm_text_console_init();
+ ret = drm_text_vt_init();
return ret;
}
@@ -327,6 +328,7 @@ static void __exit drm_text_exit(void)
unsigned int i;
drm_text_console_exit();
+ drm_text_vt_exit();
drm_text_debugfs_exit();
for (i = 0; i < MAX_DRM_TEXT_BUFFERS; i++)
new file mode 100644
@@ -0,0 +1,197 @@
+#define DEBUG
+/*
+ * Copyright 2016 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/console.h>
+#include <linux/err.h>
+#include <linux/vt_buffer.h>
+#include <linux/vt_kern.h>
+
+#include "drm-text.h"
+
+static unsigned int drm_text_vt_map[MAX_DRM_TEXT_BUFFERS];
+
+/* TODO: Some kind of mapping might be needed */
+static inline struct drm_text_buffer *drm_text_vt_get(unsigned int index)
+{
+ return drm_text_get(drm_text_vt_map[index]);
+}
+
+static const char *drm_text_con_startup(void)
+{
+ drm_text_debug("%s\n", __func__);
+ return "drm-vt";
+}
+
+static void drm_text_con_init(struct vc_data *vc, int init)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+
+ drm_text_log("%s[%u](init=%d)\n", __func__, vc->vc_num, init);
+
+ vc->vc_can_do_color = 1;
+
+ if (!text) {
+ drm_text_log("%s[%u] no DRM device\n", __func__, vc->vc_num);
+ return;
+ }
+
+ if (init) {
+ vc->vc_cols = text->cols;
+ vc->vc_rows = text->rows;
+ } else {
+ vc_resize(vc, text->cols, text->rows);
+ }
+
+ drm_text_enable(text);
+}
+
+static void drm_text_con_deinit(struct vc_data *vc)
+{
+ drm_text_debug("%s[%u]\n", __func__, vc->vc_num);
+ pr_info("%s\n", __func__);
+}
+
+static void drm_text_con_putcs(struct vc_data *vc, const unsigned short *s,
+ int count, int y, int x)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+ u16 *dest;
+
+ if (!text)
+ return;
+
+ dest = &text->text_buf[x + (y * text->cols)];
+
+ for (; count > 0; count--) {
+ scr_writew(scr_readw(s++), dest++);
+ }
+ drm_text_flush(text, false);
+}
+
+static void drm_text_con_putc(struct vc_data *vc, int ch, int y, int x)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+ unsigned short chr;
+
+ if (!text)
+ return;
+
+ scr_writew(ch, &chr);
+ drm_text_con_putcs(vc, &chr, 1, y, x);
+}
+
+/* TODO: How do I actually test this? */
+static void drm_text_con_clear(struct vc_data *vc, int y, int x,
+ int height, int width)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+
+ drm_text_debug("%s[%u]\n", __func__, vc->vc_num);
+
+ if (!text)
+ return;
+
+ scr_memcpyw(text->text_buf, (unsigned short *)vc->vc_pos,
+ vc->vc_cols * vc->vc_rows);
+ drm_text_flush(text, false);
+}
+
+static int drm_text_con_switch(struct vc_data *vc)
+{
+ drm_text_debug("%s[%u] %ux%u\n", __func__, vc->vc_num, vc->vc_cols, vc->vc_rows);
+
+ return 1; /* redrawing needed */
+}
+
+static void drm_text_con_set_palette(struct vc_data *vc, const unsigned char *table)
+{
+ drm_text_debug("%s[%u]\n", __func__, vc->vc_num);
+}
+
+static int drm_text_con_blank(struct vc_data *vc, int blank, int mode_switch)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+ int ret;
+
+ drm_text_debug("%s[%u](blank=%d, mode_switch=%d)\n", __func__, vc->vc_num, blank, mode_switch);
+
+ if (!text)
+ return 0;
+
+ if (blank)
+ ret = drm_text_disable(text);
+ else
+ ret = drm_text_enable(text);
+
+ return ret;
+}
+
+static void drm_text_con_scrolldelta(struct vc_data *vc, int lines)
+{
+ drm_text_debug("%s[%u](lines=%d)\n", __func__, vc->vc_num, lines);
+}
+
+static void drm_text_con_cursor(struct vc_data *vc, int mode)
+{
+ /* TODO: Do we need a blinking cursor? */
+}
+
+static int drm_text_con_scroll(struct vc_data *vc, int t, int b, int dir, int lines)
+{
+ struct drm_text_buffer *text = drm_text_vt_get(vc->vc_num);
+
+ if (!text)
+ return 0;
+
+ switch (dir) {
+ case SM_UP:
+ drm_text_scroll(text, t, b, lines);
+ break;
+ case SM_DOWN:
+ drm_text_scroll(text, t, b, -lines);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct consw drm_text_vt = {
+ .owner = THIS_MODULE,
+ .con_startup = drm_text_con_startup,
+ .con_init = drm_text_con_init,
+ .con_deinit = drm_text_con_deinit,
+ .con_clear = drm_text_con_clear,
+ .con_putc = drm_text_con_putc,
+ .con_putcs = drm_text_con_putcs,
+ .con_cursor = drm_text_con_cursor,
+ .con_scroll = drm_text_con_scroll,
+ .con_switch = drm_text_con_switch,
+ .con_blank = drm_text_con_blank,
+ .con_set_palette = drm_text_con_set_palette,
+ .con_scrolldelta = drm_text_con_scrolldelta,
+};
+
+int drm_text_vt_init(void)
+{
+ int ret;
+
+ drm_text_debug("%s\n", __func__);
+
+ console_lock();
+ ret = do_take_over_console(&drm_text_vt, 0, MAX_NR_CONSOLES - 1, 0);
+ console_unlock();
+
+ return ret;
+}
+
+void drm_text_vt_exit(void)
+{
+ give_up_console(&drm_text_vt);
+}
@@ -43,6 +43,20 @@ int drm_text_console_init(void);
void drm_text_console_exit(void);
int drm_text_panic(struct notifier_block *this, unsigned long ev, void *ptr);
+#ifdef CONFIG_VT
+int drm_text_vt_init(void);
+void drm_text_vt_exit(void);
+#else
+int drm_text_vt_init(void)
+{
+ return 0;
+}
+
+void drm_text_vt_exit(void)
+{
+}
+#endif
+
#ifdef DEBUG
#define drm_text_debug(fmt, ...) \
drm_text_log(fmt, ##__VA_ARGS__)
This adds VT console support. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- drivers/gpu/drm/drm-text/Makefile | 1 + drivers/gpu/drm/drm-text/drm-text-buffer.c | 2 + drivers/gpu/drm/drm-text/drm-text-vt.c | 197 +++++++++++++++++++++++++++++ drivers/gpu/drm/drm-text/drm-text.h | 14 ++ 4 files changed, 214 insertions(+) create mode 100644 drivers/gpu/drm/drm-text/drm-text-vt.c