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