1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-11-11     GuEe-GUI     the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #include <virtio_gpu.h>
15 #include <virtio_input.h>
16 
17 #define GRAPHIC_THREAD_PRIORITY     25
18 #define GRAPHIC_THREAD_STACK_SIZE   4096
19 #define GRAPHIC_THREAD_TIMESLICE    5
20 
21 static rt_uint32_t cur_min[2];
22 static rt_uint32_t cur_max[2];
23 static rt_uint32_t cur_range[2];
24 static rt_uint32_t cur_points[2];
25 static rt_uint32_t cur_last_points[2];
26 static rt_bool_t cur_event_sync;
27 static rt_uint32_t color[2] = { 0xff0000, 0x0000ff };
28 static rt_uint8_t cursor[VIRTIO_GPU_CURSOR_IMG_SIZE] rt_align(VIRTIO_PAGE_SIZE);
29 
tablet_event_handler(struct virtio_input_event event)30 void tablet_event_handler(struct virtio_input_event event)
31 {
32     static rt_bool_t cur_btn_down = RT_FALSE;
33 
34     if (event.type == EV_ABS)
35     {
36         if (event.code == 0)
37         {
38             cur_points[0] = (cur_max[0] * (event.value - cur_min[0]) + cur_range[0] / 2) / cur_range[0];
39         }
40         else if (event.code == 1)
41         {
42             cur_points[1] = (cur_max[1] * (event.value - cur_min[1]) + cur_range[1] / 2) / cur_range[1];
43         }
44     }
45     else if (event.type == EV_KEY)
46     {
47         if (event.code == BTN_LEFT)
48         {
49             if (cur_btn_down && event.value == 0)
50             {
51                 color[0] ^= color[1];
52                 color[1] ^= color[0];
53                 color[0] ^= color[1];
54                 cur_btn_down = RT_FALSE;
55                 cur_event_sync = RT_TRUE;
56             }
57             else
58             {
59                 cur_btn_down = RT_TRUE;
60             }
61         }
62     }
63     else if (event.type == EV_SYN)
64     {
65         cur_event_sync = RT_TRUE;
66     }
67 }
68 
graphic_thread(void * param)69 void graphic_thread(void *param)
70 {
71     int i;
72     char dev_name[RT_NAME_MAX];
73     rt_device_t device = RT_NULL;
74 
75     rt_device_t tablet_dev = RT_NULL;
76     struct virtio_input_config tablet_config;
77 
78     rt_uint32_t white = 0xffffff;
79     rt_device_t gpu_dev = RT_NULL;
80     struct rt_device_rect_info rect_info;
81     struct rt_device_graphic_info graphic_info;
82     struct rt_device_graphic_ops *virtio_gpu_graphic_ops;
83 
84     /* GPU */
85     device = rt_device_find("virtio-gpu0");
86 
87     if (device != RT_NULL && rt_device_open(device, 0) == RT_EOK)
88     {
89         virtio_gpu_graphic_ops = rt_graphix_ops(device);
90 
91         rt_memset(&rect_info, 0, sizeof(rect_info));
92         rt_memset(&graphic_info, 0, sizeof(graphic_info));
93 
94         rt_device_control(device, VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY, RT_NULL);
95         rt_device_control(device, VIRTIO_DEVICE_CTRL_GPU_CREATE_2D, (void *)RTGRAPHIC_PIXEL_FORMAT_RGB888);
96         rt_device_control(device, RTGRAPHIC_CTRL_GET_INFO, &graphic_info);
97 
98         rect_info.x = 0;
99         rect_info.y = 0;
100         rect_info.width = graphic_info.width;
101         rect_info.height = graphic_info.height;
102 
103         if (graphic_info.framebuffer != RT_NULL)
104         {
105             int i = 0;
106 
107             rt_memset(graphic_info.framebuffer, 0xff, graphic_info.pitch * graphic_info.height);
108 
109             cur_last_points[0] = graphic_info.width / 2;
110             cur_last_points[1] = graphic_info.height / 2;
111 
112             virtio_gpu_graphic_ops->draw_hline((char *)&color[0], 0, graphic_info.width, cur_last_points[1]);
113             virtio_gpu_graphic_ops->draw_vline((char *)&color[1], cur_last_points[0], 0, graphic_info.height);
114 
115             rt_device_control(device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
116 
117             while (i < sizeof(cursor) / 4)
118             {
119                 /* R: 0x4c G: 0xaf B: 0x50 A: 0.8 */
120                 ((rt_uint32_t *)cursor)[i] = 0xcc4caf50;
121                 ++i;
122             }
123 
124             rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_SETUP, cursor);
125             rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_MOVE, (rt_uint32_t[]){0, 0});
126 
127             gpu_dev = device;
128         }
129     }
130 
131     /* Keyboard, Mouse, Tablet */
132     for (i = 0; i < 3; ++i)
133     {
134         rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", i);
135 
136         device = rt_device_find(dev_name);
137 
138         if (device != RT_NULL && rt_device_open(device, 0) == RT_EOK)
139         {
140             enum virtio_input_type type;
141             rt_device_control(device, VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE, &type);
142 
143             if (type == VIRTIO_INPUT_TYPE_TABLET)
144             {
145                 tablet_dev = device;
146             }
147             else
148             {
149                 rt_device_close(device);
150             }
151         }
152     }
153 
154     if (tablet_dev == RT_NULL || gpu_dev == RT_NULL)
155     {
156         goto _graphic_fail;
157     }
158 
159     cur_max[0] = graphic_info.width;
160     cur_max[1] = graphic_info.height;
161 
162     rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO, &tablet_config);
163 
164     cur_min[0] = tablet_config.abs.min;
165     cur_range[0] = tablet_config.abs.max - cur_min[0];
166 
167     rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO, &tablet_config);
168 
169     cur_min[1] = tablet_config.abs.min;
170     cur_range[1] = tablet_config.abs.max - cur_min[1];
171 
172     cur_event_sync = RT_FALSE;
173 
174     rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER, tablet_event_handler);
175 
176     for (;;)
177     {
178         while (cur_event_sync)
179         {
180             virtio_gpu_graphic_ops->draw_hline((char *)&white, 0, graphic_info.width, cur_last_points[1]);
181             virtio_gpu_graphic_ops->draw_vline((char *)&white, cur_last_points[0], 0, graphic_info.height);
182 
183             cur_last_points[0] = cur_points[0];
184             cur_last_points[1] = cur_points[1];
185 
186             virtio_gpu_graphic_ops->draw_hline((char *)&color[0], 0, graphic_info.width, cur_last_points[1]);
187             virtio_gpu_graphic_ops->draw_vline((char *)&color[1], cur_last_points[0], 0, graphic_info.height);
188 
189             rt_device_control(gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
190 
191             cur_event_sync = RT_FALSE;
192 
193             rt_thread_mdelay(1);
194         }
195     }
196 
197 _graphic_fail:
198 
199     if (gpu_dev != RT_NULL)
200     {
201         rt_device_close(gpu_dev);
202     }
203 
204     if (tablet_dev != RT_NULL)
205     {
206         rt_device_close(tablet_dev);
207     }
208 }
209 
graphic_test(void)210 int graphic_test(void)
211 {
212     rt_thread_t graphic_tid = rt_thread_create("graphic work", graphic_thread, RT_NULL,
213             GRAPHIC_THREAD_STACK_SIZE, GRAPHIC_THREAD_PRIORITY, GRAPHIC_THREAD_TIMESLICE);
214 
215     if (graphic_tid != RT_NULL)
216     {
217         rt_thread_startup(graphic_tid);
218 
219         return RT_EOK;
220     }
221 
222     return -RT_ERROR;
223 }
224 MSH_CMD_EXPORT(graphic_test, Graphic test);
225