1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8 This header contains bare-bone mock implementations of some device classes in order to test various layers of the USB
9 Host stack.
10 */
11 
12 #pragma once
13 
14 #include <stdint.h>
15 #include <stdbool.h>
16 #include "usb/usb_types_ch9.h"
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 // ---------------------------------------------------- MSC SCSI -------------------------------------------------------
23 
24 const char *MSC_CLIENT_TAG;
25 
26 /*
27 Note: The mock MSC SCSI tests requires that USB flash drive be connected. The flash drive should...
28 
29 - Be implement the Mass Storage class supporting BULK only transfers using SCSI commands
30 - It's configuration 1 should have the following endpoints
31 
32 Device Descriptor:
33     bLength                18
34     bDescriptorType         1
35     bcdUSB               2.00
36     bDeviceClass            0
37     bDeviceSubClass         0
38     bDeviceProtocol         0
39     bMaxPacketSize0        64
40     idVendor           0x125f
41     idProduct          0xc08a
42     bcdDevice            1.00
43     iManufacturer           1
44     iProduct                2
45     iSerial                 3
46     bNumConfigurations      1
47 Configuration Descriptor:
48     bLength                 9
49     bDescriptorType         2
50     wTotalLength       0x0020
51     bNumInterfaces          1
52     bConfigurationValue     1
53     iConfiguration          0
54     bmAttributes         0x80
55         (Bus Powered)
56     MaxPower              480mA
57     Interface Descriptor:
58         bLength                 9
59         bDescriptorType         4
60         bInterfaceNumber        0
61         bAlternateSetting       0
62         bNumEndpoints           2
63         bInterfaceClass         8 Mass Storage
64         bInterfaceSubClass      6 SCSI
65         bInterfaceProtocol     80 Bulk-Only
66         iInterface              0
67         Endpoint Descriptor:
68             bLength             7
69             bDescriptorType     5
70             bEndpointAddress    0x01  EP 1 OUT
71             bmAttributes        2
72                 Transfer Type   Bulk
73                 Synch Type      None
74                 Usage Type      Data
75             wMaxPacketSize      0x0040  1x 64 bytes
76             bInterval           1
77         Endpoint Descriptor:
78             bLength             7
79             bDescriptorType     5
80             bEndpointAddress    0x82  EP 2 IN
81             bmAttributes        2
82                 Transfer Type   Bulk
83                 Synch Type      None
84                 Usage Type      Data
85             wMaxPacketSize      0x0040  1x 64 bytes
86             bInterval           1
87 
88 If you're using a flash driver with different endpoints, modify the endpoint descriptors below.
89 */
90 
91 //Constant descriptors
92 extern const uint8_t mock_msc_scsi_dev_desc[];
93 extern const uint8_t mock_msc_scsi_config_desc[];
94 extern const uint8_t mock_msc_scsi_str_desc_manu[];
95 extern const uint8_t mock_msc_scsi_str_desc_prod[];
96 extern const uint8_t mock_msc_scsi_str_desc_ser_num[];
97 extern const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc;
98 extern const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc;
99 
100 #define MOCK_MSC_SCSI_DEV_ID_VENDOR     0x125F
101 #define MOCK_MSC_SCSI_DEV_ID_PRODUCT    0xc08A
102 #define MOCK_MSC_SCSI_DEV_DFLT_EP_MPS   64
103 #define MOCK_MSC_SCSI_SECTOR_SIZE       512
104 #define MOCK_MSC_SCSI_LUN               0
105 #define MOCK_MSC_SCSI_INTF_NUMBER       0
106 #define MOCK_MSC_SCSI_INTF_ALT_SETTING  0
107 #define MOCK_MSC_SCSI_BULK_OUT_EP_ADDR  0x01
108 #define MOCK_MSC_SCSI_BULK_IN_EP_ADDR   0x82
109 #define MOCK_MSC_SCSI_BULK_EP_MPS       64
110 
111 #define MOCK_MSC_SCSI_REQ_INIT_RESET(setup_pkt_ptr, intf_num) ({  \
112     (setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
113     (setup_pkt_ptr)->bRequest = 0xFF;    \
114     (setup_pkt_ptr)->wValue = 0; \
115     (setup_pkt_ptr)->wIndex = (intf_num);    \
116     (setup_pkt_ptr)->wLength = 0;    \
117 })
118 
119 typedef struct __attribute__((packed)) {
120     uint8_t opcode; //0x28 = read(10), 0x2A=write(10)
121     uint8_t flags;
122     uint8_t lba_3;
123     uint8_t lba_2;
124     uint8_t lba_1;
125     uint8_t lba_0;
126     uint8_t group;
127     uint8_t len_1;
128     uint8_t len_0;
129     uint8_t control;
130 } mock_scsi_cmd10_t;
131 
132 typedef struct __attribute__((packed)) {
133     uint32_t dCBWSignature;
134     uint32_t dCBWTag;
135     uint32_t dCBWDataTransferLength;
136     uint8_t bmCBWFlags;
137     uint8_t bCBWLUN;
138     uint8_t bCBWCBLength;
139     mock_scsi_cmd10_t CBWCB;
140     uint8_t padding[6];
141 } mock_msc_bulk_cbw_t;
142 
143 // USB Bulk Transfer Command Status Wrapper data
144 typedef struct __attribute__((packed)) {
145     uint32_t dCSWSignature;
146     uint32_t dCSWTag;
147     uint32_t dCSWDataResidue;
148     uint8_t bCSWStatus;
149 } mock_msc_bulk_csw_t;
150 
151 /**
152  * @brief Initialize a MSC Command Block Wrapper (CBW) as an SCSI command
153  *
154  * @param cbw CBW structure
155  * @param is_read Is a read command
156  * @param offset Block offset
157  * @param num_sectors Number of sectors to read
158  * @param tag Tag (this is simply echoed back
159  */
160 void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag);
161 
162 /**
163  * @brief Check that returned Command Status Wrapper (CSW) is valid
164  *
165  * @param csw CSW structure
166  * @param tag_expect Expected tag
167  * @return true CSW is valid
168  * @return false CSW is not valid
169  */
170 bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expect);
171 
172 // ---------------------------------------------------- HID Mouse ------------------------------------------------------
173 
174 
175 /*
176 Note: The mock HID mouse tests require that USB low speed mouse be connected. The mouse should...
177 
178 - Be implement the HID with standard report format used by mice
179 - It's configuration 1 should have the following endpoint
180 
181 Device Descriptor:
182     bLength                18
183     bDescriptorType         1
184     bcdUSB               2.00
185     bDeviceClass            0
186     bDeviceSubClass         0
187     bDeviceProtocol         0
188     bMaxPacketSize0         8
189     idVendor           0x413c Dell Computer Corp.
190     idProduct          0x301a
191     bcdDevice            1.00
192     iManufacturer           1
193     iProduct                2
194     iSerial                 0
195     bNumConfigurations      1
196     Configuration Descriptor:
197         bLength                 9
198         bDescriptorType         2
199         wTotalLength       0x0022
200         bNumInterfaces          1
201         bConfigurationValue     1
202         iConfiguration          0
203         bmAttributes         0xa0
204         (Bus Powered)
205         Remote Wakeup
206         MaxPower              100mA
207         Interface Descriptor:
208             bLength                 9
209             bDescriptorType         4
210             bInterfaceNumber        0
211             bAlternateSetting       0
212             bNumEndpoints           1
213             bInterfaceClass         3 Human Interface Device
214             bInterfaceSubClass      1 Boot Interface Subclass
215             bInterfaceProtocol      2 Mouse
216             iInterface              0
217                 HID Device Descriptor:
218                 bLength                 9
219                 bDescriptorType        33
220                 bcdHID               1.11
221                 bCountryCode            0 Not supported
222                 bNumDescriptors         1
223                 bDescriptorType        34 Report
224                 wDescriptorLength      46
225                 Report Descriptors:
226                 ** UNAVAILABLE **
227             Endpoint Descriptor:
228                 bLength                 7
229                 bDescriptorType         5
230                 bEndpointAddress     0x81  EP 1 IN
231                 bmAttributes            3
232                 Transfer Type            Interrupt
233                 Synch Type               None
234                 Usage Type               Data
235                 wMaxPacketSize     0x0004  1x 4 bytes
236                 bInterval              10
237 
238 If you're using another mice with different endpoints, modify the endpoint descriptor below
239 */
240 
241 extern  const usb_ep_desc_t mock_hid_mouse_in_ep_desc;
242 
243 #define MOCK_HID_MOUSE_DEV_ID_VENDOR        0x413C
244 #define MOCK_HID_MOUSE_DEV_ID_PRODUCT       0x301A
245 #define MOCK_HID_MOUSE_DEV_DFLT_EP_MPS      8
246 #define MOCK_HID_MOUSE_INTF_NUMBER          0
247 #define MOCK_HID_MOUSE_INTF_ALT_SETTING     0
248 #define MOCK_HID_MOUSE_INTR_IN_EP_ADDR      0x81
249 #define MOCK_HID_MOUSE_INTR_IN_MPS          0x04
250 
251 typedef union {
252     struct {
253         uint32_t left_button: 1;
254         uint32_t right_button: 1;
255         uint32_t middle_button: 1;
256         uint32_t reserved5: 5;
257         uint8_t x_movement;
258         uint8_t y_movement;
259     } __attribute__((packed));
260     uint8_t val[3];
261 } mock_hid_mouse_report_t;
262 _Static_assert(sizeof(mock_hid_mouse_report_t) == 3, "Size of HID mouse report incorrect");
263 
264 void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter);
265 
266 // ---------------------------------------------------- Mock ISOC ------------------------------------------------------
267 
268 /*
269 Note: ISOC test rely on communicating with a non existent endpoint using ISOC OUT transfers. Since no ACK is given for
270 ISOC, transferring to a non-existent endpoint should work. The non-existent endpoint descriptor is described below:
271 */
272 
273 #define MOCK_ISOC_EP_NUM        2
274 #define MOCK_ISOC_EP_MPS        512
275 
276 
277 static const usb_ep_desc_t mock_isoc_out_ep_desc = {
278     .bLength = sizeof(usb_ep_desc_t),
279     .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
280     .bEndpointAddress = MOCK_ISOC_EP_NUM,
281     .bmAttributes = USB_BM_ATTRIBUTES_XFER_ISOC,
282     .wMaxPacketSize = MOCK_ISOC_EP_MPS,     //MPS of 512 bytes
283     .bInterval = 1,     //Isoc interval is (2 ^ (bInterval - 1)) which means an interval of 1ms
284 };
285 
286 
287 #ifdef __cplusplus
288 }
289 #endif
290