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