summaryrefslogtreecommitdiff
path: root/drivers/video/sandbox_osd.c
blob: 7e722326b3d9364e57a651ea37711fcd7e15425a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SPDX-License-Identifier: GPL-2.0+
/*
 * (C) Copyright 2018
 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
 */
#include <common.h>
#include <display.h>
#include <dm.h>
#include <malloc.h>
#include <video_osd.h>

#include "sandbox_osd.h"

struct sandbox_osd_priv {
	uint width;
	uint height;
	u16 *buf;
};

static const struct udevice_id sandbox_osd_ids[] = {
	{ .compatible = "sandbox,sandbox_osd" },
	{ }
};

inline u16 make_memval(u8 chr, u8 color)
{
	return chr * 0x100 + color;
}

int sandbox_osd_get_info(struct udevice *dev, struct video_osd_info *info)
{
	struct sandbox_osd_priv *priv = dev_get_priv(dev);

	info->width = priv->width;
	info->height = priv->height;
	info->major_version = 1;
	info->minor_version = 0;

	return 0;
}

int sandbox_osd_set_mem(struct udevice *dev, uint col, uint row, u8 *buf,
			size_t buflen, uint count)
{
	struct sandbox_osd_priv *priv = dev_get_priv(dev);
	int pos;
	u8 *mem = (u8 *)priv->buf;
	int i;

	pos = 2 * (row * priv->width + col);

	if (pos >= 2 * (priv->width * priv->height))
		return -EINVAL;

	for (i = 0; i < count; i++)
		memcpy(mem + pos + (i * buflen), buf, buflen);

	return 0;
}

int _sandbox_osd_set_size(struct udevice *dev, uint col, uint row)
{
	struct sandbox_osd_priv *priv = dev_get_priv(dev);
	int i;
	uint size;

	priv->width = col;
	priv->height = row;
	size = priv->width * priv->height;
	if (!priv->buf)
		priv->buf = calloc(size, sizeof(u16));
	else
		priv->buf = realloc(priv->buf, size * sizeof(u16));

	if (!priv->buf)
		return -ENOMEM;

	/* Fill OSD with black spaces */
	for (i = 0; i < size; i++)
		priv->buf[i] = make_memval(' ', 'k');

	return 0;
}

int sandbox_osd_set_size(struct udevice *dev, uint col, uint row)
{
	return _sandbox_osd_set_size(dev, col, row);
}

int sandbox_osd_print(struct udevice *dev, uint col, uint row, ulong color,
		      char *text)
{
	struct sandbox_osd_priv *priv = dev_get_priv(dev);
	char cval;
	char *p;
	int pos;

	if (col >= priv->width || row >= priv->height)
		return -EINVAL;

	switch (color) {
	case COLOR_BLACK:
		cval = 'k';
		break;
	case COLOR_WHITE:
		cval = 'w';
		break;
	case COLOR_RED:
		cval = 'r';
		break;
	case COLOR_GREEN:
		cval = 'g';
		break;
	case COLOR_BLUE:
		cval = 'b';
		break;
	default:
		return -EINVAL;
	}

	p = text;
	pos = row * priv->width + col;

	while (*p)
		priv->buf[pos++] = make_memval(*(p++), cval);

	return 0;
}

int sandbox_osd_get_mem(struct udevice *dev, u8 *buf, size_t buflen)
{
	struct sandbox_osd_priv *priv = dev_get_priv(dev);
	uint memsize = 2 * (priv->width * priv->height);

	if (buflen < memsize)
		return -EINVAL;

	memcpy(buf, priv->buf, memsize);

	return 0;
}

static const struct video_osd_ops sandbox_osd_ops = {
	.get_info = sandbox_osd_get_info,
	.set_mem = sandbox_osd_set_mem,
	.set_size = sandbox_osd_set_size,
	.print = sandbox_osd_print,
};

int sandbox_osd_probe(struct udevice *dev)
{
	return _sandbox_osd_set_size(dev, 10, 10);
}

U_BOOT_DRIVER(sandbox_osd_drv) = {
	.name           = "sandbox_osd_drv",
	.id             = UCLASS_VIDEO_OSD,
	.ops		= &sandbox_osd_ops,
	.of_match       = sandbox_osd_ids,
	.probe          = sandbox_osd_probe,
	.priv_auto_alloc_size = sizeof(struct sandbox_osd_priv),
};