1 /*******************************************************************************
2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * PolarFire SoC MSS USB Driver Stack
7 * USB Logical Layer (USB-LL)
8 * USBD-HID class driver
9 *
10 * This file implements HID class functionality.
11 * HID Mouse report is supported.
12 *
13 */
14
15 #include "mpfs_hal/mss_hal.h"
16 #include "mss_usb_device.h"
17 #include "mss_usb_std_def.h"
18 #include "mss_usb_device_hid.h"
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 #ifdef MSS_USB_DEVICE_ENABLED
25
26 #define HID_CONF_DESCR_DESCTYPE_IDX 1u
27 #define HID_CONF_DESCR_HIDDESCRTYPE_IDX 18u
28
29 /***************************************************************************//**
30 * Private Functions
31 */
32 static uint8_t* usbd_hid_get_descriptor_cb(uint8_t recepient,
33 uint8_t type,
34 uint32_t* length,
35 mss_usb_device_speed_t musb_speed);
36
37 static uint8_t usbd_hid_init_cb(uint8_t cfgidx, mss_usb_device_speed_t musb_speed);
38 static uint8_t usbd_hid_release_cb(uint8_t cfgidx);
39
40 static uint8_t usbd_hid_process_request_cb(mss_usbd_setup_pkt_t * setup_pkt,
41 uint8_t** buf_pp,
42 uint32_t* length);
43
44 static uint8_t usbd_hid_tx_complete_cb(mss_usb_ep_num_t num, uint8_t status);
45 static uint8_t usbd_hid_rx_cb(mss_usb_ep_num_t num, uint8_t status, uint32_t rx_count);
46 static uint8_t usbd_hid_cep_tx_done_cb(uint8_t status);
47 static uint8_t usbd_hid_cep_rx_done_cb(uint8_t status);
48
49 /* Call-back function structure definition needed by USB Device Core Driver */
50 mss_usbd_class_cb_t usbd_hid_cb = {
51 usbd_hid_init_cb,
52 usbd_hid_release_cb,
53 usbd_hid_get_descriptor_cb,
54 usbd_hid_process_request_cb,
55 usbd_hid_tx_complete_cb,
56 usbd_hid_rx_cb,
57 usbd_hid_cep_tx_done_cb,
58 usbd_hid_cep_rx_done_cb
59 };
60
61 volatile uint32_t g_tx_complete_status = 1u;
62
63 /* USB current Speed of operation selected by user*/
64 mss_usb_device_speed_t g_usbd_hid_user_speed;
65
66 mss_usbd_hid_state_t g_hid_state = USBD_HID_NOT_CONFIGURED;
67
68 uint8_t hid_conf_descr[HID_CONFIG_DESCR_LENGTH] = {
69 /*----------------------- Configuration Descriptor -----------------------*/
70 USB_STD_CONFIG_DESCR_LEN, /* bLength */
71 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
72 0x22u, /* wTotalLength LSB */
73 0x00u, /* wTotalLength MSB */
74 0x01u, /* bNumInterfaces */
75 0x01u, /* bConfigurationValue */
76 0x04u, /* iConfiguration */
77 0xC0u, /* bmAttributes */
78 0x32u, /* bMaxPower */
79 /*------------------------- Interface Descriptor -------------------------*/
80 USB_STD_INTERFACE_DESCR_LEN, /* bLength */
81 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
82 0x00u, /* bInterfaceNumber */
83 0x00u, /* bAlternateSetting */
84 0x01u, /* bNumEndpoints */
85 0x03u, /* bInterfaceClass */
86 0x00u, /* bInterfaceSubClass */
87 0x02u, /* bInterfaceProtocol */
88 0x00u, /* bInterface */
89 /*---------------------------- HID Descriptor ----------------------------*/
90 USB_HID_DESCR_LENGTH, /* bLength */
91 0x21u, /* bDescriptorType */
92 0x10u, /* bcdHID */
93 0x01u,
94 0x00u, /* bCountryCode */
95 0x01u, /* bNumDescriptor */
96 0x22u, /* bDescriptorType */
97 0x34u, /* wDescriptorLength */
98 0x00u,
99 /*------------------------- Endpoint Descriptor --------------------------*/
100 USB_STD_ENDPOINT_DESCR_LEN, /* bLength */
101 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
102 (0x80u | HID_INTR_TX_EP), /* bEndpointAddress */
103 0x03u, /* bmAttributes */
104 0x08u, /* wMaxPacketSize LSB */
105 0x00u, /* wMaxPacketSize MSB */
106 0x06u /* bInterval */
107 };
108
109 /*
110 Report descriptor: sent to the host during enumeration process.
111 This descriptors defines the format of the HID report.
112 */
113 uint8_t report_descr[] = {
114 0x05u, 0x01u, /* USAGE_PAGE (Generic Desktop) */
115 0x09u, 0x02u, /* USAGE (Mouse) */
116 0xA1u, 0x01u, /* COLLECTION (Application) */
117 0x09u, 0x01u, /* USAGE (Pointer) */
118 0xA1u, 0x00u, /* COLLECTION (Physical) */
119 0x05u, 0x09u, /* USAGE_PAGE (Button) */
120 0x19u, 0x01u, /* USAGE_MINIMUM (Button 1) */
121 0x29u, 0x03u, /* USAGE_MAXIMUM (Button 3) */
122 0x15u, 0x00u, /* LOGICAL_MINIMUM (0) */
123 0x25u, 0x01u, /* LOGICAL_MAXIMUM (1) */
124 0x75u, 0x01u, /* REPORT_SIZE (1) */
125 0x95u, 0x03u, /* REPORT_COUNT (3) */
126 0x81u, 0x02u, /* INPUT (Data,Var,Abs) */
127 0x75u, 0x05u, /* REPORT_SIZE (5) */
128 0x95u, 0x01u, /* REPORT_COUNT (1) */
129 0x81u, 0x01u, /* INPUT (Const,Array,Abs) */
130 0x05u, 0x01u, /* USAGE_PAGE (Generic Desktop) */
131 0x09u, 0x30u, /* USAGE (X) */
132 0x09u, 0x31u, /* USAGE (Y) */
133 0x09u, 0x38u, /* USAGE(Wheel) */
134 0x15u, 0x81u, /* LOGICAL_MINIMUM (-127) */
135 0x25u, 0x7Fu, /* LOGICAL_MAXIMUM (127) */
136 0x75u, 0x08u, /* REPORT_SIZE (8) */
137 0x95u, 0x03u, /* REPORT_COUNT (3) */
138 0x81u, 0x06u, /* INPUT (Data,Var,Rel) */
139 0xC0u, 0xC0u /* END_COLLECTION */
140 };
141
142 /***************************************************************************//**
143 * Exported function from HID Class driver.
144 *******************************************************************************/
145
146 /***************************************************************************//**
147 * See mss_usb_device_hid.h for details of how to use this function.
148 */
149 void
MSS_USBD_HID_init(mss_usb_device_speed_t speed)150 MSS_USBD_HID_init
151 (
152 mss_usb_device_speed_t speed
153 )
154 {
155 g_usbd_hid_user_speed = speed;
156 MSS_USBD_set_class_cb_handler(&usbd_hid_cb);
157 }
158
159 /***************************************************************************//**
160 * See mss_usb_device_hid.h for details of how to use this function.
161 */
162 uint32_t
MSS_USBD_HID_tx_report(uint8_t * buf,uint32_t length)163 MSS_USBD_HID_tx_report
164 (
165 uint8_t * buf,
166 uint32_t length
167 )
168 {
169 if(USBD_HID_CONFIGURED == g_hid_state)
170 {
171 g_tx_complete_status = 0u;
172 MSS_USBD_tx_ep_write(HID_INTR_TX_EP, buf, length);
173 return (USB_SUCCESS);
174 }
175 else
176 {
177 return (USB_FAIL);
178 }
179 }
180
181 /***************************************************************************//**
182 * See mss_usb_device_hid.h for details of how to use this function.
183 */
184 uint8_t
MSS_USBD_HID_tx_done(void)185 MSS_USBD_HID_tx_done
186 (
187 void
188 )
189 {
190 return(g_tx_complete_status);
191 }
192
193 /***************************************************************************//**
194 Private functions to USBD_HID class driver.
195 ******************************************************************************/
196
197 static uint8_t*
usbd_hid_get_descriptor_cb(uint8_t recepient,uint8_t type,uint32_t * length,mss_usb_device_speed_t musb_speed)198 usbd_hid_get_descriptor_cb
199 (
200 uint8_t recepient,
201 uint8_t type,
202 uint32_t* length,
203 mss_usb_device_speed_t musb_speed
204 )
205 {
206 /*User Selected FS:
207 Operate only in FS
208 User Selected HS:
209 Device connected to 2.0 Host(musb_speed = HS):Operate in HS
210 Device connected to 1.x Host(musb_speed = FS):Operate in FS
211 */
212
213 /*
214 Since Endpoint Size is wMaxpacketSize is 8, which is valid for both
215 FS and HS, no need to make decision based on musb_speed.
216
217 bInterval value is 6.
218 For FS it results in 6mSec polling period
219 For HS it results in 4mSec polling period
220 Since this is OK for mouse app, we will return same configuration for
221 Other Speed Config as well.
222 */
223
224 if(USB_STD_REQ_RECIPIENT_DEVICE == recepient )
225 {
226 if(USB_CONFIGURATION_DESCRIPTOR_TYPE == type)
227 {
228 hid_conf_descr[HID_CONF_DESCR_DESCTYPE_IDX] = USB_CONFIGURATION_DESCRIPTOR_TYPE;
229 *length = sizeof(hid_conf_descr);
230 return(hid_conf_descr);
231 }
232 else if(USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE == type)
233 {
234 hid_conf_descr[HID_CONF_DESCR_DESCTYPE_IDX] = USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE;
235 *length = sizeof(hid_conf_descr);
236 return(hid_conf_descr);
237 }
238 }
239 else if( USB_STD_REQ_RECIPIENT_ENDPOINT == recepient )/*Need index(EP Num)*/
240 {
241 /*Do nothing*/
242 }
243 else if(USB_STD_REQ_RECIPIENT_INTERFACE == recepient)/*Need index(interface number)*/
244 {
245 if(USB_REPORT_DESCRIPTOR_TYPE == type)
246 {
247 *length = sizeof(report_descr);
248 return(report_descr);
249 }
250 else if (USB_HID_DESCRIPTOR_TYPE == type)
251 {
252 *length = USB_HID_DESCR_LENGTH;
253 return(&hid_conf_descr[HID_CONF_DESCR_HIDDESCRTYPE_IDX]);
254 }
255 }
256 else
257 {
258 /*Do nothing*/
259 }
260
261 return USB_FAIL;
262 }
263
264 static uint8_t
usbd_hid_init_cb(uint8_t cfgidx,mss_usb_device_speed_t musb_speed)265 usbd_hid_init_cb
266 (
267 uint8_t cfgidx,
268 mss_usb_device_speed_t musb_speed
269 )
270 {
271 /*
272 Since Endpoint Size is wMaxpacketSize is 8, which is valid for both
273 FS and HS, we don't need to make decision based on musb_speed
274 */
275 g_tx_complete_status = 1u;
276 MSS_USBD_tx_ep_configure(HID_INTR_TX_EP,
277 HID_INTR_TX_EP_FIFO_ADDR,
278 HID_INTR_TX_EP_MAX_PKT_SIZE,
279 HID_INTR_TX_EP_MAX_PKT_SIZE,
280 1u,
281 DMA_ENABLE,//DMA_DISABLE,
282 MSS_USB_DMA_CHANNEL1,
283 MSS_USB_XFR_INTERRUPT,
284 NO_ZLP_TO_XFR);
285
286 g_hid_state = USBD_HID_CONFIGURED;
287 return USB_SUCCESS;
288 }
289
290 static uint8_t
usbd_hid_release_cb(uint8_t cfgidx)291 usbd_hid_release_cb
292 (
293 uint8_t cfgidx
294 )
295 {
296 g_hid_state = USBD_HID_NOT_CONFIGURED;
297 return USB_SUCCESS;
298 }
299
300 static uint8_t
usbd_hid_process_request_cb(mss_usbd_setup_pkt_t * setup_pkt,uint8_t ** buf_pp,uint32_t * length)301 usbd_hid_process_request_cb
302 (
303 mss_usbd_setup_pkt_t * setup_pkt,
304 uint8_t** buf_pp,
305 uint32_t* length
306 )
307 {
308 return USB_FAIL;
309 }
310
311 static uint8_t
usbd_hid_tx_complete_cb(mss_usb_ep_num_t num,uint8_t status)312 usbd_hid_tx_complete_cb
313 (
314 mss_usb_ep_num_t num,
315 uint8_t status
316 )
317 {
318 if(status & (TX_EP_UNDER_RUN_ERROR|TX_EP_STALL_ERROR) )
319 {
320 MSS_USBD_tx_ep_flush_fifo(HID_INTR_TX_EP);
321 }
322 g_tx_complete_status = 1u;
323
324
325 return USB_SUCCESS;
326 }
327
328 static uint8_t
usbd_hid_rx_cb(mss_usb_ep_num_t num,uint8_t status,uint32_t rx_count)329 usbd_hid_rx_cb
330 (
331 mss_usb_ep_num_t num,
332 uint8_t status,
333 uint32_t rx_count
334 )
335 {
336 return USB_SUCCESS;
337 }
338
339 static uint8_t
usbd_hid_cep_tx_done_cb(uint8_t status)340 usbd_hid_cep_tx_done_cb
341 (
342 uint8_t status
343 )
344 {
345 return USB_SUCCESS;
346 }
347 static uint8_t
usbd_hid_cep_rx_done_cb(uint8_t status)348 usbd_hid_cep_rx_done_cb
349 (
350 uint8_t status
351 )
352 {
353 return USB_SUCCESS;
354 }
355
356 #endif //MSS_USB_DEVICE_ENABLED
357
358 #ifdef __cplusplus
359 }
360 #endif
361