1 /*
2 * Copyright (c) 2019 Intel corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /* Disable syscall tracing for all calls from this compilation unit to avoid
8 * undefined symbols as the macros are not expanded recursively
9 */
10 #define DISABLE_SYSCALL_TRACING
11
12 #include <zephyr/sys/util.h>
13 #include <zephyr/sys/atomic.h>
14 #include <zephyr/sys/__assert.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/usb/usb_device.h>
17 #include <tracing_core.h>
18 #include <tracing_buffer.h>
19 #include <tracing_backend.h>
20
21 #define USB_TRANSFER_ONGOING 1
22 #define USB_TRANSFER_FREE 0
23
24 #define TRACING_IF_IN_EP_ADDR 0x81
25 #define TRACING_IF_OUT_EP_ADDR 0x01
26
27 struct usb_device_desc {
28 struct usb_if_descriptor if0;
29 struct usb_ep_descriptor if0_in_ep;
30 struct usb_ep_descriptor if0_out_ep;
31 } __packed;
32
33 static volatile int transfer_state;
34 static enum usb_dc_status_code usb_device_status = USB_DC_UNKNOWN;
35
36 USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = {
37 /*
38 * Interface descriptor 0
39 */
40 .if0 = {
41 .bLength = sizeof(struct usb_if_descriptor),
42 .bDescriptorType = USB_DESC_INTERFACE,
43 .bInterfaceNumber = 0,
44 .bAlternateSetting = 0,
45 .bNumEndpoints = 2,
46 .bInterfaceClass = USB_BCC_VENDOR,
47 .bInterfaceSubClass = 0,
48 .bInterfaceProtocol = 0,
49 .iInterface = 0,
50 },
51
52 /*
53 * Data Endpoint IN
54 */
55 .if0_in_ep = {
56 .bLength = sizeof(struct usb_ep_descriptor),
57 .bDescriptorType = USB_DESC_ENDPOINT,
58 .bEndpointAddress = TRACING_IF_IN_EP_ADDR,
59 .bmAttributes = USB_DC_EP_BULK,
60 .wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS),
61 .bInterval = 0x00,
62 },
63
64 /*
65 * Data Endpoint OUT
66 */
67 .if0_out_ep = {
68 .bLength = sizeof(struct usb_ep_descriptor),
69 .bDescriptorType = USB_DESC_ENDPOINT,
70 .bEndpointAddress = TRACING_IF_OUT_EP_ADDR,
71 .bmAttributes = USB_DC_EP_BULK,
72 .wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS),
73 .bInterval = 0x00,
74 },
75 };
76
dev_status_cb(struct usb_cfg_data * cfg,enum usb_dc_status_code status,const uint8_t * param)77 static void dev_status_cb(struct usb_cfg_data *cfg,
78 enum usb_dc_status_code status,
79 const uint8_t *param)
80 {
81 ARG_UNUSED(cfg);
82 ARG_UNUSED(param);
83
84 usb_device_status = status;
85 }
86
tracing_ep_out_cb(uint8_t ep,enum usb_dc_ep_cb_status_code ep_status)87 static void tracing_ep_out_cb(uint8_t ep, enum usb_dc_ep_cb_status_code ep_status)
88 {
89 uint8_t *cmd = NULL;
90 uint32_t bytes_to_read, length;
91
92 usb_read(ep, NULL, 0, &bytes_to_read);
93
94 while (bytes_to_read) {
95 length = tracing_cmd_buffer_alloc(&cmd);
96 if (cmd) {
97 length = MIN(length, bytes_to_read);
98 usb_read(ep, cmd, length, NULL);
99 tracing_cmd_handle(cmd, length);
100
101 bytes_to_read -= length;
102 }
103 }
104
105 /*
106 * send ZLP to sync with host receive thread
107 */
108 usb_write(TRACING_IF_IN_EP_ADDR, NULL, 0, NULL);
109 }
110
tracing_ep_in_cb(uint8_t ep,enum usb_dc_ep_cb_status_code ep_status)111 static void tracing_ep_in_cb(uint8_t ep, enum usb_dc_ep_cb_status_code ep_status)
112 {
113 ARG_UNUSED(ep);
114 ARG_UNUSED(ep_status);
115
116 transfer_state = USB_TRANSFER_FREE;
117 }
118
119 static struct usb_ep_cfg_data ep_cfg[] = {
120 {
121 .ep_cb = tracing_ep_out_cb,
122 .ep_addr = TRACING_IF_OUT_EP_ADDR,
123 },
124 {
125 .ep_cb = tracing_ep_in_cb,
126 .ep_addr = TRACING_IF_IN_EP_ADDR,
127 },
128 };
129
130 USBD_DEFINE_CFG_DATA(tracing_backend_usb_config) = {
131 .usb_device_description = NULL,
132 .interface_descriptor = &dev_desc.if0,
133 .cb_usb_status = dev_status_cb,
134 .interface = {
135 .class_handler = NULL,
136 .custom_handler = NULL,
137 .vendor_handler = NULL,
138 },
139 .num_endpoints = ARRAY_SIZE(ep_cfg),
140 .endpoint = ep_cfg,
141 };
142
tracing_backend_usb_output(const struct tracing_backend * backend,uint8_t * data,uint32_t length)143 static void tracing_backend_usb_output(const struct tracing_backend *backend,
144 uint8_t *data, uint32_t length)
145 {
146 int ret = 0;
147 uint32_t bytes;
148
149 while (length > 0) {
150 transfer_state = USB_TRANSFER_ONGOING;
151
152 /*
153 * make sure every USB transfer no need ZLP at all
154 * because we are in lowest priority thread content
155 * there are no deterministic time between real USB
156 * packet and ZLP
157 */
158 ret = usb_write(TRACING_IF_IN_EP_ADDR, data,
159 length >= CONFIG_TRACING_USB_MPS ?
160 CONFIG_TRACING_USB_MPS - 1 : length, &bytes);
161 if (ret) {
162 continue;
163 }
164
165 data += bytes;
166 length -= bytes;
167
168 while (transfer_state == USB_TRANSFER_ONGOING) {
169 }
170 }
171 }
172
173 const struct tracing_backend_api tracing_backend_usb_api = {
174 .output = tracing_backend_usb_output
175 };
176
177 TRACING_BACKEND_DEFINE(tracing_backend_usb, tracing_backend_usb_api);
178