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