Skip to content

Commit a609872

Browse files
committed
feat(class/display): add usb vendor display device driver
Signed-off-by: sakumisu <1203593632@qq.com>
1 parent 6b0ec0e commit a609872

12 files changed

Lines changed: 405 additions & 0 deletions

File tree

Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ if CHERRYUSB
138138
prompt "Enable usb dfu device"
139139
default n
140140

141+
config CHERRYUSB_DEVICE_DISPLAY
142+
bool
143+
prompt "Enable usb display device"
144+
default n
145+
141146
config USBDEV_REQUEST_BUFFER_LEN
142147
int
143148
prompt "Set device control transfer max buffer size"
@@ -237,6 +242,10 @@ if CHERRYUSB
237242
bool
238243
prompt "webusb_hid"
239244
depends on CHERRYUSB_DEVICE_HID
245+
config CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
246+
bool
247+
prompt "display"
248+
depends on CHERRYUSB_DEVICE_DISPLAY
240249
endchoice
241250
endif
242251

Kconfig.rtt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ if RT_USING_CHERRYUSB
139139
prompt "Enable usb dfu device"
140140
default n
141141

142+
config RT_CHERRYUSB_DEVICE_DISPLAY
143+
bool
144+
prompt "Enable usb display device"
145+
default n
146+
142147
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
143148
bool
144149
prompt "Enable chardev for cdc acm device"
@@ -247,6 +252,10 @@ if RT_USING_CHERRYUSB
247252
bool
248253
prompt "webusb_hid"
249254
depends on RT_CHERRYUSB_DEVICE_HID
255+
config RT_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
256+
bool
257+
prompt "display"
258+
depends on RT_CHERRYUSB_DEVICE_DISPLAY
250259
config RT_CHERRYUSB_DEVICE_TEMPLATE_ADB
251260
bool
252261
prompt "adb"

Kconfig.rttpkg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ if PKG_USING_CHERRYUSB
138138
prompt "Enable usb dfu device"
139139
default n
140140

141+
config PKG_CHERRYUSB_DEVICE_DISPLAY
142+
bool
143+
prompt "Enable usb display device"
144+
default n
145+
141146
config PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
142147
bool
143148
prompt "Enable chardev for cdc acm device"
@@ -246,6 +251,10 @@ if PKG_USING_CHERRYUSB
246251
bool
247252
prompt "webusb_hid"
248253
depends on PKG_CHERRYUSB_DEVICE_HID
254+
config PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
255+
bool
256+
prompt "display"
257+
depends on PKG_CHERRYUSB_DEVICE_DISPLAY
249258
config PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB
250259
bool
251260
prompt "adb"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ CherryUSB Device Stack has the following functions:
7575
- Support Remote NDIS (RNDIS)
7676
- Support Media Transfer Protocol (MTP)
7777
- Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
78+
- Support Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
7879
- Support Vendor class
7980
- Support UF2
8081
- Support Android Debug Bridge (Only support shell)

README_zh.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ CherryUSB Device 协议栈当前实现以下功能:
7575
- 支持 Remote NDIS (RNDIS)
7676
- 支持 Media Transfer Protocol (MTP)
7777
- 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
78+
- 支持 Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
7879
- 支持 Vendor 类 class
7980
- 支持 UF2
8081
- 支持 Android Debug Bridge (Only support shell)

SConscript

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ path += [cwd + '/class/dfu']
1717
path += [cwd + '/class/serial']
1818
path += [cwd + '/class/vendor/net']
1919
path += [cwd + '/class/vendor/wifi']
20+
path += [cwd + '/class/vendor/display']
2021
src = []
2122

2223
LIBS = []
@@ -179,6 +180,8 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
179180
src += Glob('demo/winusb2.0_cdc_template.c')
180181
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID']):
181182
src += Glob('demo/webusb_hid_template.c')
183+
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY']):
184+
src += Glob('demo/display/usbdisplay_template.c')
182185
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB']):
183186
src += Glob('demo/adb/usbd_adb_template.c')
184187
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV']):

cherryusb.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ list(
5050
${CMAKE_CURRENT_LIST_DIR}/class/serial
5151
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
5252
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
53+
${CMAKE_CURRENT_LIST_DIR}/class/vendor/display
5354
${CMAKE_CURRENT_LIST_DIR}/class/aoa
5455
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
5556
)
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright (c) 2026, sakumisu
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "usbd_core.h"
8+
#include "usbd_display.h"
9+
#include "chry_mempool.h"
10+
11+
struct usbd_disp_frame_header {
12+
uint16_t crc16; //payload crc16
13+
uint8_t type; //raw rgb,yuv,jpg,other
14+
uint8_t cmd;
15+
uint16_t x; //32bit
16+
uint16_t y;
17+
uint16_t width; //32bit
18+
uint16_t height;
19+
uint32_t frame_id : 10;
20+
uint32_t payload_total : 22; //payload max 4MB
21+
} __PACKED;
22+
23+
struct usbd_display_priv {
24+
struct chry_mempool pool;
25+
struct usbd_endpoint out_ep;
26+
struct usbd_endpoint in_ep;
27+
struct usbd_display_frame *current_frame;
28+
} g_usbd_display;
29+
30+
int usbd_display_frame_create(struct usbd_display_frame *frame, uint32_t count)
31+
{
32+
return chry_mempool_create(&g_usbd_display.pool, frame, sizeof(struct usbd_display_frame), count);
33+
}
34+
35+
struct usbd_display_frame *usbd_display_frame_alloc(void)
36+
{
37+
return (struct usbd_display_frame *)chry_mempool_alloc(&g_usbd_display.pool);
38+
}
39+
40+
int usbd_display_frame_free(struct usbd_display_frame *frame)
41+
{
42+
return chry_mempool_free(&g_usbd_display.pool, (uintptr_t *)frame);
43+
}
44+
45+
int usbd_display_frame_send(struct usbd_display_frame *frame)
46+
{
47+
return chry_mempool_send(&g_usbd_display.pool, (uintptr_t *)frame);
48+
}
49+
50+
int usbd_display_frame_recv(struct usbd_display_frame **frame, uint32_t timeout)
51+
{
52+
return chry_mempool_recv(&g_usbd_display.pool, (uintptr_t **)frame, timeout);
53+
}
54+
55+
uint8_t usb_dispay_dummy[512];
56+
volatile uint32_t usb_display_buf_offset;
57+
volatile bool usb_display_ignore_frame;
58+
59+
static void display_notify_handler(uint8_t busid, uint8_t event, void *arg)
60+
{
61+
switch (event) {
62+
case USBD_EVENT_RESET:
63+
break;
64+
case USBD_EVENT_CONFIGURED:
65+
usb_display_buf_offset = 0;
66+
usb_display_ignore_frame = true;
67+
g_usbd_display.current_frame = NULL;
68+
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
69+
break;
70+
default:
71+
break;
72+
}
73+
}
74+
75+
void usbd_display_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
76+
{
77+
if (usb_display_ignore_frame) {
78+
// alloc frame for next at the end of current frame
79+
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
80+
if (g_usbd_display.current_frame == NULL) {
81+
g_usbd_display.current_frame = usbd_display_frame_alloc();
82+
if (g_usbd_display.current_frame) {
83+
usb_display_ignore_frame = false;
84+
usb_display_buf_offset = 0;
85+
86+
goto get_frame;
87+
} else {
88+
goto drop_frame;
89+
}
90+
} else {
91+
usb_display_ignore_frame = false;
92+
usb_display_buf_offset = 0;
93+
94+
goto get_frame;
95+
}
96+
} else {
97+
goto drop_frame;
98+
}
99+
} else {
100+
struct usbd_disp_frame_header *header = (struct usbd_disp_frame_header *)&g_usbd_display.current_frame->frame_buf[0];
101+
struct usbd_display_frame *frame;
102+
103+
if (header->payload_total > g_usbd_display.current_frame->frame_bufsize) {
104+
USB_LOG_ERR("frame overflow, drop it\r\n");
105+
usb_display_ignore_frame = true;
106+
107+
goto drop_frame;
108+
}
109+
110+
usb_display_buf_offset += nbytes;
111+
112+
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
113+
frame = g_usbd_display.current_frame;
114+
g_usbd_display.current_frame = NULL;
115+
116+
frame->frame_format = header->type;
117+
frame->frame_size = header->payload_total;
118+
usbd_display_frame_send(frame);
119+
120+
g_usbd_display.current_frame = usbd_display_frame_alloc();
121+
if (g_usbd_display.current_frame) {
122+
usb_display_ignore_frame = false;
123+
usb_display_buf_offset = 0;
124+
125+
goto get_frame;
126+
} else {
127+
usb_display_ignore_frame = true;
128+
129+
goto drop_frame;
130+
}
131+
} else {
132+
goto get_frame;
133+
}
134+
}
135+
return;
136+
137+
drop_frame:
138+
// drop current frame
139+
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
140+
return;
141+
get_frame:
142+
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, &g_usbd_display.current_frame->frame_buf[usb_display_buf_offset], 16384);
143+
return;
144+
}
145+
146+
void usbd_display_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
147+
{
148+
}
149+
150+
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
151+
const uint8_t out_ep,
152+
const uint8_t in_ep,
153+
struct usbd_display_frame *frame,
154+
uint32_t count)
155+
{
156+
intf->class_interface_handler = NULL;
157+
intf->class_endpoint_handler = NULL;
158+
intf->vendor_handler = NULL;
159+
intf->notify_handler = display_notify_handler;
160+
161+
g_usbd_display.out_ep.ep_addr = out_ep;
162+
g_usbd_display.out_ep.ep_cb = usbd_display_bulk_out;
163+
g_usbd_display.in_ep.ep_addr = in_ep;
164+
g_usbd_display.in_ep.ep_cb = usbd_display_bulk_in;
165+
usbd_add_endpoint(0, &g_usbd_display.out_ep);
166+
usbd_add_endpoint(0, &g_usbd_display.in_ep);
167+
168+
for (uint32_t i = 0; i < count; i++) {
169+
USB_ASSERT_MSG(frame[i].frame_bufsize % 16384, "frame_bufsize must be the multiple of 16384");
170+
}
171+
172+
usbd_display_frame_create(frame, count);
173+
return intf;
174+
}
175+
176+
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout)
177+
{
178+
return usbd_display_frame_recv(frame, timeout);
179+
}
180+
181+
int usbd_display_enqueue(struct usbd_display_frame *frame)
182+
{
183+
return usbd_display_frame_free(frame);
184+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2026, sakumisu
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef USBD_DISPLAY_H
7+
#define USBD_DISPLAY_H
8+
9+
#define USBD_DISPLAY_TYPE_RGB565 0
10+
#define USBD_DISPLAY_TYPE_RGB888 1
11+
#define USBD_DISPLAY_TYPE_YUV420 2
12+
#define USBD_DISPLAY_TYPE_JPG 3
13+
14+
struct usbd_display_frame {
15+
uint8_t *frame_buf;
16+
uint32_t frame_bufsize;
17+
uint32_t frame_format;
18+
uint32_t frame_size;
19+
};
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
/* Init display interface driver */
26+
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
27+
const uint8_t out_ep,
28+
const uint8_t in_ep,
29+
struct usbd_display_frame *frame,
30+
uint32_t count);
31+
32+
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout);
33+
int usbd_display_enqueue(struct usbd_display_frame *frame);
34+
35+
#ifdef __cplusplus
36+
}
37+
#endif
38+
39+
#endif /* USBD_DISPLAY_H */

demo/display/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Thanks to https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display project.
2+
3+
Install tools/display/xfz1986_usb_graphic_250224_rc_sign.exe in windows before use.

0 commit comments

Comments
 (0)