summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsakimisu <[email protected]>2022-02-08 11:44:46 +0800
committersakimisu <[email protected]>2022-02-08 11:44:46 +0800
commit1edbae8e07ddb7c03d97d455cee8c091c81ce986 (patch)
tree1367990e7a9c104ba3bbf3592239a82cf3de8eda
parentfeb5a8fb52326b5306c10b7a9c4838411af06b7c (diff)
format codes
-rw-r--r--class/audio/usbd_audio.c272
-rw-r--r--class/cdc/usbd_cdc.c342
-rw-r--r--class/cdc/usbh_cdc_acm.c670
-rw-r--r--class/cdc/usbh_cdc_acm.h102
-rw-r--r--class/hid/usbd_hid.c572
-rw-r--r--class/hid/usbh_hid.c548
-rw-r--r--class/hid/usbh_hid.h88
-rw-r--r--class/hub/usbh_hub.c992
-rw-r--r--class/hub/usbh_hub.h84
-rw-r--r--class/msc/usbd_msc.c1984
-rw-r--r--class/msc/usbh_msc.c874
-rw-r--r--class/msc/usbh_msc.h96
-rw-r--r--class/video/usbd_video.c266
-rw-r--r--common/usb_dc.h400
-rw-r--r--common/usb_def.h1342
-rw-r--r--common/usb_util.h600
-rw-r--r--core/usbd_core.c2598
-rw-r--r--core/usbd_core.h276
-rw-r--r--core/usbh_core.c1978
-rw-r--r--core/usbh_core.h256
-rw-r--r--usb_config.h90
21 files changed, 7215 insertions, 7215 deletions
diff --git a/class/audio/usbd_audio.c b/class/audio/usbd_audio.c
index 0ec73c77..6d0fdeb7 100644
--- a/class/audio/usbd_audio.c
+++ b/class/audio/usbd_audio.c
@@ -1,136 +1,136 @@
-/**
- * @file usbd_audio.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-#include "usbd_audio.h"
-
-struct usbd_audio_control_info audio_control_info = { 0xdb00, 0x0000, 0x0100, 0xf600, 0 };
-
-int audio_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("AUDIO Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- switch (setup->bRequest) {
- case AUDIO_REQUEST_SET_CUR:
-
- if (LO_BYTE(setup->wValue) == 0x01) {
- if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) {
- memcpy(&audio_control_info.mute, *data, *len);
- } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) {
- memcpy(&audio_control_info.vol_current, *data, *len);
- int vol;
- if (audio_control_info.vol_current == 0) {
- vol = 100;
- } else {
- vol = (audio_control_info.vol_current - 0xDB00 + 1) * 100 / (0xFFFF - 0xDB00);
- }
- usbd_audio_set_volume(vol);
- USB_LOG_INFO("current audio volume:%d\r\n", vol);
- }
- }
-
- break;
-
- case AUDIO_REQUEST_GET_CUR:
- if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) {
- *data = (uint8_t *)&audio_control_info.mute;
- *len = 1;
- } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) {
- *data = (uint8_t *)&audio_control_info.vol_current;
- *len = 2;
- }
-
- break;
-
- case AUDIO_REQUEST_SET_RES:
- break;
-
- case AUDIO_REQUEST_SET_MEM:
- break;
-
- case AUDIO_REQUEST_GET_MIN:
- *data = (uint8_t *)&audio_control_info.vol_min;
- *len = 2;
- break;
-
- case AUDIO_REQUEST_GET_MAX:
- *data = (uint8_t *)&audio_control_info.vol_max;
- *len = 2;
- break;
-
- case AUDIO_REQUEST_GET_RES:
- *data = (uint8_t *)&audio_control_info.vol_res;
- *len = 2;
- break;
- case AUDIO_REQUEST_GET_MEM:
- *data[0] = 0;
- *len = 1;
- break;
-
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
-
- return 0;
-}
-
-void audio_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
-
- break;
-
- case USBD_EVENT_SOF:
- break;
-
- case USBD_EVENT_SET_INTERFACE:
- usbd_audio_set_interface_callback(((uint8_t *)arg)[3]);
- break;
-
- default:
- break;
- }
-}
-
-void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
-{
- static usbd_class_t *last_class = NULL;
-
- if (last_class != devclass) {
- last_class = devclass;
- usbd_class_register(devclass);
- }
-
- intf->class_handler = audio_class_request_handler;
- intf->custom_handler = NULL;
- intf->vendor_handler = NULL;
- intf->notify_handler = audio_notify_handler;
- usbd_class_add_interface(devclass, intf);
-}
-
-__WEAK void usbd_audio_set_volume(uint8_t vol)
-{
-}
+/**
+ * @file usbd_audio.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+#include "usbd_audio.h"
+
+struct usbd_audio_control_info audio_control_info = { 0xdb00, 0x0000, 0x0100, 0xf600, 0 };
+
+int audio_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("AUDIO Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ switch (setup->bRequest) {
+ case AUDIO_REQUEST_SET_CUR:
+
+ if (LO_BYTE(setup->wValue) == 0x01) {
+ if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) {
+ memcpy(&audio_control_info.mute, *data, *len);
+ } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) {
+ memcpy(&audio_control_info.vol_current, *data, *len);
+ int vol;
+ if (audio_control_info.vol_current == 0) {
+ vol = 100;
+ } else {
+ vol = (audio_control_info.vol_current - 0xDB00 + 1) * 100 / (0xFFFF - 0xDB00);
+ }
+ usbd_audio_set_volume(vol);
+ USB_LOG_INFO("current audio volume:%d\r\n", vol);
+ }
+ }
+
+ break;
+
+ case AUDIO_REQUEST_GET_CUR:
+ if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) {
+ *data = (uint8_t *)&audio_control_info.mute;
+ *len = 1;
+ } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) {
+ *data = (uint8_t *)&audio_control_info.vol_current;
+ *len = 2;
+ }
+
+ break;
+
+ case AUDIO_REQUEST_SET_RES:
+ break;
+
+ case AUDIO_REQUEST_SET_MEM:
+ break;
+
+ case AUDIO_REQUEST_GET_MIN:
+ *data = (uint8_t *)&audio_control_info.vol_min;
+ *len = 2;
+ break;
+
+ case AUDIO_REQUEST_GET_MAX:
+ *data = (uint8_t *)&audio_control_info.vol_max;
+ *len = 2;
+ break;
+
+ case AUDIO_REQUEST_GET_RES:
+ *data = (uint8_t *)&audio_control_info.vol_res;
+ *len = 2;
+ break;
+ case AUDIO_REQUEST_GET_MEM:
+ *data[0] = 0;
+ *len = 1;
+ break;
+
+ default:
+ USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+void audio_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+
+ break;
+
+ case USBD_EVENT_SOF:
+ break;
+
+ case USBD_EVENT_SET_INTERFACE:
+ usbd_audio_set_interface_callback(((uint8_t *)arg)[3]);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
+{
+ static usbd_class_t *last_class = NULL;
+
+ if (last_class != devclass) {
+ last_class = devclass;
+ usbd_class_register(devclass);
+ }
+
+ intf->class_handler = audio_class_request_handler;
+ intf->custom_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = audio_notify_handler;
+ usbd_class_add_interface(devclass, intf);
+}
+
+__WEAK void usbd_audio_set_volume(uint8_t vol)
+{
+}
diff --git a/class/cdc/usbd_cdc.c b/class/cdc/usbd_cdc.c
index a47a35d0..008ca671 100644
--- a/class/cdc/usbd_cdc.c
+++ b/class/cdc/usbd_cdc.c
@@ -1,171 +1,171 @@
-/**
- * @file usbd_cdc.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-#include "usbd_cdc.h"
-
-const char *stop_name[] = { "1", "1.5", "2" };
-const char *parity_name[] = { "N", "O", "E", "M", "S" };
-
-/* Device data structure */
-struct cdc_acm_cfg_private {
- /* CDC ACM line coding properties. LE order */
- struct cdc_line_coding line_coding;
- /* CDC ACM line state bitmap, DTE side */
- uint8_t line_state;
- /* CDC ACM serial state bitmap, DCE side */
- uint8_t serial_state;
- /* CDC ACM notification sent status */
- uint8_t notification_sent;
- /* CDC ACM configured flag */
- bool configured;
- /* CDC ACM suspended flag */
- bool suspended;
- uint32_t uart_first_init_flag;
-
-} usbd_cdc_acm_cfg;
-
-static void usbd_cdc_acm_reset(void)
-{
- usbd_cdc_acm_cfg.line_coding.dwDTERate = 2000000;
- usbd_cdc_acm_cfg.line_coding.bDataBits = 8;
- usbd_cdc_acm_cfg.line_coding.bParityType = 0;
- usbd_cdc_acm_cfg.line_coding.bCharFormat = 0;
- usbd_cdc_acm_cfg.configured = false;
- usbd_cdc_acm_cfg.uart_first_init_flag = 0;
-}
-
-/**
- * @brief Handler called for Class requests not handled by the USB stack.
- *
- * @param setup Information about the request to execute.
- * @param len Size of the buffer.
- * @param data Buffer containing the request result.
- *
- * @return 0 on success, negative errno code on fail.
- */
-static int cdc_acm_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("CDC Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- switch (setup->bRequest) {
- case CDC_REQUEST_SET_LINE_CODING:
-
- /*******************************************************************************/
- /* Line Coding Structure */
- /*-----------------------------------------------------------------------------*/
- /* Offset | Field | Size | Value | Description */
- /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
- /* 4 | bCharFormat | 1 | Number | Stop bits */
- /* 0 - 1 Stop bit */
- /* 1 - 1.5 Stop bits */
- /* 2 - 2 Stop bits */
- /* 5 | bParityType | 1 | Number | Parity */
- /* 0 - None */
- /* 1 - Odd */
- /* 2 - Even */
- /* 3 - Mark */
- /* 4 - Space */
- /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
- /*******************************************************************************/
- if (usbd_cdc_acm_cfg.uart_first_init_flag == 0) {
- usbd_cdc_acm_cfg.uart_first_init_flag = 1;
- return 0;
- }
-
- memcpy(&usbd_cdc_acm_cfg.line_coding, *data, sizeof(usbd_cdc_acm_cfg.line_coding));
- USB_LOG_DBG("CDC_SET_LINE_CODING <%d %d %s %s>\r\n",
- usbd_cdc_acm_cfg.line_coding.dwDTERate,
- usbd_cdc_acm_cfg.line_coding.bDataBits,
- parity_name[usbd_cdc_acm_cfg.line_coding.bParityType],
- stop_name[usbd_cdc_acm_cfg.line_coding.bCharFormat]);
- usbd_cdc_acm_set_line_coding(usbd_cdc_acm_cfg.line_coding.dwDTERate, usbd_cdc_acm_cfg.line_coding.bDataBits,
- usbd_cdc_acm_cfg.line_coding.bParityType, usbd_cdc_acm_cfg.line_coding.bCharFormat);
- break;
-
- case CDC_REQUEST_SET_CONTROL_LINE_STATE:
- usbd_cdc_acm_cfg.line_state = (uint8_t)setup->wValue;
- bool dtr = (setup->wValue & 0x01);
- bool rts = (setup->wValue & 0x02);
- USB_LOG_DBG("DTR 0x%x,RTS 0x%x\r\n",
- dtr, rts);
- usbd_cdc_acm_set_dtr(dtr);
- usbd_cdc_acm_set_rts(rts);
- break;
-
- case CDC_REQUEST_GET_LINE_CODING:
- *data = (uint8_t *)(&usbd_cdc_acm_cfg.line_coding);
- *len = sizeof(usbd_cdc_acm_cfg.line_coding);
- USB_LOG_DBG("CDC_GET_LINE_CODING %d %d %d %d\r\n",
- usbd_cdc_acm_cfg.line_coding.dwDTERate,
- usbd_cdc_acm_cfg.line_coding.bCharFormat,
- usbd_cdc_acm_cfg.line_coding.bParityType,
- usbd_cdc_acm_cfg.line_coding.bDataBits);
- break;
-
- default:
- USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
-
- return 0;
-}
-
-static void cdc_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
- usbd_cdc_acm_reset();
- break;
-
- default:
- break;
- }
-}
-
-__WEAK void usbd_cdc_acm_set_line_coding(uint32_t baudrate, uint8_t databits, uint8_t parity, uint8_t stopbits)
-{
-}
-__WEAK void usbd_cdc_acm_set_dtr(bool dtr)
-{
-}
-__WEAK void usbd_cdc_acm_set_rts(bool rts)
-{
-}
-
-void usbd_cdc_add_acm_interface(usbd_class_t *devclass, usbd_interface_t *intf)
-{
- static usbd_class_t *last_class = NULL;
-
- if (last_class != devclass) {
- last_class = devclass;
- usbd_class_register(devclass);
- }
-
- intf->class_handler = cdc_acm_class_request_handler;
- intf->custom_handler = NULL;
- intf->vendor_handler = NULL;
- intf->notify_handler = cdc_notify_handler;
- usbd_class_add_interface(devclass, intf);
-}
+/**
+ * @file usbd_cdc.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+#include "usbd_cdc.h"
+
+const char *stop_name[] = { "1", "1.5", "2" };
+const char *parity_name[] = { "N", "O", "E", "M", "S" };
+
+/* Device data structure */
+struct cdc_acm_cfg_private {
+ /* CDC ACM line coding properties. LE order */
+ struct cdc_line_coding line_coding;
+ /* CDC ACM line state bitmap, DTE side */
+ uint8_t line_state;
+ /* CDC ACM serial state bitmap, DCE side */
+ uint8_t serial_state;
+ /* CDC ACM notification sent status */
+ uint8_t notification_sent;
+ /* CDC ACM configured flag */
+ bool configured;
+ /* CDC ACM suspended flag */
+ bool suspended;
+ uint32_t uart_first_init_flag;
+
+} usbd_cdc_acm_cfg;
+
+static void usbd_cdc_acm_reset(void)
+{
+ usbd_cdc_acm_cfg.line_coding.dwDTERate = 2000000;
+ usbd_cdc_acm_cfg.line_coding.bDataBits = 8;
+ usbd_cdc_acm_cfg.line_coding.bParityType = 0;
+ usbd_cdc_acm_cfg.line_coding.bCharFormat = 0;
+ usbd_cdc_acm_cfg.configured = false;
+ usbd_cdc_acm_cfg.uart_first_init_flag = 0;
+}
+
+/**
+ * @brief Handler called for Class requests not handled by the USB stack.
+ *
+ * @param setup Information about the request to execute.
+ * @param len Size of the buffer.
+ * @param data Buffer containing the request result.
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+static int cdc_acm_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("CDC Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ switch (setup->bRequest) {
+ case CDC_REQUEST_SET_LINE_CODING:
+
+ /*******************************************************************************/
+ /* Line Coding Structure */
+ /*-----------------------------------------------------------------------------*/
+ /* Offset | Field | Size | Value | Description */
+ /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
+ /* 4 | bCharFormat | 1 | Number | Stop bits */
+ /* 0 - 1 Stop bit */
+ /* 1 - 1.5 Stop bits */
+ /* 2 - 2 Stop bits */
+ /* 5 | bParityType | 1 | Number | Parity */
+ /* 0 - None */
+ /* 1 - Odd */
+ /* 2 - Even */
+ /* 3 - Mark */
+ /* 4 - Space */
+ /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
+ /*******************************************************************************/
+ if (usbd_cdc_acm_cfg.uart_first_init_flag == 0) {
+ usbd_cdc_acm_cfg.uart_first_init_flag = 1;
+ return 0;
+ }
+
+ memcpy(&usbd_cdc_acm_cfg.line_coding, *data, sizeof(usbd_cdc_acm_cfg.line_coding));
+ USB_LOG_DBG("CDC_SET_LINE_CODING <%d %d %s %s>\r\n",
+ usbd_cdc_acm_cfg.line_coding.dwDTERate,
+ usbd_cdc_acm_cfg.line_coding.bDataBits,
+ parity_name[usbd_cdc_acm_cfg.line_coding.bParityType],
+ stop_name[usbd_cdc_acm_cfg.line_coding.bCharFormat]);
+ usbd_cdc_acm_set_line_coding(usbd_cdc_acm_cfg.line_coding.dwDTERate, usbd_cdc_acm_cfg.line_coding.bDataBits,
+ usbd_cdc_acm_cfg.line_coding.bParityType, usbd_cdc_acm_cfg.line_coding.bCharFormat);
+ break;
+
+ case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+ usbd_cdc_acm_cfg.line_state = (uint8_t)setup->wValue;
+ bool dtr = (setup->wValue & 0x01);
+ bool rts = (setup->wValue & 0x02);
+ USB_LOG_DBG("DTR 0x%x,RTS 0x%x\r\n",
+ dtr, rts);
+ usbd_cdc_acm_set_dtr(dtr);
+ usbd_cdc_acm_set_rts(rts);
+ break;
+
+ case CDC_REQUEST_GET_LINE_CODING:
+ *data = (uint8_t *)(&usbd_cdc_acm_cfg.line_coding);
+ *len = sizeof(usbd_cdc_acm_cfg.line_coding);
+ USB_LOG_DBG("CDC_GET_LINE_CODING %d %d %d %d\r\n",
+ usbd_cdc_acm_cfg.line_coding.dwDTERate,
+ usbd_cdc_acm_cfg.line_coding.bCharFormat,
+ usbd_cdc_acm_cfg.line_coding.bParityType,
+ usbd_cdc_acm_cfg.line_coding.bDataBits);
+ break;
+
+ default:
+ USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void cdc_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ usbd_cdc_acm_reset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+__WEAK void usbd_cdc_acm_set_line_coding(uint32_t baudrate, uint8_t databits, uint8_t parity, uint8_t stopbits)
+{
+}
+__WEAK void usbd_cdc_acm_set_dtr(bool dtr)
+{
+}
+__WEAK void usbd_cdc_acm_set_rts(bool rts)
+{
+}
+
+void usbd_cdc_add_acm_interface(usbd_class_t *devclass, usbd_interface_t *intf)
+{
+ static usbd_class_t *last_class = NULL;
+
+ if (last_class != devclass) {
+ last_class = devclass;
+ usbd_class_register(devclass);
+ }
+
+ intf->class_handler = cdc_acm_class_request_handler;
+ intf->custom_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = cdc_notify_handler;
+ usbd_class_add_interface(devclass, intf);
+}
diff --git a/class/cdc/usbh_cdc_acm.c b/class/cdc/usbh_cdc_acm.c
index fdc020a3..0b927381 100644
--- a/class/cdc/usbh_cdc_acm.c
+++ b/class/cdc/usbh_cdc_acm.c
@@ -1,336 +1,336 @@
-/**
- * @file usbh_cdc_acm.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbh_core.h"
-#include "usbh_cdc_acm.h"
-
-#define DEV_FORMAT "/dev/ttyACM%d"
-#define DEV_NAMELEN 16
-
-static uint32_t g_devinuse = 0;
-
-void usbh_cdc_acm_callback(void *arg, int nbytes);
-
-/****************************************************************************
- * Name: usbh_cdc_acm_devno_alloc
- *
- * Description:
- * Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
- *
- ****************************************************************************/
-
-static int usbh_cdc_acm_devno_alloc(struct usbh_cdc_acm *priv)
-{
- uint32_t flags;
- int devno;
-
- flags = usb_osal_enter_critical_section();
- for (devno = 0; devno < 32; devno++) {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0) {
- g_devinuse |= bitno;
- priv->minor = devno;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- }
-
- usb_osal_leave_critical_section(flags);
- return -EMFILE;
-}
-
-/****************************************************************************
- * Name: usbh_cdc_acm_devno_free
- *
- * Description:
- * Free a /dev/ttyACM[n] minor number so that it can be used.
- *
- ****************************************************************************/
-
-static void usbh_cdc_acm_devno_free(struct usbh_cdc_acm *priv)
-{
- int devno = priv->minor;
-
- if (devno >= 0 && devno < 32) {
- uint32_t flags = usb_osal_enter_critical_section();
- g_devinuse &= ~(1 << devno);
- usb_osal_leave_critical_section(flags);
- }
-}
-
-/****************************************************************************
- * Name: usbh_cdc_acm_mkdevname
- *
- * Description:
- * Format a /dev/ttyACM[n] device name given a minor number.
- *
- ****************************************************************************/
-
-static inline void usbh_cdc_acm_mkdevname(struct usbh_cdc_acm *priv, char *devname)
-{
- snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
-}
-
-int usbh_cdc_acm_set_line_coding(struct usbh_hubport *hport, uint8_t intf, struct cdc_line_coding *line_coding)
-{
- int ret;
- struct usb_setup_packet *setup;
- struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
-
- setup = cdc_acm_class->setup;
-
- if (cdc_acm_class->ctrl_intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
- setup->wValue = 0;
- setup->wIndex = intf;
- setup->wLength = 7;
-
- ret = usbh_control_transfer(hport->ep0, setup, (uint8_t *)line_coding);
- if (ret < 0) {
- return ret;
- }
- memcpy(cdc_acm_class->linecoding, line_coding, sizeof(struct cdc_line_coding));
- return 0;
-}
-
-int usbh_cdc_acm_get_line_coding(struct usbh_hubport *hport, uint8_t intf, struct cdc_line_coding *line_coding)
-{
- int ret;
- struct usb_setup_packet *setup;
- struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
-
- setup = cdc_acm_class->setup;
-
- if (cdc_acm_class->ctrl_intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
- setup->wValue = 0;
- setup->wIndex = intf;
- setup->wLength = 7;
-
- ret = usbh_control_transfer(hport->ep0, setup, (uint8_t *)line_coding);
- if (ret < 0) {
- return ret;
- }
- memcpy(cdc_acm_class->linecoding, line_coding, sizeof(struct cdc_line_coding));
- return 0;
-}
-
-int usbh_cdc_acm_set_line_state(struct usbh_hubport *hport, uint8_t intf, bool dtr, bool rts)
-{
- int ret;
- struct usb_setup_packet *setup;
- struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
-
- setup = cdc_acm_class->setup;
-
- if (cdc_acm_class->ctrl_intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
- setup->wValue = (dtr << 0) | (rts << 1);
- setup->wIndex = intf;
- setup->wLength = 0;
-
- ret = usbh_control_transfer(hport->ep0, setup, NULL);
- if (ret < 0) {
- return ret;
- }
-
- cdc_acm_class->dtr = dtr;
- cdc_acm_class->rts = rts;
-
- return 0;
-}
-USB_NOCACHE_RAM_SECTION uint8_t cdc_buffer[4096];
-
-int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
-{
- struct usbh_endpoint_cfg ep_cfg = { 0 };
- struct usb_endpoint_descriptor *ep_desc;
- char devname[DEV_NAMELEN];
- int ret;
-
- struct usbh_cdc_acm *cdc_acm_class = usb_malloc(sizeof(struct usbh_cdc_acm));
- if (cdc_acm_class == NULL) {
- USB_LOG_ERR("Fail to alloc cdc_acm_class\r\n");
- return -ENOMEM;
- }
-
- memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
-
- usbh_cdc_acm_devno_alloc(cdc_acm_class);
- usbh_cdc_acm_mkdevname(cdc_acm_class, devname);
-
- hport->config.intf[intf].priv = cdc_acm_class;
- hport->config.intf[intf + 1].priv = cdc_acm_class;
-
- cdc_acm_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
- if (cdc_acm_class->setup == NULL) {
- USB_LOG_ERR("Fail to alloc setup\r\n");
- return -ENOMEM;
- }
- cdc_acm_class->linecoding = usb_iomalloc(sizeof(struct cdc_line_coding));
- if (cdc_acm_class->linecoding == NULL) {
- USB_LOG_ERR("Fail to alloc linecoding\r\n");
- return -ENOMEM;
- }
- cdc_acm_class->ctrl_intf = intf;
- cdc_acm_class->data_intf = intf + 1;
-
- cdc_acm_class->linecoding->dwDTERate = 115200;
- cdc_acm_class->linecoding->bDataBits = 8;
- cdc_acm_class->linecoding->bParityType = 0;
- cdc_acm_class->linecoding->bCharFormat = 0;
- ret = usbh_cdc_acm_set_line_coding(hport, intf, cdc_acm_class->linecoding);
- if (ret < 0) {
- return ret;
- }
-
- ret = usbh_cdc_acm_set_line_state(hport, intf, true, true);
- if (ret < 0) {
- return ret;
- }
-
-#if 0
- ep_desc = &hport->config.intf[intf].ep[0].ep_desc;
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_interval = ep_desc->bInterval;
- ep_cfg.hport = hport;
- usbh_ep_alloc(&cdc_acm_class->intin, &ep_cfg);
-
-#endif
- for (uint8_t i = 0; i < hport->config.intf[intf + 1].intf_desc.bNumEndpoints; i++) {
- ep_desc = &hport->config.intf[intf + 1].ep[i].ep_desc;
-
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_interval = ep_desc->bInterval;
- ep_cfg.hport = hport;
- if (ep_desc->bEndpointAddress & 0x80) {
- usbh_ep_alloc(&cdc_acm_class->bulkin, &ep_cfg);
- } else {
- usbh_ep_alloc(&cdc_acm_class->bulkout, &ep_cfg);
- }
- }
-
- USB_LOG_INFO("Register CDC ACM Class:%s\r\n", devname);
-
- memset(cdc_buffer, 0, 512);
- ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
- if (ret < 0) {
- printf("bulk in error\r\n");
- return ret;
- }
- printf("recv over:%d\r\n", ret);
- for (size_t i = 0; i < ret; i++) {
- printf("0x%02x ", cdc_buffer[i]);
- }
- printf("\r\n");
- const uint8_t data1[10] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x08, 0x14 };
-
- memcpy(cdc_buffer, data1, 8);
- ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkout, cdc_buffer, 8);
- if (ret < 0) {
- printf("bulk out error\r\n");
- return ret;
- }
- printf("send over:%d\r\n", ret);
-
-#if 0
- usbh_ep_bulk_async_transfer(cdc_acm_class->bulkin, cdc_buffer, 512, usbh_cdc_acm_callback, NULL);
-#else
- ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
- if (ret < 0) {
- printf("bulk in error\r\n");
- return ret;
- }
- printf("recv over:%d\r\n", ret);
- for (size_t i = 0; i < ret; i++) {
- printf("0x%02x ", cdc_buffer[i]);
- }
- printf("\r\n");
-#endif
- return ret;
-}
-
-int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
-{
- char devname[DEV_NAMELEN];
- int ret = 0;
-
- struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
-
- if (cdc_acm_class) {
- usbh_cdc_acm_devno_free(cdc_acm_class);
- usbh_cdc_acm_mkdevname(cdc_acm_class, devname);
-
- if (cdc_acm_class->bulkin) {
- ret = usb_ep_cancel(cdc_acm_class->bulkin);
- if (ret < 0) {
- }
- usbh_ep_free(cdc_acm_class->bulkin);
- }
-
- if (cdc_acm_class->bulkout) {
- ret = usb_ep_cancel(cdc_acm_class->bulkout);
- if (ret < 0) {
- }
- usbh_ep_free(cdc_acm_class->bulkout);
- }
- if (cdc_acm_class->setup)
- usb_iofree(cdc_acm_class->setup);
- if (cdc_acm_class->linecoding)
- usb_iofree(cdc_acm_class->linecoding);
-
- usb_free(cdc_acm_class);
-
- hport->config.intf[intf].priv = NULL;
- hport->config.intf[intf + 1].priv = NULL;
-
- USB_LOG_INFO("Unregister CDC ACM Class:%s\r\n", devname);
- }
-
- return ret;
-}
-
-void usbh_cdc_acm_callback(void *arg, int result)
-{
- printf("result:%d\r\n", result);
-}
-
-const struct usbh_class_driver cdc_acm_class_driver = {
- .driver_name = "cdc_acm",
- .connect = usbh_cdc_acm_connect,
- .disconnect = usbh_cdc_acm_disconnect
+/**
+ * @file usbh_cdc_acm.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbh_core.h"
+#include "usbh_cdc_acm.h"
+
+#define DEV_FORMAT "/dev/ttyACM%d"
+#define DEV_NAMELEN 16
+
+static uint32_t g_devinuse = 0;
+
+void usbh_cdc_acm_callback(void *arg, int nbytes);
+
+/****************************************************************************
+ * Name: usbh_cdc_acm_devno_alloc
+ *
+ * Description:
+ * Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
+ *
+ ****************************************************************************/
+
+static int usbh_cdc_acm_devno_alloc(struct usbh_cdc_acm *priv)
+{
+ uint32_t flags;
+ int devno;
+
+ flags = usb_osal_enter_critical_section();
+ for (devno = 0; devno < 32; devno++) {
+ uint32_t bitno = 1 << devno;
+ if ((g_devinuse & bitno) == 0) {
+ g_devinuse |= bitno;
+ priv->minor = devno;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ }
+
+ usb_osal_leave_critical_section(flags);
+ return -EMFILE;
+}
+
+/****************************************************************************
+ * Name: usbh_cdc_acm_devno_free
+ *
+ * Description:
+ * Free a /dev/ttyACM[n] minor number so that it can be used.
+ *
+ ****************************************************************************/
+
+static void usbh_cdc_acm_devno_free(struct usbh_cdc_acm *priv)
+{
+ int devno = priv->minor;
+
+ if (devno >= 0 && devno < 32) {
+ uint32_t flags = usb_osal_enter_critical_section();
+ g_devinuse &= ~(1 << devno);
+ usb_osal_leave_critical_section(flags);
+ }
+}
+
+/****************************************************************************
+ * Name: usbh_cdc_acm_mkdevname
+ *
+ * Description:
+ * Format a /dev/ttyACM[n] device name given a minor number.
+ *
+ ****************************************************************************/
+
+static inline void usbh_cdc_acm_mkdevname(struct usbh_cdc_acm *priv, char *devname)
+{
+ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
+}
+
+int usbh_cdc_acm_set_line_coding(struct usbh_hubport *hport, uint8_t intf, struct cdc_line_coding *line_coding)
+{
+ int ret;
+ struct usb_setup_packet *setup;
+ struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
+
+ setup = cdc_acm_class->setup;
+
+ if (cdc_acm_class->ctrl_intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
+ setup->wValue = 0;
+ setup->wIndex = intf;
+ setup->wLength = 7;
+
+ ret = usbh_control_transfer(hport->ep0, setup, (uint8_t *)line_coding);
+ if (ret < 0) {
+ return ret;
+ }
+ memcpy(cdc_acm_class->linecoding, line_coding, sizeof(struct cdc_line_coding));
+ return 0;
+}
+
+int usbh_cdc_acm_get_line_coding(struct usbh_hubport *hport, uint8_t intf, struct cdc_line_coding *line_coding)
+{
+ int ret;
+ struct usb_setup_packet *setup;
+ struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
+
+ setup = cdc_acm_class->setup;
+
+ if (cdc_acm_class->ctrl_intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
+ setup->wValue = 0;
+ setup->wIndex = intf;
+ setup->wLength = 7;
+
+ ret = usbh_control_transfer(hport->ep0, setup, (uint8_t *)line_coding);
+ if (ret < 0) {
+ return ret;
+ }
+ memcpy(cdc_acm_class->linecoding, line_coding, sizeof(struct cdc_line_coding));
+ return 0;
+}
+
+int usbh_cdc_acm_set_line_state(struct usbh_hubport *hport, uint8_t intf, bool dtr, bool rts)
+{
+ int ret;
+ struct usb_setup_packet *setup;
+ struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
+
+ setup = cdc_acm_class->setup;
+
+ if (cdc_acm_class->ctrl_intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
+ setup->wValue = (dtr << 0) | (rts << 1);
+ setup->wIndex = intf;
+ setup->wLength = 0;
+
+ ret = usbh_control_transfer(hport->ep0, setup, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ cdc_acm_class->dtr = dtr;
+ cdc_acm_class->rts = rts;
+
+ return 0;
+}
+USB_NOCACHE_RAM_SECTION uint8_t cdc_buffer[4096];
+
+int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+ struct usbh_endpoint_cfg ep_cfg = { 0 };
+ struct usb_endpoint_descriptor *ep_desc;
+ char devname[DEV_NAMELEN];
+ int ret;
+
+ struct usbh_cdc_acm *cdc_acm_class = usb_malloc(sizeof(struct usbh_cdc_acm));
+ if (cdc_acm_class == NULL) {
+ USB_LOG_ERR("Fail to alloc cdc_acm_class\r\n");
+ return -ENOMEM;
+ }
+
+ memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
+
+ usbh_cdc_acm_devno_alloc(cdc_acm_class);
+ usbh_cdc_acm_mkdevname(cdc_acm_class, devname);
+
+ hport->config.intf[intf].priv = cdc_acm_class;
+ hport->config.intf[intf + 1].priv = cdc_acm_class;
+
+ cdc_acm_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
+ if (cdc_acm_class->setup == NULL) {
+ USB_LOG_ERR("Fail to alloc setup\r\n");
+ return -ENOMEM;
+ }
+ cdc_acm_class->linecoding = usb_iomalloc(sizeof(struct cdc_line_coding));
+ if (cdc_acm_class->linecoding == NULL) {
+ USB_LOG_ERR("Fail to alloc linecoding\r\n");
+ return -ENOMEM;
+ }
+ cdc_acm_class->ctrl_intf = intf;
+ cdc_acm_class->data_intf = intf + 1;
+
+ cdc_acm_class->linecoding->dwDTERate = 115200;
+ cdc_acm_class->linecoding->bDataBits = 8;
+ cdc_acm_class->linecoding->bParityType = 0;
+ cdc_acm_class->linecoding->bCharFormat = 0;
+ ret = usbh_cdc_acm_set_line_coding(hport, intf, cdc_acm_class->linecoding);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = usbh_cdc_acm_set_line_state(hport, intf, true, true);
+ if (ret < 0) {
+ return ret;
+ }
+
+#if 0
+ ep_desc = &hport->config.intf[intf].ep[0].ep_desc;
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_interval = ep_desc->bInterval;
+ ep_cfg.hport = hport;
+ usbh_ep_alloc(&cdc_acm_class->intin, &ep_cfg);
+
+#endif
+ for (uint8_t i = 0; i < hport->config.intf[intf + 1].intf_desc.bNumEndpoints; i++) {
+ ep_desc = &hport->config.intf[intf + 1].ep[i].ep_desc;
+
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_interval = ep_desc->bInterval;
+ ep_cfg.hport = hport;
+ if (ep_desc->bEndpointAddress & 0x80) {
+ usbh_ep_alloc(&cdc_acm_class->bulkin, &ep_cfg);
+ } else {
+ usbh_ep_alloc(&cdc_acm_class->bulkout, &ep_cfg);
+ }
+ }
+
+ USB_LOG_INFO("Register CDC ACM Class:%s\r\n", devname);
+
+ memset(cdc_buffer, 0, 512);
+ ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
+ if (ret < 0) {
+ printf("bulk in error\r\n");
+ return ret;
+ }
+ printf("recv over:%d\r\n", ret);
+ for (size_t i = 0; i < ret; i++) {
+ printf("0x%02x ", cdc_buffer[i]);
+ }
+ printf("\r\n");
+ const uint8_t data1[10] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x08, 0x14 };
+
+ memcpy(cdc_buffer, data1, 8);
+ ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkout, cdc_buffer, 8);
+ if (ret < 0) {
+ printf("bulk out error\r\n");
+ return ret;
+ }
+ printf("send over:%d\r\n", ret);
+
+#if 0
+ usbh_ep_bulk_async_transfer(cdc_acm_class->bulkin, cdc_buffer, 512, usbh_cdc_acm_callback, NULL);
+#else
+ ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
+ if (ret < 0) {
+ printf("bulk in error\r\n");
+ return ret;
+ }
+ printf("recv over:%d\r\n", ret);
+ for (size_t i = 0; i < ret; i++) {
+ printf("0x%02x ", cdc_buffer[i]);
+ }
+ printf("\r\n");
+#endif
+ return ret;
+}
+
+int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+ char devname[DEV_NAMELEN];
+ int ret = 0;
+
+ struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
+
+ if (cdc_acm_class) {
+ usbh_cdc_acm_devno_free(cdc_acm_class);
+ usbh_cdc_acm_mkdevname(cdc_acm_class, devname);
+
+ if (cdc_acm_class->bulkin) {
+ ret = usb_ep_cancel(cdc_acm_class->bulkin);
+ if (ret < 0) {
+ }
+ usbh_ep_free(cdc_acm_class->bulkin);
+ }
+
+ if (cdc_acm_class->bulkout) {
+ ret = usb_ep_cancel(cdc_acm_class->bulkout);
+ if (ret < 0) {
+ }
+ usbh_ep_free(cdc_acm_class->bulkout);
+ }
+ if (cdc_acm_class->setup)
+ usb_iofree(cdc_acm_class->setup);
+ if (cdc_acm_class->linecoding)
+ usb_iofree(cdc_acm_class->linecoding);
+
+ usb_free(cdc_acm_class);
+
+ hport->config.intf[intf].priv = NULL;
+ hport->config.intf[intf + 1].priv = NULL;
+
+ USB_LOG_INFO("Unregister CDC ACM Class:%s\r\n", devname);
+ }
+
+ return ret;
+}
+
+void usbh_cdc_acm_callback(void *arg, int result)
+{
+ printf("result:%d\r\n", result);
+}
+
+const struct usbh_class_driver cdc_acm_class_driver = {
+ .driver_name = "cdc_acm",
+ .connect = usbh_cdc_acm_connect,
+ .disconnect = usbh_cdc_acm_disconnect
}; \ No newline at end of file
diff --git a/class/cdc/usbh_cdc_acm.h b/class/cdc/usbh_cdc_acm.h
index 0de425e8..e1283504 100644
--- a/class/cdc/usbh_cdc_acm.h
+++ b/class/cdc/usbh_cdc_acm.h
@@ -1,52 +1,52 @@
-/**
- * @file usbh_cdc_acm.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBH_CDC_ACM_H
-#define _USBH_CDC_ACM_H
-
-#include "usb_cdc.h"
-
-struct usbh_cdc_acm {
- struct usb_setup_packet *setup;
- struct cdc_line_coding *linecoding;
- uint8_t ctrl_intf; /* Control interface number */
- uint8_t data_intf; /* Data interface number */
- bool dtr;
- bool rts;
- uint8_t minor;
- usbh_epinfo_t bulkin; /* Bulk IN endpoint */
- usbh_epinfo_t bulkout; /* Bulk OUT endpoint */
-#ifdef HAVE_INTIN_ENDPOINT
- usbh_epinfo_t intin; /* Interrupt IN endpoint (optional) */
-#endif
-};
-
-extern const struct usbh_class_driver cdc_acm_class_driver;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
+/**
+ * @file usbh_cdc_acm.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBH_CDC_ACM_H
+#define _USBH_CDC_ACM_H
+
+#include "usb_cdc.h"
+
+struct usbh_cdc_acm {
+ struct usb_setup_packet *setup;
+ struct cdc_line_coding *linecoding;
+ uint8_t ctrl_intf; /* Control interface number */
+ uint8_t data_intf; /* Data interface number */
+ bool dtr;
+ bool rts;
+ uint8_t minor;
+ usbh_epinfo_t bulkin; /* Bulk IN endpoint */
+ usbh_epinfo_t bulkout; /* Bulk OUT endpoint */
+#ifdef HAVE_INTIN_ENDPOINT
+ usbh_epinfo_t intin; /* Interrupt IN endpoint (optional) */
+#endif
+};
+
+extern const struct usbh_class_driver cdc_acm_class_driver;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
#endif \ No newline at end of file
diff --git a/class/hid/usbd_hid.c b/class/hid/usbd_hid.c
index 52a1b265..7aa0f60d 100644
--- a/class/hid/usbd_hid.c
+++ b/class/hid/usbd_hid.c
@@ -1,286 +1,286 @@
-/**
- * @file usbd_hid.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-#include "usbd_hid.h"
-
-#define HID_STATE_IDLE 0
-#define HID_STATE_BUSY 1
-
-struct usbd_hid_cfg_private {
- const uint8_t *hid_descriptor;
- const uint8_t *hid_report_descriptor;
- uint32_t hid_report_descriptor_len;
- uint8_t current_intf_num;
- uint8_t hid_state;
- uint8_t report;
- uint8_t idle_state;
- uint8_t protocol;
-
- uint8_t (*get_report_callback)(uint8_t report_id, uint8_t report_type);
- void (*set_report_callback)(uint8_t report_id, uint8_t report_type, uint8_t *report, uint8_t report_len);
- uint8_t (*get_idle_callback)(uint8_t report_id);
- void (*set_idle_callback)(uint8_t report_id, uint8_t duration);
- void (*set_protocol_callback)(uint8_t protocol);
- uint8_t (*get_protocol_callback)(void);
-
- usb_slist_t list;
-} usbd_hid_cfg[4];
-
-static usb_slist_t usbd_hid_class_head = USB_SLIST_OBJECT_INIT(usbd_hid_class_head);
-
-static void usbd_hid_reset(void)
-{
- usb_slist_t *i;
- usb_slist_for_each(i, &usbd_hid_class_head)
- {
- struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
- hid_intf->hid_state = HID_STATE_IDLE;
- hid_intf->report = 0;
- hid_intf->idle_state = 0;
- hid_intf->protocol = 0;
- }
-}
-
-int hid_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("HID Custom request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- if (((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_IN) &&
- setup->bRequest == USB_REQUEST_GET_DESCRIPTOR) {
- uint8_t value = (uint8_t)(setup->wValue >> 8);
- uint8_t intf_num = (uint8_t)setup->wIndex;
-
- struct usbd_hid_cfg_private *current_hid_intf = NULL;
- usb_slist_t *i;
- usb_slist_for_each(i, &usbd_hid_class_head)
- {
- struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
-
- if (hid_intf->current_intf_num == intf_num) {
- current_hid_intf = hid_intf;
- break;
- }
- }
-
- if (current_hid_intf == NULL) {
- return -2;
- }
-
- switch (value) {
- case HID_DESCRIPTOR_TYPE_HID:
- USB_LOG_INFO("get HID Descriptor\r\n");
- *data = (uint8_t *)current_hid_intf->hid_descriptor;
- *len = current_hid_intf->hid_descriptor[0];
- break;
-
- case HID_DESCRIPTOR_TYPE_HID_REPORT:
- USB_LOG_INFO("get Report Descriptor\r\n");
- *data = (uint8_t *)current_hid_intf->hid_report_descriptor;
- *len = current_hid_intf->hid_report_descriptor_len;
- break;
-
- case HID_DESCRIPTOR_TYPE_HID_PHYSICAL:
- USB_LOG_INFO("get PHYSICAL Descriptor\r\n");
-
- break;
-
- default:
- return -2;
- }
-
- return 0;
- }
-
- return -1;
-}
-
-int hid_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("HID Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- struct usbd_hid_cfg_private *current_hid_intf = NULL;
- usb_slist_t *i;
- usb_slist_for_each(i, &usbd_hid_class_head)
- {
- struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
- uint8_t intf_num = (uint8_t)setup->wIndex;
- if (hid_intf->current_intf_num == intf_num) {
- current_hid_intf = hid_intf;
- break;
- }
- }
-
- if (current_hid_intf == NULL) {
- return -2;
- }
-
- switch (setup->bRequest) {
- case HID_REQUEST_GET_REPORT:
- if (current_hid_intf->get_report_callback)
- current_hid_intf->report = current_hid_intf->get_report_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wValue)); /*report id ,report type*/
-
- *data = (uint8_t *)&current_hid_intf->report;
- *len = 1;
- break;
- case HID_REQUEST_GET_IDLE:
- if (current_hid_intf->get_idle_callback)
- current_hid_intf->idle_state = current_hid_intf->get_idle_callback(LO_BYTE(setup->wValue));
-
- *data = (uint8_t *)&current_hid_intf->idle_state;
- *len = 1;
- break;
- case HID_REQUEST_GET_PROTOCOL:
- if (current_hid_intf->get_protocol_callback)
- current_hid_intf->protocol = current_hid_intf->get_protocol_callback();
-
- *data = (uint8_t *)&current_hid_intf->protocol;
- *len = 1;
- break;
- case HID_REQUEST_SET_REPORT:
- if (current_hid_intf->set_report_callback)
- current_hid_intf->set_report_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), *data, *len); /*report id ,report type,report,report len*/
-
- current_hid_intf->report = **data;
- break;
- case HID_REQUEST_SET_IDLE:
- if (current_hid_intf->set_idle_callback)
- current_hid_intf->set_idle_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wIndex)); /*report id ,duration*/
-
- current_hid_intf->idle_state = HI_BYTE(setup->wIndex);
- break;
- case HID_REQUEST_SET_PROTOCOL:
- if (current_hid_intf->set_protocol_callback)
- current_hid_intf->set_protocol_callback(LO_BYTE(setup->wValue)); /*protocol*/
-
- current_hid_intf->protocol = LO_BYTE(setup->wValue);
- break;
-
- default:
- USB_LOG_WRN("Unhandled HID Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
-
- return 0;
-}
-
-static void hid_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
- usbd_hid_reset();
- break;
-
- default:
- break;
- }
-}
-
-void usbd_hid_reset_state(void)
-{
- // usbd_hid_cfg.hid_state = HID_STATE_IDLE;
-}
-
-void usbd_hid_send_report(uint8_t ep, uint8_t *data, uint8_t len)
-{
- // if(usbd_hid_cfg.hid_state == HID_STATE_IDLE)
- // {
- // usbd_hid_cfg.hid_state = HID_STATE_BUSY;
- // usbd_ep_write(ep, data, len, NULL);
- // }
-}
-
-void usbd_hid_descriptor_register(uint8_t intf_num, const uint8_t *desc)
-{
- // usbd_hid_cfg.hid_descriptor = desc;
-}
-
-void usbd_hid_report_descriptor_register(uint8_t intf_num, const uint8_t *desc, uint32_t desc_len)
-{
- usb_slist_t *i;
- usb_slist_for_each(i, &usbd_hid_class_head)
- {
- struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
-
- if (hid_intf->current_intf_num == intf_num) {
- hid_intf->hid_report_descriptor = desc;
- hid_intf->hid_report_descriptor_len = desc_len;
- return;
- }
- }
-}
-// clang-format off
-void usbd_hid_set_request_callback( uint8_t intf_num,
- uint8_t (*get_report_callback)(uint8_t report_id, uint8_t report_type),
- void (*set_report_callback)(uint8_t report_id, uint8_t report_type, uint8_t *report, uint8_t report_len),
- uint8_t (*get_idle_callback)(uint8_t report_id),
- void (*set_idle_callback)(uint8_t report_id, uint8_t duration),
- void (*set_protocol_callback)(uint8_t protocol),
- uint8_t (*get_protocol_callback)(void))
-// clang-format on
-{
- usb_slist_t *i;
- usb_slist_for_each(i, &usbd_hid_class_head)
- {
- struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
-
- if (hid_intf->current_intf_num == intf_num) {
- if (get_report_callback)
- hid_intf->get_report_callback = get_report_callback;
- if (set_report_callback)
- hid_intf->set_report_callback = set_report_callback;
- if (get_idle_callback)
- hid_intf->get_idle_callback = get_idle_callback;
- if (set_idle_callback)
- hid_intf->set_idle_callback = set_idle_callback;
- if (set_protocol_callback)
- hid_intf->set_protocol_callback = set_protocol_callback;
- if (get_protocol_callback)
- hid_intf->get_protocol_callback = get_protocol_callback;
- return;
- }
- }
-}
-
-void usbd_hid_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
-{
- static usbd_class_t *last_class = NULL;
- static uint8_t hid_num = 0;
- if (last_class != devclass) {
- last_class = devclass;
- usbd_class_register(devclass);
- }
-
- intf->class_handler = hid_class_request_handler;
- intf->custom_handler = hid_custom_request_handler;
- intf->vendor_handler = NULL;
- intf->notify_handler = hid_notify_handler;
- usbd_class_add_interface(devclass, intf);
-
- usbd_hid_cfg[hid_num].current_intf_num = intf->intf_num;
- usb_slist_add_tail(&usbd_hid_class_head, &usbd_hid_cfg[hid_num].list);
- hid_num++;
-}
+/**
+ * @file usbd_hid.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+#include "usbd_hid.h"
+
+#define HID_STATE_IDLE 0
+#define HID_STATE_BUSY 1
+
+struct usbd_hid_cfg_private {
+ const uint8_t *hid_descriptor;
+ const uint8_t *hid_report_descriptor;
+ uint32_t hid_report_descriptor_len;
+ uint8_t current_intf_num;
+ uint8_t hid_state;
+ uint8_t report;
+ uint8_t idle_state;
+ uint8_t protocol;
+
+ uint8_t (*get_report_callback)(uint8_t report_id, uint8_t report_type);
+ void (*set_report_callback)(uint8_t report_id, uint8_t report_type, uint8_t *report, uint8_t report_len);
+ uint8_t (*get_idle_callback)(uint8_t report_id);
+ void (*set_idle_callback)(uint8_t report_id, uint8_t duration);
+ void (*set_protocol_callback)(uint8_t protocol);
+ uint8_t (*get_protocol_callback)(void);
+
+ usb_slist_t list;
+} usbd_hid_cfg[4];
+
+static usb_slist_t usbd_hid_class_head = USB_SLIST_OBJECT_INIT(usbd_hid_class_head);
+
+static void usbd_hid_reset(void)
+{
+ usb_slist_t *i;
+ usb_slist_for_each(i, &usbd_hid_class_head)
+ {
+ struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
+ hid_intf->hid_state = HID_STATE_IDLE;
+ hid_intf->report = 0;
+ hid_intf->idle_state = 0;
+ hid_intf->protocol = 0;
+ }
+}
+
+int hid_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("HID Custom request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ if (((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_IN) &&
+ setup->bRequest == USB_REQUEST_GET_DESCRIPTOR) {
+ uint8_t value = (uint8_t)(setup->wValue >> 8);
+ uint8_t intf_num = (uint8_t)setup->wIndex;
+
+ struct usbd_hid_cfg_private *current_hid_intf = NULL;
+ usb_slist_t *i;
+ usb_slist_for_each(i, &usbd_hid_class_head)
+ {
+ struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
+
+ if (hid_intf->current_intf_num == intf_num) {
+ current_hid_intf = hid_intf;
+ break;
+ }
+ }
+
+ if (current_hid_intf == NULL) {
+ return -2;
+ }
+
+ switch (value) {
+ case HID_DESCRIPTOR_TYPE_HID:
+ USB_LOG_INFO("get HID Descriptor\r\n");
+ *data = (uint8_t *)current_hid_intf->hid_descriptor;
+ *len = current_hid_intf->hid_descriptor[0];
+ break;
+
+ case HID_DESCRIPTOR_TYPE_HID_REPORT:
+ USB_LOG_INFO("get Report Descriptor\r\n");
+ *data = (uint8_t *)current_hid_intf->hid_report_descriptor;
+ *len = current_hid_intf->hid_report_descriptor_len;
+ break;
+
+ case HID_DESCRIPTOR_TYPE_HID_PHYSICAL:
+ USB_LOG_INFO("get PHYSICAL Descriptor\r\n");
+
+ break;
+
+ default:
+ return -2;
+ }
+
+ return 0;
+ }
+
+ return -1;
+}
+
+int hid_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("HID Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ struct usbd_hid_cfg_private *current_hid_intf = NULL;
+ usb_slist_t *i;
+ usb_slist_for_each(i, &usbd_hid_class_head)
+ {
+ struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
+ uint8_t intf_num = (uint8_t)setup->wIndex;
+ if (hid_intf->current_intf_num == intf_num) {
+ current_hid_intf = hid_intf;
+ break;
+ }
+ }
+
+ if (current_hid_intf == NULL) {
+ return -2;
+ }
+
+ switch (setup->bRequest) {
+ case HID_REQUEST_GET_REPORT:
+ if (current_hid_intf->get_report_callback)
+ current_hid_intf->report = current_hid_intf->get_report_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wValue)); /*report id ,report type*/
+
+ *data = (uint8_t *)&current_hid_intf->report;
+ *len = 1;
+ break;
+ case HID_REQUEST_GET_IDLE:
+ if (current_hid_intf->get_idle_callback)
+ current_hid_intf->idle_state = current_hid_intf->get_idle_callback(LO_BYTE(setup->wValue));
+
+ *data = (uint8_t *)&current_hid_intf->idle_state;
+ *len = 1;
+ break;
+ case HID_REQUEST_GET_PROTOCOL:
+ if (current_hid_intf->get_protocol_callback)
+ current_hid_intf->protocol = current_hid_intf->get_protocol_callback();
+
+ *data = (uint8_t *)&current_hid_intf->protocol;
+ *len = 1;
+ break;
+ case HID_REQUEST_SET_REPORT:
+ if (current_hid_intf->set_report_callback)
+ current_hid_intf->set_report_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), *data, *len); /*report id ,report type,report,report len*/
+
+ current_hid_intf->report = **data;
+ break;
+ case HID_REQUEST_SET_IDLE:
+ if (current_hid_intf->set_idle_callback)
+ current_hid_intf->set_idle_callback(LO_BYTE(setup->wValue), HI_BYTE(setup->wIndex)); /*report id ,duration*/
+
+ current_hid_intf->idle_state = HI_BYTE(setup->wIndex);
+ break;
+ case HID_REQUEST_SET_PROTOCOL:
+ if (current_hid_intf->set_protocol_callback)
+ current_hid_intf->set_protocol_callback(LO_BYTE(setup->wValue)); /*protocol*/
+
+ current_hid_intf->protocol = LO_BYTE(setup->wValue);
+ break;
+
+ default:
+ USB_LOG_WRN("Unhandled HID Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void hid_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ usbd_hid_reset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void usbd_hid_reset_state(void)
+{
+ // usbd_hid_cfg.hid_state = HID_STATE_IDLE;
+}
+
+void usbd_hid_send_report(uint8_t ep, uint8_t *data, uint8_t len)
+{
+ // if(usbd_hid_cfg.hid_state == HID_STATE_IDLE)
+ // {
+ // usbd_hid_cfg.hid_state = HID_STATE_BUSY;
+ // usbd_ep_write(ep, data, len, NULL);
+ // }
+}
+
+void usbd_hid_descriptor_register(uint8_t intf_num, const uint8_t *desc)
+{
+ // usbd_hid_cfg.hid_descriptor = desc;
+}
+
+void usbd_hid_report_descriptor_register(uint8_t intf_num, const uint8_t *desc, uint32_t desc_len)
+{
+ usb_slist_t *i;
+ usb_slist_for_each(i, &usbd_hid_class_head)
+ {
+ struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
+
+ if (hid_intf->current_intf_num == intf_num) {
+ hid_intf->hid_report_descriptor = desc;
+ hid_intf->hid_report_descriptor_len = desc_len;
+ return;
+ }
+ }
+}
+// clang-format off
+void usbd_hid_set_request_callback( uint8_t intf_num,
+ uint8_t (*get_report_callback)(uint8_t report_id, uint8_t report_type),
+ void (*set_report_callback)(uint8_t report_id, uint8_t report_type, uint8_t *report, uint8_t report_len),
+ uint8_t (*get_idle_callback)(uint8_t report_id),
+ void (*set_idle_callback)(uint8_t report_id, uint8_t duration),
+ void (*set_protocol_callback)(uint8_t protocol),
+ uint8_t (*get_protocol_callback)(void))
+// clang-format on
+{
+ usb_slist_t *i;
+ usb_slist_for_each(i, &usbd_hid_class_head)
+ {
+ struct usbd_hid_cfg_private *hid_intf = usb_slist_entry(i, struct usbd_hid_cfg_private, list);
+
+ if (hid_intf->current_intf_num == intf_num) {
+ if (get_report_callback)
+ hid_intf->get_report_callback = get_report_callback;
+ if (set_report_callback)
+ hid_intf->set_report_callback = set_report_callback;
+ if (get_idle_callback)
+ hid_intf->get_idle_callback = get_idle_callback;
+ if (set_idle_callback)
+ hid_intf->set_idle_callback = set_idle_callback;
+ if (set_protocol_callback)
+ hid_intf->set_protocol_callback = set_protocol_callback;
+ if (get_protocol_callback)
+ hid_intf->get_protocol_callback = get_protocol_callback;
+ return;
+ }
+ }
+}
+
+void usbd_hid_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
+{
+ static usbd_class_t *last_class = NULL;
+ static uint8_t hid_num = 0;
+ if (last_class != devclass) {
+ last_class = devclass;
+ usbd_class_register(devclass);
+ }
+
+ intf->class_handler = hid_class_request_handler;
+ intf->custom_handler = hid_custom_request_handler;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = hid_notify_handler;
+ usbd_class_add_interface(devclass, intf);
+
+ usbd_hid_cfg[hid_num].current_intf_num = intf->intf_num;
+ usb_slist_add_tail(&usbd_hid_class_head, &usbd_hid_cfg[hid_num].list);
+ hid_num++;
+}
diff --git a/class/hid/usbh_hid.c b/class/hid/usbh_hid.c
index 0a240318..5c6e4fc9 100644
--- a/class/hid/usbh_hid.c
+++ b/class/hid/usbh_hid.c
@@ -1,275 +1,275 @@
-/**
- * @file usbh_hid.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbh_core.h"
-#include "usbh_hid.h"
-
-#define DEV_FORMAT "/dev/input%d"
-#define DEV_NAMELEN 16
-
-static uint32_t g_devinuse = 0;
-
-/****************************************************************************
- * Name: usbh_hid_devno_alloc
- *
- * Description:
- * Allocate a unique /dev/hid[n] minor number in the range 0-31.
- *
- ****************************************************************************/
-
-static int usbh_hid_devno_alloc(struct usbh_hid *priv)
-{
- uint32_t flags;
- int devno;
-
- flags = usb_osal_enter_critical_section();
- for (devno = 0; devno < 32; devno++) {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0) {
- g_devinuse |= bitno;
- priv->minor = devno;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- }
-
- usb_osal_leave_critical_section(flags);
- return -EMFILE;
-}
-
-/****************************************************************************
- * Name: usbh_hid_devno_free
- *
- * Description:
- * Free a /dev/hid[n] minor number so that it can be used.
- *
- ****************************************************************************/
-
-static void usbh_hid_devno_free(struct usbh_hid *priv)
-{
- int devno = priv->minor;
-
- if (devno >= 0 && devno < 32) {
- uint32_t flags = usb_osal_enter_critical_section();
- g_devinuse &= ~(1 << devno);
- usb_osal_leave_critical_section(flags);
- }
-}
-
-/****************************************************************************
- * Name: usbh_hid_mkdevname
- *
- * Description:
- * Format a /dev/hid[n] device name given a minor number.
- *
- ****************************************************************************/
-
-static inline void usbh_hid_mkdevname(struct usbh_hid *priv, char *devname)
-{
- snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
-}
-
-int usbh_hid_get_report_descriptor(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
-{
- struct usb_setup_packet *setup;
- struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
-
- setup = hid_class->setup;
-
- if (hid_class->intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
- setup->wIndex = intf;
- setup->wLength = 128;
-
- return usbh_control_transfer(hport->ep0, setup, buffer);
-}
-
-int usbh_hid_set_idle(struct usbh_hubport *hport, uint8_t intf, uint8_t report_id, uint8_t duration)
-{
- int ret;
- struct usb_setup_packet *setup;
- struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
-
- setup = hid_class->setup;
-
- if (hid_class->intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = HID_REQUEST_SET_IDLE;
- setup->wValue = report_id;
- setup->wIndex = (duration << 8) | intf;
- setup->wLength = 0;
-
- ret = usbh_control_transfer(hport->ep0, setup, NULL);
- if (ret < 0) {
- return ret;
- }
-
- return 0;
-}
-
-int usbh_hid_get_idle(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
-{
- int ret;
- struct usb_setup_packet *setup;
- struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
-
- setup = hid_class->setup;
-
- if (hid_class->intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = HID_REQUEST_GET_IDLE;
- setup->wValue = 0;
- setup->wIndex = intf;
- setup->wLength = 1;
-
- ret = usbh_control_transfer(hport->ep0, setup, buffer);
- if (ret < 0) {
- return ret;
- }
-
- return 0;
-}
-
-USB_NOCACHE_RAM_SECTION uint8_t report_buffer[128];
-
-void usbh_hid_callback(void *arg, int nbytes)
-{
- printf("nbytes:%d\r\n", nbytes);
-}
-
-int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
-{
- struct usbh_endpoint_cfg ep_cfg = { 0 };
- struct usb_endpoint_descriptor *ep_desc;
- char devname[DEV_NAMELEN];
- int ret;
-
- struct usbh_hid *hid_class = usb_malloc(sizeof(struct usbh_hid));
- if (hid_class == NULL) {
- USB_LOG_ERR("Fail to alloc hid_class\r\n");
- return -ENOMEM;
- }
- memset(hid_class, 0, sizeof(struct usbh_hid));
-
- usbh_hid_devno_alloc(hid_class);
- usbh_hid_mkdevname(hid_class, devname);
-
- hport->config.intf[intf].priv = hid_class;
-
- hid_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
- if (hid_class->setup == NULL) {
- USB_LOG_ERR("Fail to alloc setup\r\n");
- return -ENOMEM;
- }
- hid_class->intf = intf;
-
- ret = usbh_hid_set_idle(hport, intf, 0, 0);
- if (ret < 0) {
- return ret;
- }
-
- ret = usbh_hid_get_report_descriptor(hport, intf, report_buffer);
- if (ret < 0) {
- return ret;
- }
-
- for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
- ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_interval = ep_desc->bInterval;
- ep_cfg.hport = hport;
- if (ep_desc->bEndpointAddress & 0x80) {
- usbh_ep_alloc(&hid_class->intin, &ep_cfg);
- } else {
- usbh_ep_alloc(&hid_class->intout, &ep_cfg);
- }
- }
-
- USB_LOG_INFO("Register HID Class:%s\r\n", devname);
-
- ret = usbh_ep_intr_async_transfer(hid_class->intin, report_buffer, 128, usbh_hid_callback, NULL);
- if (ret < 0) {
- return ret;
- }
-#if 0
- ret = usbh_ep_intr_transfer(hid_class->intin, report_buffer, 128);
- if (ret < 0) {
- return ret;
- }
- USB_LOG_INFO("recv len:%d\r\n", ret);
-#endif
- return 0;
-}
-
-int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
-{
- char devname[DEV_NAMELEN];
- int ret = 0;
-
- struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
-
- if (hid_class) {
- usbh_hid_devno_free(hid_class);
- usbh_hid_mkdevname(hid_class, devname);
-
- if (hid_class->intin) {
- ret = usb_ep_cancel(hid_class->intin);
- if (ret < 0) {
- }
- usbh_ep_free(hid_class->intin);
- }
-
- if (hid_class->intout) {
- ret = usb_ep_cancel(hid_class->intout);
- if (ret < 0) {
- }
- usbh_ep_free(hid_class->intout);
- }
- if (hid_class->setup)
- usb_iofree(hid_class->setup);
-
- usb_free(hid_class);
- hport->config.intf[intf].priv = NULL;
-
- USB_LOG_INFO("Unregister HID Class:%s\r\n", devname);
- }
-
- return ret;
-}
-
-const struct usbh_class_driver hid_class_driver = {
- .driver_name = "hid",
- .connect = usbh_hid_connect,
- .disconnect = usbh_hid_disconnect
+/**
+ * @file usbh_hid.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbh_core.h"
+#include "usbh_hid.h"
+
+#define DEV_FORMAT "/dev/input%d"
+#define DEV_NAMELEN 16
+
+static uint32_t g_devinuse = 0;
+
+/****************************************************************************
+ * Name: usbh_hid_devno_alloc
+ *
+ * Description:
+ * Allocate a unique /dev/hid[n] minor number in the range 0-31.
+ *
+ ****************************************************************************/
+
+static int usbh_hid_devno_alloc(struct usbh_hid *priv)
+{
+ uint32_t flags;
+ int devno;
+
+ flags = usb_osal_enter_critical_section();
+ for (devno = 0; devno < 32; devno++) {
+ uint32_t bitno = 1 << devno;
+ if ((g_devinuse & bitno) == 0) {
+ g_devinuse |= bitno;
+ priv->minor = devno;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ }
+
+ usb_osal_leave_critical_section(flags);
+ return -EMFILE;
+}
+
+/****************************************************************************
+ * Name: usbh_hid_devno_free
+ *
+ * Description:
+ * Free a /dev/hid[n] minor number so that it can be used.
+ *
+ ****************************************************************************/
+
+static void usbh_hid_devno_free(struct usbh_hid *priv)
+{
+ int devno = priv->minor;
+
+ if (devno >= 0 && devno < 32) {
+ uint32_t flags = usb_osal_enter_critical_section();
+ g_devinuse &= ~(1 << devno);
+ usb_osal_leave_critical_section(flags);
+ }
+}
+
+/****************************************************************************
+ * Name: usbh_hid_mkdevname
+ *
+ * Description:
+ * Format a /dev/hid[n] device name given a minor number.
+ *
+ ****************************************************************************/
+
+static inline void usbh_hid_mkdevname(struct usbh_hid *priv, char *devname)
+{
+ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
+}
+
+int usbh_hid_get_report_descriptor(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
+{
+ struct usb_setup_packet *setup;
+ struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
+
+ setup = hid_class->setup;
+
+ if (hid_class->intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
+ setup->wIndex = intf;
+ setup->wLength = 128;
+
+ return usbh_control_transfer(hport->ep0, setup, buffer);
+}
+
+int usbh_hid_set_idle(struct usbh_hubport *hport, uint8_t intf, uint8_t report_id, uint8_t duration)
+{
+ int ret;
+ struct usb_setup_packet *setup;
+ struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
+
+ setup = hid_class->setup;
+
+ if (hid_class->intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = HID_REQUEST_SET_IDLE;
+ setup->wValue = report_id;
+ setup->wIndex = (duration << 8) | intf;
+ setup->wLength = 0;
+
+ ret = usbh_control_transfer(hport->ep0, setup, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+int usbh_hid_get_idle(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
+{
+ int ret;
+ struct usb_setup_packet *setup;
+ struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
+
+ setup = hid_class->setup;
+
+ if (hid_class->intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = HID_REQUEST_GET_IDLE;
+ setup->wValue = 0;
+ setup->wIndex = intf;
+ setup->wLength = 1;
+
+ ret = usbh_control_transfer(hport->ep0, setup, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+USB_NOCACHE_RAM_SECTION uint8_t report_buffer[128];
+
+void usbh_hid_callback(void *arg, int nbytes)
+{
+ printf("nbytes:%d\r\n", nbytes);
+}
+
+int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+ struct usbh_endpoint_cfg ep_cfg = { 0 };
+ struct usb_endpoint_descriptor *ep_desc;
+ char devname[DEV_NAMELEN];
+ int ret;
+
+ struct usbh_hid *hid_class = usb_malloc(sizeof(struct usbh_hid));
+ if (hid_class == NULL) {
+ USB_LOG_ERR("Fail to alloc hid_class\r\n");
+ return -ENOMEM;
+ }
+ memset(hid_class, 0, sizeof(struct usbh_hid));
+
+ usbh_hid_devno_alloc(hid_class);
+ usbh_hid_mkdevname(hid_class, devname);
+
+ hport->config.intf[intf].priv = hid_class;
+
+ hid_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
+ if (hid_class->setup == NULL) {
+ USB_LOG_ERR("Fail to alloc setup\r\n");
+ return -ENOMEM;
+ }
+ hid_class->intf = intf;
+
+ ret = usbh_hid_set_idle(hport, intf, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = usbh_hid_get_report_descriptor(hport, intf, report_buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
+ ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_interval = ep_desc->bInterval;
+ ep_cfg.hport = hport;
+ if (ep_desc->bEndpointAddress & 0x80) {
+ usbh_ep_alloc(&hid_class->intin, &ep_cfg);
+ } else {
+ usbh_ep_alloc(&hid_class->intout, &ep_cfg);
+ }
+ }
+
+ USB_LOG_INFO("Register HID Class:%s\r\n", devname);
+
+ ret = usbh_ep_intr_async_transfer(hid_class->intin, report_buffer, 128, usbh_hid_callback, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+#if 0
+ ret = usbh_ep_intr_transfer(hid_class->intin, report_buffer, 128);
+ if (ret < 0) {
+ return ret;
+ }
+ USB_LOG_INFO("recv len:%d\r\n", ret);
+#endif
+ return 0;
+}
+
+int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+ char devname[DEV_NAMELEN];
+ int ret = 0;
+
+ struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
+
+ if (hid_class) {
+ usbh_hid_devno_free(hid_class);
+ usbh_hid_mkdevname(hid_class, devname);
+
+ if (hid_class->intin) {
+ ret = usb_ep_cancel(hid_class->intin);
+ if (ret < 0) {
+ }
+ usbh_ep_free(hid_class->intin);
+ }
+
+ if (hid_class->intout) {
+ ret = usb_ep_cancel(hid_class->intout);
+ if (ret < 0) {
+ }
+ usbh_ep_free(hid_class->intout);
+ }
+ if (hid_class->setup)
+ usb_iofree(hid_class->setup);
+
+ usb_free(hid_class);
+ hport->config.intf[intf].priv = NULL;
+
+ USB_LOG_INFO("Unregister HID Class:%s\r\n", devname);
+ }
+
+ return ret;
+}
+
+const struct usbh_class_driver hid_class_driver = {
+ .driver_name = "hid",
+ .connect = usbh_hid_connect,
+ .disconnect = usbh_hid_disconnect
}; \ No newline at end of file
diff --git a/class/hid/usbh_hid.h b/class/hid/usbh_hid.h
index 7d01f100..a22c0653 100644
--- a/class/hid/usbh_hid.h
+++ b/class/hid/usbh_hid.h
@@ -1,45 +1,45 @@
-/**
- * @file usbh_hid.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBH_HID_H
-#define _USBH_HID_H
-
-#include "usb_hid.h"
-
-struct usbh_hid {
- struct usb_setup_packet *setup;
- uint8_t intf; /* interface number */
- uint8_t minor;
- usbh_epinfo_t intin; /* INTR IN endpoint */
- usbh_epinfo_t intout; /* INTR OUT endpoint */
-};
-
-extern const struct usbh_class_driver hid_class_driver;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
+/**
+ * @file usbh_hid.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBH_HID_H
+#define _USBH_HID_H
+
+#include "usb_hid.h"
+
+struct usbh_hid {
+ struct usb_setup_packet *setup;
+ uint8_t intf; /* interface number */
+ uint8_t minor;
+ usbh_epinfo_t intin; /* INTR IN endpoint */
+ usbh_epinfo_t intout; /* INTR OUT endpoint */
+};
+
+extern const struct usbh_class_driver hid_class_driver;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
#endif \ No newline at end of file
diff --git a/class/hub/usbh_hub.c b/class/hub/usbh_hub.c
index 5b010c58..8eb875d9 100644
--- a/class/hub/usbh_hub.c
+++ b/class/hub/usbh_hub.c
@@ -1,497 +1,497 @@
-/**
- * @file usbh_hub.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbh_core.h"
-#include "usbh_hub.h"
-
-#define DEV_FORMAT "/dev/hub%d"
-#define DEV_NAMELEN 16
-
-static uint32_t g_devinuse = 0;
-
-usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
-
-USB_NOCACHE_RAM_SECTION uint8_t int_buffer[6][USBH_HUB_INTIN_BUFSIZE];
-extern void usbh_external_hport_connect(struct usbh_hubport *hport);
-extern void usbh_external_hport_disconnect(struct usbh_hubport *hport);
-extern void usbh_hport_activate(struct usbh_hubport *hport);
-extern void usbh_hport_deactivate(struct usbh_hubport *hport);
-
-static void usbh_external_hub_callback(void *arg, int nbytes);
-
-static inline void usbh_hub_register(struct usbh_hub *hub)
-{
- usb_slist_add_tail(&hub_class_head, &hub->list);
-}
-
-static inline void usbh_hub_unregister(struct usbh_hub *hub)
-{
- usb_slist_remove(&hub_class_head, &hub->list);
-}
-
-/****************************************************************************
- * Name: usbh_hub_devno_alloc
- *
- * Description:
- * Allocate a unique /dev/hub[n] minor number in the range 2-31.
- *
- ****************************************************************************/
-
-static int usbh_hub_devno_alloc(struct usbh_hub *hub)
-{
- uint32_t flags;
- int devno;
-
- flags = usb_osal_enter_critical_section();
- for (devno = 2; devno < 32; devno++) {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0) {
- g_devinuse |= bitno;
- hub->index = devno;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- }
-
- usb_osal_leave_critical_section(flags);
- return -EMFILE;
-}
-
-/****************************************************************************
- * Name: usbh_hub_devno_free
- *
- * Description:
- * Free a /dev/hub[n] minor number so that it can be used.
- *
- ****************************************************************************/
-
-static void usbh_hub_devno_free(struct usbh_hub *hub)
-{
- int devno = hub->index;
-
- if (devno >= 2 && devno < 32) {
- uint32_t flags = usb_osal_enter_critical_section();
- g_devinuse &= ~(1 << devno);
- usb_osal_leave_critical_section(flags);
- }
-}
-
-/****************************************************************************
- * Name: usbh_hub_mkdevname
- *
- * Description:
- * Format a /dev/hub[n] device name given a minor number.
- *
- ****************************************************************************/
-
-static inline void usbh_hub_mkdevname(struct usbh_hub *hub, char *devname)
-{
- snprintf(devname, DEV_NAMELEN, DEV_FORMAT, hub->index);
-}
-
-int usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
-{
- struct usb_setup_packet *setup;
-
- setup = hub->setup;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
- setup->wIndex = 0;
- setup->wLength = USB_SIZEOF_HUB_DESC;
-
- return usbh_control_transfer(hub->parent->ep0, setup, buffer);
-}
-
-int usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
-{
- struct usb_setup_packet *setup;
-
- setup = hub->setup;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = HUB_REQUEST_GET_STATUS;
- setup->wValue = 0;
- setup->wIndex = 0;
- setup->wLength = 2;
-
- return usbh_control_transfer(hub->parent->ep0, setup, buffer);
-}
-
-int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
-{
- struct usb_setup_packet *setup;
-
- setup = hub->setup;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_GET_STATUS;
- setup->wValue = 0;
- setup->wIndex = port;
- setup->wLength = 4;
-
- return usbh_control_transfer(hub->parent->ep0, setup, (uint8_t *)port_status);
-}
-
-int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
-{
- struct usb_setup_packet *setup;
-
- setup = hub->setup;
-
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_SET_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
-
- return usbh_control_transfer(hub->parent->ep0, setup, NULL);
-}
-
-int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
-{
- struct usb_setup_packet *setup;
-
- setup = hub->setup;
-
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
-
- return usbh_control_transfer(hub->parent->ep0, setup, NULL);
-}
-
-static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
-{
- if (desc->bLength != USB_SIZEOF_HUB_DESC) {
- USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
- return -1;
- } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -2;
- } else {
- USB_LOG_INFO("Device Descriptor:\r\n");
- USB_LOG_INFO("bLength: 0x%02x \r\n", desc->bLength);
- USB_LOG_INFO("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
- USB_LOG_INFO("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
- USB_LOG_INFO("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
- USB_LOG_INFO("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
- USB_LOG_INFO("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
- USB_LOG_INFO("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
- USB_LOG_INFO("PortPwrCtrlMask: 0x%02x \r\n", desc->PortPwrCtrlMask);
- }
- return 0;
-}
-
-int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
-{
- struct usbh_endpoint_cfg ep_cfg = { 0 };
- struct usb_endpoint_descriptor *ep_desc;
- char devname[DEV_NAMELEN];
- int ret;
- uint8_t *hub_desc_buffer;
- struct usbh_hub *hub_class;
-
- hub_class = usb_malloc(sizeof(struct usbh_hub));
- if (hub_class == NULL) {
- USB_LOG_ERR("Fail to alloc hub_class\r\n");
- return -ENOMEM;
- }
- memset(hub_class, 0, sizeof(struct usbh_hub));
- hub_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
- if (hub_class->setup == NULL) {
- USB_LOG_ERR("Fail to alloc setup\r\n");
- return -ENOMEM;
- }
- hub_class->port_status = usb_iomalloc(sizeof(struct hub_port_status));
- if (hub_class->port_status == NULL) {
- USB_LOG_ERR("Fail to alloc port_status\r\n");
- return -ENOMEM;
- }
-
- hub_desc_buffer = usb_iomalloc(32);
-
- usbh_hub_devno_alloc(hub_class);
- usbh_hub_mkdevname(hub_class, devname);
-
- hub_class->dev_addr = hport->dev_addr;
- hub_class->parent = hport;
- hport->config.intf[0].priv = hub_class;
-
- ret = usbh_hub_get_hub_descriptor(hub_class, hub_desc_buffer);
- if (ret != 0) {
- usb_iofree(hub_desc_buffer);
- return ret;
- }
-
- parse_hub_descriptor((struct usb_hub_descriptor *)hub_desc_buffer, USB_SIZEOF_HUB_DESC);
- memcpy(&hub_class->hub_desc, hub_desc_buffer, USB_SIZEOF_HUB_DESC);
- usb_iofree(hub_desc_buffer);
-
- hub_class->nports = hub_class->hub_desc.bNbrPorts;
-
- for (uint8_t port = 1; port <= hub_class->nports; port++) {
- hub_class->child[port - 1].port = port;
- hub_class->child[port - 1].parent = hub_class;
- }
-
- hub_class->int_buffer = int_buffer[hub_class->index - 2];
- usbh_hub_register(hub_class);
-
- ep_desc = &hport->config.intf[intf].ep[0].ep_desc;
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_interval = ep_desc->bInterval;
- ep_cfg.hport = hport;
- if (ep_desc->bEndpointAddress & 0x80) {
- usbh_ep_alloc(&hub_class->intin, &ep_cfg);
- } else {
- return -1;
- }
-
- for (uint8_t port = 1; port <= hub_class->nports; port++) {
- ret = usbh_hub_set_feature(hub_class, 1, HUB_PORT_FEATURE_POWER);
- if (ret < 0) {
- return ret;
- }
- }
-
- for (uint8_t port = 1; port <= hub_class->nports; port++) {
- ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
- USB_LOG_INFO("Port:%d, status:0x%02x, change:0x%02x\r\n", port, hub_class->port_status->wPortStatus, hub_class->port_status->wPortChange);
- if (ret < 0) {
- return ret;
- }
- }
-
- USB_LOG_INFO("Register HUB Class:%s\r\n", devname);
-
- ret = usbh_ep_intr_async_transfer(hub_class->intin, hub_class->int_buffer, USBH_HUB_INTIN_BUFSIZE, usbh_external_hub_callback, hub_class);
- return 0;
-}
-
-int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
-{
- struct usbh_hubport *child;
- char devname[DEV_NAMELEN];
- int ret = 0;
-
- struct usbh_hub *hub_class = (struct usbh_hub *)hport->config.intf[intf].priv;
-
- if (hub_class) {
- usbh_hub_devno_free(hub_class);
- usbh_hub_mkdevname(hub_class, devname);
-
- if (hub_class->intin) {
- ret = usb_ep_cancel(hub_class->intin);
- if (ret < 0) {
- }
- usbh_ep_free(hub_class->intin);
- }
-
- if (hub_class->setup)
- usb_iofree(hub_class->setup);
- if (hub_class->port_status)
- usb_iofree(hub_class->port_status);
-
- for (uint8_t port = 1; port <= hub_class->nports; port++) {
- child = &hub_class->child[port - 1];
- usbh_hport_deactivate(child);
- for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
- if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
- ret = CLASS_DISCONNECT(child, i);
- }
- }
-
- child->config.config_desc.bNumInterfaces = 0;
- child->parent = NULL;
- }
-
- usbh_hub_unregister(hub_class);
- usb_free(hub_class);
- hport->config.intf[intf].priv = NULL;
-
- USB_LOG_INFO("Unregister HUB Class:%s\r\n", devname);
- }
- return ret;
-}
-
-static void usbh_extern_hub_psc_event(void *arg)
-{
- struct usbh_hub *hub_class;
- struct usbh_hubport *connport;
- uint8_t port_change;
- uint16_t status;
- uint16_t change;
- uint16_t mask;
- uint16_t feat;
- uint32_t flags;
- int ret;
-
- hub_class = (struct usbh_hub *)arg;
-
- /* Has the hub been disconnected? */
- if (!hub_class->parent->connected) {
- return;
- }
-
- port_change = hub_class->int_buffer[0];
- USB_LOG_DBG("port_change:0x%02x\r\n", port_change);
-
- /* Check for status change on any port */
- for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
- /* Check if port status has changed */
- if ((port_change & (1 << port)) == 0) {
- continue;
- }
- USB_LOG_DBG("Port %d change\r\n", port);
-
- /* Port status changed, check what happened */
- port_change &= ~(1 << port);
-
- /* Read hub port status */
- ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
- continue;
- }
- status = hub_class->port_status->wPortStatus;
- change = hub_class->port_status->wPortChange;
-
- USB_LOG_DBG("Port:%d, status:0x%02x, change:0x%02x\r\n", port, status, change);
-
- /* First, clear all change bits */
- mask = 1;
- feat = HUB_PORT_FEATURE_C_CONNECTION;
- while (change) {
- if (change & mask) {
- ret = usbh_hub_clear_feature(hub_class, port, feat);
- if (ret < 0) {
- USB_LOG_ERR("Failed to clear port:%d, change mask:%04x, errorcode:%d\r\n", port, mask, ret);
- }
- change &= (~mask);
- }
- mask <<= 1;
- feat++;
- }
-
- change = hub_class->port_status->wPortChange;
-
- /* Handle connect or disconnect, no power management */
- if (change & HUB_PORT_STATUS_C_CONNECTION) {
- ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
- }
- status = hub_class->port_status->wPortStatus;
- change = hub_class->port_status->wPortChange;
-
- if (status & HUB_PORT_STATUS_CONNECTION) {
- /* Device connected to a port on the hub */
- //USB_LOG_INFO("Connection on port:%d\n", port);
-
- ret = usbh_hub_set_feature(hub_class, port, HUB_PORT_FEATURE_RESET);
- if (ret < 0) {
- USB_LOG_ERR("Failed to reset port:%d,errorcode:%d\r\n", port, ret);
- continue;
- }
-
- usb_osal_msleep(100);
-
- ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
- continue;
- }
- status = hub_class->port_status->wPortStatus;
- change = hub_class->port_status->wPortChange;
-
- USB_LOG_DBG("Port:%d, status:0x%02x, change:0x%02x after reset\r\n", port, status, change);
-
- if ((status & HUB_PORT_STATUS_RESET) == 0 && (status & HUB_PORT_STATUS_ENABLE) != 0) {
- if (change & HUB_PORT_STATUS_C_RESET) {
- ret = usbh_hub_clear_feature(hub_class, port, HUB_PORT_FEATURE_C_RESET);
- if (ret < 0) {
- USB_LOG_ERR("Failed to clear port:%d reset change, errorcode: %d\r\n", port, ret);
- }
- }
- connport = &hub_class->child[port - 1];
-
- if (status & HUB_PORT_STATUS_HIGH_SPEED) {
- connport->speed = USB_SPEED_HIGH;
- } else if (status & HUB_PORT_STATUS_LOW_SPEED) {
- connport->speed = USB_SPEED_LOW;
- } else {
- connport->speed = USB_SPEED_FULL;
- }
-
- /* Device connected from a port on the hub, wakeup psc thread. */
- usbh_external_hport_connect(connport);
-
- } else {
- USB_LOG_ERR("Failed to enable port:%d\r\n", port);
- continue;
- }
- } else {
- /* Device disconnected from a port on the hub, wakeup psc thread. */
- connport = &hub_class->child[port - 1];
- usbh_external_hport_disconnect(connport);
- }
- } else {
- USB_LOG_WRN("status %04x change %04x not handled\r\n", status, change);
- }
- }
-
- /* Check for hub status change */
-
- if ((port_change & 1) != 0) {
- /* Hub status changed */
- USB_LOG_WRN("Hub status changed, not handled\n");
- }
- flags = usb_osal_enter_critical_section();
- if (hub_class->parent->connected) {
- ret = usbh_ep_intr_async_transfer(hub_class->intin, hub_class->int_buffer, USBH_HUB_INTIN_BUFSIZE, usbh_external_hub_callback, hub_class);
- }
- usb_osal_leave_critical_section(flags);
-}
-
-static void usbh_external_hub_callback(void *arg, int nbytes)
-{
- struct usbh_hub *hub_class = (struct usbh_hub *)arg;
- uint32_t delay = 0;
- if (nbytes < 0) {
- hub_class->int_buffer[0] = 0;
- delay = 100;
- }
- if (hub_class->parent->connected) {
- usb_workqueue_submit(&g_lpworkq, &hub_class->work, usbh_extern_hub_psc_event, (void *)hub_class, delay);
- }
-}
-
-const struct usbh_class_driver hub_class_driver = {
- .driver_name = "hub",
- .connect = usbh_hub_connect,
- .disconnect = usbh_hub_disconnect
+/**
+ * @file usbh_hub.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbh_core.h"
+#include "usbh_hub.h"
+
+#define DEV_FORMAT "/dev/hub%d"
+#define DEV_NAMELEN 16
+
+static uint32_t g_devinuse = 0;
+
+usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
+
+USB_NOCACHE_RAM_SECTION uint8_t int_buffer[6][USBH_HUB_INTIN_BUFSIZE];
+extern void usbh_external_hport_connect(struct usbh_hubport *hport);
+extern void usbh_external_hport_disconnect(struct usbh_hubport *hport);
+extern void usbh_hport_activate(struct usbh_hubport *hport);
+extern void usbh_hport_deactivate(struct usbh_hubport *hport);
+
+static void usbh_external_hub_callback(void *arg, int nbytes);
+
+static inline void usbh_hub_register(struct usbh_hub *hub)
+{
+ usb_slist_add_tail(&hub_class_head, &hub->list);
+}
+
+static inline void usbh_hub_unregister(struct usbh_hub *hub)
+{
+ usb_slist_remove(&hub_class_head, &hub->list);
+}
+
+/****************************************************************************
+ * Name: usbh_hub_devno_alloc
+ *
+ * Description:
+ * Allocate a unique /dev/hub[n] minor number in the range 2-31.
+ *
+ ****************************************************************************/
+
+static int usbh_hub_devno_alloc(struct usbh_hub *hub)
+{
+ uint32_t flags;
+ int devno;
+
+ flags = usb_osal_enter_critical_section();
+ for (devno = 2; devno < 32; devno++) {
+ uint32_t bitno = 1 << devno;
+ if ((g_devinuse & bitno) == 0) {
+ g_devinuse |= bitno;
+ hub->index = devno;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ }
+
+ usb_osal_leave_critical_section(flags);
+ return -EMFILE;
+}
+
+/****************************************************************************
+ * Name: usbh_hub_devno_free
+ *
+ * Description:
+ * Free a /dev/hub[n] minor number so that it can be used.
+ *
+ ****************************************************************************/
+
+static void usbh_hub_devno_free(struct usbh_hub *hub)
+{
+ int devno = hub->index;
+
+ if (devno >= 2 && devno < 32) {
+ uint32_t flags = usb_osal_enter_critical_section();
+ g_devinuse &= ~(1 << devno);
+ usb_osal_leave_critical_section(flags);
+ }
+}
+
+/****************************************************************************
+ * Name: usbh_hub_mkdevname
+ *
+ * Description:
+ * Format a /dev/hub[n] device name given a minor number.
+ *
+ ****************************************************************************/
+
+static inline void usbh_hub_mkdevname(struct usbh_hub *hub, char *devname)
+{
+ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, hub->index);
+}
+
+int usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
+{
+ struct usb_setup_packet *setup;
+
+ setup = hub->setup;
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
+ setup->wIndex = 0;
+ setup->wLength = USB_SIZEOF_HUB_DESC;
+
+ return usbh_control_transfer(hub->parent->ep0, setup, buffer);
+}
+
+int usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
+{
+ struct usb_setup_packet *setup;
+
+ setup = hub->setup;
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = HUB_REQUEST_GET_STATUS;
+ setup->wValue = 0;
+ setup->wIndex = 0;
+ setup->wLength = 2;
+
+ return usbh_control_transfer(hub->parent->ep0, setup, buffer);
+}
+
+int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
+{
+ struct usb_setup_packet *setup;
+
+ setup = hub->setup;
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+ setup->bRequest = HUB_REQUEST_GET_STATUS;
+ setup->wValue = 0;
+ setup->wIndex = port;
+ setup->wLength = 4;
+
+ return usbh_control_transfer(hub->parent->ep0, setup, (uint8_t *)port_status);
+}
+
+int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+ struct usb_setup_packet *setup;
+
+ setup = hub->setup;
+
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+ setup->bRequest = HUB_REQUEST_SET_FEATURE;
+ setup->wValue = feature;
+ setup->wIndex = port;
+ setup->wLength = 0;
+
+ return usbh_control_transfer(hub->parent->ep0, setup, NULL);
+}
+
+int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+ struct usb_setup_packet *setup;
+
+ setup = hub->setup;
+
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+ setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
+ setup->wValue = feature;
+ setup->wIndex = port;
+ setup->wLength = 0;
+
+ return usbh_control_transfer(hub->parent->ep0, setup, NULL);
+}
+
+static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
+{
+ if (desc->bLength != USB_SIZEOF_HUB_DESC) {
+ USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
+ return -1;
+ } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB) {
+ USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+ return -2;
+ } else {
+ USB_LOG_INFO("Device Descriptor:\r\n");
+ USB_LOG_INFO("bLength: 0x%02x \r\n", desc->bLength);
+ USB_LOG_INFO("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
+ USB_LOG_INFO("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
+ USB_LOG_INFO("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
+ USB_LOG_INFO("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
+ USB_LOG_INFO("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
+ USB_LOG_INFO("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
+ USB_LOG_INFO("PortPwrCtrlMask: 0x%02x \r\n", desc->PortPwrCtrlMask);
+ }
+ return 0;
+}
+
+int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+ struct usbh_endpoint_cfg ep_cfg = { 0 };
+ struct usb_endpoint_descriptor *ep_desc;
+ char devname[DEV_NAMELEN];
+ int ret;
+ uint8_t *hub_desc_buffer;
+ struct usbh_hub *hub_class;
+
+ hub_class = usb_malloc(sizeof(struct usbh_hub));
+ if (hub_class == NULL) {
+ USB_LOG_ERR("Fail to alloc hub_class\r\n");
+ return -ENOMEM;
+ }
+ memset(hub_class, 0, sizeof(struct usbh_hub));
+ hub_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
+ if (hub_class->setup == NULL) {
+ USB_LOG_ERR("Fail to alloc setup\r\n");
+ return -ENOMEM;
+ }
+ hub_class->port_status = usb_iomalloc(sizeof(struct hub_port_status));
+ if (hub_class->port_status == NULL) {
+ USB_LOG_ERR("Fail to alloc port_status\r\n");
+ return -ENOMEM;
+ }
+
+ hub_desc_buffer = usb_iomalloc(32);
+
+ usbh_hub_devno_alloc(hub_class);
+ usbh_hub_mkdevname(hub_class, devname);
+
+ hub_class->dev_addr = hport->dev_addr;
+ hub_class->parent = hport;
+ hport->config.intf[0].priv = hub_class;
+
+ ret = usbh_hub_get_hub_descriptor(hub_class, hub_desc_buffer);
+ if (ret != 0) {
+ usb_iofree(hub_desc_buffer);
+ return ret;
+ }
+
+ parse_hub_descriptor((struct usb_hub_descriptor *)hub_desc_buffer, USB_SIZEOF_HUB_DESC);
+ memcpy(&hub_class->hub_desc, hub_desc_buffer, USB_SIZEOF_HUB_DESC);
+ usb_iofree(hub_desc_buffer);
+
+ hub_class->nports = hub_class->hub_desc.bNbrPorts;
+
+ for (uint8_t port = 1; port <= hub_class->nports; port++) {
+ hub_class->child[port - 1].port = port;
+ hub_class->child[port - 1].parent = hub_class;
+ }
+
+ hub_class->int_buffer = int_buffer[hub_class->index - 2];
+ usbh_hub_register(hub_class);
+
+ ep_desc = &hport->config.intf[intf].ep[0].ep_desc;
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_interval = ep_desc->bInterval;
+ ep_cfg.hport = hport;
+ if (ep_desc->bEndpointAddress & 0x80) {
+ usbh_ep_alloc(&hub_class->intin, &ep_cfg);
+ } else {
+ return -1;
+ }
+
+ for (uint8_t port = 1; port <= hub_class->nports; port++) {
+ ret = usbh_hub_set_feature(hub_class, 1, HUB_PORT_FEATURE_POWER);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ for (uint8_t port = 1; port <= hub_class->nports; port++) {
+ ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
+ USB_LOG_INFO("Port:%d, status:0x%02x, change:0x%02x\r\n", port, hub_class->port_status->wPortStatus, hub_class->port_status->wPortChange);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ USB_LOG_INFO("Register HUB Class:%s\r\n", devname);
+
+ ret = usbh_ep_intr_async_transfer(hub_class->intin, hub_class->int_buffer, USBH_HUB_INTIN_BUFSIZE, usbh_external_hub_callback, hub_class);
+ return 0;
+}
+
+int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+ struct usbh_hubport *child;
+ char devname[DEV_NAMELEN];
+ int ret = 0;
+
+ struct usbh_hub *hub_class = (struct usbh_hub *)hport->config.intf[intf].priv;
+
+ if (hub_class) {
+ usbh_hub_devno_free(hub_class);
+ usbh_hub_mkdevname(hub_class, devname);
+
+ if (hub_class->intin) {
+ ret = usb_ep_cancel(hub_class->intin);
+ if (ret < 0) {
+ }
+ usbh_ep_free(hub_class->intin);
+ }
+
+ if (hub_class->setup)
+ usb_iofree(hub_class->setup);
+ if (hub_class->port_status)
+ usb_iofree(hub_class->port_status);
+
+ for (uint8_t port = 1; port <= hub_class->nports; port++) {
+ child = &hub_class->child[port - 1];
+ usbh_hport_deactivate(child);
+ for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
+ if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
+ ret = CLASS_DISCONNECT(child, i);
+ }
+ }
+
+ child->config.config_desc.bNumInterfaces = 0;
+ child->parent = NULL;
+ }
+
+ usbh_hub_unregister(hub_class);
+ usb_free(hub_class);
+ hport->config.intf[intf].priv = NULL;
+
+ USB_LOG_INFO("Unregister HUB Class:%s\r\n", devname);
+ }
+ return ret;
+}
+
+static void usbh_extern_hub_psc_event(void *arg)
+{
+ struct usbh_hub *hub_class;
+ struct usbh_hubport *connport;
+ uint8_t port_change;
+ uint16_t status;
+ uint16_t change;
+ uint16_t mask;
+ uint16_t feat;
+ uint32_t flags;
+ int ret;
+
+ hub_class = (struct usbh_hub *)arg;
+
+ /* Has the hub been disconnected? */
+ if (!hub_class->parent->connected) {
+ return;
+ }
+
+ port_change = hub_class->int_buffer[0];
+ USB_LOG_DBG("port_change:0x%02x\r\n", port_change);
+
+ /* Check for status change on any port */
+ for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
+ /* Check if port status has changed */
+ if ((port_change & (1 << port)) == 0) {
+ continue;
+ }
+ USB_LOG_DBG("Port %d change\r\n", port);
+
+ /* Port status changed, check what happened */
+ port_change &= ~(1 << port);
+
+ /* Read hub port status */
+ ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
+ continue;
+ }
+ status = hub_class->port_status->wPortStatus;
+ change = hub_class->port_status->wPortChange;
+
+ USB_LOG_DBG("Port:%d, status:0x%02x, change:0x%02x\r\n", port, status, change);
+
+ /* First, clear all change bits */
+ mask = 1;
+ feat = HUB_PORT_FEATURE_C_CONNECTION;
+ while (change) {
+ if (change & mask) {
+ ret = usbh_hub_clear_feature(hub_class, port, feat);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to clear port:%d, change mask:%04x, errorcode:%d\r\n", port, mask, ret);
+ }
+ change &= (~mask);
+ }
+ mask <<= 1;
+ feat++;
+ }
+
+ change = hub_class->port_status->wPortChange;
+
+ /* Handle connect or disconnect, no power management */
+ if (change & HUB_PORT_STATUS_C_CONNECTION) {
+ ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
+ }
+ status = hub_class->port_status->wPortStatus;
+ change = hub_class->port_status->wPortChange;
+
+ if (status & HUB_PORT_STATUS_CONNECTION) {
+ /* Device connected to a port on the hub */
+ //USB_LOG_INFO("Connection on port:%d\n", port);
+
+ ret = usbh_hub_set_feature(hub_class, port, HUB_PORT_FEATURE_RESET);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to reset port:%d,errorcode:%d\r\n", port, ret);
+ continue;
+ }
+
+ usb_osal_msleep(100);
+
+ ret = usbh_hub_get_portstatus(hub_class, port, hub_class->port_status);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to read port:%d status, errorcode: %d\r\n", port, ret);
+ continue;
+ }
+ status = hub_class->port_status->wPortStatus;
+ change = hub_class->port_status->wPortChange;
+
+ USB_LOG_DBG("Port:%d, status:0x%02x, change:0x%02x after reset\r\n", port, status, change);
+
+ if ((status & HUB_PORT_STATUS_RESET) == 0 && (status & HUB_PORT_STATUS_ENABLE) != 0) {
+ if (change & HUB_PORT_STATUS_C_RESET) {
+ ret = usbh_hub_clear_feature(hub_class, port, HUB_PORT_FEATURE_C_RESET);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to clear port:%d reset change, errorcode: %d\r\n", port, ret);
+ }
+ }
+ connport = &hub_class->child[port - 1];
+
+ if (status & HUB_PORT_STATUS_HIGH_SPEED) {
+ connport->speed = USB_SPEED_HIGH;
+ } else if (status & HUB_PORT_STATUS_LOW_SPEED) {
+ connport->speed = USB_SPEED_LOW;
+ } else {
+ connport->speed = USB_SPEED_FULL;
+ }
+
+ /* Device connected from a port on the hub, wakeup psc thread. */
+ usbh_external_hport_connect(connport);
+
+ } else {
+ USB_LOG_ERR("Failed to enable port:%d\r\n", port);
+ continue;
+ }
+ } else {
+ /* Device disconnected from a port on the hub, wakeup psc thread. */
+ connport = &hub_class->child[port - 1];
+ usbh_external_hport_disconnect(connport);
+ }
+ } else {
+ USB_LOG_WRN("status %04x change %04x not handled\r\n", status, change);
+ }
+ }
+
+ /* Check for hub status change */
+
+ if ((port_change & 1) != 0) {
+ /* Hub status changed */
+ USB_LOG_WRN("Hub status changed, not handled\n");
+ }
+ flags = usb_osal_enter_critical_section();
+ if (hub_class->parent->connected) {
+ ret = usbh_ep_intr_async_transfer(hub_class->intin, hub_class->int_buffer, USBH_HUB_INTIN_BUFSIZE, usbh_external_hub_callback, hub_class);
+ }
+ usb_osal_leave_critical_section(flags);
+}
+
+static void usbh_external_hub_callback(void *arg, int nbytes)
+{
+ struct usbh_hub *hub_class = (struct usbh_hub *)arg;
+ uint32_t delay = 0;
+ if (nbytes < 0) {
+ hub_class->int_buffer[0] = 0;
+ delay = 100;
+ }
+ if (hub_class->parent->connected) {
+ usb_workqueue_submit(&g_lpworkq, &hub_class->work, usbh_extern_hub_psc_event, (void *)hub_class, delay);
+ }
+}
+
+const struct usbh_class_driver hub_class_driver = {
+ .driver_name = "hub",
+ .connect = usbh_hub_connect,
+ .disconnect = usbh_hub_disconnect
}; \ No newline at end of file
diff --git a/class/hub/usbh_hub.h b/class/hub/usbh_hub.h
index 98c46542..ee0df9e3 100644
--- a/class/hub/usbh_hub.h
+++ b/class/hub/usbh_hub.h
@@ -1,42 +1,42 @@
-/**
- * @file usbh_hub.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBH_HUB_H_
-#define _USBH_HUB_H_
-
-#include "usb_hub.h"
-
-#define USBH_HUB_MAX_PORTS 4
-/* Maximum size of an interrupt IN transfer */
-#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
-
-extern const struct usbh_class_driver hub_class_driver;
-extern usb_slist_t hub_class_head;
-extern usb_osal_thread_t hub_thread;
-#ifdef __cplusplus
-extern "C" {
-#endif
-int usbh_hub_initialize(void);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _USBH_HUB_H_ */
+/**
+ * @file usbh_hub.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBH_HUB_H_
+#define _USBH_HUB_H_
+
+#include "usb_hub.h"
+
+#define USBH_HUB_MAX_PORTS 4
+/* Maximum size of an interrupt IN transfer */
+#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
+
+extern const struct usbh_class_driver hub_class_driver;
+extern usb_slist_t hub_class_head;
+extern usb_osal_thread_t hub_thread;
+#ifdef __cplusplus
+extern "C" {
+#endif
+int usbh_hub_initialize(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _USBH_HUB_H_ */
diff --git a/class/msc/usbd_msc.c b/class/msc/usbd_msc.c
index 563888d9..3f88cdd5 100644
--- a/class/msc/usbd_msc.c
+++ b/class/msc/usbd_msc.c
@@ -1,992 +1,992 @@
-/**
- * @file usbd_msc.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-#include "usbd_msc.h"
-#include "usb_scsi.h"
-
-/* max USB packet size */
-#ifndef CONFIG_USB_HS
-#define MASS_STORAGE_BULK_EP_MPS 64
-#else
-#define MASS_STORAGE_BULK_EP_MPS 512
-#endif
-
-#define MSD_OUT_EP_IDX 0
-#define MSD_IN_EP_IDX 1
-
-/* Describe EndPoints configuration */
-static usbd_endpoint_t mass_ep_data[2];
-
-/* MSC Bulk-only Stage */
-enum Stage {
- MSC_READ_CBW = 0, /* Command Block Wrapper */
- MSC_DATA_OUT = 1, /* Data Out Phase */
- MSC_DATA_IN = 2, /* Data In Phase */
- MSC_SEND_CSW = 3, /* Command Status Wrapper */
- MSC_WAIT_CSW = 4, /* Command Status Wrapper */
-};
-
-/* Device data structure */
-struct usbd_msc_cfg_private {
- /* state of the bulk-only state machine */
- enum Stage stage;
- struct CBW cbw;
- struct CSW csw;
-
- uint8_t sKey; /* Sense key */
- uint8_t ASC; /* Additional Sense Code */
- uint8_t ASQ; /* Additional Sense Qualifier */
- uint8_t max_lun;
- uint16_t scsi_blk_size;
- uint32_t scsi_blk_nbr;
-
- uint32_t scsi_blk_addr;
- uint32_t scsi_blk_len;
- uint8_t *block_buffer;
-
-} usbd_msc_cfg;
-
-/*memory OK (after a usbd_msc_memory_verify)*/
-static bool memOK;
-
-static void usbd_msc_reset(void)
-{
- usbd_msc_cfg.stage = MSC_READ_CBW;
- usbd_msc_cfg.scsi_blk_addr = 0U;
- usbd_msc_cfg.scsi_blk_len = 0U;
- usbd_msc_cfg.max_lun = 0;
- usbd_msc_cfg.sKey = 0;
- usbd_msc_cfg.ASC = 0;
- usbd_msc_cfg.ASQ = 0;
-
- (void)memset((void *)&usbd_msc_cfg.cbw, 0, sizeof(struct CBW));
- (void)memset((void *)&usbd_msc_cfg.csw, 0, sizeof(struct CSW));
-
- usbd_msc_get_cap(0, &usbd_msc_cfg.scsi_blk_nbr, &usbd_msc_cfg.scsi_blk_size);
-
- if (usbd_msc_cfg.block_buffer) {
- free(usbd_msc_cfg.block_buffer);
- }
- usbd_msc_cfg.block_buffer = malloc(usbd_msc_cfg.scsi_blk_size * sizeof(uint8_t));
- memset(usbd_msc_cfg.block_buffer, 0, usbd_msc_cfg.scsi_blk_size * sizeof(uint8_t));
-}
-
-/**
- * @brief Handler called for Class requests not handled by the USB stack.
- *
- * @param setup Information about the request to execute.
- * @param len Size of the buffer.
- * @param data Buffer containing the request result.
- *
- * @return 0 on success, negative errno code on fail.
- */
-static int msc_storage_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("MSC Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- switch (setup->bRequest) {
- case MSC_REQUEST_RESET:
- USB_LOG_DBG("MSC_REQUEST_RESET\r\n");
-
- if (setup->wLength) {
- USB_LOG_WRN("Invalid length\r\n");
- return -1;
- }
-
- usbd_msc_reset();
- break;
-
- case MSC_REQUEST_GET_MAX_LUN:
- USB_LOG_DBG("MSC_REQUEST_GET_MAX_LUN\r\n");
-
- if (setup->wLength != 1) {
- USB_LOG_WRN("Invalid length\r\n");
- return -1;
- }
-
- *data = (uint8_t *)(&usbd_msc_cfg.max_lun);
- *len = 1;
- break;
-
- default:
- USB_LOG_WRN("Unhandled MSC Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
-
- return 0;
-}
-
-static void usbd_msc_bot_abort(void)
-{
- if ((usbd_msc_cfg.cbw.bmFlags == 0) && (usbd_msc_cfg.cbw.dDataLength != 0)) {
- usbd_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- }
- usbd_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
-}
-
-static void sendCSW(uint8_t CSW_Status)
-{
- usbd_msc_cfg.csw.dSignature = MSC_CSW_Signature;
- usbd_msc_cfg.csw.bStatus = CSW_Status;
-
- /* updating the State Machine , so that we wait CSW when this
- * transfer is complete, ie when we get a bulk in callback
- */
- usbd_msc_cfg.stage = MSC_WAIT_CSW;
-
- if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.csw,
- sizeof(struct CSW), NULL) != 0) {
- USB_LOG_ERR("usb write failure\r\n");
- }
-}
-
-static void sendLastData(uint8_t *buffer, uint8_t size)
-{
- size = MIN(size, usbd_msc_cfg.cbw.dDataLength);
-
- /* updating the State Machine , so that we send CSW when this
- * transfer is complete, ie when we get a bulk in callback
- */
- usbd_msc_cfg.stage = MSC_SEND_CSW;
-
- if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, buffer, size, NULL) != 0) {
- USB_LOG_ERR("USB write failed\r\n");
- }
-
- usbd_msc_cfg.csw.dDataResidue -= size;
- usbd_msc_cfg.csw.bStatus = CSW_STATUS_CMD_PASSED;
-}
-
-/**
- * @brief SCSI COMMAND
- */
-static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len);
-static bool SCSI_requestSense(uint8_t **data, uint32_t *len);
-static bool SCSI_inquiry(uint8_t **data, uint32_t *len);
-static bool SCSI_startStopUnit(uint8_t **data, uint32_t *len);
-static bool SCSI_preventAllowMediaRemoval(uint8_t **data, uint32_t *len);
-static bool SCSI_modeSense6(uint8_t **data, uint32_t *len);
-static bool SCSI_modeSense10(uint8_t **data, uint32_t *len);
-static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len);
-static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len);
-static bool SCSI_read10(uint8_t **data, uint32_t *len);
-static bool SCSI_read12(uint8_t **data, uint32_t *len);
-static bool SCSI_write10(uint8_t **data, uint32_t *len);
-static bool SCSI_write12(uint8_t **data, uint32_t *len);
-static bool SCSI_verify10(uint8_t **data, uint32_t *len);
-
-/**
-* @brief SCSI_SenseCode
-* Load the last error code in the error list
-* @param sKey: Sense Key
-* @param ASC: Additional Sense Code
-* @retval none
-
-*/
-static void SCSI_SenseCode(uint8_t sKey, uint8_t ASC)
-{
- usbd_msc_cfg.sKey = sKey;
- usbd_msc_cfg.ASC = ASC;
-}
-
-static bool SCSI_processRead(void)
-{
- uint32_t transfer_len;
-
- USB_LOG_DBG("read addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
-
- transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, MASS_STORAGE_BULK_EP_MPS);
-
- /* we read an entire block */
- if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
- if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
- SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_UNRECOVERED_READ_ERROR);
- return false;
- }
- }
-
- usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
- &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], transfer_len, NULL);
-
- usbd_msc_cfg.scsi_blk_addr += transfer_len;
- usbd_msc_cfg.scsi_blk_len -= transfer_len;
- usbd_msc_cfg.csw.dDataResidue -= transfer_len;
-
- if (usbd_msc_cfg.scsi_blk_len == 0) {
- usbd_msc_cfg.stage = MSC_SEND_CSW;
- }
-
- return true;
-}
-
-static bool SCSI_processWrite()
-{
- uint32_t bytes_read;
- USB_LOG_DBG("write addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
-
- /* we fill an array in RAM of 1 block before writing it in memory */
- usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], MASS_STORAGE_BULK_EP_MPS,
- &bytes_read);
-
- /* if the array is filled, write it in memory */
- if ((usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size) + bytes_read >= usbd_msc_cfg.scsi_blk_size) {
- if (usbd_msc_sector_write((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
- SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_WRITE_FAULT);
- return false;
- }
- }
-
- usbd_msc_cfg.scsi_blk_addr += bytes_read;
- usbd_msc_cfg.scsi_blk_len -= bytes_read;
- usbd_msc_cfg.csw.dDataResidue -= bytes_read;
-
- if (usbd_msc_cfg.scsi_blk_len == 0) {
- sendCSW(CSW_STATUS_CMD_PASSED);
- }
-
- return true;
-}
-
-static bool SCSI_processVerify()
-{
-#if 0
- uint32_t bytes_read;
- uint8_t out_buffer[MASS_STORAGE_BULK_EP_MPS];
-
- USB_LOG_DBG("verify addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
-
- /* we fill an array in RAM of 1 block before writing it in memory */
- usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, out_buffer, MASS_STORAGE_BULK_EP_MPS,
- &bytes_read);
-
- /* we read an entire block */
- if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
- if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
- SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_UNRECOVERED_READ_ERROR);
- return false;
- }
- }
-
- /* info are in RAM -> no need to re-read memory */
- for (uint16_t i = 0U; i < bytes_read; i++) {
- if (usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size + i] != out_buffer[i]) {
- USB_LOG_DBG("Mismatch sector %d offset %d",
- usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size, i);
- memOK = false;
- break;
- }
- }
-
- usbd_msc_cfg.scsi_blk_addr += bytes_read;
- usbd_msc_cfg.scsi_blk_len -= bytes_read;
- usbd_msc_cfg.csw.dDataResidue -= bytes_read;
-
- if (usbd_msc_cfg.scsi_blk_len == 0) {
- sendCSW(CSW_STATUS_CMD_PASSED);
- }
-#endif
- return true;
-}
-
-static bool SCSI_CBWDecode()
-{
- uint8_t *buf2send = usbd_msc_cfg.block_buffer;
- uint32_t len2send = 0;
- uint32_t bytes_read;
- bool ret = false;
-
- usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW,
- &bytes_read);
-
- if (bytes_read != sizeof(struct CBW)) {
- USB_LOG_ERR("size != sizeof(cbw)\r\n");
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- usbd_msc_cfg.csw.dTag = usbd_msc_cfg.cbw.dTag;
- usbd_msc_cfg.csw.dDataResidue = usbd_msc_cfg.cbw.dDataLength;
-
- if ((usbd_msc_cfg.cbw.bLUN > 1) || (usbd_msc_cfg.cbw.dSignature != MSC_CBW_Signature) || (usbd_msc_cfg.cbw.bCBLength < 1) || (usbd_msc_cfg.cbw.bCBLength > 16)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- } else {
- switch (usbd_msc_cfg.cbw.CB[0]) {
- case SCSI_TEST_UNIT_READY:
- ret = SCSI_testUnitReady(&buf2send, &len2send);
- break;
- case SCSI_REQUEST_SENSE:
- ret = SCSI_requestSense(&buf2send, &len2send);
- break;
- case SCSI_INQUIRY:
- ret = SCSI_inquiry(&buf2send, &len2send);
- break;
- case SCSI_START_STOP_UNIT:
- ret = SCSI_startStopUnit(&buf2send, &len2send);
- break;
- case SCSI_PREVENT_ALLOW_MEDIA_REMOVAL:
- ret = SCSI_preventAllowMediaRemoval(&buf2send, &len2send);
- break;
- case SCSI_MODE_SENSE6:
- ret = SCSI_modeSense6(&buf2send, &len2send);
- break;
- case SCSI_MODE_SENSE10:
- ret = SCSI_modeSense10(&buf2send, &len2send);
- break;
- case SCSI_READ_FORMAT_CAPACITIES:
- ret = SCSI_readFormatCapacity(&buf2send, &len2send);
- break;
- case SCSI_READ_CAPACITY10:
- ret = SCSI_readCapacity10(&buf2send, &len2send);
- break;
- case SCSI_READ10:
- ret = SCSI_read10(NULL, 0);
- break;
- case SCSI_READ12:
- ret = SCSI_read12(NULL, 0);
- break;
- case SCSI_WRITE10:
- ret = SCSI_write10(NULL, 0);
- break;
- case SCSI_WRITE12:
- ret = SCSI_write12(NULL, 0);
- break;
- case SCSI_VERIFY10:
- ret = SCSI_verify10(NULL, 0);
- break;
-
- default:
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- USB_LOG_WRN("unsupported cmd:0x%02x\r\n", usbd_msc_cfg.cbw.CB[0]);
- ret = false;
- break;
- }
- }
- if (ret) {
- if (usbd_msc_cfg.stage == MSC_READ_CBW) {
- if (len2send) {
- sendLastData(buf2send, len2send);
- } else {
- sendCSW(CSW_STATUS_CMD_PASSED);
- }
- }
- }
- return ret;
-}
-
-static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len)
-{
- if (usbd_msc_cfg.cbw.dDataLength != 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
- *data = NULL;
- *len = 0;
- return true;
-}
-
-static bool SCSI_requestSense(uint8_t **data, uint32_t *len)
-{
- uint8_t data_len = REQUEST_SENSE_DATA_LEN;
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- if (usbd_msc_cfg.cbw.CB[4] < REQUEST_SENSE_DATA_LEN) {
- data_len = usbd_msc_cfg.cbw.CB[4];
- }
-
- uint8_t request_sense[REQUEST_SENSE_DATA_LEN] = {
- 0x70,
- 0x00,
- 0x00, /* Sense Key */
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- REQUEST_SENSE_DATA_LEN - 8,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00, /* Additional Sense Code */
- 0x00, /* Additional Sense Request */
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- };
-
- request_sense[2] = usbd_msc_cfg.sKey;
- request_sense[12] = usbd_msc_cfg.ASC;
- request_sense[13] = usbd_msc_cfg.ASQ;
-#if 0
- request_sense[ 2] = 0x06; /* UNIT ATTENTION */
- request_sense[12] = 0x28; /* Additional Sense Code: Not ready to ready transition */
- request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
-#endif
-#if 0
- request_sense[ 2] = 0x02; /* NOT READY */
- request_sense[12] = 0x3A; /* Additional Sense Code: Medium not present */
- request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
-#endif
-#if 0
- request_sense[ 2] = 0x05; /* ILLEGAL REQUEST */
- request_sense[12] = 0x20; /* Additional Sense Code: Invalid command */
- request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
-#endif
-#if 0
- request_sense[ 2] = 0x00; /* NO SENSE */
- request_sense[12] = 0x00; /* Additional Sense Code: No additional code */
- request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
-#endif
-
- memcpy(*data, (uint8_t *)request_sense, data_len);
- *len = data_len;
- return true;
-}
-
-static bool SCSI_inquiry(uint8_t **data, uint32_t *len)
-{
- uint8_t data_len = STANDARD_INQUIRY_DATA_LEN;
-
- uint8_t inquiry00[6] = {
- 0x00,
- 0x00,
- 0x00,
- (0x06 - 4U),
- 0x00,
- 0x80
- };
-
- /* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */
- uint8_t inquiry80[8] = {
- 0x00,
- 0x80,
- 0x00,
- 0x08,
- 0x20, /* Put Product Serial number */
- 0x20,
- 0x20,
- 0x20
- };
-
- uint8_t inquiry[STANDARD_INQUIRY_DATA_LEN] = {
- /* 36 */
-
- /* LUN 0 */
- 0x00,
- 0x80,
- 0x02,
- 0x02,
- (STANDARD_INQUIRY_DATA_LEN - 5),
- 0x00,
- 0x00,
- 0x00,
- 'B', 'o', 'u', 'f', 'f', 'a', 'l', 'o', /* Manufacturer : 8 bytes */
- 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
- ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
- '0', '.', '0', '1' /* Version : 4 Bytes */
- };
-
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- if ((usbd_msc_cfg.cbw.CB[1] & 0x01U) != 0U) { /* Evpd is set */
- if (usbd_msc_cfg.cbw.CB[2] == 0U) { /* Request for Supported Vital Product Data Pages*/
- data_len = 0x06;
- memcpy(*data, (uint8_t *)inquiry00, data_len);
- } else if (usbd_msc_cfg.cbw.CB[2] == 0x80U) { /* Request for VPD page 0x80 Unit Serial Number */
- data_len = 0x08;
- memcpy(*data, (uint8_t *)inquiry80, data_len);
- } else { /* Request Not supported */
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELED_IN_COMMAND);
- return false;
- }
- } else {
- if (usbd_msc_cfg.cbw.CB[4] < STANDARD_INQUIRY_DATA_LEN) {
- data_len = usbd_msc_cfg.cbw.CB[4];
- }
- memcpy(*data, (uint8_t *)inquiry, data_len);
- }
-
- *len = data_len;
- return true;
-}
-
-static bool SCSI_startStopUnit(uint8_t **data, uint32_t *len)
-{
- if (usbd_msc_cfg.cbw.dDataLength != 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x1U) /* START=1 */
- {
- //SCSI_MEDIUM_UNLOCKED;
- } else if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */
- {
- //SCSI_MEDIUM_EJECTED;
- } else if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */
- {
- //SCSI_MEDIUM_UNLOCKED;
- } else {
- }
-
- *data = NULL;
- *len = 0;
- return true;
-}
-
-static bool SCSI_preventAllowMediaRemoval(uint8_t **data, uint32_t *len)
-{
- if (usbd_msc_cfg.cbw.dDataLength != 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
- if (usbd_msc_cfg.cbw.CB[4] == 0U) {
- //SCSI_MEDIUM_UNLOCKED;
- } else {
- //SCSI_MEDIUM_LOCKED;
- }
- *data = NULL;
- *len = 0;
- return true;
-}
-
-static bool SCSI_modeSense6(uint8_t **data, uint32_t *len)
-{
- uint8_t data_len = 4;
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
- if (usbd_msc_cfg.cbw.CB[4] < MODE_SENSE6_DATA_LEN) {
- data_len = usbd_msc_cfg.cbw.CB[4];
- }
-
- uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
-
- memcpy(*data, (uint8_t *)sense6, data_len);
- *len = data_len;
- return true;
-}
-
-static bool SCSI_modeSense10(uint8_t **data, uint32_t *len)
-{
- uint8_t data_len = MODE_SENSE10_DATA_LEN;
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- if (usbd_msc_cfg.cbw.CB[8] < MODE_SENSE10_DATA_LEN) {
- data_len = usbd_msc_cfg.cbw.CB[8];
- }
-
- uint8_t sense10[MODE_SENSE10_DATA_LEN] = {
- 0x00,
- 0x26,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x08,
- 0x12,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00
- };
-
- memcpy(*data, (uint8_t *)sense10, data_len);
- *len = data_len;
- return true;
-}
-
-static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len)
-{
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
- uint8_t format_capacity[READ_FORMAT_CAPACITY_DATA_LEN] = {
- 0x00,
- 0x00,
- 0x00,
- 0x08, /* Capacity List Length */
- (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 24) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 16) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 8) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 0) & 0xff),
-
- 0x02, /* Descriptor Code: Formatted Media */
- 0x00,
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 8) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 0) & 0xff),
- };
-
- memcpy(*data, (uint8_t *)format_capacity, READ_FORMAT_CAPACITY_DATA_LEN);
- *len = READ_FORMAT_CAPACITY_DATA_LEN;
- return true;
-}
-
-static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len)
-{
- if (usbd_msc_cfg.cbw.dDataLength == 0U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- uint8_t capacity10[READ_CAPACITY10_DATA_LEN] = {
- (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 24) & 0xff),
- (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 16) & 0xff),
- (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 8) & 0xff),
- (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 0) & 0xff),
-
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 24) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 16) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 8) & 0xff),
- (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 0) & 0xff),
- };
-
- memcpy(*data, (uint8_t *)&capacity10, READ_CAPACITY10_DATA_LEN);
- *len = READ_CAPACITY10_DATA_LEN;
- return true;
-}
-
-static bool SCSI_read10(uint8_t **data, uint32_t *len)
-{
- /* Logical Block Address of First Block */
- uint32_t lba = 0;
- uint32_t blk_num = 0;
- if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x80U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
- USB_LOG_DBG("lba: 0x%x\r\n", lba);
-
- usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
-
- /* Number of Blocks to transfer */
- blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
-
- usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
-
- if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ADDRESS_OUT_OF_RANGE);
- USB_LOG_ERR("LBA out of range\r\n");
- return false;
- }
-
- if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
- USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
- return false;
- }
- usbd_msc_cfg.stage = MSC_DATA_IN;
- return SCSI_processRead();
-}
-
-static bool SCSI_read12(uint8_t **data, uint32_t *len)
-{
- /* Logical Block Address of First Block */
- uint32_t lba = 0;
- uint32_t blk_num = 0;
- if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x80U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
- USB_LOG_DBG("lba: 0x%x\r\n", lba);
-
- usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
-
- /* Number of Blocks to transfer */
- blk_num = GET_BE32(&usbd_msc_cfg.cbw.CB[6]);
-
- USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
- usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
-
- if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ADDRESS_OUT_OF_RANGE);
- USB_LOG_ERR("LBA out of range\r\n");
- return false;
- }
-
- if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
- USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
- return false;
- }
- usbd_msc_cfg.stage = MSC_DATA_IN;
- return SCSI_processRead();
-}
-
-static bool SCSI_write10(uint8_t **data, uint32_t *len)
-{
- /* Logical Block Address of First Block */
- uint32_t lba = 0;
- uint32_t blk_num = 0;
- if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
- USB_LOG_DBG("lba: 0x%x\r\n", lba);
-
- usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
-
- /* Number of Blocks to transfer */
- blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
-
- USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
- usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
-
- if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
- USB_LOG_ERR("LBA out of range\r\n");
- return false;
- }
-
- if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
- return false;
- }
- usbd_msc_cfg.stage = MSC_DATA_OUT;
- return true;
-}
-
-static bool SCSI_write12(uint8_t **data, uint32_t *len)
-{
- /* Logical Block Address of First Block */
- uint32_t lba = 0;
- uint32_t blk_num = 0;
- if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
- USB_LOG_DBG("lba: 0x%x\r\n", lba);
-
- usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
-
- /* Number of Blocks to transfer */
- blk_num = GET_BE32(&usbd_msc_cfg.cbw.CB[6]);
-
- USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
- usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
-
- if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
- USB_LOG_ERR("LBA out of range\r\n");
- return false;
- }
-
- if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
- return false;
- }
- usbd_msc_cfg.stage = MSC_DATA_OUT;
- return true;
-}
-
-static bool SCSI_verify10(uint8_t **data, uint32_t *len)
-{
- /* Logical Block Address of First Block */
- uint32_t lba = 0;
- uint32_t blk_num = 0;
-
- if ((usbd_msc_cfg.cbw.CB[1] & 0x02U) == 0x00U) {
- return true;
- }
-
- if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
- return false;
- }
-
- if ((usbd_msc_cfg.cbw.CB[1] & 0x02U) == 0x02U) {
- SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELED_IN_COMMAND);
- return false; /* Error, Verify Mode Not supported*/
- }
-
- lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
- USB_LOG_DBG("lba: 0x%x\r\n", lba);
-
- usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
-
- /* Number of Blocks to transfer */
- blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
-
- USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
- usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
-
- if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
- USB_LOG_ERR("LBA out of range\r\n");
- return false;
- }
-
- if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
- return false;
- }
-
- memOK = true;
- usbd_msc_cfg.stage = MSC_DATA_OUT;
- return true;
-}
-
-static void mass_storage_bulk_out(uint8_t ep)
-{
- switch (usbd_msc_cfg.stage) {
- case MSC_READ_CBW:
- if (SCSI_CBWDecode() == false) {
- USB_LOG_ERR("Command:0x%02x decode err\r\n", usbd_msc_cfg.cbw.CB[0]);
- usbd_msc_bot_abort();
- return;
- }
- break;
- /* last command is write10 or write12,and has caculated blk_addr and blk_len,so the device start reading data from host*/
- case MSC_DATA_OUT:
- switch (usbd_msc_cfg.cbw.CB[0]) {
- case SCSI_WRITE10:
- case SCSI_WRITE12:
- if (SCSI_processWrite() == false) {
- sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
- //return;
- }
- break;
- case SCSI_VERIFY10:
- if (SCSI_processVerify() == false) {
- sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
- //return;
- }
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- /*set ep ack to recv next data*/
- usbd_ep_read(ep, NULL, 0, NULL);
-}
-
-/**
- * @brief EP Bulk IN handler, used to send data to the Host
- *
- * @param ep Endpoint address.
- * @param ep_status Endpoint status code.
- *
- * @return N/A.
- */
-static void mass_storage_bulk_in(uint8_t ep)
-{
- switch (usbd_msc_cfg.stage) {
- /* last command is read10 or read12,and has caculated blk_addr and blk_len,so the device has to send remain data to host*/
- case MSC_DATA_IN:
- switch (usbd_msc_cfg.cbw.CB[0]) {
- case SCSI_READ10:
- case SCSI_READ12:
- if (SCSI_processRead() == false) {
- sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
- return;
- }
- break;
- default:
- break;
- }
-
- break;
-
- /*the device has to send a CSW*/
- case MSC_SEND_CSW:
- sendCSW(CSW_STATUS_CMD_PASSED);
- break;
-
- /*the host has received the CSW*/
- case MSC_WAIT_CSW:
- usbd_msc_cfg.stage = MSC_READ_CBW;
- break;
-
- default:
- break;
- }
-}
-
-void msc_storage_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
- usbd_msc_reset();
- break;
-
- default:
- break;
- }
-}
-
-static usbd_class_t msc_class;
-
-static usbd_interface_t msc_intf = {
- .class_handler = msc_storage_class_request_handler,
- .vendor_handler = NULL,
- .notify_handler = msc_storage_notify_handler,
-};
-
-void usbd_msc_class_init(uint8_t out_ep, uint8_t in_ep)
-{
- msc_class.name = "usbd_msc";
-
- usbd_class_register(&msc_class);
- usbd_class_add_interface(&msc_class, &msc_intf);
-
- mass_ep_data[0].ep_addr = out_ep;
- mass_ep_data[0].ep_cb = mass_storage_bulk_out;
- mass_ep_data[1].ep_addr = in_ep;
- mass_ep_data[1].ep_cb = mass_storage_bulk_in;
-
- usbd_interface_add_endpoint(&msc_intf, &mass_ep_data[0]);
- usbd_interface_add_endpoint(&msc_intf, &mass_ep_data[1]);
-}
+/**
+ * @file usbd_msc.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+#include "usbd_msc.h"
+#include "usb_scsi.h"
+
+/* max USB packet size */
+#ifndef CONFIG_USB_HS
+#define MASS_STORAGE_BULK_EP_MPS 64
+#else
+#define MASS_STORAGE_BULK_EP_MPS 512
+#endif
+
+#define MSD_OUT_EP_IDX 0
+#define MSD_IN_EP_IDX 1
+
+/* Describe EndPoints configuration */
+static usbd_endpoint_t mass_ep_data[2];
+
+/* MSC Bulk-only Stage */
+enum Stage {
+ MSC_READ_CBW = 0, /* Command Block Wrapper */
+ MSC_DATA_OUT = 1, /* Data Out Phase */
+ MSC_DATA_IN = 2, /* Data In Phase */
+ MSC_SEND_CSW = 3, /* Command Status Wrapper */
+ MSC_WAIT_CSW = 4, /* Command Status Wrapper */
+};
+
+/* Device data structure */
+struct usbd_msc_cfg_private {
+ /* state of the bulk-only state machine */
+ enum Stage stage;
+ struct CBW cbw;
+ struct CSW csw;
+
+ uint8_t sKey; /* Sense key */
+ uint8_t ASC; /* Additional Sense Code */
+ uint8_t ASQ; /* Additional Sense Qualifier */
+ uint8_t max_lun;
+ uint16_t scsi_blk_size;
+ uint32_t scsi_blk_nbr;
+
+ uint32_t scsi_blk_addr;
+ uint32_t scsi_blk_len;
+ uint8_t *block_buffer;
+
+} usbd_msc_cfg;
+
+/*memory OK (after a usbd_msc_memory_verify)*/
+static bool memOK;
+
+static void usbd_msc_reset(void)
+{
+ usbd_msc_cfg.stage = MSC_READ_CBW;
+ usbd_msc_cfg.scsi_blk_addr = 0U;
+ usbd_msc_cfg.scsi_blk_len = 0U;
+ usbd_msc_cfg.max_lun = 0;
+ usbd_msc_cfg.sKey = 0;
+ usbd_msc_cfg.ASC = 0;
+ usbd_msc_cfg.ASQ = 0;
+
+ (void)memset((void *)&usbd_msc_cfg.cbw, 0, sizeof(struct CBW));
+ (void)memset((void *)&usbd_msc_cfg.csw, 0, sizeof(struct CSW));
+
+ usbd_msc_get_cap(0, &usbd_msc_cfg.scsi_blk_nbr, &usbd_msc_cfg.scsi_blk_size);
+
+ if (usbd_msc_cfg.block_buffer) {
+ free(usbd_msc_cfg.block_buffer);
+ }
+ usbd_msc_cfg.block_buffer = malloc(usbd_msc_cfg.scsi_blk_size * sizeof(uint8_t));
+ memset(usbd_msc_cfg.block_buffer, 0, usbd_msc_cfg.scsi_blk_size * sizeof(uint8_t));
+}
+
+/**
+ * @brief Handler called for Class requests not handled by the USB stack.
+ *
+ * @param setup Information about the request to execute.
+ * @param len Size of the buffer.
+ * @param data Buffer containing the request result.
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+static int msc_storage_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("MSC Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ switch (setup->bRequest) {
+ case MSC_REQUEST_RESET:
+ USB_LOG_DBG("MSC_REQUEST_RESET\r\n");
+
+ if (setup->wLength) {
+ USB_LOG_WRN("Invalid length\r\n");
+ return -1;
+ }
+
+ usbd_msc_reset();
+ break;
+
+ case MSC_REQUEST_GET_MAX_LUN:
+ USB_LOG_DBG("MSC_REQUEST_GET_MAX_LUN\r\n");
+
+ if (setup->wLength != 1) {
+ USB_LOG_WRN("Invalid length\r\n");
+ return -1;
+ }
+
+ *data = (uint8_t *)(&usbd_msc_cfg.max_lun);
+ *len = 1;
+ break;
+
+ default:
+ USB_LOG_WRN("Unhandled MSC Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void usbd_msc_bot_abort(void)
+{
+ if ((usbd_msc_cfg.cbw.bmFlags == 0) && (usbd_msc_cfg.cbw.dDataLength != 0)) {
+ usbd_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
+ }
+ usbd_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
+}
+
+static void sendCSW(uint8_t CSW_Status)
+{
+ usbd_msc_cfg.csw.dSignature = MSC_CSW_Signature;
+ usbd_msc_cfg.csw.bStatus = CSW_Status;
+
+ /* updating the State Machine , so that we wait CSW when this
+ * transfer is complete, ie when we get a bulk in callback
+ */
+ usbd_msc_cfg.stage = MSC_WAIT_CSW;
+
+ if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.csw,
+ sizeof(struct CSW), NULL) != 0) {
+ USB_LOG_ERR("usb write failure\r\n");
+ }
+}
+
+static void sendLastData(uint8_t *buffer, uint8_t size)
+{
+ size = MIN(size, usbd_msc_cfg.cbw.dDataLength);
+
+ /* updating the State Machine , so that we send CSW when this
+ * transfer is complete, ie when we get a bulk in callback
+ */
+ usbd_msc_cfg.stage = MSC_SEND_CSW;
+
+ if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, buffer, size, NULL) != 0) {
+ USB_LOG_ERR("USB write failed\r\n");
+ }
+
+ usbd_msc_cfg.csw.dDataResidue -= size;
+ usbd_msc_cfg.csw.bStatus = CSW_STATUS_CMD_PASSED;
+}
+
+/**
+ * @brief SCSI COMMAND
+ */
+static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len);
+static bool SCSI_requestSense(uint8_t **data, uint32_t *len);
+static bool SCSI_inquiry(uint8_t **data, uint32_t *len);
+static bool SCSI_startStopUnit(uint8_t **data, uint32_t *len);
+static bool SCSI_preventAllowMediaRemoval(uint8_t **data, uint32_t *len);
+static bool SCSI_modeSense6(uint8_t **data, uint32_t *len);
+static bool SCSI_modeSense10(uint8_t **data, uint32_t *len);
+static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len);
+static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len);
+static bool SCSI_read10(uint8_t **data, uint32_t *len);
+static bool SCSI_read12(uint8_t **data, uint32_t *len);
+static bool SCSI_write10(uint8_t **data, uint32_t *len);
+static bool SCSI_write12(uint8_t **data, uint32_t *len);
+static bool SCSI_verify10(uint8_t **data, uint32_t *len);
+
+/**
+* @brief SCSI_SenseCode
+* Load the last error code in the error list
+* @param sKey: Sense Key
+* @param ASC: Additional Sense Code
+* @retval none
+
+*/
+static void SCSI_SenseCode(uint8_t sKey, uint8_t ASC)
+{
+ usbd_msc_cfg.sKey = sKey;
+ usbd_msc_cfg.ASC = ASC;
+}
+
+static bool SCSI_processRead(void)
+{
+ uint32_t transfer_len;
+
+ USB_LOG_DBG("read addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
+
+ transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, MASS_STORAGE_BULK_EP_MPS);
+
+ /* we read an entire block */
+ if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
+ if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
+ SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_UNRECOVERED_READ_ERROR);
+ return false;
+ }
+ }
+
+ usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
+ &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], transfer_len, NULL);
+
+ usbd_msc_cfg.scsi_blk_addr += transfer_len;
+ usbd_msc_cfg.scsi_blk_len -= transfer_len;
+ usbd_msc_cfg.csw.dDataResidue -= transfer_len;
+
+ if (usbd_msc_cfg.scsi_blk_len == 0) {
+ usbd_msc_cfg.stage = MSC_SEND_CSW;
+ }
+
+ return true;
+}
+
+static bool SCSI_processWrite()
+{
+ uint32_t bytes_read;
+ USB_LOG_DBG("write addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
+
+ /* we fill an array in RAM of 1 block before writing it in memory */
+ usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], MASS_STORAGE_BULK_EP_MPS,
+ &bytes_read);
+
+ /* if the array is filled, write it in memory */
+ if ((usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size) + bytes_read >= usbd_msc_cfg.scsi_blk_size) {
+ if (usbd_msc_sector_write((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
+ SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_WRITE_FAULT);
+ return false;
+ }
+ }
+
+ usbd_msc_cfg.scsi_blk_addr += bytes_read;
+ usbd_msc_cfg.scsi_blk_len -= bytes_read;
+ usbd_msc_cfg.csw.dDataResidue -= bytes_read;
+
+ if (usbd_msc_cfg.scsi_blk_len == 0) {
+ sendCSW(CSW_STATUS_CMD_PASSED);
+ }
+
+ return true;
+}
+
+static bool SCSI_processVerify()
+{
+#if 0
+ uint32_t bytes_read;
+ uint8_t out_buffer[MASS_STORAGE_BULK_EP_MPS];
+
+ USB_LOG_DBG("verify addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
+
+ /* we fill an array in RAM of 1 block before writing it in memory */
+ usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, out_buffer, MASS_STORAGE_BULK_EP_MPS,
+ &bytes_read);
+
+ /* we read an entire block */
+ if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
+ if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
+ SCSI_SenseCode(SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_UNRECOVERED_READ_ERROR);
+ return false;
+ }
+ }
+
+ /* info are in RAM -> no need to re-read memory */
+ for (uint16_t i = 0U; i < bytes_read; i++) {
+ if (usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size + i] != out_buffer[i]) {
+ USB_LOG_DBG("Mismatch sector %d offset %d",
+ usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size, i);
+ memOK = false;
+ break;
+ }
+ }
+
+ usbd_msc_cfg.scsi_blk_addr += bytes_read;
+ usbd_msc_cfg.scsi_blk_len -= bytes_read;
+ usbd_msc_cfg.csw.dDataResidue -= bytes_read;
+
+ if (usbd_msc_cfg.scsi_blk_len == 0) {
+ sendCSW(CSW_STATUS_CMD_PASSED);
+ }
+#endif
+ return true;
+}
+
+static bool SCSI_CBWDecode()
+{
+ uint8_t *buf2send = usbd_msc_cfg.block_buffer;
+ uint32_t len2send = 0;
+ uint32_t bytes_read;
+ bool ret = false;
+
+ usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW,
+ &bytes_read);
+
+ if (bytes_read != sizeof(struct CBW)) {
+ USB_LOG_ERR("size != sizeof(cbw)\r\n");
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ usbd_msc_cfg.csw.dTag = usbd_msc_cfg.cbw.dTag;
+ usbd_msc_cfg.csw.dDataResidue = usbd_msc_cfg.cbw.dDataLength;
+
+ if ((usbd_msc_cfg.cbw.bLUN > 1) || (usbd_msc_cfg.cbw.dSignature != MSC_CBW_Signature) || (usbd_msc_cfg.cbw.bCBLength < 1) || (usbd_msc_cfg.cbw.bCBLength > 16)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ } else {
+ switch (usbd_msc_cfg.cbw.CB[0]) {
+ case SCSI_TEST_UNIT_READY:
+ ret = SCSI_testUnitReady(&buf2send, &len2send);
+ break;
+ case SCSI_REQUEST_SENSE:
+ ret = SCSI_requestSense(&buf2send, &len2send);
+ break;
+ case SCSI_INQUIRY:
+ ret = SCSI_inquiry(&buf2send, &len2send);
+ break;
+ case SCSI_START_STOP_UNIT:
+ ret = SCSI_startStopUnit(&buf2send, &len2send);
+ break;
+ case SCSI_PREVENT_ALLOW_MEDIA_REMOVAL:
+ ret = SCSI_preventAllowMediaRemoval(&buf2send, &len2send);
+ break;
+ case SCSI_MODE_SENSE6:
+ ret = SCSI_modeSense6(&buf2send, &len2send);
+ break;
+ case SCSI_MODE_SENSE10:
+ ret = SCSI_modeSense10(&buf2send, &len2send);
+ break;
+ case SCSI_READ_FORMAT_CAPACITIES:
+ ret = SCSI_readFormatCapacity(&buf2send, &len2send);
+ break;
+ case SCSI_READ_CAPACITY10:
+ ret = SCSI_readCapacity10(&buf2send, &len2send);
+ break;
+ case SCSI_READ10:
+ ret = SCSI_read10(NULL, 0);
+ break;
+ case SCSI_READ12:
+ ret = SCSI_read12(NULL, 0);
+ break;
+ case SCSI_WRITE10:
+ ret = SCSI_write10(NULL, 0);
+ break;
+ case SCSI_WRITE12:
+ ret = SCSI_write12(NULL, 0);
+ break;
+ case SCSI_VERIFY10:
+ ret = SCSI_verify10(NULL, 0);
+ break;
+
+ default:
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ USB_LOG_WRN("unsupported cmd:0x%02x\r\n", usbd_msc_cfg.cbw.CB[0]);
+ ret = false;
+ break;
+ }
+ }
+ if (ret) {
+ if (usbd_msc_cfg.stage == MSC_READ_CBW) {
+ if (len2send) {
+ sendLastData(buf2send, len2send);
+ } else {
+ sendCSW(CSW_STATUS_CMD_PASSED);
+ }
+ }
+ }
+ return ret;
+}
+
+static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len)
+{
+ if (usbd_msc_cfg.cbw.dDataLength != 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+ *data = NULL;
+ *len = 0;
+ return true;
+}
+
+static bool SCSI_requestSense(uint8_t **data, uint32_t *len)
+{
+ uint8_t data_len = REQUEST_SENSE_DATA_LEN;
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.CB[4] < REQUEST_SENSE_DATA_LEN) {
+ data_len = usbd_msc_cfg.cbw.CB[4];
+ }
+
+ uint8_t request_sense[REQUEST_SENSE_DATA_LEN] = {
+ 0x70,
+ 0x00,
+ 0x00, /* Sense Key */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ REQUEST_SENSE_DATA_LEN - 8,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, /* Additional Sense Code */
+ 0x00, /* Additional Sense Request */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ };
+
+ request_sense[2] = usbd_msc_cfg.sKey;
+ request_sense[12] = usbd_msc_cfg.ASC;
+ request_sense[13] = usbd_msc_cfg.ASQ;
+#if 0
+ request_sense[ 2] = 0x06; /* UNIT ATTENTION */
+ request_sense[12] = 0x28; /* Additional Sense Code: Not ready to ready transition */
+ request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
+#endif
+#if 0
+ request_sense[ 2] = 0x02; /* NOT READY */
+ request_sense[12] = 0x3A; /* Additional Sense Code: Medium not present */
+ request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
+#endif
+#if 0
+ request_sense[ 2] = 0x05; /* ILLEGAL REQUEST */
+ request_sense[12] = 0x20; /* Additional Sense Code: Invalid command */
+ request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
+#endif
+#if 0
+ request_sense[ 2] = 0x00; /* NO SENSE */
+ request_sense[12] = 0x00; /* Additional Sense Code: No additional code */
+ request_sense[13] = 0x00; /* Additional Sense Code Qualifier */
+#endif
+
+ memcpy(*data, (uint8_t *)request_sense, data_len);
+ *len = data_len;
+ return true;
+}
+
+static bool SCSI_inquiry(uint8_t **data, uint32_t *len)
+{
+ uint8_t data_len = STANDARD_INQUIRY_DATA_LEN;
+
+ uint8_t inquiry00[6] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ (0x06 - 4U),
+ 0x00,
+ 0x80
+ };
+
+ /* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */
+ uint8_t inquiry80[8] = {
+ 0x00,
+ 0x80,
+ 0x00,
+ 0x08,
+ 0x20, /* Put Product Serial number */
+ 0x20,
+ 0x20,
+ 0x20
+ };
+
+ uint8_t inquiry[STANDARD_INQUIRY_DATA_LEN] = {
+ /* 36 */
+
+ /* LUN 0 */
+ 0x00,
+ 0x80,
+ 0x02,
+ 0x02,
+ (STANDARD_INQUIRY_DATA_LEN - 5),
+ 0x00,
+ 0x00,
+ 0x00,
+ 'B', 'o', 'u', 'f', 'f', 'a', 'l', 'o', /* Manufacturer : 8 bytes */
+ 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ '0', '.', '0', '1' /* Version : 4 Bytes */
+ };
+
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ if ((usbd_msc_cfg.cbw.CB[1] & 0x01U) != 0U) { /* Evpd is set */
+ if (usbd_msc_cfg.cbw.CB[2] == 0U) { /* Request for Supported Vital Product Data Pages*/
+ data_len = 0x06;
+ memcpy(*data, (uint8_t *)inquiry00, data_len);
+ } else if (usbd_msc_cfg.cbw.CB[2] == 0x80U) { /* Request for VPD page 0x80 Unit Serial Number */
+ data_len = 0x08;
+ memcpy(*data, (uint8_t *)inquiry80, data_len);
+ } else { /* Request Not supported */
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELED_IN_COMMAND);
+ return false;
+ }
+ } else {
+ if (usbd_msc_cfg.cbw.CB[4] < STANDARD_INQUIRY_DATA_LEN) {
+ data_len = usbd_msc_cfg.cbw.CB[4];
+ }
+ memcpy(*data, (uint8_t *)inquiry, data_len);
+ }
+
+ *len = data_len;
+ return true;
+}
+
+static bool SCSI_startStopUnit(uint8_t **data, uint32_t *len)
+{
+ if (usbd_msc_cfg.cbw.dDataLength != 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x1U) /* START=1 */
+ {
+ //SCSI_MEDIUM_UNLOCKED;
+ } else if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */
+ {
+ //SCSI_MEDIUM_EJECTED;
+ } else if ((usbd_msc_cfg.cbw.CB[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */
+ {
+ //SCSI_MEDIUM_UNLOCKED;
+ } else {
+ }
+
+ *data = NULL;
+ *len = 0;
+ return true;
+}
+
+static bool SCSI_preventAllowMediaRemoval(uint8_t **data, uint32_t *len)
+{
+ if (usbd_msc_cfg.cbw.dDataLength != 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+ if (usbd_msc_cfg.cbw.CB[4] == 0U) {
+ //SCSI_MEDIUM_UNLOCKED;
+ } else {
+ //SCSI_MEDIUM_LOCKED;
+ }
+ *data = NULL;
+ *len = 0;
+ return true;
+}
+
+static bool SCSI_modeSense6(uint8_t **data, uint32_t *len)
+{
+ uint8_t data_len = 4;
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+ if (usbd_msc_cfg.cbw.CB[4] < MODE_SENSE6_DATA_LEN) {
+ data_len = usbd_msc_cfg.cbw.CB[4];
+ }
+
+ uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
+
+ memcpy(*data, (uint8_t *)sense6, data_len);
+ *len = data_len;
+ return true;
+}
+
+static bool SCSI_modeSense10(uint8_t **data, uint32_t *len)
+{
+ uint8_t data_len = MODE_SENSE10_DATA_LEN;
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.CB[8] < MODE_SENSE10_DATA_LEN) {
+ data_len = usbd_msc_cfg.cbw.CB[8];
+ }
+
+ uint8_t sense10[MODE_SENSE10_DATA_LEN] = {
+ 0x00,
+ 0x26,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x12,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ };
+
+ memcpy(*data, (uint8_t *)sense10, data_len);
+ *len = data_len;
+ return true;
+}
+
+static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len)
+{
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+ uint8_t format_capacity[READ_FORMAT_CAPACITY_DATA_LEN] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x08, /* Capacity List Length */
+ (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 24) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 16) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 8) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_nbr >> 0) & 0xff),
+
+ 0x02, /* Descriptor Code: Formatted Media */
+ 0x00,
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 8) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 0) & 0xff),
+ };
+
+ memcpy(*data, (uint8_t *)format_capacity, READ_FORMAT_CAPACITY_DATA_LEN);
+ *len = READ_FORMAT_CAPACITY_DATA_LEN;
+ return true;
+}
+
+static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len)
+{
+ if (usbd_msc_cfg.cbw.dDataLength == 0U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ uint8_t capacity10[READ_CAPACITY10_DATA_LEN] = {
+ (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 24) & 0xff),
+ (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 16) & 0xff),
+ (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 8) & 0xff),
+ (uint8_t)(((usbd_msc_cfg.scsi_blk_nbr - 1) >> 0) & 0xff),
+
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 24) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 16) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 8) & 0xff),
+ (uint8_t)((usbd_msc_cfg.scsi_blk_size >> 0) & 0xff),
+ };
+
+ memcpy(*data, (uint8_t *)&capacity10, READ_CAPACITY10_DATA_LEN);
+ *len = READ_CAPACITY10_DATA_LEN;
+ return true;
+}
+
+static bool SCSI_read10(uint8_t **data, uint32_t *len)
+{
+ /* Logical Block Address of First Block */
+ uint32_t lba = 0;
+ uint32_t blk_num = 0;
+ if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x80U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
+ USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+ usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
+
+ /* Number of Blocks to transfer */
+ blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
+
+ usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
+
+ if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ADDRESS_OUT_OF_RANGE);
+ USB_LOG_ERR("LBA out of range\r\n");
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
+ USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
+ return false;
+ }
+ usbd_msc_cfg.stage = MSC_DATA_IN;
+ return SCSI_processRead();
+}
+
+static bool SCSI_read12(uint8_t **data, uint32_t *len)
+{
+ /* Logical Block Address of First Block */
+ uint32_t lba = 0;
+ uint32_t blk_num = 0;
+ if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x80U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
+ USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+ usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
+
+ /* Number of Blocks to transfer */
+ blk_num = GET_BE32(&usbd_msc_cfg.cbw.CB[6]);
+
+ USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
+ usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
+
+ if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ADDRESS_OUT_OF_RANGE);
+ USB_LOG_ERR("LBA out of range\r\n");
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
+ USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
+ return false;
+ }
+ usbd_msc_cfg.stage = MSC_DATA_IN;
+ return SCSI_processRead();
+}
+
+static bool SCSI_write10(uint8_t **data, uint32_t *len)
+{
+ /* Logical Block Address of First Block */
+ uint32_t lba = 0;
+ uint32_t blk_num = 0;
+ if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
+ USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+ usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
+
+ /* Number of Blocks to transfer */
+ blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
+
+ USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
+ usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
+
+ if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
+ USB_LOG_ERR("LBA out of range\r\n");
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
+ return false;
+ }
+ usbd_msc_cfg.stage = MSC_DATA_OUT;
+ return true;
+}
+
+static bool SCSI_write12(uint8_t **data, uint32_t *len)
+{
+ /* Logical Block Address of First Block */
+ uint32_t lba = 0;
+ uint32_t blk_num = 0;
+ if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
+ USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+ usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
+
+ /* Number of Blocks to transfer */
+ blk_num = GET_BE32(&usbd_msc_cfg.cbw.CB[6]);
+
+ USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
+ usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
+
+ if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
+ USB_LOG_ERR("LBA out of range\r\n");
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
+ return false;
+ }
+ usbd_msc_cfg.stage = MSC_DATA_OUT;
+ return true;
+}
+
+static bool SCSI_verify10(uint8_t **data, uint32_t *len)
+{
+ /* Logical Block Address of First Block */
+ uint32_t lba = 0;
+ uint32_t blk_num = 0;
+
+ if ((usbd_msc_cfg.cbw.CB[1] & 0x02U) == 0x00U) {
+ return true;
+ }
+
+ if (((usbd_msc_cfg.cbw.bmFlags & 0x80U) != 0x00U) || (usbd_msc_cfg.cbw.dDataLength == 0U)) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB);
+ return false;
+ }
+
+ if ((usbd_msc_cfg.cbw.CB[1] & 0x02U) == 0x02U) {
+ SCSI_SenseCode(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELED_IN_COMMAND);
+ return false; /* Error, Verify Mode Not supported*/
+ }
+
+ lba = GET_BE32(&usbd_msc_cfg.cbw.CB[2]);
+ USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+ usbd_msc_cfg.scsi_blk_addr = lba * usbd_msc_cfg.scsi_blk_size;
+
+ /* Number of Blocks to transfer */
+ blk_num = GET_BE16(&usbd_msc_cfg.cbw.CB[7]);
+
+ USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
+ usbd_msc_cfg.scsi_blk_len = blk_num * usbd_msc_cfg.scsi_blk_size;
+
+ if ((lba + blk_num) > usbd_msc_cfg.scsi_blk_nbr) {
+ USB_LOG_ERR("LBA out of range\r\n");
+ return false;
+ }
+
+ if (usbd_msc_cfg.cbw.dDataLength != usbd_msc_cfg.scsi_blk_len) {
+ return false;
+ }
+
+ memOK = true;
+ usbd_msc_cfg.stage = MSC_DATA_OUT;
+ return true;
+}
+
+static void mass_storage_bulk_out(uint8_t ep)
+{
+ switch (usbd_msc_cfg.stage) {
+ case MSC_READ_CBW:
+ if (SCSI_CBWDecode() == false) {
+ USB_LOG_ERR("Command:0x%02x decode err\r\n", usbd_msc_cfg.cbw.CB[0]);
+ usbd_msc_bot_abort();
+ return;
+ }
+ break;
+ /* last command is write10 or write12,and has caculated blk_addr and blk_len,so the device start reading data from host*/
+ case MSC_DATA_OUT:
+ switch (usbd_msc_cfg.cbw.CB[0]) {
+ case SCSI_WRITE10:
+ case SCSI_WRITE12:
+ if (SCSI_processWrite() == false) {
+ sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+ //return;
+ }
+ break;
+ case SCSI_VERIFY10:
+ if (SCSI_processVerify() == false) {
+ sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+ //return;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*set ep ack to recv next data*/
+ usbd_ep_read(ep, NULL, 0, NULL);
+}
+
+/**
+ * @brief EP Bulk IN handler, used to send data to the Host
+ *
+ * @param ep Endpoint address.
+ * @param ep_status Endpoint status code.
+ *
+ * @return N/A.
+ */
+static void mass_storage_bulk_in(uint8_t ep)
+{
+ switch (usbd_msc_cfg.stage) {
+ /* last command is read10 or read12,and has caculated blk_addr and blk_len,so the device has to send remain data to host*/
+ case MSC_DATA_IN:
+ switch (usbd_msc_cfg.cbw.CB[0]) {
+ case SCSI_READ10:
+ case SCSI_READ12:
+ if (SCSI_processRead() == false) {
+ sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ break;
+
+ /*the device has to send a CSW*/
+ case MSC_SEND_CSW:
+ sendCSW(CSW_STATUS_CMD_PASSED);
+ break;
+
+ /*the host has received the CSW*/
+ case MSC_WAIT_CSW:
+ usbd_msc_cfg.stage = MSC_READ_CBW;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void msc_storage_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ usbd_msc_reset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+static usbd_class_t msc_class;
+
+static usbd_interface_t msc_intf = {
+ .class_handler = msc_storage_class_request_handler,
+ .vendor_handler = NULL,
+ .notify_handler = msc_storage_notify_handler,
+};
+
+void usbd_msc_class_init(uint8_t out_ep, uint8_t in_ep)
+{
+ msc_class.name = "usbd_msc";
+
+ usbd_class_register(&msc_class);
+ usbd_class_add_interface(&msc_class, &msc_intf);
+
+ mass_ep_data[0].ep_addr = out_ep;
+ mass_ep_data[0].ep_cb = mass_storage_bulk_out;
+ mass_ep_data[1].ep_addr = in_ep;
+ mass_ep_data[1].ep_cb = mass_storage_bulk_in;
+
+ usbd_interface_add_endpoint(&msc_intf, &mass_ep_data[0]);
+ usbd_interface_add_endpoint(&msc_intf, &mass_ep_data[1]);
+}
diff --git a/class/msc/usbh_msc.c b/class/msc/usbh_msc.c
index a7498fa8..f47ecf4a 100644
--- a/class/msc/usbh_msc.c
+++ b/class/msc/usbh_msc.c
@@ -1,438 +1,438 @@
-/**
- * @file usbh_msc.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbh_core.h"
-#include "usbh_msc.h"
-#include "scsi.h"
-
-#define DEV_FORMAT "/dev/sd%c"
-#define DEV_NAMELEN 16
-
-static uint32_t g_devinuse = 0;
-
-/****************************************************************************
- * Name: usbh_msc_devno_alloc
- *
- * Description:
- * Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
- *
- ****************************************************************************/
-
-static int usbh_msc_devno_alloc(struct usbh_msc *priv)
-{
- uint32_t flags;
- int devno;
-
- flags = usb_osal_enter_critical_section();
- for (devno = 0; devno < 26; devno++) {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0) {
- g_devinuse |= bitno;
- priv->sdchar = 'a' + devno;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- }
-
- usb_osal_leave_critical_section(flags);
- return -EMFILE;
-}
-
-/****************************************************************************
- * Name: usbh_msc_devno_free
- *
- * Description:
- * Free a /dev/sd[n] minor number so that it can be used.
- *
- ****************************************************************************/
-
-static void usbh_msc_devno_free(struct usbh_msc *priv)
-{
- int devno = priv->sdchar - 'a';
-
- if (devno >= 0 && devno < 26) {
- uint32_t flags = usb_osal_enter_critical_section();
- g_devinuse &= ~(1 << devno);
- usb_osal_leave_critical_section(flags);
- }
-}
-
-/****************************************************************************
- * Name: usbh_msc_mkdevname
- *
- * Description:
- * Format a /dev/sd[n] device name given a minor number.
- *
- ****************************************************************************/
-
-static inline void usbh_msc_mkdevname(struct usbh_msc *priv, char *devname)
-{
- snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
-}
-
-static int usbh_msc_get_maxlun(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
-{
- struct usb_setup_packet *setup;
- struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
-
- setup = msc_class->setup;
-
- if (msc_class->intf != intf) {
- return -1;
- }
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = MSC_REQUEST_GET_MAX_LUN;
- setup->wValue = 0;
- setup->wIndex = intf;
- setup->wLength = 1;
-
- return usbh_control_transfer(hport->ep0, setup, buffer);
-}
-
-static void usbh_msc_cbw_dump(struct CBW *cbw)
-{
- int i;
-
- USB_LOG_INFO("CBW:\r\n");
- USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)cbw->dSignature);
- USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)cbw->dTag);
- USB_LOG_INFO(" datlen: 0x%08x\r\n", (unsigned int)cbw->dDataLength);
- USB_LOG_INFO(" flags: 0x%02x\r\n", cbw->bmFlags);
- USB_LOG_INFO(" lun: 0x%02x\r\n", cbw->bLUN);
- USB_LOG_INFO(" cblen: 0x%02x\r\n", cbw->bCBLength);
-
- USB_LOG_INFO("CB:\r\n");
- for (i = 0; i < cbw->bCBLength; i += 8) {
- USB_LOG_INFO(" 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
- cbw->CB[i], cbw->CB[i + 1], cbw->CB[i + 2],
- cbw->CB[i + 3], cbw->CB[i + 4], cbw->CB[i + 5],
- cbw->CB[i + 6], cbw->CB[i + 7]);
- }
-}
-
-static void usbh_msc_csw_dump(struct CSW *csw)
-{
- USB_LOG_INFO("CSW:\r\n");
- USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)csw->dSignature);
- USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)csw->dTag);
- USB_LOG_INFO(" residue: 0x%08x\r\n", (unsigned int)csw->dDataResidue);
- USB_LOG_INFO(" status: 0x%02x\r\n", csw->bStatus);
-}
-
-static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->bCBLength = SCSICMD_TESTUNITREADY_SIZEOF;
- cbw->CB[0] = SCSI_CMD_TESTUNITREADY;
-
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->bmFlags = 0x80;
- cbw->bCBLength = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
- cbw->dDataLength = SCSICMD_REQUESTSENSE_SIZEOF;
- cbw->CB[0] = SCSI_REQUEST_SENSE;
- cbw->CB[4] = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Receive the sense data response */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
- if (nbytes >= 0) {
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->dDataLength = SCSIRESP_INQUIRY_SIZEOF;
- cbw->bmFlags = 0x80;
- cbw->bCBLength = SCSICMD_INQUIRY_SIZEOF;
- cbw->CB[0] = SCSI_INQUIRY;
- cbw->CB[4] = SCSIRESP_INQUIRY_SIZEOF;
-
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Receive the sense data response */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_INQUIRY_SIZEOF);
- if (nbytes >= 0) {
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->dDataLength = SCSIRESP_READCAPACITY10_SIZEOF;
- cbw->bmFlags = 0x80;
- cbw->bCBLength = SCSICMD_READCAPACITY10_SIZEOF;
- cbw->CB[0] = SCSI_READ_CAPACITY10;
-
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Receive the sense data response */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_READCAPACITY10_SIZEOF);
- if (nbytes >= 0) {
- /* Save the capacity information */
- msc_class->blocknum = GET_BE32(&msc_class->tx_buffer[0]) + 1;
- msc_class->blocksize = GET_BE32(&msc_class->tx_buffer[4]);
- USB_LOG_INFO("capacity info:\r\n");
- USB_LOG_INFO("block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-int usbh_msc_mem_write(struct usbh_msc *msc_class, uint32_t sector, const uint8_t *buffer, uint32_t nsectors)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->dDataLength = (msc_class->blocksize * nsectors);
- cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
- cbw->CB[0] = SCSI_WRITE10;
-
- SET_BE24(&cbw->CB[2], sector);
- SET_BE24(&cbw->CB[7], nsectors);
-
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Send the user data */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)buffer, msc_class->blocksize * nsectors);
- if (nbytes >= 0) {
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-int usbh_msc_mem_read(struct usbh_msc *msc_class, uint32_t sector, const uint8_t *buffer, uint32_t nsectors)
-{
- int nbytes;
- struct CBW *cbw;
-
- /* Construct the CBW */
- cbw = (struct CBW *)msc_class->tx_buffer;
- memset(cbw, 0, USB_SIZEOF_MSC_CBW);
- cbw->dSignature = MSC_CBW_Signature;
-
- cbw->dDataLength = (msc_class->blocksize * nsectors);
- cbw->bmFlags = 0x80;
- cbw->bCBLength = SCSICMD_READ10_SIZEOF;
- cbw->CB[0] = SCSI_READ10;
-
- SET_BE24(&cbw->CB[2], sector);
- SET_BE24(&cbw->CB[7], nsectors);
-
- /* Send the CBW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
- if (nbytes >= 0) {
- /* Receive the user data */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, (uint8_t *)buffer, msc_class->blocksize * nsectors);
- if (nbytes >= 0) {
- /* Receive the CSW */
- nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
- if (nbytes >= 0) {
- usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
- }
- }
- }
- return nbytes < 0 ? (int)nbytes : 0;
-}
-
-int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
-{
- struct usbh_endpoint_cfg ep_cfg = { 0 };
- struct usb_endpoint_descriptor *ep_desc;
-
- char devname[DEV_NAMELEN];
- int ret;
-
- struct usbh_msc *msc_class = usb_malloc(sizeof(struct usbh_msc));
- if (msc_class == NULL) {
- USB_LOG_ERR("Fail to alloc msc_class\r\n");
- return -ENOMEM;
- }
-
- memset(msc_class, 0, sizeof(struct usbh_msc));
-
- usbh_msc_devno_alloc(msc_class);
- usbh_msc_mkdevname(msc_class, devname);
-
- hport->config.intf[intf].priv = msc_class;
-
- msc_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
- if (msc_class->setup == NULL) {
- USB_LOG_ERR("Fail to alloc setup\r\n");
- return -ENOMEM;
- }
- msc_class->tx_buffer = usb_iomalloc(128);
- if (msc_class->tx_buffer == NULL) {
- USB_LOG_ERR("Fail to alloc tx_buffer\r\n");
- return -ENOMEM;
- }
- ret = usbh_msc_get_maxlun(hport, intf, msc_class->tx_buffer);
- if (ret < 0) {
- return ret;
- }
-
- USB_LOG_INFO("Get max LUN:%u\r\n", msc_class->tx_buffer[0]);
-
- for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
- ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
-
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_interval = ep_desc->bInterval;
- ep_cfg.hport = hport;
- if (ep_desc->bEndpointAddress & 0x80) {
- usbh_ep_alloc(&msc_class->bulkin, &ep_cfg);
- } else {
- usbh_ep_alloc(&msc_class->bulkout, &ep_cfg);
- }
- }
-
- USB_LOG_INFO("Register MSC Class:%s\r\n", devname);
-
- ret = usbh_msc_scsi_testunitready(msc_class);
- ret = usbh_msc_scsi_inquiry(msc_class);
- ret = usbh_msc_scsi_readcapacity10(msc_class);
-
- return ret;
-}
-
-int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
-{
- char devname[DEV_NAMELEN];
- int ret = 0;
-
- struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
-
- if (msc_class) {
- usbh_msc_devno_free(msc_class);
- usbh_msc_mkdevname(msc_class, devname);
-
- if (msc_class->bulkin) {
- ret = usb_ep_cancel(msc_class->bulkin);
- if (ret < 0) {
- }
- usbh_ep_free(msc_class->bulkin);
- }
-
- if (msc_class->bulkout) {
- ret = usb_ep_cancel(msc_class->bulkout);
- if (ret < 0) {
- }
- usbh_ep_free(msc_class->bulkout);
- }
-
- if (msc_class->setup)
- usb_iofree(msc_class->setup);
- if (msc_class->tx_buffer)
- usb_iofree(msc_class->tx_buffer);
-
- usb_free(msc_class);
-
- hport->config.intf[intf].priv = NULL;
-
- USB_LOG_INFO("Unregister MSC Class:%s\r\n", devname);
- }
-
- return ret;
-}
-
-const struct usbh_class_driver msc_class_driver = {
- .driver_name = "msc",
- .connect = usbh_msc_connect,
- .disconnect = usbh_msc_disconnect
+/**
+ * @file usbh_msc.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbh_core.h"
+#include "usbh_msc.h"
+#include "scsi.h"
+
+#define DEV_FORMAT "/dev/sd%c"
+#define DEV_NAMELEN 16
+
+static uint32_t g_devinuse = 0;
+
+/****************************************************************************
+ * Name: usbh_msc_devno_alloc
+ *
+ * Description:
+ * Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
+ *
+ ****************************************************************************/
+
+static int usbh_msc_devno_alloc(struct usbh_msc *priv)
+{
+ uint32_t flags;
+ int devno;
+
+ flags = usb_osal_enter_critical_section();
+ for (devno = 0; devno < 26; devno++) {
+ uint32_t bitno = 1 << devno;
+ if ((g_devinuse & bitno) == 0) {
+ g_devinuse |= bitno;
+ priv->sdchar = 'a' + devno;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ }
+
+ usb_osal_leave_critical_section(flags);
+ return -EMFILE;
+}
+
+/****************************************************************************
+ * Name: usbh_msc_devno_free
+ *
+ * Description:
+ * Free a /dev/sd[n] minor number so that it can be used.
+ *
+ ****************************************************************************/
+
+static void usbh_msc_devno_free(struct usbh_msc *priv)
+{
+ int devno = priv->sdchar - 'a';
+
+ if (devno >= 0 && devno < 26) {
+ uint32_t flags = usb_osal_enter_critical_section();
+ g_devinuse &= ~(1 << devno);
+ usb_osal_leave_critical_section(flags);
+ }
+}
+
+/****************************************************************************
+ * Name: usbh_msc_mkdevname
+ *
+ * Description:
+ * Format a /dev/sd[n] device name given a minor number.
+ *
+ ****************************************************************************/
+
+static inline void usbh_msc_mkdevname(struct usbh_msc *priv, char *devname)
+{
+ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
+}
+
+static int usbh_msc_get_maxlun(struct usbh_hubport *hport, uint8_t intf, uint8_t *buffer)
+{
+ struct usb_setup_packet *setup;
+ struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
+
+ setup = msc_class->setup;
+
+ if (msc_class->intf != intf) {
+ return -1;
+ }
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = MSC_REQUEST_GET_MAX_LUN;
+ setup->wValue = 0;
+ setup->wIndex = intf;
+ setup->wLength = 1;
+
+ return usbh_control_transfer(hport->ep0, setup, buffer);
+}
+
+static void usbh_msc_cbw_dump(struct CBW *cbw)
+{
+ int i;
+
+ USB_LOG_INFO("CBW:\r\n");
+ USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)cbw->dSignature);
+ USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)cbw->dTag);
+ USB_LOG_INFO(" datlen: 0x%08x\r\n", (unsigned int)cbw->dDataLength);
+ USB_LOG_INFO(" flags: 0x%02x\r\n", cbw->bmFlags);
+ USB_LOG_INFO(" lun: 0x%02x\r\n", cbw->bLUN);
+ USB_LOG_INFO(" cblen: 0x%02x\r\n", cbw->bCBLength);
+
+ USB_LOG_INFO("CB:\r\n");
+ for (i = 0; i < cbw->bCBLength; i += 8) {
+ USB_LOG_INFO(" 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
+ cbw->CB[i], cbw->CB[i + 1], cbw->CB[i + 2],
+ cbw->CB[i + 3], cbw->CB[i + 4], cbw->CB[i + 5],
+ cbw->CB[i + 6], cbw->CB[i + 7]);
+ }
+}
+
+static void usbh_msc_csw_dump(struct CSW *csw)
+{
+ USB_LOG_INFO("CSW:\r\n");
+ USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)csw->dSignature);
+ USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)csw->dTag);
+ USB_LOG_INFO(" residue: 0x%08x\r\n", (unsigned int)csw->dDataResidue);
+ USB_LOG_INFO(" status: 0x%02x\r\n", csw->bStatus);
+}
+
+static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->bCBLength = SCSICMD_TESTUNITREADY_SIZEOF;
+ cbw->CB[0] = SCSI_CMD_TESTUNITREADY;
+
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->bmFlags = 0x80;
+ cbw->bCBLength = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
+ cbw->dDataLength = SCSICMD_REQUESTSENSE_SIZEOF;
+ cbw->CB[0] = SCSI_REQUEST_SENSE;
+ cbw->CB[4] = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Receive the sense data response */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
+ if (nbytes >= 0) {
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->dDataLength = SCSIRESP_INQUIRY_SIZEOF;
+ cbw->bmFlags = 0x80;
+ cbw->bCBLength = SCSICMD_INQUIRY_SIZEOF;
+ cbw->CB[0] = SCSI_INQUIRY;
+ cbw->CB[4] = SCSIRESP_INQUIRY_SIZEOF;
+
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Receive the sense data response */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_INQUIRY_SIZEOF);
+ if (nbytes >= 0) {
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->dDataLength = SCSIRESP_READCAPACITY10_SIZEOF;
+ cbw->bmFlags = 0x80;
+ cbw->bCBLength = SCSICMD_READCAPACITY10_SIZEOF;
+ cbw->CB[0] = SCSI_READ_CAPACITY10;
+
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Receive the sense data response */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_READCAPACITY10_SIZEOF);
+ if (nbytes >= 0) {
+ /* Save the capacity information */
+ msc_class->blocknum = GET_BE32(&msc_class->tx_buffer[0]) + 1;
+ msc_class->blocksize = GET_BE32(&msc_class->tx_buffer[4]);
+ USB_LOG_INFO("capacity info:\r\n");
+ USB_LOG_INFO("block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+int usbh_msc_mem_write(struct usbh_msc *msc_class, uint32_t sector, const uint8_t *buffer, uint32_t nsectors)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->dDataLength = (msc_class->blocksize * nsectors);
+ cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
+ cbw->CB[0] = SCSI_WRITE10;
+
+ SET_BE24(&cbw->CB[2], sector);
+ SET_BE24(&cbw->CB[7], nsectors);
+
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Send the user data */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)buffer, msc_class->blocksize * nsectors);
+ if (nbytes >= 0) {
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+int usbh_msc_mem_read(struct usbh_msc *msc_class, uint32_t sector, const uint8_t *buffer, uint32_t nsectors)
+{
+ int nbytes;
+ struct CBW *cbw;
+
+ /* Construct the CBW */
+ cbw = (struct CBW *)msc_class->tx_buffer;
+ memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+ cbw->dSignature = MSC_CBW_Signature;
+
+ cbw->dDataLength = (msc_class->blocksize * nsectors);
+ cbw->bmFlags = 0x80;
+ cbw->bCBLength = SCSICMD_READ10_SIZEOF;
+ cbw->CB[0] = SCSI_READ10;
+
+ SET_BE24(&cbw->CB[2], sector);
+ SET_BE24(&cbw->CB[7], nsectors);
+
+ /* Send the CBW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+ if (nbytes >= 0) {
+ /* Receive the user data */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, (uint8_t *)buffer, msc_class->blocksize * nsectors);
+ if (nbytes >= 0) {
+ /* Receive the CSW */
+ nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+ if (nbytes >= 0) {
+ usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
+ }
+ }
+ }
+ return nbytes < 0 ? (int)nbytes : 0;
+}
+
+int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+ struct usbh_endpoint_cfg ep_cfg = { 0 };
+ struct usb_endpoint_descriptor *ep_desc;
+
+ char devname[DEV_NAMELEN];
+ int ret;
+
+ struct usbh_msc *msc_class = usb_malloc(sizeof(struct usbh_msc));
+ if (msc_class == NULL) {
+ USB_LOG_ERR("Fail to alloc msc_class\r\n");
+ return -ENOMEM;
+ }
+
+ memset(msc_class, 0, sizeof(struct usbh_msc));
+
+ usbh_msc_devno_alloc(msc_class);
+ usbh_msc_mkdevname(msc_class, devname);
+
+ hport->config.intf[intf].priv = msc_class;
+
+ msc_class->setup = usb_iomalloc(sizeof(struct usb_setup_packet));
+ if (msc_class->setup == NULL) {
+ USB_LOG_ERR("Fail to alloc setup\r\n");
+ return -ENOMEM;
+ }
+ msc_class->tx_buffer = usb_iomalloc(128);
+ if (msc_class->tx_buffer == NULL) {
+ USB_LOG_ERR("Fail to alloc tx_buffer\r\n");
+ return -ENOMEM;
+ }
+ ret = usbh_msc_get_maxlun(hport, intf, msc_class->tx_buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ USB_LOG_INFO("Get max LUN:%u\r\n", msc_class->tx_buffer[0]);
+
+ for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
+ ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
+
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_interval = ep_desc->bInterval;
+ ep_cfg.hport = hport;
+ if (ep_desc->bEndpointAddress & 0x80) {
+ usbh_ep_alloc(&msc_class->bulkin, &ep_cfg);
+ } else {
+ usbh_ep_alloc(&msc_class->bulkout, &ep_cfg);
+ }
+ }
+
+ USB_LOG_INFO("Register MSC Class:%s\r\n", devname);
+
+ ret = usbh_msc_scsi_testunitready(msc_class);
+ ret = usbh_msc_scsi_inquiry(msc_class);
+ ret = usbh_msc_scsi_readcapacity10(msc_class);
+
+ return ret;
+}
+
+int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+ char devname[DEV_NAMELEN];
+ int ret = 0;
+
+ struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
+
+ if (msc_class) {
+ usbh_msc_devno_free(msc_class);
+ usbh_msc_mkdevname(msc_class, devname);
+
+ if (msc_class->bulkin) {
+ ret = usb_ep_cancel(msc_class->bulkin);
+ if (ret < 0) {
+ }
+ usbh_ep_free(msc_class->bulkin);
+ }
+
+ if (msc_class->bulkout) {
+ ret = usb_ep_cancel(msc_class->bulkout);
+ if (ret < 0) {
+ }
+ usbh_ep_free(msc_class->bulkout);
+ }
+
+ if (msc_class->setup)
+ usb_iofree(msc_class->setup);
+ if (msc_class->tx_buffer)
+ usb_iofree(msc_class->tx_buffer);
+
+ usb_free(msc_class);
+
+ hport->config.intf[intf].priv = NULL;
+
+ USB_LOG_INFO("Unregister MSC Class:%s\r\n", devname);
+ }
+
+ return ret;
+}
+
+const struct usbh_class_driver msc_class_driver = {
+ .driver_name = "msc",
+ .connect = usbh_msc_connect,
+ .disconnect = usbh_msc_disconnect
}; \ No newline at end of file
diff --git a/class/msc/usbh_msc.h b/class/msc/usbh_msc.h
index ccc7806e..7318028a 100644
--- a/class/msc/usbh_msc.h
+++ b/class/msc/usbh_msc.h
@@ -1,49 +1,49 @@
-/**
- * @file usbh_msc.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBH_MSC_H
-#define _USBH_MSC_H
-
-#include "usb_msc.h"
-#include "usb_scsi.h"
-
-struct usbh_msc {
- struct usb_setup_packet *setup;
- uint8_t intf; /* Data interface number */
- uint8_t sdchar;
- usbh_epinfo_t bulkin; /* Bulk IN endpoint */
- usbh_epinfo_t bulkout; /* Bulk OUT endpoint */
- uint8_t *tx_buffer;
- uint32_t blocknum; /* Number of blocks on the USB mass storage device */
- uint16_t blocksize; /* Block size of USB mass storage device */
-};
-
-extern const struct usbh_class_driver msc_class_driver;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
+/**
+ * @file usbh_msc.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBH_MSC_H
+#define _USBH_MSC_H
+
+#include "usb_msc.h"
+#include "usb_scsi.h"
+
+struct usbh_msc {
+ struct usb_setup_packet *setup;
+ uint8_t intf; /* Data interface number */
+ uint8_t sdchar;
+ usbh_epinfo_t bulkin; /* Bulk IN endpoint */
+ usbh_epinfo_t bulkout; /* Bulk OUT endpoint */
+ uint8_t *tx_buffer;
+ uint32_t blocknum; /* Number of blocks on the USB mass storage device */
+ uint16_t blocksize; /* Block size of USB mass storage device */
+};
+
+extern const struct usbh_class_driver msc_class_driver;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
#endif \ No newline at end of file
diff --git a/class/video/usbd_video.c b/class/video/usbd_video.c
index ae71171d..ccf30da9 100644
--- a/class/video/usbd_video.c
+++ b/class/video/usbd_video.c
@@ -1,134 +1,134 @@
-/**
- * @file usbd_video.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-#include "usbd_video.h"
-
-extern struct video_probe_and_commit_controls probe;
-extern struct video_probe_and_commit_controls commit;
-
-int video_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("Video Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
-
- switch (setup->bRequest) {
- case VIDEO_REQUEST_SET_CUR:
- if (setup->wValue == 256) {
- memcpy((uint8_t *)&probe, *data, setup->wLength);
- } else if (setup->wValue == 512) {
- memcpy((uint8_t *)&commit, *data, setup->wLength);
- }
-
- break;
-
- case VIDEO_REQUEST_GET_CUR:
- if (setup->wValue == 256) {
- *data = (uint8_t *)&probe;
- } else if (setup->wValue == 512) {
- *data = (uint8_t *)&commit;
- }
-
- break;
-
- case VIDEO_REQUEST_GET_MIN:
- if (setup->wValue == 256) {
- *data = (uint8_t *)&probe;
- } else if (setup->wValue == 512) {
- *data = (uint8_t *)&commit;
- }
-
- break;
-
- case VIDEO_REQUEST_GET_MAX:
- if (setup->wValue == 256) {
- *data = (uint8_t *)&probe;
- } else if (setup->wValue == 512) {
- *data = (uint8_t *)&commit;
- }
-
- break;
-
- case VIDEO_REQUEST_GET_RES:
-
- break;
-
- case VIDEO_REQUEST_GET_LEN:
-
- break;
-
- case VIDEO_REQUEST_GET_INFO:
-
- break;
-
- case VIDEO_REQUEST_GET_DEF:
- if (setup->wLength == 256) {
- *data = (uint8_t *)&probe;
- } else if (setup->wLength == 512) {
- *data = (uint8_t *)&commit;
- }
-
- break;
-
- default:
- USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
-
- return 0;
-}
-
-void video_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
-
- break;
-
- case USBD_EVENT_SOF:
- usbd_video_sof_callback();
- break;
-
- case USBD_EVENT_SET_INTERFACE:
- usbd_video_set_interface_callback(((uint8_t *)arg)[3]);
- break;
-
- default:
- break;
- }
-}
-
-void usbd_video_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
-{
- static usbd_class_t *last_class = NULL;
-
- if (last_class != devclass) {
- last_class = devclass;
- usbd_class_register(devclass);
- }
-
- intf->class_handler = video_class_request_handler;
- intf->custom_handler = NULL;
- intf->vendor_handler = NULL;
- intf->notify_handler = video_notify_handler;
- usbd_class_add_interface(devclass, intf);
+/**
+ * @file usbd_video.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+#include "usbd_video.h"
+
+extern struct video_probe_and_commit_controls probe;
+extern struct video_probe_and_commit_controls commit;
+
+int video_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("Video Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ switch (setup->bRequest) {
+ case VIDEO_REQUEST_SET_CUR:
+ if (setup->wValue == 256) {
+ memcpy((uint8_t *)&probe, *data, setup->wLength);
+ } else if (setup->wValue == 512) {
+ memcpy((uint8_t *)&commit, *data, setup->wLength);
+ }
+
+ break;
+
+ case VIDEO_REQUEST_GET_CUR:
+ if (setup->wValue == 256) {
+ *data = (uint8_t *)&probe;
+ } else if (setup->wValue == 512) {
+ *data = (uint8_t *)&commit;
+ }
+
+ break;
+
+ case VIDEO_REQUEST_GET_MIN:
+ if (setup->wValue == 256) {
+ *data = (uint8_t *)&probe;
+ } else if (setup->wValue == 512) {
+ *data = (uint8_t *)&commit;
+ }
+
+ break;
+
+ case VIDEO_REQUEST_GET_MAX:
+ if (setup->wValue == 256) {
+ *data = (uint8_t *)&probe;
+ } else if (setup->wValue == 512) {
+ *data = (uint8_t *)&commit;
+ }
+
+ break;
+
+ case VIDEO_REQUEST_GET_RES:
+
+ break;
+
+ case VIDEO_REQUEST_GET_LEN:
+
+ break;
+
+ case VIDEO_REQUEST_GET_INFO:
+
+ break;
+
+ case VIDEO_REQUEST_GET_DEF:
+ if (setup->wLength == 256) {
+ *data = (uint8_t *)&probe;
+ } else if (setup->wLength == 512) {
+ *data = (uint8_t *)&commit;
+ }
+
+ break;
+
+ default:
+ USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+void video_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+
+ break;
+
+ case USBD_EVENT_SOF:
+ usbd_video_sof_callback();
+ break;
+
+ case USBD_EVENT_SET_INTERFACE:
+ usbd_video_set_interface_callback(((uint8_t *)arg)[3]);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void usbd_video_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
+{
+ static usbd_class_t *last_class = NULL;
+
+ if (last_class != devclass) {
+ last_class = devclass;
+ usbd_class_register(devclass);
+ }
+
+ intf->class_handler = video_class_request_handler;
+ intf->custom_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = video_notify_handler;
+ usbd_class_add_interface(devclass, intf);
} \ No newline at end of file
diff --git a/common/usb_dc.h b/common/usb_dc.h
index 139b0ae7..0b8ae7e7 100644
--- a/common/usb_dc.h
+++ b/common/usb_dc.h
@@ -1,200 +1,200 @@
-/**
- * @file usb_dc.h
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USB_DC_H
-#define _USB_DC_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * USB endpoint direction and number.
- */
-#define USB_EP_DIR_MASK 0x80U
-#define USB_EP_DIR_IN 0x80U
-#define USB_EP_DIR_OUT 0x00U
-
-/** Get endpoint index (number) from endpoint address */
-#define USB_EP_GET_IDX(ep) ((ep) & ~USB_EP_DIR_MASK)
-/** Get direction from endpoint address */
-#define USB_EP_GET_DIR(ep) ((ep)&USB_EP_DIR_MASK)
-/** Get endpoint address from endpoint index and direction */
-#define USB_EP_GET_ADDR(idx, dir) ((idx) | ((dir)&USB_EP_DIR_MASK))
-/** True if the endpoint is an IN endpoint */
-#define USB_EP_DIR_IS_IN(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_IN)
-/** True if the endpoint is an OUT endpoint */
-#define USB_EP_DIR_IS_OUT(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_OUT)
-
-/* Default USB control EP, always 0 and 0x80 */
-#define USB_CONTROL_OUT_EP0 0
-#define USB_CONTROL_IN_EP0 0x80
-
-/**< maximum packet size (MPS) for EP 0 */
-#define USB_CTRL_EP_MPS 64
-
-/**
- * USB endpoint Transfer Type mask.
- */
-#define USBD_EP_TYPE_CTRL 0
-#define USBD_EP_TYPE_ISOC 1
-#define USBD_EP_TYPE_BULK 2
-#define USBD_EP_TYPE_INTR 3
-#define USBD_EP_TYPE_MASK 3
-
-/**
- * @brief USB Endpoint Configuration.
- *
- * Structure containing the USB endpoint configuration.
- */
-struct usbd_endpoint_cfg {
- /** The number associated with the EP in the device
- * configuration structure
- * IN EP = 0x80 | \<endpoint number\>
- * OUT EP = 0x00 | \<endpoint number\>
- */
- uint8_t ep_addr;
- /** Endpoint Transfer Type.
- * May be Bulk, Interrupt, Control or Isochronous
- */
- uint8_t ep_type;
- /** Endpoint max packet size */
- uint16_t ep_mps;
-};
-
-/**
- * @brief USB Device Core Layer API
- * @defgroup _usb_device_core_api USB Device Core API
- * @{
- */
-
-/**
- * @brief Set USB device address
- *
- * @param[in] addr Device address
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_set_address(const uint8_t addr);
-
-/*
- * @brief configure and enable endpoint
- *
- * This function sets endpoint configuration according to one specified in USB
- * endpoint descriptor and then enables it for data transfers.
- *
- * @param [in] ep_desc Endpoint descriptor byte array
- *
- * @return true if successfully configured and enabled
- */
-int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg);
-/**
- * @brief Disable the selected endpoint
- *
- * Function to disable the selected endpoint. Upon success interrupts are
- * disabled for the corresponding endpoint and the endpoint is no longer able
- * for transmitting/receiving data.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_close(const uint8_t ep);
-/**
- * @brief Set stall condition for the selected endpoint
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_set_stall(const uint8_t ep);
-/**
- * @brief Clear stall condition for the selected endpoint
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_clear_stall(const uint8_t ep);
-/**
- * @brief Check if the selected endpoint is stalled
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[out] stalled Endpoint stall status
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled);
-/**
- * @brief Write data to the specified endpoint
- *
- * This function is called to write data to the specified endpoint. The
- * supplied usbd_endpoint_callback function will be called when data is transmitted
- * out.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data to write
- * @param[in] data_len Length of the data requested to write. This may
- * be zero for a zero length status packet.
- * @param[out] ret_bytes Bytes scheduled for transmission. This value
- * may be NULL if the application expects all
- * bytes to be written
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes);
-/**
- * @brief Read data from the specified endpoint
- *
- * This is similar to usb_dc_ep_read, the difference being that, it doesn't
- * clear the endpoint NAKs so that the consumer is not bogged down by further
- * upcalls till he is done with the processing of the data. The caller should
- * reactivate ep by setting max_data_len 0 do so.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data buffer to write to
- * @param[in] max_data_len Max length of data to read
- * @param[out] read_bytes Number of bytes read. If data is NULL and
- * max_data_len is 0 the number of bytes
- * available for read should be returned.
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes);
-
-/**
- * @}
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/**
+ * @file usb_dc.h
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USB_DC_H
+#define _USB_DC_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * USB endpoint direction and number.
+ */
+#define USB_EP_DIR_MASK 0x80U
+#define USB_EP_DIR_IN 0x80U
+#define USB_EP_DIR_OUT 0x00U
+
+/** Get endpoint index (number) from endpoint address */
+#define USB_EP_GET_IDX(ep) ((ep) & ~USB_EP_DIR_MASK)
+/** Get direction from endpoint address */
+#define USB_EP_GET_DIR(ep) ((ep)&USB_EP_DIR_MASK)
+/** Get endpoint address from endpoint index and direction */
+#define USB_EP_GET_ADDR(idx, dir) ((idx) | ((dir)&USB_EP_DIR_MASK))
+/** True if the endpoint is an IN endpoint */
+#define USB_EP_DIR_IS_IN(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_IN)
+/** True if the endpoint is an OUT endpoint */
+#define USB_EP_DIR_IS_OUT(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_OUT)
+
+/* Default USB control EP, always 0 and 0x80 */
+#define USB_CONTROL_OUT_EP0 0
+#define USB_CONTROL_IN_EP0 0x80
+
+/**< maximum packet size (MPS) for EP 0 */
+#define USB_CTRL_EP_MPS 64
+
+/**
+ * USB endpoint Transfer Type mask.
+ */
+#define USBD_EP_TYPE_CTRL 0
+#define USBD_EP_TYPE_ISOC 1
+#define USBD_EP_TYPE_BULK 2
+#define USBD_EP_TYPE_INTR 3
+#define USBD_EP_TYPE_MASK 3
+
+/**
+ * @brief USB Endpoint Configuration.
+ *
+ * Structure containing the USB endpoint configuration.
+ */
+struct usbd_endpoint_cfg {
+ /** The number associated with the EP in the device
+ * configuration structure
+ * IN EP = 0x80 | \<endpoint number\>
+ * OUT EP = 0x00 | \<endpoint number\>
+ */
+ uint8_t ep_addr;
+ /** Endpoint Transfer Type.
+ * May be Bulk, Interrupt, Control or Isochronous
+ */
+ uint8_t ep_type;
+ /** Endpoint max packet size */
+ uint16_t ep_mps;
+};
+
+/**
+ * @brief USB Device Core Layer API
+ * @defgroup _usb_device_core_api USB Device Core API
+ * @{
+ */
+
+/**
+ * @brief Set USB device address
+ *
+ * @param[in] addr Device address
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_set_address(const uint8_t addr);
+
+/*
+ * @brief configure and enable endpoint
+ *
+ * This function sets endpoint configuration according to one specified in USB
+ * endpoint descriptor and then enables it for data transfers.
+ *
+ * @param [in] ep_desc Endpoint descriptor byte array
+ *
+ * @return true if successfully configured and enabled
+ */
+int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg);
+/**
+ * @brief Disable the selected endpoint
+ *
+ * Function to disable the selected endpoint. Upon success interrupts are
+ * disabled for the corresponding endpoint and the endpoint is no longer able
+ * for transmitting/receiving data.
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_close(const uint8_t ep);
+/**
+ * @brief Set stall condition for the selected endpoint
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_set_stall(const uint8_t ep);
+/**
+ * @brief Clear stall condition for the selected endpoint
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_clear_stall(const uint8_t ep);
+/**
+ * @brief Check if the selected endpoint is stalled
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ * @param[out] stalled Endpoint stall status
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled);
+/**
+ * @brief Write data to the specified endpoint
+ *
+ * This function is called to write data to the specified endpoint. The
+ * supplied usbd_endpoint_callback function will be called when data is transmitted
+ * out.
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ * @param[in] data Pointer to data to write
+ * @param[in] data_len Length of the data requested to write. This may
+ * be zero for a zero length status packet.
+ * @param[out] ret_bytes Bytes scheduled for transmission. This value
+ * may be NULL if the application expects all
+ * bytes to be written
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes);
+/**
+ * @brief Read data from the specified endpoint
+ *
+ * This is similar to usb_dc_ep_read, the difference being that, it doesn't
+ * clear the endpoint NAKs so that the consumer is not bogged down by further
+ * upcalls till he is done with the processing of the data. The caller should
+ * reactivate ep by setting max_data_len 0 do so.
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ * listed in the device configuration table
+ * @param[in] data Pointer to data buffer to write to
+ * @param[in] max_data_len Max length of data to read
+ * @param[out] read_bytes Number of bytes read. If data is NULL and
+ * max_data_len is 0 the number of bytes
+ * available for read should be returned.
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/usb_def.h b/common/usb_def.h
index f6b9cbda..ae5a468f 100644
--- a/common/usb_def.h
+++ b/common/usb_def.h
@@ -1,671 +1,671 @@
-/**
- * @file usb_def.h
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef USB_DEF_H
-#define USB_DEF_H
-
-/* Useful define */
-#define USB_1_1 0x0110
-#define USB_2_0 0x0200
-/* Set USB version to 2.1 so that the host will request the BOS descriptor */
-#define USB_2_1 0x0210
-
-/* Device speeds */
-#define USB_SPEED_UNKNOWN 0 /* Transfer rate not yet set */
-#define USB_SPEED_LOW 1 /* USB 1.1 */
-#define USB_SPEED_FULL 2 /* USB 1.1 */
-#define USB_SPEED_HIGH 3 /* USB 2.0 */
-#define USB_SPEED_VARIABLE 4 /* Wireless USB 2.5 */
-
-/* Maximum number of devices per controller */
-#define USB_MAX_DEVICES (127)
-
-// USB PID Types
-#define USB_PID_OUT (0x01) /* Tokens */
-#define USB_PID_IN (0x09)
-#define USB_PID_SOF (0x05)
-#define USB_PID_SETUP (0x0d)
-
-#define USB_PID_DATA0 (0x03) /* Data */
-#define USB_PID_DATA1 (0x0b)
-#define USB_PID_DATA2 (0x07)
-#define USB_PID_MDATA (0x0f)
-
-#define USB_PID_ACK (0x02) /* Handshake */
-#define USB_PID_NAK (0x0a)
-#define USB_PID_STALL (0x0e)
-#define USB_PID_NYET (0x06)
-
-#define USB_PID_PRE (0x0c) /* Special */
-#define USB_PID_ERR (0x0c)
-#define USB_PID_SPLIT (0x08)
-#define USB_PID_PING (0x04)
-#define USB_PID_RESERVED (0x00)
-
-#define USB_REQUEST_DIR_SHIFT 7U /* Bits 7: Request dir */
-#define USB_REQUEST_DIR_OUT (0U << USB_REQUEST_DIR_SHIFT) /* Bit 7=0: Host-to-device */
-#define USB_REQUEST_DIR_IN (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Device-to-host */
-#define USB_REQUEST_DIR_MASK (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Direction bit */
-
-#define USB_REQUEST_TYPE_SHIFT 5U /* Bits 5:6: Request type */
-#define USB_REQUEST_STANDARD (0U << USB_REQUEST_TYPE_SHIFT)
-#define USB_REQUEST_CLASS (1U << USB_REQUEST_TYPE_SHIFT)
-#define USB_REQUEST_VENDOR (2U << USB_REQUEST_TYPE_SHIFT)
-#define USB_REQUEST_RESERVED (3U << USB_REQUEST_TYPE_SHIFT)
-#define USB_REQUEST_TYPE_MASK (3U << USB_REQUEST_TYPE_SHIFT)
-
-#define USB_REQUEST_RECIPIENT_SHIFT 0U /* Bits 0:4: Recipient */
-#define USB_REQUEST_RECIPIENT_DEVICE (0U << USB_REQUEST_RECIPIENT_SHIFT)
-#define USB_REQUEST_RECIPIENT_INTERFACE (1U << USB_REQUEST_RECIPIENT_SHIFT)
-#define USB_REQUEST_RECIPIENT_ENDPOINT (2U << USB_REQUEST_RECIPIENT_SHIFT)
-#define USB_REQUEST_RECIPIENT_OTHER (3U << USB_REQUEST_RECIPIENT_SHIFT)
-#define USB_REQUEST_RECIPIENT_MASK (3U << USB_REQUEST_RECIPIENT_SHIFT)
-
-/* USB Standard Request Codes */
-#define USB_REQUEST_GET_STATUS 0x00
-#define USB_REQUEST_CLEAR_FEATURE 0x01
-#define USB_REQUEST_SET_FEATURE 0x03
-#define USB_REQUEST_SET_ADDRESS 0x05
-#define USB_REQUEST_GET_DESCRIPTOR 0x06
-#define USB_REQUEST_SET_DESCRIPTOR 0x07
-#define USB_REQUEST_GET_CONFIGURATION 0x08
-#define USB_REQUEST_SET_CONFIGURATION 0x09
-#define USB_REQUEST_GET_INTERFACE 0x0A
-#define USB_REQUEST_SET_INTERFACE 0x0B
-#define USB_REQUEST_SYNCH_FRAME 0x0C
-#define USB_REQUEST_SET_ENCRYPTION 0x0D
-#define USB_REQUEST_GET_ENCRYPTION 0x0E
-#define USB_REQUEST_RPIPE_ABORT 0x0E
-#define USB_REQUEST_SET_HANDSHAKE 0x0F
-#define USB_REQUEST_RPIPE_RESET 0x0F
-#define USB_REQUEST_GET_HANDSHAKE 0x10
-#define USB_REQUEST_SET_CONNECTION 0x11
-#define USB_REQUEST_SET_SECURITY_DATA 0x12
-#define USB_REQUEST_GET_SECURITY_DATA 0x13
-#define USB_REQUEST_SET_WUSB_DATA 0x14
-#define USB_REQUEST_LOOPBACK_DATA_WRITE 0x15
-#define USB_REQUEST_LOOPBACK_DATA_READ 0x16
-#define USB_REQUEST_SET_INTERFACE_DS 0x17
-
-/* USB Standard Feature selectors */
-#define USB_FEATURE_ENDPOINT_HALT 0
-#define USB_FEATURE_SELF_POWERED 0
-#define USB_FEATURE_REMOTE_WAKEUP 1
-#define USB_FEATURE_TEST_MODE 2
-#define USB_FEATURE_BATTERY 2
-#define USB_FEATURE_BHNPENABLE 3
-#define USB_FEATURE_WUSBDEVICE 3
-#define USB_FEATURE_AHNPSUPPORT 4
-#define USB_FEATURE_AALTHNPSUPPORT 5
-#define USB_FEATURE_DEBUGMODE 6
-
-/* USB GET_STATUS Bit Values */
-#define USB_GETSTATUS_ENDPOINT_HALT 0x01
-#define USB_GETSTATUS_SELF_POWERED 0x01
-#define USB_GETSTATUS_REMOTE_WAKEUP 0x02
-
-/* USB Descriptor Types */
-#define USB_DESCRIPTOR_TYPE_DEVICE 0x01U
-#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02U
-#define USB_DESCRIPTOR_TYPE_STRING 0x03U
-#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04U
-#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05U
-#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06U
-#define USB_DESCRIPTOR_TYPE_OTHER_SPEED 0x07U
-#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08U
-#define USB_DESCRIPTOR_TYPE_OTG 0x09U
-#define USB_DESCRIPTOR_TYPE_DEBUG 0x0AU
-#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0BU
-#define USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE 0x0FU
-#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 0x10U
-#define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINTCOMP 0x11U
-
-/* Class Specific Descriptor */
-#define USB_CS_DESCRIPTOR_TYPE_DEVICE 0x21U
-#define USB_CS_DESCRIPTOR_TYPE_CONFIGURATION 0x22U
-#define USB_CS_DESCRIPTOR_TYPE_STRING 0x23U
-#define USB_CS_DESCRIPTOR_TYPE_INTERFACE 0x24U
-#define USB_CS_DESCRIPTOR_TYPE_ENDPOINT 0x25U
-
-#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ENDPOINT_COMPANION 0x30U
-#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ISO_ENDPOINT_COMPANION 0x31U
-
-/* USB Device Classes */
-#define USB_DEVICE_CLASS_RESERVED 0x00
-#define USB_DEVICE_CLASS_AUDIO 0x01
-#define USB_DEVICE_CLASS_CDC 0x02
-#define USB_DEVICE_CLASS_HID 0x03
-#define USB_DEVICE_CLASS_MONITOR 0x04
-#define USB_DEVICE_CLASS_PHYSICAL 0x05
-#define USB_DEVICE_CLASS_IMAGE 0x06
-#define USB_DEVICE_CLASS_PRINTER 0x07
-#define USB_DEVICE_CLASS_MASS_STORAGE 0x08
-#define USB_DEVICE_CLASS_HUB 0x09
-#define USB_DEVICE_CLASS_CDC_DATA 0x0a
-#define USB_DEVICE_CLASS_SMART_CARD 0x0b
-#define USB_DEVICE_CLASS_SECURITY 0x0d
-#define USB_DEVICE_CLASS_VIDEO 0x0e
-#define USB_DEVICE_CLASS_HEALTHCARE 0x0f
-#define USB_DEVICE_CLASS_DIAG_DEVICE 0xdc
-#define USB_DEVICE_CLASS_WIRELESS 0xe0
-#define USB_DEVICE_CLASS_MISC 0xef
-#define USB_DEVICE_CLASS_APP_SPECIFIC 0xfe
-#define USB_DEVICE_CLASS_VEND_SPECIFIC 0xff
-
-/* usb string index define */
-#define USB_STRING_LANGID_INDEX 0x00
-#define USB_STRING_MFC_INDEX 0x01
-#define USB_STRING_PRODUCT_INDEX 0x02
-#define USB_STRING_SERIAL_INDEX 0x03
-#define USB_STRING_CONFIG_INDEX 0x04
-#define USB_STRING_INTERFACE_INDEX 0x05
-#define USB_STRING_OS_INDEX 0x06
-#define USB_STRING_MAX USB_STRING_OS_INDEX
-/*
- * Devices supporting Microsoft OS Descriptors store special string
- * descriptor at fixed index (0xEE). It is read when a new device is
- * attached to a computer for the first time.
- */
-#define USB_OSDESC_STRING_DESC_INDEX 0xEE
-
-/* bmAttributes in Configuration Descriptor */
-#define USB_CONFIG_REMOTE_WAKEUP 0x20
-#define USB_CONFIG_POWERED_MASK 0x40
-#define USB_CONFIG_BUS_POWERED 0x80
-#define USB_CONFIG_SELF_POWERED 0xC0
-
-/* bMaxPower in Configuration Descriptor */
-#define USB_CONFIG_POWER_MA(mA) ((mA) / 2)
-
-/* bEndpointAddress in Endpoint Descriptor */
-#define USB_ENDPOINT_DIRECTION_MASK 0x80
-#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00)
-#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
-
-/* bmAttributes in Endpoint Descriptor */
-#define USB_ENDPOINT_TYPE_SHIFT 0
-#define USB_ENDPOINT_TYPE_CONTROL (0 << USB_ENDPOINT_TYPE_SHIFT)
-#define USB_ENDPOINT_TYPE_ISOCHRONOUS (1 << USB_ENDPOINT_TYPE_SHIFT)
-#define USB_ENDPOINT_TYPE_BULK (2 << USB_ENDPOINT_TYPE_SHIFT)
-#define USB_ENDPOINT_TYPE_INTERRUPT (3 << USB_ENDPOINT_TYPE_SHIFT)
-#define USB_ENDPOINT_TYPE_MASK (3 << USB_ENDPOINT_TYPE_SHIFT)
-
-#define USB_ENDPOINT_SYNC_SHIFT 2
-#define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION (0 << USB_ENDPOINT_SYNC_SHIFT)
-#define USB_ENDPOINT_SYNC_ASYNCHRONOUS (1 << USB_ENDPOINT_SYNC_SHIFT)
-#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << USB_ENDPOINT_SYNC_SHIFT)
-#define USB_ENDPOINT_SYNC_SYNCHRONOUS (3 << USB_ENDPOINT_SYNC_SHIFT)
-#define USB_ENDPOINT_SYNC_MASK (3 << USB_ENDPOINT_SYNC_SHIFT)
-
-#define USB_ENDPOINT_USAGE_SHIFT 4
-#define USB_ENDPOINT_USAGE_DATA (0 << USB_ENDPOINT_USAGE_SHIFT)
-#define USB_ENDPOINT_USAGE_FEEDBACK (1 << USB_ENDPOINT_USAGE_SHIFT)
-#define USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << USB_ENDPOINT_USAGE_SHIFT)
-#define USB_ENDPOINT_USAGE_MASK (3 << USB_ENDPOINT_USAGE_SHIFT)
-
-#define USB_ENDPOINT_MAX_ADJUSTABLE (1 << 7)
-
-/* bDevCapabilityType in Device Capability Descriptor */
-#define USB_DEVICE_CAPABILITY_WIRELESS_USB 1
-#define USB_DEVICE_CAPABILITY_USB_2_0_EXTENSION 2
-#define USB_DEVICE_CAPABILITY_SUPERSPEED_USB 3
-#define USB_DEVICE_CAPABILITY_CONTAINER_ID 4
-#define USB_DEVICE_CAPABILITY_PLATFORM 5
-#define USB_DEVICE_CAPABILITY_POWER_DELIVERY_CAPABILITY 6
-#define USB_DEVICE_CAPABILITY_BATTERY_INFO_CAPABILITY 7
-#define USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_CAPABILITY 8
-#define USB_DEVICE_CAPABILITY_PD_PROVIDER_PORT_CAPABILITY 9
-#define USB_DEVICE_CAPABILITY_SUPERSPEED_PLUS 10
-#define USB_DEVICE_CAPABILITY_PRECISION_TIME_MEASUREMENT 11
-#define USB_DEVICE_CAPABILITY_WIRELESS_USB_EXT 12
-
-#define USB_BOS_CAPABILITY_EXTENSION 0x02
-#define USB_BOS_CAPABILITY_PLATFORM 0x05
-
-/* OTG SET FEATURE Constants */
-#define USB_OTG_FEATURE_B_HNP_ENABLE 3 /* Enable B device to perform HNP */
-#define USB_OTG_FEATURE_A_HNP_SUPPORT 4 /* A device supports HNP */
-#define USB_OTG_FEATURE_A_ALT_HNP_SUPPORT 5 /* Another port on the A device supports HNP */
-
-/* WinUSB Microsoft OS 2.0 descriptor request codes */
-#define WINUSB_REQUEST_GET_DESCRIPTOR_SET 0x07
-#define WINUSB_REQUEST_SET_ALT_ENUM 0x08
-
-/* WinUSB Microsoft OS 2.0 descriptor sizes */
-#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
-#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
-#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
-
-/* WinUSB Microsoft OS 2.0 Descriptor Types */
-#define WINUSB_SET_HEADER_DESCRIPTOR_TYPE 0x00
-#define WINUSB_SUBSET_HEADER_CONFIGURATION_TYPE 0x01
-#define WINUSB_SUBSET_HEADER_FUNCTION_TYPE 0x02
-#define WINUSB_FEATURE_COMPATIBLE_ID_TYPE 0x03
-#define WINUSB_FEATURE_REG_PROPERTY_TYPE 0x04
-#define WINUSB_FEATURE_MIN_RESUME_TIME_TYPE 0x05
-#define WINUSB_FEATURE_MODEL_ID_TYPE 0x06
-#define WINUSB_FEATURE_CCGP_DEVICE_TYPE 0x07
-
-#define WINUSB_PROP_DATA_TYPE_REG_SZ 0x01
-#define WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ 0x07
-
-/* WebUSB Descriptor Types */
-#define WEBUSB_DESCRIPTOR_SET_HEADER_TYPE 0x00
-#define WEBUSB_CONFIGURATION_SUBSET_HEADER_TYPE 0x01
-#define WEBUSB_FUNCTION_SUBSET_HEADER_TYPE 0x02
-#define WEBUSB_URL_TYPE 0x03
-
-/* WebUSB Request Codes */
-#define WEBUSB_REQUEST_GET_URL 0x02
-
-/* bScheme in URL descriptor */
-#define WEBUSB_URL_SCHEME_HTTP 0x00
-#define WEBUSB_URL_SCHEME_HTTPS 0x01
-
-/* WebUSB Descriptor sizes */
-#define WEBUSB_DESCRIPTOR_SET_HEADER_SIZE 5
-#define WEBUSB_CONFIGURATION_SUBSET_HEADER_SIZE 4
-#define WEBUSB_FUNCTION_SUBSET_HEADER_SIZE 3
-
-/* Setup packet definition used to read raw data from USB line */
-struct usb_setup_packet {
- /** Request type. Bits 0:4 determine recipient, see
- * \ref usb_request_recipient. Bits 5:6 determine type, see
- * \ref usb_request_type. Bit 7 determines data transfer direction, see
- * \ref usb_endpoint_direction.
- */
- uint8_t bmRequestType;
-
- /** Request. If the type bits of bmRequestType are equal to
- * \ref usb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
- * "USB_REQUEST_TYPE_STANDARD" then this field refers to
- * \ref usb_standard_request. For other cases, use of this field is
- * application-specific. */
- uint8_t bRequest;
-
- /** Value. Varies according to request */
- uint16_t wValue;
-
- /** Index. Varies according to request, typically used to pass an index
- * or offset */
- uint16_t wIndex;
-
- /** Number of bytes to transfer */
- uint16_t wLength;
-} __PACKED;
-
-#define USB_SIZEOF_SETUP_PACKET 8
-
-/** Standard Device Descriptor */
-struct usb_device_descriptor {
- uint8_t bLength; /* Descriptor size in bytes = 18 */
- uint8_t bDescriptorType; /* DEVICE descriptor type = 1 */
- uint16_t bcdUSB; /* USB spec in BCD, e.g. 0x0200 */
- uint8_t bDeviceClass; /* Class code, if 0 see interface */
- uint8_t bDeviceSubClass; /* Sub-Class code, 0 if class = 0 */
- uint8_t bDeviceProtocol; /* Protocol, if 0 see interface */
- uint8_t bMaxPacketSize0; /* Endpoint 0 max. size */
- uint16_t idVendor; /* Vendor ID per USB-IF */
- uint16_t idProduct; /* Product ID per manufacturer */
- uint16_t bcdDevice; /* Device release # in BCD */
- uint8_t iManufacturer; /* Index to manufacturer string */
- uint8_t iProduct; /* Index to product string */
- uint8_t iSerialNumber; /* Index to serial number string */
- uint8_t bNumConfigurations; /* Number of possible configurations */
-} __PACKED;
-
-#define USB_SIZEOF_DEVICE_DESC 18
-
-/** Standard Configuration Descriptor */
-struct usb_configuration_descriptor {
- uint8_t bLength; /* Descriptor size in bytes = 9 */
- uint8_t bDescriptorType; /* CONFIGURATION type = 2 or 7 */
- uint16_t wTotalLength; /* Length of concatenated descriptors */
- uint8_t bNumInterfaces; /* Number of interfaces, this config. */
- uint8_t bConfigurationValue; /* Value to set this config. */
- uint8_t iConfiguration; /* Index to configuration string */
- uint8_t bmAttributes; /* Config. characteristics */
- uint8_t bMaxPower; /* Max.power from bus, 2mA units */
-} __PACKED;
-
-#define USB_SIZEOF_CONFIG_DESC 9
-
-/** Standard Interface Descriptor */
-struct usb_interface_descriptor {
- uint8_t bLength; /* Descriptor size in bytes = 9 */
- uint8_t bDescriptorType; /* INTERFACE descriptor type = 4 */
- uint8_t bInterfaceNumber; /* Interface no.*/
- uint8_t bAlternateSetting; /* Value to select this IF */
- uint8_t bNumEndpoints; /* Number of endpoints excluding 0 */
- uint8_t bInterfaceClass; /* Class code, 0xFF = vendor */
- uint8_t bInterfaceSubClass; /* Sub-Class code, 0 if class = 0 */
- uint8_t bInterfaceProtocol; /* Protocol, 0xFF = vendor */
- uint8_t iInterface; /* Index to interface string */
-} __PACKED;
-
-#define USB_SIZEOF_INTERFACE_DESC 9
-
-/** Standard Endpoint Descriptor */
-struct usb_endpoint_descriptor {
- uint8_t bLength; /* Descriptor size in bytes = 7 */
- uint8_t bDescriptorType; /* ENDPOINT descriptor type = 5 */
- uint8_t bEndpointAddress; /* Endpoint # 0 - 15 | IN/OUT */
- uint8_t bmAttributes; /* Transfer type */
- uint16_t wMaxPacketSize; /* Bits 10:0 = max. packet size */
- uint8_t bInterval; /* Polling interval in (micro) frames */
-} __PACKED;
-
-#define USB_SIZEOF_ENDPOINT_DESC 7
-
-/** Unicode (UTF16LE) String Descriptor */
-struct usb_string_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint16_t bString;
-} __PACKED;
-
-#define USB_SIZEOF_STRING_LANGID_DESC 4
-
-/* USB Interface Association Descriptor */
-struct usb_interface_association_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bFirstInterface;
- uint8_t bInterfaceCount;
- uint8_t bFunctionClass;
- uint8_t bFunctionSubClass;
- uint8_t bFunctionProtocol;
- uint8_t iFunction;
-} __PACKED;
-
-#define USB_SIZEOF_IAD_DESC 8
-
-/** USB device_qualifier descriptor */
-struct usb_device_qualifier_descriptor {
- uint8_t bLength; /* Descriptor size in bytes = 10 */
- uint8_t bDescriptorType; /* DEVICE QUALIFIER type = 6 */
- uint16_t bcdUSB; /* USB spec in BCD, e.g. 0x0200 */
- uint8_t bDeviceClass; /* Class code, if 0 see interface */
- uint8_t bDeviceSubClass; /* Sub-Class code, 0 if class = 0 */
- uint8_t bDeviceProtocol; /* Protocol, if 0 see interface */
- uint8_t bMaxPacketSize; /* Endpoint 0 max. size */
- uint8_t bNumConfigurations; /* Number of possible configurations */
- uint8_t bReserved; /* Reserved = 0 */
-} __PACKED;
-
-#define USB_SIZEOF_DEVICE_QUALIFIER_DESC 10
-
-/* Microsoft OS function descriptor.
- * This can be used to request a specific driver (such as WINUSB) to be
- * loaded on Windows. Unlike other descriptors, it is requested by a special
- * request USB_REQ_GETMSFTOSDESCRIPTOR.
- * More details:
- * https://msdn.microsoft.com/en-us/windows/hardware/gg463179
- * And excellent explanation:
- * https://github.com/pbatard/libwdi/wiki/WCID-Devices
- *
- * The device will have exactly one "Extended Compat ID Feature Descriptor",
- * which may contain multiple "Function Descriptors" associated with
- * different interfaces.
- */
-
-/* MS OS 1.0 string descriptor */
-struct usb_msosv1_string_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bString[14];
- uint8_t bMS_VendorCode; /* Vendor Code, used for a control request */
- uint8_t bPad; /* Padding byte for VendorCode look as UTF16 */
-} __PACKED;
-
-/* MS OS 1.0 Header descriptor */
-struct usb_msosv1_compat_id_header_descriptor {
- uint32_t dwLength;
- uint16_t bcdVersion;
- uint16_t wIndex;
- uint8_t bCount;
- uint8_t reserved[7];
-} __PACKED;
-
-/* MS OS 1.0 Function descriptor */
-struct usb_msosv1_comp_id_function_descriptor {
- uint8_t bFirstInterfaceNumber;
- uint8_t reserved1;
- uint8_t compatibleID[8];
- uint8_t subCompatibleID[8];
- uint8_t reserved2[6];
-} __PACKED;
-
-#define usb_msosv1_comp_id_create(x) \
- struct usb_msosv1_comp_id { \
- struct usb_msosv1_compat_id_header_descriptor compat_id_header; \
- struct usb_msosv1_comp_id_function_descriptor compat_id_function[x]; \
- };
-
-struct usb_msosv1_descriptor {
- uint8_t *string;
- uint8_t string_len;
- uint8_t vendor_code;
- uint8_t *compat_id;
- uint16_t compat_id_len;
- uint8_t *comp_id_property;
- uint16_t comp_id_property_len;
-};
-
-/* MS OS 2.0 Header descriptor */
-struct usb_msosv2_header_descriptor {
- uint32_t dwLength;
- uint16_t bcdVersion;
- uint16_t wIndex;
- uint8_t bCount;
-} __PACKED;
-
-/*Microsoft OS 2.0 set header descriptor*/
-struct usb_msosv2_set_header_descriptor {
- uint16_t wLength;
- uint16_t wDescriptorType;
- uint32_t dwWindowsVersion;
- uint16_t wDescriptorSetTotalLength;
-} __PACKED;
-
-/* Microsoft OS 2.0 compatibleID descriptor*/
-struct usb_msosv2_comp_id_descriptor {
- uint16_t wLength;
- uint16_t wDescriptorType;
- uint8_t compatibleID[8];
- uint8_t subCompatibleID[8];
-} __PACKED;
-
-/* MS OS 2.0 property descriptor */
-struct usb_msosv2_property_descriptor {
- uint16_t wLength;
- uint16_t wDescriptorType;
- uint32_t dwPropertyDataType;
- uint16_t wPropertyNameLength;
- const char *bPropertyName;
- uint32_t dwPropertyDataLength;
- const char *bPropertyData;
-};
-
-/* Microsoft OS 2.0 subset function descriptor */
-struct usb_msosv2_subset_function_descriptor {
- uint16_t wLength;
- uint16_t wDescriptorType;
- uint8_t bFirstInterface;
- uint8_t bReserved;
- uint16_t wSubsetLength;
-} __PACKED;
-
-struct usb_msosv2_descriptor {
- uint8_t *compat_id;
- uint16_t compat_id_len;
- uint8_t vendor_code;
-};
-
-/* BOS header Descriptor */
-struct usb_bos_header_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint16_t wTotalLength;
- uint8_t bNumDeviceCaps;
-} __PACKED;
-
-/* BOS Capability platform Descriptor */
-struct usb_bos_capability_platform_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bDevCapabilityType;
- uint8_t bReserved;
- uint8_t PlatformCapabilityUUID[16];
-} __PACKED;
-
-/* BOS Capability MS OS Descriptors version 2 */
-struct usb_bos_capability_msosv2_descriptor {
- uint32_t dwWindowsVersion;
- uint16_t wMSOSDescriptorSetTotalLength;
- uint8_t bVendorCode;
- uint8_t bAltEnumCode;
-} __PACKED;
-
-/* BOS Capability webusb */
-struct usb_bos_capability_webusb_descriptor {
- uint16_t bcdVersion;
- uint8_t bVendorCode;
- uint8_t iLandingPage;
-} __PACKED;
-
-/* BOS Capability extension Descriptor*/
-struct usb_bos_capability_extension_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bDevCapabilityType;
- uint32_t bmAttributes;
-} __PACKED;
-
-/* Microsoft OS 2.0 Platform Capability Descriptor
-* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
-* microsoft-defined-usb-descriptors
-* Adapted from the source:
-* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
-* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
-*/
-struct usb_bos_capability_platform_msosv2_descriptor {
- struct usb_bos_capability_platform_descriptor platform_msos;
- struct usb_bos_capability_msosv2_descriptor data_msosv2;
-} __PACKED;
-
-/* WebUSB Platform Capability Descriptor:
-* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
-*/
-struct usb_bos_capability_platform_webusb_descriptor {
- struct usb_bos_capability_platform_descriptor platform_webusb;
- struct usb_bos_capability_webusb_descriptor data_webusb;
-} __PACKED;
-
-struct usb_webusb_url_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bScheme;
- char URL[];
-} __PACKED;
-
-struct usb_bos_descriptor {
- uint8_t *string;
- uint32_t string_len;
-};
-
-/* USB Device Capability Descriptor */
-struct usb_device_capability_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bDevCapabilityType;
-} __PACKED;
-
-/** USB descriptor header */
-struct usb_desc_header {
- uint8_t bLength; /**< descriptor length */
- uint8_t bDescriptorType; /**< descriptor type */
-};
-// clang-format off
-#define USB_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
- 0x12, /* bLength */ \
- USB_DESCRIPTOR_TYPE_DEVICE, /* bDescriptorType */ \
- WBVAL(bcdUSB), /* bcdUSB */ \
- bDeviceClass, /* bDeviceClass */ \
- bDeviceSubClass, /* bDeviceSubClass */ \
- bDeviceProtocol, /* bDeviceProtocol */ \
- 0x40, /* bMaxPacketSize */ \
- WBVAL(idVendor), /* idVendor */ \
- WBVAL(idProduct), /* idProduct */ \
- WBVAL(bcdDevice), /* bcdDevice */ \
- USB_STRING_MFC_INDEX, /* iManufacturer */ \
- USB_STRING_PRODUCT_INDEX, /* iProduct */ \
- USB_STRING_SERIAL_INDEX, /* iSerial */ \
- bNumConfigurations /* bNumConfigurations */
-
-#define USB_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
- 0x09, /* bLength */ \
- USB_DESCRIPTOR_TYPE_CONFIGURATION, /* bDescriptorType */ \
- WBVAL(wTotalLength), /* wTotalLength */ \
- bNumInterfaces, /* bNumInterfaces */ \
- bConfigurationValue, /* bConfigurationValue */ \
- 0x00, /* iConfiguration */ \
- bmAttributes, /* bmAttributes */ \
- USB_CONFIG_POWER_MA(bMaxPower) /* bMaxPower */
-
-#define USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints, \
- bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface) \
- 0x09, /* bLength */ \
- USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
- bInterfaceNumber, /* bInterfaceNumber */ \
- bAlternateSetting, /* bAlternateSetting */ \
- bNumEndpoints, /* bNumEndpoints */ \
- bInterfaceClass, /* bInterfaceClass */ \
- bInterfaceSubClass, /* bInterfaceSubClass */ \
- bInterfaceProtocol, /* bInterfaceProtocol */ \
- iInterface /* iInterface */
-
-#define USB_ENDPOINT_DESCRIPTOR_INIT(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \
- 0x07, /* bLength */ \
- USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
- bEndpointAddress, /* bEndpointAddress */ \
- bmAttributes, /* bmAttributes */ \
- WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
- bInterval /* bInterval */
-
-#define USB_IAD_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
- 0x08, /* bLength */ \
- USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
- bFirstInterface, /* bFirstInterface */ \
- bInterfaceCount, /* bInterfaceCount */ \
- bFunctionClass, /* bFunctionClass */ \
- bFunctionSubClass, /* bFunctionSubClass */ \
- bFunctionProtocol, /* bFunctionProtocol */ \
- 0x00 /* iFunction */
-
-#define USB_LANGID_INIT(id) \
- 0x04, /* bLength */ \
- USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ \
- WBVAL(id) /* wLangID0 */
-// clang-format on
-
-#endif
+/**
+ * @file usb_def.h
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef USB_DEF_H
+#define USB_DEF_H
+
+/* Useful define */
+#define USB_1_1 0x0110
+#define USB_2_0 0x0200
+/* Set USB version to 2.1 so that the host will request the BOS descriptor */
+#define USB_2_1 0x0210
+
+/* Device speeds */
+#define USB_SPEED_UNKNOWN 0 /* Transfer rate not yet set */
+#define USB_SPEED_LOW 1 /* USB 1.1 */
+#define USB_SPEED_FULL 2 /* USB 1.1 */
+#define USB_SPEED_HIGH 3 /* USB 2.0 */
+#define USB_SPEED_VARIABLE 4 /* Wireless USB 2.5 */
+
+/* Maximum number of devices per controller */
+#define USB_MAX_DEVICES (127)
+
+// USB PID Types
+#define USB_PID_OUT (0x01) /* Tokens */
+#define USB_PID_IN (0x09)
+#define USB_PID_SOF (0x05)
+#define USB_PID_SETUP (0x0d)
+
+#define USB_PID_DATA0 (0x03) /* Data */
+#define USB_PID_DATA1 (0x0b)
+#define USB_PID_DATA2 (0x07)
+#define USB_PID_MDATA (0x0f)
+
+#define USB_PID_ACK (0x02) /* Handshake */
+#define USB_PID_NAK (0x0a)
+#define USB_PID_STALL (0x0e)
+#define USB_PID_NYET (0x06)
+
+#define USB_PID_PRE (0x0c) /* Special */
+#define USB_PID_ERR (0x0c)
+#define USB_PID_SPLIT (0x08)
+#define USB_PID_PING (0x04)
+#define USB_PID_RESERVED (0x00)
+
+#define USB_REQUEST_DIR_SHIFT 7U /* Bits 7: Request dir */
+#define USB_REQUEST_DIR_OUT (0U << USB_REQUEST_DIR_SHIFT) /* Bit 7=0: Host-to-device */
+#define USB_REQUEST_DIR_IN (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Device-to-host */
+#define USB_REQUEST_DIR_MASK (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Direction bit */
+
+#define USB_REQUEST_TYPE_SHIFT 5U /* Bits 5:6: Request type */
+#define USB_REQUEST_STANDARD (0U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_CLASS (1U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_VENDOR (2U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_RESERVED (3U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_TYPE_MASK (3U << USB_REQUEST_TYPE_SHIFT)
+
+#define USB_REQUEST_RECIPIENT_SHIFT 0U /* Bits 0:4: Recipient */
+#define USB_REQUEST_RECIPIENT_DEVICE (0U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_INTERFACE (1U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_ENDPOINT (2U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_OTHER (3U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_MASK (3U << USB_REQUEST_RECIPIENT_SHIFT)
+
+/* USB Standard Request Codes */
+#define USB_REQUEST_GET_STATUS 0x00
+#define USB_REQUEST_CLEAR_FEATURE 0x01
+#define USB_REQUEST_SET_FEATURE 0x03
+#define USB_REQUEST_SET_ADDRESS 0x05
+#define USB_REQUEST_GET_DESCRIPTOR 0x06
+#define USB_REQUEST_SET_DESCRIPTOR 0x07
+#define USB_REQUEST_GET_CONFIGURATION 0x08
+#define USB_REQUEST_SET_CONFIGURATION 0x09
+#define USB_REQUEST_GET_INTERFACE 0x0A
+#define USB_REQUEST_SET_INTERFACE 0x0B
+#define USB_REQUEST_SYNCH_FRAME 0x0C
+#define USB_REQUEST_SET_ENCRYPTION 0x0D
+#define USB_REQUEST_GET_ENCRYPTION 0x0E
+#define USB_REQUEST_RPIPE_ABORT 0x0E
+#define USB_REQUEST_SET_HANDSHAKE 0x0F
+#define USB_REQUEST_RPIPE_RESET 0x0F
+#define USB_REQUEST_GET_HANDSHAKE 0x10
+#define USB_REQUEST_SET_CONNECTION 0x11
+#define USB_REQUEST_SET_SECURITY_DATA 0x12
+#define USB_REQUEST_GET_SECURITY_DATA 0x13
+#define USB_REQUEST_SET_WUSB_DATA 0x14
+#define USB_REQUEST_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQUEST_LOOPBACK_DATA_READ 0x16
+#define USB_REQUEST_SET_INTERFACE_DS 0x17
+
+/* USB Standard Feature selectors */
+#define USB_FEATURE_ENDPOINT_HALT 0
+#define USB_FEATURE_SELF_POWERED 0
+#define USB_FEATURE_REMOTE_WAKEUP 1
+#define USB_FEATURE_TEST_MODE 2
+#define USB_FEATURE_BATTERY 2
+#define USB_FEATURE_BHNPENABLE 3
+#define USB_FEATURE_WUSBDEVICE 3
+#define USB_FEATURE_AHNPSUPPORT 4
+#define USB_FEATURE_AALTHNPSUPPORT 5
+#define USB_FEATURE_DEBUGMODE 6
+
+/* USB GET_STATUS Bit Values */
+#define USB_GETSTATUS_ENDPOINT_HALT 0x01
+#define USB_GETSTATUS_SELF_POWERED 0x01
+#define USB_GETSTATUS_REMOTE_WAKEUP 0x02
+
+/* USB Descriptor Types */
+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01U
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02U
+#define USB_DESCRIPTOR_TYPE_STRING 0x03U
+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04U
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05U
+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06U
+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED 0x07U
+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08U
+#define USB_DESCRIPTOR_TYPE_OTG 0x09U
+#define USB_DESCRIPTOR_TYPE_DEBUG 0x0AU
+#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0BU
+#define USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE 0x0FU
+#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 0x10U
+#define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINTCOMP 0x11U
+
+/* Class Specific Descriptor */
+#define USB_CS_DESCRIPTOR_TYPE_DEVICE 0x21U
+#define USB_CS_DESCRIPTOR_TYPE_CONFIGURATION 0x22U
+#define USB_CS_DESCRIPTOR_TYPE_STRING 0x23U
+#define USB_CS_DESCRIPTOR_TYPE_INTERFACE 0x24U
+#define USB_CS_DESCRIPTOR_TYPE_ENDPOINT 0x25U
+
+#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ENDPOINT_COMPANION 0x30U
+#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ISO_ENDPOINT_COMPANION 0x31U
+
+/* USB Device Classes */
+#define USB_DEVICE_CLASS_RESERVED 0x00
+#define USB_DEVICE_CLASS_AUDIO 0x01
+#define USB_DEVICE_CLASS_CDC 0x02
+#define USB_DEVICE_CLASS_HID 0x03
+#define USB_DEVICE_CLASS_MONITOR 0x04
+#define USB_DEVICE_CLASS_PHYSICAL 0x05
+#define USB_DEVICE_CLASS_IMAGE 0x06
+#define USB_DEVICE_CLASS_PRINTER 0x07
+#define USB_DEVICE_CLASS_MASS_STORAGE 0x08
+#define USB_DEVICE_CLASS_HUB 0x09
+#define USB_DEVICE_CLASS_CDC_DATA 0x0a
+#define USB_DEVICE_CLASS_SMART_CARD 0x0b
+#define USB_DEVICE_CLASS_SECURITY 0x0d
+#define USB_DEVICE_CLASS_VIDEO 0x0e
+#define USB_DEVICE_CLASS_HEALTHCARE 0x0f
+#define USB_DEVICE_CLASS_DIAG_DEVICE 0xdc
+#define USB_DEVICE_CLASS_WIRELESS 0xe0
+#define USB_DEVICE_CLASS_MISC 0xef
+#define USB_DEVICE_CLASS_APP_SPECIFIC 0xfe
+#define USB_DEVICE_CLASS_VEND_SPECIFIC 0xff
+
+/* usb string index define */
+#define USB_STRING_LANGID_INDEX 0x00
+#define USB_STRING_MFC_INDEX 0x01
+#define USB_STRING_PRODUCT_INDEX 0x02
+#define USB_STRING_SERIAL_INDEX 0x03
+#define USB_STRING_CONFIG_INDEX 0x04
+#define USB_STRING_INTERFACE_INDEX 0x05
+#define USB_STRING_OS_INDEX 0x06
+#define USB_STRING_MAX USB_STRING_OS_INDEX
+/*
+ * Devices supporting Microsoft OS Descriptors store special string
+ * descriptor at fixed index (0xEE). It is read when a new device is
+ * attached to a computer for the first time.
+ */
+#define USB_OSDESC_STRING_DESC_INDEX 0xEE
+
+/* bmAttributes in Configuration Descriptor */
+#define USB_CONFIG_REMOTE_WAKEUP 0x20
+#define USB_CONFIG_POWERED_MASK 0x40
+#define USB_CONFIG_BUS_POWERED 0x80
+#define USB_CONFIG_SELF_POWERED 0xC0
+
+/* bMaxPower in Configuration Descriptor */
+#define USB_CONFIG_POWER_MA(mA) ((mA) / 2)
+
+/* bEndpointAddress in Endpoint Descriptor */
+#define USB_ENDPOINT_DIRECTION_MASK 0x80
+#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00)
+#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
+
+/* bmAttributes in Endpoint Descriptor */
+#define USB_ENDPOINT_TYPE_SHIFT 0
+#define USB_ENDPOINT_TYPE_CONTROL (0 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS (1 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_BULK (2 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_INTERRUPT (3 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_MASK (3 << USB_ENDPOINT_TYPE_SHIFT)
+
+#define USB_ENDPOINT_SYNC_SHIFT 2
+#define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION (0 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_ASYNCHRONOUS (1 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_SYNCHRONOUS (3 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_MASK (3 << USB_ENDPOINT_SYNC_SHIFT)
+
+#define USB_ENDPOINT_USAGE_SHIFT 4
+#define USB_ENDPOINT_USAGE_DATA (0 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_FEEDBACK (1 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_MASK (3 << USB_ENDPOINT_USAGE_SHIFT)
+
+#define USB_ENDPOINT_MAX_ADJUSTABLE (1 << 7)
+
+/* bDevCapabilityType in Device Capability Descriptor */
+#define USB_DEVICE_CAPABILITY_WIRELESS_USB 1
+#define USB_DEVICE_CAPABILITY_USB_2_0_EXTENSION 2
+#define USB_DEVICE_CAPABILITY_SUPERSPEED_USB 3
+#define USB_DEVICE_CAPABILITY_CONTAINER_ID 4
+#define USB_DEVICE_CAPABILITY_PLATFORM 5
+#define USB_DEVICE_CAPABILITY_POWER_DELIVERY_CAPABILITY 6
+#define USB_DEVICE_CAPABILITY_BATTERY_INFO_CAPABILITY 7
+#define USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_CAPABILITY 8
+#define USB_DEVICE_CAPABILITY_PD_PROVIDER_PORT_CAPABILITY 9
+#define USB_DEVICE_CAPABILITY_SUPERSPEED_PLUS 10
+#define USB_DEVICE_CAPABILITY_PRECISION_TIME_MEASUREMENT 11
+#define USB_DEVICE_CAPABILITY_WIRELESS_USB_EXT 12
+
+#define USB_BOS_CAPABILITY_EXTENSION 0x02
+#define USB_BOS_CAPABILITY_PLATFORM 0x05
+
+/* OTG SET FEATURE Constants */
+#define USB_OTG_FEATURE_B_HNP_ENABLE 3 /* Enable B device to perform HNP */
+#define USB_OTG_FEATURE_A_HNP_SUPPORT 4 /* A device supports HNP */
+#define USB_OTG_FEATURE_A_ALT_HNP_SUPPORT 5 /* Another port on the A device supports HNP */
+
+/* WinUSB Microsoft OS 2.0 descriptor request codes */
+#define WINUSB_REQUEST_GET_DESCRIPTOR_SET 0x07
+#define WINUSB_REQUEST_SET_ALT_ENUM 0x08
+
+/* WinUSB Microsoft OS 2.0 descriptor sizes */
+#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
+#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
+#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
+
+/* WinUSB Microsoft OS 2.0 Descriptor Types */
+#define WINUSB_SET_HEADER_DESCRIPTOR_TYPE 0x00
+#define WINUSB_SUBSET_HEADER_CONFIGURATION_TYPE 0x01
+#define WINUSB_SUBSET_HEADER_FUNCTION_TYPE 0x02
+#define WINUSB_FEATURE_COMPATIBLE_ID_TYPE 0x03
+#define WINUSB_FEATURE_REG_PROPERTY_TYPE 0x04
+#define WINUSB_FEATURE_MIN_RESUME_TIME_TYPE 0x05
+#define WINUSB_FEATURE_MODEL_ID_TYPE 0x06
+#define WINUSB_FEATURE_CCGP_DEVICE_TYPE 0x07
+
+#define WINUSB_PROP_DATA_TYPE_REG_SZ 0x01
+#define WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ 0x07
+
+/* WebUSB Descriptor Types */
+#define WEBUSB_DESCRIPTOR_SET_HEADER_TYPE 0x00
+#define WEBUSB_CONFIGURATION_SUBSET_HEADER_TYPE 0x01
+#define WEBUSB_FUNCTION_SUBSET_HEADER_TYPE 0x02
+#define WEBUSB_URL_TYPE 0x03
+
+/* WebUSB Request Codes */
+#define WEBUSB_REQUEST_GET_URL 0x02
+
+/* bScheme in URL descriptor */
+#define WEBUSB_URL_SCHEME_HTTP 0x00
+#define WEBUSB_URL_SCHEME_HTTPS 0x01
+
+/* WebUSB Descriptor sizes */
+#define WEBUSB_DESCRIPTOR_SET_HEADER_SIZE 5
+#define WEBUSB_CONFIGURATION_SUBSET_HEADER_SIZE 4
+#define WEBUSB_FUNCTION_SUBSET_HEADER_SIZE 3
+
+/* Setup packet definition used to read raw data from USB line */
+struct usb_setup_packet {
+ /** Request type. Bits 0:4 determine recipient, see
+ * \ref usb_request_recipient. Bits 5:6 determine type, see
+ * \ref usb_request_type. Bit 7 determines data transfer direction, see
+ * \ref usb_endpoint_direction.
+ */
+ uint8_t bmRequestType;
+
+ /** Request. If the type bits of bmRequestType are equal to
+ * \ref usb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+ * "USB_REQUEST_TYPE_STANDARD" then this field refers to
+ * \ref usb_standard_request. For other cases, use of this field is
+ * application-specific. */
+ uint8_t bRequest;
+
+ /** Value. Varies according to request */
+ uint16_t wValue;
+
+ /** Index. Varies according to request, typically used to pass an index
+ * or offset */
+ uint16_t wIndex;
+
+ /** Number of bytes to transfer */
+ uint16_t wLength;
+} __PACKED;
+
+#define USB_SIZEOF_SETUP_PACKET 8
+
+/** Standard Device Descriptor */
+struct usb_device_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 18 */
+ uint8_t bDescriptorType; /* DEVICE descriptor type = 1 */
+ uint16_t bcdUSB; /* USB spec in BCD, e.g. 0x0200 */
+ uint8_t bDeviceClass; /* Class code, if 0 see interface */
+ uint8_t bDeviceSubClass; /* Sub-Class code, 0 if class = 0 */
+ uint8_t bDeviceProtocol; /* Protocol, if 0 see interface */
+ uint8_t bMaxPacketSize0; /* Endpoint 0 max. size */
+ uint16_t idVendor; /* Vendor ID per USB-IF */
+ uint16_t idProduct; /* Product ID per manufacturer */
+ uint16_t bcdDevice; /* Device release # in BCD */
+ uint8_t iManufacturer; /* Index to manufacturer string */
+ uint8_t iProduct; /* Index to product string */
+ uint8_t iSerialNumber; /* Index to serial number string */
+ uint8_t bNumConfigurations; /* Number of possible configurations */
+} __PACKED;
+
+#define USB_SIZEOF_DEVICE_DESC 18
+
+/** Standard Configuration Descriptor */
+struct usb_configuration_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 9 */
+ uint8_t bDescriptorType; /* CONFIGURATION type = 2 or 7 */
+ uint16_t wTotalLength; /* Length of concatenated descriptors */
+ uint8_t bNumInterfaces; /* Number of interfaces, this config. */
+ uint8_t bConfigurationValue; /* Value to set this config. */
+ uint8_t iConfiguration; /* Index to configuration string */
+ uint8_t bmAttributes; /* Config. characteristics */
+ uint8_t bMaxPower; /* Max.power from bus, 2mA units */
+} __PACKED;
+
+#define USB_SIZEOF_CONFIG_DESC 9
+
+/** Standard Interface Descriptor */
+struct usb_interface_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 9 */
+ uint8_t bDescriptorType; /* INTERFACE descriptor type = 4 */
+ uint8_t bInterfaceNumber; /* Interface no.*/
+ uint8_t bAlternateSetting; /* Value to select this IF */
+ uint8_t bNumEndpoints; /* Number of endpoints excluding 0 */
+ uint8_t bInterfaceClass; /* Class code, 0xFF = vendor */
+ uint8_t bInterfaceSubClass; /* Sub-Class code, 0 if class = 0 */
+ uint8_t bInterfaceProtocol; /* Protocol, 0xFF = vendor */
+ uint8_t iInterface; /* Index to interface string */
+} __PACKED;
+
+#define USB_SIZEOF_INTERFACE_DESC 9
+
+/** Standard Endpoint Descriptor */
+struct usb_endpoint_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 7 */
+ uint8_t bDescriptorType; /* ENDPOINT descriptor type = 5 */
+ uint8_t bEndpointAddress; /* Endpoint # 0 - 15 | IN/OUT */
+ uint8_t bmAttributes; /* Transfer type */
+ uint16_t wMaxPacketSize; /* Bits 10:0 = max. packet size */
+ uint8_t bInterval; /* Polling interval in (micro) frames */
+} __PACKED;
+
+#define USB_SIZEOF_ENDPOINT_DESC 7
+
+/** Unicode (UTF16LE) String Descriptor */
+struct usb_string_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bString;
+} __PACKED;
+
+#define USB_SIZEOF_STRING_LANGID_DESC 4
+
+/* USB Interface Association Descriptor */
+struct usb_interface_association_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bFirstInterface;
+ uint8_t bInterfaceCount;
+ uint8_t bFunctionClass;
+ uint8_t bFunctionSubClass;
+ uint8_t bFunctionProtocol;
+ uint8_t iFunction;
+} __PACKED;
+
+#define USB_SIZEOF_IAD_DESC 8
+
+/** USB device_qualifier descriptor */
+struct usb_device_qualifier_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 10 */
+ uint8_t bDescriptorType; /* DEVICE QUALIFIER type = 6 */
+ uint16_t bcdUSB; /* USB spec in BCD, e.g. 0x0200 */
+ uint8_t bDeviceClass; /* Class code, if 0 see interface */
+ uint8_t bDeviceSubClass; /* Sub-Class code, 0 if class = 0 */
+ uint8_t bDeviceProtocol; /* Protocol, if 0 see interface */
+ uint8_t bMaxPacketSize; /* Endpoint 0 max. size */
+ uint8_t bNumConfigurations; /* Number of possible configurations */
+ uint8_t bReserved; /* Reserved = 0 */
+} __PACKED;
+
+#define USB_SIZEOF_DEVICE_QUALIFIER_DESC 10
+
+/* Microsoft OS function descriptor.
+ * This can be used to request a specific driver (such as WINUSB) to be
+ * loaded on Windows. Unlike other descriptors, it is requested by a special
+ * request USB_REQ_GETMSFTOSDESCRIPTOR.
+ * More details:
+ * https://msdn.microsoft.com/en-us/windows/hardware/gg463179
+ * And excellent explanation:
+ * https://github.com/pbatard/libwdi/wiki/WCID-Devices
+ *
+ * The device will have exactly one "Extended Compat ID Feature Descriptor",
+ * which may contain multiple "Function Descriptors" associated with
+ * different interfaces.
+ */
+
+/* MS OS 1.0 string descriptor */
+struct usb_msosv1_string_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bString[14];
+ uint8_t bMS_VendorCode; /* Vendor Code, used for a control request */
+ uint8_t bPad; /* Padding byte for VendorCode look as UTF16 */
+} __PACKED;
+
+/* MS OS 1.0 Header descriptor */
+struct usb_msosv1_compat_id_header_descriptor {
+ uint32_t dwLength;
+ uint16_t bcdVersion;
+ uint16_t wIndex;
+ uint8_t bCount;
+ uint8_t reserved[7];
+} __PACKED;
+
+/* MS OS 1.0 Function descriptor */
+struct usb_msosv1_comp_id_function_descriptor {
+ uint8_t bFirstInterfaceNumber;
+ uint8_t reserved1;
+ uint8_t compatibleID[8];
+ uint8_t subCompatibleID[8];
+ uint8_t reserved2[6];
+} __PACKED;
+
+#define usb_msosv1_comp_id_create(x) \
+ struct usb_msosv1_comp_id { \
+ struct usb_msosv1_compat_id_header_descriptor compat_id_header; \
+ struct usb_msosv1_comp_id_function_descriptor compat_id_function[x]; \
+ };
+
+struct usb_msosv1_descriptor {
+ uint8_t *string;
+ uint8_t string_len;
+ uint8_t vendor_code;
+ uint8_t *compat_id;
+ uint16_t compat_id_len;
+ uint8_t *comp_id_property;
+ uint16_t comp_id_property_len;
+};
+
+/* MS OS 2.0 Header descriptor */
+struct usb_msosv2_header_descriptor {
+ uint32_t dwLength;
+ uint16_t bcdVersion;
+ uint16_t wIndex;
+ uint8_t bCount;
+} __PACKED;
+
+/*Microsoft OS 2.0 set header descriptor*/
+struct usb_msosv2_set_header_descriptor {
+ uint16_t wLength;
+ uint16_t wDescriptorType;
+ uint32_t dwWindowsVersion;
+ uint16_t wDescriptorSetTotalLength;
+} __PACKED;
+
+/* Microsoft OS 2.0 compatibleID descriptor*/
+struct usb_msosv2_comp_id_descriptor {
+ uint16_t wLength;
+ uint16_t wDescriptorType;
+ uint8_t compatibleID[8];
+ uint8_t subCompatibleID[8];
+} __PACKED;
+
+/* MS OS 2.0 property descriptor */
+struct usb_msosv2_property_descriptor {
+ uint16_t wLength;
+ uint16_t wDescriptorType;
+ uint32_t dwPropertyDataType;
+ uint16_t wPropertyNameLength;
+ const char *bPropertyName;
+ uint32_t dwPropertyDataLength;
+ const char *bPropertyData;
+};
+
+/* Microsoft OS 2.0 subset function descriptor */
+struct usb_msosv2_subset_function_descriptor {
+ uint16_t wLength;
+ uint16_t wDescriptorType;
+ uint8_t bFirstInterface;
+ uint8_t bReserved;
+ uint16_t wSubsetLength;
+} __PACKED;
+
+struct usb_msosv2_descriptor {
+ uint8_t *compat_id;
+ uint16_t compat_id_len;
+ uint8_t vendor_code;
+};
+
+/* BOS header Descriptor */
+struct usb_bos_header_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumDeviceCaps;
+} __PACKED;
+
+/* BOS Capability platform Descriptor */
+struct usb_bos_capability_platform_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint8_t bReserved;
+ uint8_t PlatformCapabilityUUID[16];
+} __PACKED;
+
+/* BOS Capability MS OS Descriptors version 2 */
+struct usb_bos_capability_msosv2_descriptor {
+ uint32_t dwWindowsVersion;
+ uint16_t wMSOSDescriptorSetTotalLength;
+ uint8_t bVendorCode;
+ uint8_t bAltEnumCode;
+} __PACKED;
+
+/* BOS Capability webusb */
+struct usb_bos_capability_webusb_descriptor {
+ uint16_t bcdVersion;
+ uint8_t bVendorCode;
+ uint8_t iLandingPage;
+} __PACKED;
+
+/* BOS Capability extension Descriptor*/
+struct usb_bos_capability_extension_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint32_t bmAttributes;
+} __PACKED;
+
+/* Microsoft OS 2.0 Platform Capability Descriptor
+* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
+* microsoft-defined-usb-descriptors
+* Adapted from the source:
+* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
+* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
+*/
+struct usb_bos_capability_platform_msosv2_descriptor {
+ struct usb_bos_capability_platform_descriptor platform_msos;
+ struct usb_bos_capability_msosv2_descriptor data_msosv2;
+} __PACKED;
+
+/* WebUSB Platform Capability Descriptor:
+* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
+*/
+struct usb_bos_capability_platform_webusb_descriptor {
+ struct usb_bos_capability_platform_descriptor platform_webusb;
+ struct usb_bos_capability_webusb_descriptor data_webusb;
+} __PACKED;
+
+struct usb_webusb_url_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bScheme;
+ char URL[];
+} __PACKED;
+
+struct usb_bos_descriptor {
+ uint8_t *string;
+ uint32_t string_len;
+};
+
+/* USB Device Capability Descriptor */
+struct usb_device_capability_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+} __PACKED;
+
+/** USB descriptor header */
+struct usb_desc_header {
+ uint8_t bLength; /**< descriptor length */
+ uint8_t bDescriptorType; /**< descriptor type */
+};
+// clang-format off
+#define USB_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
+ 0x12, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_DEVICE, /* bDescriptorType */ \
+ WBVAL(bcdUSB), /* bcdUSB */ \
+ bDeviceClass, /* bDeviceClass */ \
+ bDeviceSubClass, /* bDeviceSubClass */ \
+ bDeviceProtocol, /* bDeviceProtocol */ \
+ 0x40, /* bMaxPacketSize */ \
+ WBVAL(idVendor), /* idVendor */ \
+ WBVAL(idProduct), /* idProduct */ \
+ WBVAL(bcdDevice), /* bcdDevice */ \
+ USB_STRING_MFC_INDEX, /* iManufacturer */ \
+ USB_STRING_PRODUCT_INDEX, /* iProduct */ \
+ USB_STRING_SERIAL_INDEX, /* iSerial */ \
+ bNumConfigurations /* bNumConfigurations */
+
+#define USB_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
+ 0x09, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_CONFIGURATION, /* bDescriptorType */ \
+ WBVAL(wTotalLength), /* wTotalLength */ \
+ bNumInterfaces, /* bNumInterfaces */ \
+ bConfigurationValue, /* bConfigurationValue */ \
+ 0x00, /* iConfiguration */ \
+ bmAttributes, /* bmAttributes */ \
+ USB_CONFIG_POWER_MA(bMaxPower) /* bMaxPower */
+
+#define USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints, \
+ bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface) \
+ 0x09, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
+ bInterfaceNumber, /* bInterfaceNumber */ \
+ bAlternateSetting, /* bAlternateSetting */ \
+ bNumEndpoints, /* bNumEndpoints */ \
+ bInterfaceClass, /* bInterfaceClass */ \
+ bInterfaceSubClass, /* bInterfaceSubClass */ \
+ bInterfaceProtocol, /* bInterfaceProtocol */ \
+ iInterface /* iInterface */
+
+#define USB_ENDPOINT_DESCRIPTOR_INIT(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \
+ 0x07, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
+ bEndpointAddress, /* bEndpointAddress */ \
+ bmAttributes, /* bmAttributes */ \
+ WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
+ bInterval /* bInterval */
+
+#define USB_IAD_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
+ 0x08, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
+ bFirstInterface, /* bFirstInterface */ \
+ bInterfaceCount, /* bInterfaceCount */ \
+ bFunctionClass, /* bFunctionClass */ \
+ bFunctionSubClass, /* bFunctionSubClass */ \
+ bFunctionProtocol, /* bFunctionProtocol */ \
+ 0x00 /* iFunction */
+
+#define USB_LANGID_INIT(id) \
+ 0x04, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ \
+ WBVAL(id) /* wLangID0 */
+// clang-format on
+
+#endif
diff --git a/common/usb_util.h b/common/usb_util.h
index ab4eb693..d21a5f61 100644
--- a/common/usb_util.h
+++ b/common/usb_util.h
@@ -1,300 +1,300 @@
-/**
- * @file usb_util.h
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USB_UTIL_H
-#define _USB_UTIL_H
-
-#include <stdbool.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "usb_errno.h"
-#include "usb_list.h"
-#include "usb_mem.h"
-
-#if defined(__CC_ARM)
-#ifndef __USED
-#define __USED __attribute__((used))
-#endif
-#ifndef __WEAK
-#define __WEAK __attribute__((weak))
-#endif
-#ifndef __PACKED
-#define __PACKED __attribute__((packed))
-#endif
-#ifndef __PACKED_STRUCT
-#define __PACKED_STRUCT __packed struct
-#endif
-#ifndef __PACKED_UNION
-#define __PACKED_UNION __packed union
-#endif
-#ifndef __ALIGNED
-#define __ALIGNED(x) __attribute__((aligned(x)))
-#endif
-#elif defined(__GNUC__)
-#ifndef __USED
-#define __USED __attribute__((used))
-#endif
-#ifndef __WEAK
-#define __WEAK __attribute__((weak))
-#endif
-#ifndef __PACKED
-#define __PACKED __attribute__((packed, aligned(1)))
-#endif
-#ifndef __PACKED_STRUCT
-#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
-#endif
-#ifndef __PACKED_UNION
-#define __PACKED_UNION union __attribute__((packed, aligned(1)))
-#endif
-#ifndef __ALIGNED
-#define __ALIGNED(x) __attribute__((aligned(x)))
-#endif
-#elif defined(__ICCARM__)
-#ifndef __USED
-#if __ICCARM_V8
-#define __USED __attribute__((used))
-#else
-#define __USED _Pragma("__root")
-#endif
-#endif
-
-#ifndef __WEAK
-#if __ICCARM_V8
-#define __WEAK __attribute__((weak))
-#else
-#define __WEAK _Pragma("__weak")
-#endif
-#endif
-
-#ifndef __PACKED
-#if __ICCARM_V8
-#define __PACKED __attribute__((packed, aligned(1)))
-#else
-/* Needs IAR language extensions */
-#define __PACKED __packed
-#endif
-#endif
-
-#ifndef __PACKED_STRUCT
-#if __ICCARM_V8
-#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
-#else
-/* Needs IAR language extensions */
-#define __PACKED_STRUCT __packed struct
-#endif
-#endif
-
-#ifndef __PACKED_UNION
-#if __ICCARM_V8
-#define __PACKED_UNION union __attribute__((packed, aligned(1)))
-#else
-/* Needs IAR language extensions */
-#define __PACKED_UNION __packed union
-#endif
-#endif
-
-#ifndef __ALIGNED
-#if __ICCARM_V8
-#define __ALIGNED(x) __attribute__((aligned(x)))
-#elif (__VER__ >= 7080000)
-/* Needs IAR language extensions */
-#define __ALIGNED(x) __attribute__((aligned(x)))
-#else
-#warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored.
-#define __ALIGNED(x)
-#endif
-#endif
-
-#endif
-
-#ifndef __ALIGN_BEGIN
-#define __ALIGN_BEGIN
-#endif
-#ifndef __ALIGN_END
-#define __ALIGN_END __attribute__((aligned(4)))
-#endif
-
-#ifndef ARG_UNUSED
-#define ARG_UNUSED(x) (void)(x)
-#endif
-
-#ifndef LO_BYTE
-#define LO_BYTE(x) ((uint8_t)(x & 0x00FF))
-#endif
-
-#ifndef HI_BYTE
-#define HI_BYTE(x) ((uint8_t)((x & 0xFF00) >> 8))
-#endif
-
-/**
- * @def MAX
- * @brief The larger value between @p a and @p b.
- * @note Arguments are evaluated twice.
- */
-#ifndef MAX
-/* Use Z_MAX for a GCC-only, single evaluation version */
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-/**
- * @def MIN
- * @brief The smaller value between @p a and @p b.
- * @note Arguments are evaluated twice.
- */
-#ifndef MIN
-/* Use Z_MIN for a GCC-only, single evaluation version */
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef BCD
-#define BCD(x) ((((x) / 10) << 4) | ((x) % 10))
-#endif
-
-#ifdef BIT
-#undef BIT
-#define BIT(n) (1UL << (n))
-#else
-#define BIT(n) (1UL << (n))
-#endif
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(array) \
- ((int)((sizeof(array) / sizeof((array)[0]))))
-#endif
-
-#ifndef BSWAP16
-#define BSWAP16(u16) (__builtin_bswap16(u16))
-#endif
-#ifndef BSWAP32
-#define BSWAP32(u32) (__builtin_bswap32(u32))
-#endif
-
-#define GET_BE16(field) \
- (((uint16_t)(field)[0] << 8) | ((uint16_t)(field)[1]))
-
-#define GET_BE32(field) \
- (((uint32_t)(field)[0] << 24) | ((uint32_t)(field)[1] << 16) | ((uint32_t)(field)[2] << 8) | ((uint32_t)(field)[3] << 0))
-
-#define SET_BE16(field, value) \
- do { \
- (field)[0] = (uint8_t)((value) >> 8); \
- (field)[1] = (uint8_t)((value) >> 0); \
- } while (0)
-
-#define SET_BE24(field, value) \
- do { \
- (field)[0] = (uint8_t)((value) >> 16); \
- (field)[1] = (uint8_t)((value) >> 8); \
- (field)[2] = (uint8_t)((value) >> 0); \
- } while (0)
-
-#define SET_BE32(field, value) \
- do { \
- (field)[0] = (uint8_t)((value) >> 24); \
- (field)[1] = (uint8_t)((value) >> 16); \
- (field)[2] = (uint8_t)((value) >> 8); \
- (field)[3] = (uint8_t)((value) >> 0); \
- } while (0)
-
-#define REQTYPE_GET_DIR(x) (((x) >> 7) & 0x01)
-#define REQTYPE_GET_TYPE(x) (((x) >> 5) & 0x03U)
-#define REQTYPE_GET_RECIP(x) ((x)&0x1F)
-
-#define GET_DESC_TYPE(x) (((x) >> 8) & 0xFFU)
-#define GET_DESC_INDEX(x) ((x)&0xFFU)
-
-#define WBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF)
-#define DBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF), ((x >> 16) & 0xFF), ((x >> 24) & 0xFF)
-
-#define USB_DESC_SECTION __attribute__((section("usb_desc"))) __USED __ALIGNED(1)
-
-/* DEBUG level */
-#define USB_DBG_ERROR 0
-#define USB_DBG_WARNING 1
-#define USB_DBG_INFO 2
-#define USB_DBG_LOG 3
-
-#ifndef USB_DBG_LEVEL
-#define USB_DBG_LEVEL USB_DBG_INFO
-#endif
-
-#ifndef USB_DBG_TAG
-#define USB_DBG_TAG "USB"
-#endif
-/*
- * The color for terminal (foreground)
- * BLACK 30
- * RED 31
- * GREEN 32
- * YELLOW 33
- * BLUE 34
- * PURPLE 35
- * CYAN 36
- * WHITE 37
- */
-#define _USB_DBG_COLOR(n) printf("\033[" #n "m")
-#define _USB_DBG_LOG_HDR(lvl_name, color_n) \
- printf("\033[" #color_n "m[" lvl_name "/" USB_DBG_TAG "] ")
-#define _USB_DBG_LOG_X_END \
- printf("\033[0m")
-
-#define usb_dbg_log_line(lvl, color_n, fmt, ...) \
- do { \
- _USB_DBG_LOG_HDR(lvl, color_n); \
- printf(fmt, ##__VA_ARGS__); \
- _USB_DBG_LOG_X_END; \
- } while (0)
-
-#if (USB_DBG_LEVEL >= USB_DBG_LOG)
-#define USB_LOG_DBG(fmt, ...) usb_dbg_log_line("D", 0, fmt, ##__VA_ARGS__)
-#else
-#define USB_LOG_DBG(...)
-#endif
-
-#if (USB_DBG_LEVEL >= USB_DBG_INFO)
-#define USB_LOG_INFO(fmt, ...) usb_dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
-#else
-#define USB_LOG_INFO(...)
-#endif
-
-#if (USB_DBG_LEVEL >= USB_DBG_WARNING)
-#define USB_LOG_WRN(fmt, ...) usb_dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
-#else
-#define USB_LOG_WRN(...)
-#endif
-
-#if (USB_DBG_LEVEL >= USB_DBG_ERROR)
-#define USB_LOG_ERR(fmt, ...) usb_dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
-#else
-#define USB_LOG_ERR(...)
-#endif
-
-void usb_assert(const char *filename, int linenum);
-#define USB_ASSERT(f) \
- do { \
- if (!(f)) \
- usb_assert(__FILE__, __LINE__); \
- } while (0)
-
-#endif
+/**
+ * @file usb_util.h
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USB_UTIL_H
+#define _USB_UTIL_H
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "usb_errno.h"
+#include "usb_list.h"
+#include "usb_mem.h"
+
+#if defined(__CC_ARM)
+#ifndef __USED
+#define __USED __attribute__((used))
+#endif
+#ifndef __WEAK
+#define __WEAK __attribute__((weak))
+#endif
+#ifndef __PACKED
+#define __PACKED __attribute__((packed))
+#endif
+#ifndef __PACKED_STRUCT
+#define __PACKED_STRUCT __packed struct
+#endif
+#ifndef __PACKED_UNION
+#define __PACKED_UNION __packed union
+#endif
+#ifndef __ALIGNED
+#define __ALIGNED(x) __attribute__((aligned(x)))
+#endif
+#elif defined(__GNUC__)
+#ifndef __USED
+#define __USED __attribute__((used))
+#endif
+#ifndef __WEAK
+#define __WEAK __attribute__((weak))
+#endif
+#ifndef __PACKED
+#define __PACKED __attribute__((packed, aligned(1)))
+#endif
+#ifndef __PACKED_STRUCT
+#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
+#endif
+#ifndef __PACKED_UNION
+#define __PACKED_UNION union __attribute__((packed, aligned(1)))
+#endif
+#ifndef __ALIGNED
+#define __ALIGNED(x) __attribute__((aligned(x)))
+#endif
+#elif defined(__ICCARM__)
+#ifndef __USED
+#if __ICCARM_V8
+#define __USED __attribute__((used))
+#else
+#define __USED _Pragma("__root")
+#endif
+#endif
+
+#ifndef __WEAK
+#if __ICCARM_V8
+#define __WEAK __attribute__((weak))
+#else
+#define __WEAK _Pragma("__weak")
+#endif
+#endif
+
+#ifndef __PACKED
+#if __ICCARM_V8
+#define __PACKED __attribute__((packed, aligned(1)))
+#else
+/* Needs IAR language extensions */
+#define __PACKED __packed
+#endif
+#endif
+
+#ifndef __PACKED_STRUCT
+#if __ICCARM_V8
+#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
+#else
+/* Needs IAR language extensions */
+#define __PACKED_STRUCT __packed struct
+#endif
+#endif
+
+#ifndef __PACKED_UNION
+#if __ICCARM_V8
+#define __PACKED_UNION union __attribute__((packed, aligned(1)))
+#else
+/* Needs IAR language extensions */
+#define __PACKED_UNION __packed union
+#endif
+#endif
+
+#ifndef __ALIGNED
+#if __ICCARM_V8
+#define __ALIGNED(x) __attribute__((aligned(x)))
+#elif (__VER__ >= 7080000)
+/* Needs IAR language extensions */
+#define __ALIGNED(x) __attribute__((aligned(x)))
+#else
+#warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored.
+#define __ALIGNED(x)
+#endif
+#endif
+
+#endif
+
+#ifndef __ALIGN_BEGIN
+#define __ALIGN_BEGIN
+#endif
+#ifndef __ALIGN_END
+#define __ALIGN_END __attribute__((aligned(4)))
+#endif
+
+#ifndef ARG_UNUSED
+#define ARG_UNUSED(x) (void)(x)
+#endif
+
+#ifndef LO_BYTE
+#define LO_BYTE(x) ((uint8_t)(x & 0x00FF))
+#endif
+
+#ifndef HI_BYTE
+#define HI_BYTE(x) ((uint8_t)((x & 0xFF00) >> 8))
+#endif
+
+/**
+ * @def MAX
+ * @brief The larger value between @p a and @p b.
+ * @note Arguments are evaluated twice.
+ */
+#ifndef MAX
+/* Use Z_MAX for a GCC-only, single evaluation version */
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/**
+ * @def MIN
+ * @brief The smaller value between @p a and @p b.
+ * @note Arguments are evaluated twice.
+ */
+#ifndef MIN
+/* Use Z_MIN for a GCC-only, single evaluation version */
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef BCD
+#define BCD(x) ((((x) / 10) << 4) | ((x) % 10))
+#endif
+
+#ifdef BIT
+#undef BIT
+#define BIT(n) (1UL << (n))
+#else
+#define BIT(n) (1UL << (n))
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(array) \
+ ((int)((sizeof(array) / sizeof((array)[0]))))
+#endif
+
+#ifndef BSWAP16
+#define BSWAP16(u16) (__builtin_bswap16(u16))
+#endif
+#ifndef BSWAP32
+#define BSWAP32(u32) (__builtin_bswap32(u32))
+#endif
+
+#define GET_BE16(field) \
+ (((uint16_t)(field)[0] << 8) | ((uint16_t)(field)[1]))
+
+#define GET_BE32(field) \
+ (((uint32_t)(field)[0] << 24) | ((uint32_t)(field)[1] << 16) | ((uint32_t)(field)[2] << 8) | ((uint32_t)(field)[3] << 0))
+
+#define SET_BE16(field, value) \
+ do { \
+ (field)[0] = (uint8_t)((value) >> 8); \
+ (field)[1] = (uint8_t)((value) >> 0); \
+ } while (0)
+
+#define SET_BE24(field, value) \
+ do { \
+ (field)[0] = (uint8_t)((value) >> 16); \
+ (field)[1] = (uint8_t)((value) >> 8); \
+ (field)[2] = (uint8_t)((value) >> 0); \
+ } while (0)
+
+#define SET_BE32(field, value) \
+ do { \
+ (field)[0] = (uint8_t)((value) >> 24); \
+ (field)[1] = (uint8_t)((value) >> 16); \
+ (field)[2] = (uint8_t)((value) >> 8); \
+ (field)[3] = (uint8_t)((value) >> 0); \
+ } while (0)
+
+#define REQTYPE_GET_DIR(x) (((x) >> 7) & 0x01)
+#define REQTYPE_GET_TYPE(x) (((x) >> 5) & 0x03U)
+#define REQTYPE_GET_RECIP(x) ((x)&0x1F)
+
+#define GET_DESC_TYPE(x) (((x) >> 8) & 0xFFU)
+#define GET_DESC_INDEX(x) ((x)&0xFFU)
+
+#define WBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF)
+#define DBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF), ((x >> 16) & 0xFF), ((x >> 24) & 0xFF)
+
+#define USB_DESC_SECTION __attribute__((section("usb_desc"))) __USED __ALIGNED(1)
+
+/* DEBUG level */
+#define USB_DBG_ERROR 0
+#define USB_DBG_WARNING 1
+#define USB_DBG_INFO 2
+#define USB_DBG_LOG 3
+
+#ifndef USB_DBG_LEVEL
+#define USB_DBG_LEVEL USB_DBG_INFO
+#endif
+
+#ifndef USB_DBG_TAG
+#define USB_DBG_TAG "USB"
+#endif
+/*
+ * The color for terminal (foreground)
+ * BLACK 30
+ * RED 31
+ * GREEN 32
+ * YELLOW 33
+ * BLUE 34
+ * PURPLE 35
+ * CYAN 36
+ * WHITE 37
+ */
+#define _USB_DBG_COLOR(n) printf("\033[" #n "m")
+#define _USB_DBG_LOG_HDR(lvl_name, color_n) \
+ printf("\033[" #color_n "m[" lvl_name "/" USB_DBG_TAG "] ")
+#define _USB_DBG_LOG_X_END \
+ printf("\033[0m")
+
+#define usb_dbg_log_line(lvl, color_n, fmt, ...) \
+ do { \
+ _USB_DBG_LOG_HDR(lvl, color_n); \
+ printf(fmt, ##__VA_ARGS__); \
+ _USB_DBG_LOG_X_END; \
+ } while (0)
+
+#if (USB_DBG_LEVEL >= USB_DBG_LOG)
+#define USB_LOG_DBG(fmt, ...) usb_dbg_log_line("D", 0, fmt, ##__VA_ARGS__)
+#else
+#define USB_LOG_DBG(...)
+#endif
+
+#if (USB_DBG_LEVEL >= USB_DBG_INFO)
+#define USB_LOG_INFO(fmt, ...) usb_dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
+#else
+#define USB_LOG_INFO(...)
+#endif
+
+#if (USB_DBG_LEVEL >= USB_DBG_WARNING)
+#define USB_LOG_WRN(fmt, ...) usb_dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
+#else
+#define USB_LOG_WRN(...)
+#endif
+
+#if (USB_DBG_LEVEL >= USB_DBG_ERROR)
+#define USB_LOG_ERR(fmt, ...) usb_dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
+#else
+#define USB_LOG_ERR(...)
+#endif
+
+void usb_assert(const char *filename, int linenum);
+#define USB_ASSERT(f) \
+ do { \
+ if (!(f)) \
+ usb_assert(__FILE__, __LINE__); \
+ } while (0)
+
+#endif
diff --git a/core/usbd_core.c b/core/usbd_core.c
index 34daa302..6e88ecdb 100644
--- a/core/usbd_core.c
+++ b/core/usbd_core.c
@@ -1,1299 +1,1299 @@
-/**
- * @file usbd_core.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbd_core.h"
-
-#define USBD_EP_CALLBACK_LIST_SEARCH 0
-#define USBD_EP_CALLBACK_ARR_SEARCH 1
-#define USBD_EP_CALLBACK_SEARCH_METHOD USBD_EP_CALLBACK_ARR_SEARCH
-
-/* general descriptor field offsets */
-#define DESC_bLength 0 /** Length offset */
-#define DESC_bDescriptorType 1 /** Descriptor type offset */
-
-/* config descriptor field offsets */
-#define CONF_DESC_wTotalLength 2 /** Total length offset */
-#define CONF_DESC_bConfigurationValue 5 /** Configuration value offset */
-#define CONF_DESC_bmAttributes 7 /** configuration characteristics */
-
-/* interface descriptor field offsets */
-#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
-#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
-
-#define USB_REQUEST_BUFFER_SIZE 256
-#define USB_EP_OUT_NUM 8
-#define USB_EP_IN_NUM 8
-
-static struct usbd_core_cfg_priv {
- /** Setup packet */
- struct usb_setup_packet setup;
- /** Pointer to data buffer */
- uint8_t *ep0_data_buf;
- /** Remaining bytes in buffer */
- uint32_t ep0_data_buf_residue;
- /** Total length of control transfer */
- uint32_t ep0_data_buf_len;
- /** Zero length packet flag of control transfer */
- bool zlp_flag;
- /** Pointer to registered descriptors */
- const uint8_t *descriptors;
- /* Buffer used for storing standard, class and vendor request data */
- uint8_t req_data[USB_REQUEST_BUFFER_SIZE];
-
-#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
- usbd_endpoint_callback in_ep_cb[USB_EP_IN_NUM];
- usbd_endpoint_callback out_ep_cb[USB_EP_OUT_NUM];
-#endif
- /** Variable to check whether the usb has been configured */
- bool configured;
- /** Currently selected configuration */
- uint8_t configuration;
- /** Remote wakeup feature status */
- uint16_t remote_wakeup;
- uint8_t reserved;
-} usbd_core_cfg;
-
-static usb_slist_t usbd_class_head = USB_SLIST_OBJECT_INIT(usbd_class_head);
-static struct usb_msosv1_descriptor *msosv1_desc;
-static struct usb_msosv2_descriptor *msosv2_desc;
-static struct usb_bos_descriptor *bos_desc;
-
-/**
- * @brief print the contents of a setup packet
- *
- * @param [in] setup The setup packet
- *
- */
-static void usbd_print_setup(struct usb_setup_packet *setup)
-{
- USB_LOG_INFO("Setup: "
- "bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\r\n",
- setup->bmRequestType,
- setup->bRequest,
- setup->wValue,
- setup->wIndex,
- setup->wLength);
-}
-
-/**
- * @brief Check if the device is in Configured state
- *
- * @return true if Configured, false otherwise.
- */
-static bool is_device_configured(void)
-{
- return (usbd_core_cfg.configuration != 0);
-}
-/**
- * @brief Check if the interface of given number is valid
- *
- * @param [in] interface Number of the addressed interface
- *
- * This function searches through descriptor and checks
- * is the Host has addressed valid interface.
- *
- * @return true if interface exists - valid
- */
-static bool is_interface_valid(uint8_t interface)
-{
- const uint8_t *p = (uint8_t *)usbd_core_cfg.descriptors;
- const struct usb_configuration_descriptor *cfg_descr;
-
- /* Search through descriptor for matching interface */
- while (p[DESC_bLength] != 0U) {
- if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_CONFIGURATION) {
- cfg_descr = (const struct usb_configuration_descriptor *)p;
-
- if (interface < cfg_descr->bNumInterfaces) {
- return true;
- }
- }
-
- p += p[DESC_bLength];
- }
-
- return false;
-}
-/**
- * @brief Check if the endpoint of given address is valid
- *
- * @param [in] ep Address of the Endpoint
- *
- * This function checks if the Endpoint of given address
- * is valid for the configured device. Valid Endpoint is
- * either Control Endpoint or one used by the device.
- *
- * @return true if endpoint exists - valid
- */
-static bool is_ep_valid(uint8_t ep)
-{
- /* Check if its Endpoint 0 */
- if ((ep & 0x7f) == 0) {
- return true;
- }
-
- return true;
-}
-#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
-static void usbd_ep_callback_register(void)
-{
- usb_slist_t *i, *j, *k;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- usb_slist_for_each(k, &intf->ep_list)
- {
- usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
-
- if (ept->ep_cb) {
- if (ept->ep_addr & 0x80) {
- usbd_core_cfg.in_ep_cb[ept->ep_addr & 0x7f] = ept->ep_cb;
- } else {
- usbd_core_cfg.out_ep_cb[ept->ep_addr & 0x7f] = ept->ep_cb;
- }
- }
- }
- }
- }
-}
-#endif
-/**
- * @brief configure and enable endpoint
- *
- * This function sets endpoint configuration according to one specified in USB
- * endpoint descriptor and then enables it for data transfers.
- *
- * @param [in] ep_desc Endpoint descriptor byte array
- *
- * @return true if successfully configured and enabled
- */
-static bool usbd_set_endpoint(const struct usb_endpoint_descriptor *ep_desc)
-{
- struct usbd_endpoint_cfg ep_cfg;
-
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_type = ep_desc->bmAttributes & USBD_EP_TYPE_MASK;
-
- USB_LOG_INFO("Open endpoint:0x%x type:%u mps:%u\r\n",
- ep_cfg.ep_addr, ep_cfg.ep_type, ep_cfg.ep_mps);
-
- usbd_ep_open(&ep_cfg);
- usbd_core_cfg.configured = true;
-
- return true;
-}
-/**
- * @brief Disable endpoint for transferring data
- *
- * This function cancels transfers that are associated with endpoint and
- * disabled endpoint itself.
- *
- * @param [in] ep_desc Endpoint descriptor byte array
- *
- * @return true if successfully deconfigured and disabled
- */
-static bool usbd_reset_endpoint(const struct usb_endpoint_descriptor *ep_desc)
-{
- struct usbd_endpoint_cfg ep_cfg;
-
- ep_cfg.ep_addr = ep_desc->bEndpointAddress;
- ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
- ep_cfg.ep_type = ep_desc->bmAttributes & USBD_EP_TYPE_MASK;
-
- USB_LOG_INFO("Close endpoint:0x%x type:%u\r\n",
- ep_cfg.ep_addr, ep_cfg.ep_type);
-
- usbd_ep_close(ep_cfg.ep_addr);
-
- return true;
-}
-
-/**
- * @brief get specified USB descriptor
- *
- * This function parses the list of installed USB descriptors and attempts
- * to find the specified USB descriptor.
- *
- * @param [in] type_index Type and index of the descriptor
- * @param [out] data Descriptor data
- * @param [out] len Descriptor length
- *
- * @return true if the descriptor was found, false otherwise
- */
-static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *len)
-{
- uint8_t type = 0U;
- uint8_t index = 0U;
- uint8_t *p = NULL;
- uint32_t cur_index = 0U;
- bool found = false;
-
- type = GET_DESC_TYPE(type_index);
- index = GET_DESC_INDEX(type_index);
-
- if ((type == USB_DESCRIPTOR_TYPE_STRING) && (index == USB_OSDESC_STRING_DESC_INDEX)) {
- USB_LOG_INFO("read MS OS 2.0 descriptor string\r\n");
-
- if (!msosv1_desc) {
- return false;
- }
-
- *data = (uint8_t *)msosv1_desc->string;
- *len = msosv1_desc->string_len;
-
- return true;
- } else if (type == USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE) {
- USB_LOG_INFO("read BOS descriptor string\r\n");
-
- if (!bos_desc) {
- return false;
- }
-
- *data = bos_desc->string;
- *len = bos_desc->string_len;
- return true;
- }
- /*
- * Invalid types of descriptors,
- * see USB Spec. Revision 2.0, 9.4.3 Get Descriptor
- */
- else if ((type == USB_DESCRIPTOR_TYPE_INTERFACE) || (type == USB_DESCRIPTOR_TYPE_ENDPOINT) ||
-#ifndef CONFIG_USB_HS
- (type > USB_DESCRIPTOR_TYPE_ENDPOINT)) {
-#else
- (type > USB_DESCRIPTOR_TYPE_OTHER_SPEED)) {
-#endif
- return false;
- }
-
- p = (uint8_t *)usbd_core_cfg.descriptors;
-
- cur_index = 0U;
-
- while (p[DESC_bLength] != 0U) {
- if (p[DESC_bDescriptorType] == type) {
- if (cur_index == index) {
- found = true;
- break;
- }
-
- cur_index++;
- }
-
- /* skip to next descriptor */
- p += p[DESC_bLength];
- }
-
- if (found) {
- /* set data pointer */
- *data = p;
-
- /* get length from structure */
- if (type == USB_DESCRIPTOR_TYPE_CONFIGURATION) {
- /* configuration descriptor is an
- * exception, length is at offset
- * 2 and 3
- */
- *len = (p[CONF_DESC_wTotalLength]) |
- (p[CONF_DESC_wTotalLength + 1] << 8);
- } else {
- /* normally length is at offset 0 */
- *len = p[DESC_bLength];
- }
- } else {
- /* nothing found */
- USB_LOG_ERR("descriptor <type:%x,index:%x> not found!\r\n", type, index);
- }
-
- return found;
-}
-
-/**
- * @brief set USB configuration
- *
- * This function configures the device according to the specified configuration
- * index and alternate setting by parsing the installed USB descriptor list.
- * A configuration index of 0 unconfigures the device.
- *
- * @param [in] config_index Configuration index
- * @param [in] alt_setting Alternate setting number
- *
- * @return true if successfully configured false if error or unconfigured
- */
-static bool usbd_set_configuration(uint8_t config_index, uint8_t alt_setting)
-{
- uint8_t *p = (uint8_t *)usbd_core_cfg.descriptors;
- uint8_t cur_alt_setting = 0xFF;
- uint8_t cur_config = 0xFF;
- bool found = false;
-
- if (config_index == 0U) {
- /* TODO: unconfigure device */
- USB_LOG_ERR("Device not configured - invalid configuration\r\n");
- return true;
- }
-
- /* configure endpoints for this configuration/altsetting */
- while (p[DESC_bLength] != 0U) {
- switch (p[DESC_bDescriptorType]) {
- case USB_DESCRIPTOR_TYPE_CONFIGURATION:
- /* remember current configuration index */
- cur_config = p[CONF_DESC_bConfigurationValue];
-
- if (cur_config == config_index) {
- found = true;
- }
-
- break;
-
- case USB_DESCRIPTOR_TYPE_INTERFACE:
- /* remember current alternate setting */
- cur_alt_setting =
- p[INTF_DESC_bAlternateSetting];
- break;
-
- case USB_DESCRIPTOR_TYPE_ENDPOINT:
- if ((cur_config != config_index) ||
- (cur_alt_setting != alt_setting)) {
- break;
- }
-
- found = usbd_set_endpoint((struct usb_endpoint_descriptor *)p);
- break;
-
- default:
- break;
- }
-
- /* skip to next descriptor */
- p += p[DESC_bLength];
- }
-
- return found;
-}
-
-/**
- * @brief set USB interface
- *
- * @param [in] iface Interface index
- * @param [in] alt_setting Alternate setting number
- *
- * @return true if successfully configured false if error or unconfigured
- */
-static bool usbd_set_interface(uint8_t iface, uint8_t alt_setting)
-{
- const uint8_t *p = usbd_core_cfg.descriptors;
- const uint8_t *if_desc = NULL;
- struct usb_endpoint_descriptor *ep_desc;
- uint8_t cur_alt_setting = 0xFF;
- uint8_t cur_iface = 0xFF;
- bool ret = false;
-
- USB_LOG_DBG("iface %u alt_setting %u\r\n", iface, alt_setting);
-
- while (p[DESC_bLength] != 0U) {
- switch (p[DESC_bDescriptorType]) {
- case USB_DESCRIPTOR_TYPE_INTERFACE:
- /* remember current alternate setting */
- cur_alt_setting = p[INTF_DESC_bAlternateSetting];
- cur_iface = p[INTF_DESC_bInterfaceNumber];
-
- if (cur_iface == iface &&
- cur_alt_setting == alt_setting) {
- if_desc = (void *)p;
- }
-
- USB_LOG_DBG("Current iface %u alt setting %u",
- cur_iface, cur_alt_setting);
- break;
-
- case USB_DESCRIPTOR_TYPE_ENDPOINT:
- if (cur_iface == iface) {
- ep_desc = (struct usb_endpoint_descriptor *)p;
-
- if (cur_alt_setting != alt_setting) {
- ret = usbd_reset_endpoint(ep_desc);
- } else {
- ret = usbd_set_endpoint(ep_desc);
- }
- }
-
- break;
-
- default:
- break;
- }
-
- /* skip to next descriptor */
- p += p[DESC_bLength];
- }
-
- usbd_event_notify_handler(USBD_EVENT_SET_INTERFACE, (void *)if_desc);
-
- return ret;
-}
-
-/**
- * @brief handle a standard device request
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static bool usbd_std_device_req_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- uint16_t value = setup->wValue;
- // uint16_t index = setup->wIndex;
- bool ret = true;
-
- switch (setup->bRequest) {
- case USB_REQUEST_GET_STATUS:
- USB_LOG_DBG("REQ_GET_STATUS\r\n");
- /* bit 0: self-powered */
- /* bit 1: remote wakeup */
- *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
-
- *len = 2;
- break;
-
- case USB_REQUEST_CLEAR_FEATURE:
- USB_LOG_DBG("REQ_CLEAR_FEATURE\r\n");
- ret = false;
-
- if (value == USB_FEATURE_REMOTE_WAKEUP) {
- usbd_core_cfg.remote_wakeup = 0;
- usbd_event_notify_handler(USBD_EVENT_CLEAR_REMOTE_WAKEUP, NULL);
- ret = true;
- }
-
- break;
-
- case USB_REQUEST_SET_FEATURE:
- USB_LOG_DBG("REQ_SET_FEATURE\r\n");
- ret = false;
-
- if (value == USB_FEATURE_REMOTE_WAKEUP) {
- usbd_core_cfg.remote_wakeup = 1;
- usbd_event_notify_handler(USBD_EVENT_SET_REMOTE_WAKEUP, NULL);
- ret = true;
- }
-
- if (value == USB_FEATURE_TEST_MODE) {
- /* put TEST_MODE code here */
- }
-
- break;
-
- case USB_REQUEST_SET_ADDRESS:
- USB_LOG_DBG("REQ_SET_ADDRESS, addr 0x%x\r\n", value);
- usbd_set_address(value);
- break;
-
- case USB_REQUEST_GET_DESCRIPTOR:
- USB_LOG_DBG("REQ_GET_DESCRIPTOR\r\n");
- ret = usbd_get_descriptor(value, data, len);
- break;
-
- case USB_REQUEST_SET_DESCRIPTOR:
- USB_LOG_DBG("Device req 0x%02x not implemented\r\n", setup->bRequest);
- ret = false;
- break;
-
- case USB_REQUEST_GET_CONFIGURATION:
- USB_LOG_DBG("REQ_GET_CONFIGURATION\r\n");
- /* indicate if we are configured */
- *data = (uint8_t *)&usbd_core_cfg.configuration;
- *len = 1;
- break;
-
- case USB_REQUEST_SET_CONFIGURATION:
- value &= 0xFF;
- USB_LOG_DBG("REQ_SET_CONFIGURATION, conf 0x%x\r\n", value);
-
- if (!usbd_set_configuration(value, 0)) {
- USB_LOG_DBG("USB Set Configuration failed\r\n");
- ret = false;
- } else {
- /* configuration successful,
- * update current configuration
- */
- usbd_core_cfg.configuration = value;
- usbd_event_notify_handler(USBD_EVENT_CONFIGURED, NULL);
- }
-
- break;
-
- case USB_REQUEST_GET_INTERFACE:
- break;
-
- case USB_REQUEST_SET_INTERFACE:
- break;
-
- default:
- USB_LOG_ERR("Illegal device req 0x%02x\r\n", setup->bRequest);
- ret = false;
- break;
- }
-
- return ret;
-}
-
-/**
- * @brief handle a standard interface request
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static bool usbd_std_interface_req_handler(struct usb_setup_packet *setup,
- uint8_t **data, uint32_t *len)
-{
- /** The device must be configured to accept standard interface
- * requests and the addressed Interface must be valid.
- */
- if (!is_device_configured() ||
- (!is_interface_valid((uint8_t)setup->wIndex))) {
- return false;
- }
-
- switch (setup->bRequest) {
- case USB_REQUEST_GET_STATUS:
- /* no bits specified */
- *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
-
- *len = 2;
- break;
-
- case USB_REQUEST_CLEAR_FEATURE:
- case USB_REQUEST_SET_FEATURE:
- /* not defined for interface */
- return false;
-
- case USB_REQUEST_GET_INTERFACE:
- /** This handler is called for classes that does not support
- * alternate Interfaces so always return 0. Classes that
- * support alternative interfaces handles GET_INTERFACE
- * in custom_handler.
- */
- *data = (uint8_t *)&usbd_core_cfg.reserved;
-
- *len = 1;
- break;
-
- case USB_REQUEST_SET_INTERFACE:
- USB_LOG_DBG("REQ_SET_INTERFACE\r\n");
- usbd_set_interface(setup->wIndex, setup->wValue);
- break;
-
- default:
- USB_LOG_ERR("Illegal interface req 0x%02x\r\n", setup->bRequest);
- return false;
- }
-
- return true;
-}
-
-/**
- * @brief handle a standard endpoint request
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static bool usbd_std_endpoint_req_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- uint8_t ep = (uint8_t)setup->wIndex;
-
- /* Check if request addresses valid Endpoint */
- if (!is_ep_valid(ep)) {
- return false;
- }
-
- switch (setup->bRequest) {
- case USB_REQUEST_GET_STATUS:
-
- /** This request is valid for Control Endpoints when
- * the device is not yet configured. For other
- * Endpoints the device must be configured.
- * Firstly check if addressed ep is Control Endpoint.
- * If no then the device must be in Configured state
- * to accept the request.
- */
- if (((ep & 0x7f) == 0) || is_device_configured()) {
- /* bit 0 - Endpoint halted or not */
- usbd_ep_is_stalled(ep, (uint8_t *)&usbd_core_cfg.remote_wakeup);
- *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
-
- *len = 2;
- break;
- }
-
- return false;
-
- case USB_REQUEST_CLEAR_FEATURE:
- if (setup->wValue == USB_FEATURE_ENDPOINT_HALT) {
- /** This request is valid for Control Endpoints when
- * the device is not yet configured. For other
- * Endpoints the device must be configured.
- * Firstly check if addressed ep is Control Endpoint.
- * If no then the device must be in Configured state
- * to accept the request.
- */
- if (((ep & 0x7f) == 0) || is_device_configured()) {
- USB_LOG_ERR("ep:%x clear halt\r\n", ep);
- usbd_ep_clear_stall(ep);
- usbd_event_notify_handler(USBD_EVENT_CLEAR_HALT, NULL);
- break;
- }
- }
-
- /* only ENDPOINT_HALT defined for endpoints */
- return false;
-
- case USB_REQUEST_SET_FEATURE:
- if (setup->wValue == USB_FEATURE_ENDPOINT_HALT) {
- /** This request is valid for Control Endpoints when
- * the device is not yet configured. For other
- * Endpoints the device must be configured.
- * Firstly check if addressed ep is Control Endpoint.
- * If no then the device must be in Configured state
- * to accept the request.
- */
- if (((ep & 0x7f) == 0) || is_device_configured()) {
- /* set HALT by stalling */
- USB_LOG_ERR("ep:%x set halt\r\n", ep);
- usbd_ep_set_stall(ep);
- usbd_event_notify_handler(USBD_EVENT_SET_HALT, NULL);
- break;
- }
- }
-
- /* only ENDPOINT_HALT defined for endpoints */
- return false;
-
- case USB_REQUEST_SYNCH_FRAME:
-
- /* For Synch Frame request the device must be configured */
- if (is_device_configured()) {
- /* Not supported, return false anyway */
- USB_LOG_DBG("ep req 0x%02x not implemented\r\n", setup->bRequest);
- }
-
- return false;
-
- default:
- USB_LOG_ERR("Illegal ep req 0x%02x\r\n", setup->bRequest);
- return false;
- }
-
- return true;
-}
-
-/**
- * @brief default handler for standard ('chapter 9') requests
- *
- * If a custom request handler was installed, this handler is called first.
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static int usbd_standard_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- int rc = 0;
-
- switch (setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) {
- case USB_REQUEST_RECIPIENT_DEVICE:
- if (usbd_std_device_req_handler(setup, data, len) == false) {
- rc = -1;
- }
-
- break;
-
- case USB_REQUEST_RECIPIENT_INTERFACE:
- if (usbd_std_interface_req_handler(setup, data, len) == false) {
- rc = -1;
- }
-
- break;
-
- case USB_REQUEST_RECIPIENT_ENDPOINT:
- if (usbd_std_endpoint_req_handler(setup, data, len) == false) {
- rc = -1;
- }
-
- break;
-
- default:
- rc = -1;
- }
-
- return rc;
-}
-
-/**
- * @brief handler for class requests
- *
- * If a custom request handler was installed, this handler is called first.
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static int usbd_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("bRequest 0x%02x, wIndex 0x%04x\r\n", setup->bRequest, setup->wIndex);
-
- if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_INTERFACE) {
- return -1;
- }
-
- usb_slist_t *i, *j;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- if (intf->class_handler && (intf->intf_num == (setup->wIndex & 0xFF))) {
- return intf->class_handler(setup, data, len);
- }
- }
- }
- return -1;
-}
-
-/**
- * @brief handler for vendor requests
- *
- * If a custom request handler was installed, this handler is called first.
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static int usbd_vendor_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("bRequest 0x%02x, wValue0x%04x, wIndex 0x%04x\r\n", setup->bRequest, setup->wValue, setup->wIndex);
-
- // if((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_DEVICE)
- // {
- // return -1;
- // }
-
- if (msosv1_desc) {
- if (setup->bRequest == msosv1_desc->vendor_code) {
- switch (setup->wIndex) {
- case 0x04:
- USB_LOG_INFO("get Compat ID\r\n");
- *data = (uint8_t *)msosv1_desc->compat_id;
- *len = msosv1_desc->compat_id_len;
-
- return 0;
- case 0x05:
- USB_LOG_INFO("get Compat id properties\r\n");
- *data = (uint8_t *)msosv1_desc->comp_id_property;
- *len = msosv1_desc->comp_id_property_len;
-
- return 0;
- default:
- USB_LOG_ERR("unknown vendor code\r\n");
- return -1;
- }
- }
- } else if (msosv2_desc) {
- if (setup->bRequest == msosv2_desc->vendor_code) {
- switch (setup->wIndex) {
- case WINUSB_REQUEST_GET_DESCRIPTOR_SET:
- USB_LOG_INFO("GET MS OS 2.0 Descriptor\r\n");
- *data = (uint8_t *)msosv2_desc->compat_id;
- *len = msosv2_desc->compat_id_len;
- return 0;
- default:
- USB_LOG_ERR("unknown vendor code\r\n");
- return -1;
- }
- }
- }
-
- usb_slist_t *i, *j;
-
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- if (intf->vendor_handler && !intf->vendor_handler(setup, data, len)) {
- return 0;
- }
- }
- }
-
- return -1;
-}
-
-/**
- * @brief handler for special requests
- *
- * If a custom request handler was installed, this handler is called first.
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handled successfully
- */
-static int usbd_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- USB_LOG_DBG("bRequest 0x%02x, wIndex 0x%04x\r\n", setup->bRequest, setup->wIndex);
-
- if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_INTERFACE) {
- return -1;
- }
-
- usb_slist_t *i, *j;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- if (intf->custom_handler && (intf->intf_num == (setup->wIndex & 0xFF))) {
- return intf->custom_handler(setup, data, len);
- }
- }
- }
-
- return -1;
-}
-
-/**
- * @brief handle a request by calling one of the installed request handlers
- *
- * Local function to handle a request by calling one of the installed request
- * handlers. In case of data going from host to device, the data is at *ppbData.
- * In case of data going from device to host, the handler can either choose to
- * write its data at *ppbData or update the data pointer.
- *
- * @param [in] setup The setup packet
- * @param [in,out] data Data buffer
- * @param [in,out] len Pointer to data length
- *
- * @return true if the request was handles successfully
- */
-static bool usbd_setup_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
-{
- uint8_t type = setup->bmRequestType & USB_REQUEST_TYPE_MASK;
-
- if (!usbd_custom_request_handler(setup, data, len)) {
- return true;
- }
-
- if (type == USB_REQUEST_STANDARD) {
- if (usbd_standard_request_handler(setup, data, len) < 0) {
- USB_LOG_ERR("Handler Error %d\r\n", type);
- usbd_print_setup(setup);
- return false;
- }
- } else if (type == USB_REQUEST_CLASS) {
- if (usbd_class_request_handler(setup, data, len) < 0) {
- USB_LOG_ERR("Handler Error %d\r\n", type);
- usbd_print_setup(setup);
- return false;
- }
- } else if (type == USB_REQUEST_VENDOR) {
- if (usbd_vendor_request_handler(setup, data, len) < 0) {
- USB_LOG_ERR("Handler Error %d\r\n", type);
- usbd_print_setup(setup);
- return false;
- }
- } else {
- return false;
- }
-
- return true;
-}
-/**
- * @brief send data or status to host
- *
- * @return N/A
- */
-static void usbd_send_to_host(uint16_t len)
-{
- uint32_t chunk = 0U;
-
- if (usbd_core_cfg.zlp_flag == false) {
- chunk = usbd_core_cfg.ep0_data_buf_residue;
-
- if (usbd_ep_write(USB_CONTROL_IN_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue, &chunk) < 0) {
- USB_LOG_ERR("USB write data failed\r\n");
- return;
- }
-
- usbd_core_cfg.ep0_data_buf += chunk;
- usbd_core_cfg.ep0_data_buf_residue -= chunk;
-
- /*
- * Set ZLP flag when host asks for a bigger length and the
- * last chunk is wMaxPacketSize long, to indicate the last
- * packet.
- */
- if ((!usbd_core_cfg.ep0_data_buf_residue) && (usbd_core_cfg.ep0_data_buf_len >= USB_CTRL_EP_MPS) && !(usbd_core_cfg.ep0_data_buf_len % USB_CTRL_EP_MPS)) {
- /* Transfers a zero-length packet next*/
- usbd_core_cfg.zlp_flag = true;
- }
- } else {
- usbd_core_cfg.zlp_flag = false;
- USB_LOG_DBG("send zlp\r\n");
- if (usbd_ep_write(USB_CONTROL_IN_EP0, NULL, 0, NULL) < 0) {
- USB_LOG_ERR("USB write zlp failed\r\n");
- return;
- }
- }
-}
-
-static void usbd_ep0_setup_handler(void)
-{
- struct usb_setup_packet *setup = &usbd_core_cfg.setup;
-
- /*
- * OUT transfer, Setup packet,
- * reset request message state machine
- */
- if (usbd_ep_read(USB_CONTROL_OUT_EP0, (uint8_t *)setup,
- sizeof(struct usb_setup_packet), NULL) < 0) {
- USB_LOG_ERR("Read Setup Packet failed\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- return;
- }
-
- //usbd_print_setup(setup);
-
- if (setup->wLength > USB_REQUEST_BUFFER_SIZE) {
- if ((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT) {
- USB_LOG_ERR("Request buffer too small\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- return;
- }
- }
-
- // usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
- usbd_core_cfg.ep0_data_buf_residue = setup->wLength;
- usbd_core_cfg.ep0_data_buf_len = setup->wLength;
- usbd_core_cfg.zlp_flag = false;
-
- /* this maybe set code in class request code */
- if (setup->wLength &&
- (setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT) {
- USB_LOG_DBG("prepare to out data\r\n");
- return;
- }
-
- /* Ask installed handler to process request */
- if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
- USB_LOG_ERR("usbd_setup_request_handler failed\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- return;
- }
-
- /* Send smallest of requested and offered length */
- usbd_core_cfg.ep0_data_buf_residue = MIN(usbd_core_cfg.ep0_data_buf_len,
- setup->wLength);
- /*Send data or status to host*/
- usbd_send_to_host(setup->wLength);
-}
-
-static void usbd_ep0_out_handler(void)
-{
- uint32_t chunk = 0U;
- struct usb_setup_packet *setup = &usbd_core_cfg.setup;
-
- /* OUT transfer, status packets */
- if (usbd_core_cfg.ep0_data_buf_residue == 0) {
- /* absorb zero-length status message */
- USB_LOG_DBG("recv status\r\n");
-
- if (usbd_ep_read(USB_CONTROL_OUT_EP0,
- NULL,
- 0, NULL) < 0) {
- USB_LOG_ERR("Read DATA Packet failed\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- }
-
- return;
- }
-
- usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
-
- /* OUT transfer, data packets */
- if (usbd_ep_read(USB_CONTROL_OUT_EP0,
- usbd_core_cfg.ep0_data_buf,
- usbd_core_cfg.ep0_data_buf_residue, &chunk) < 0) {
- USB_LOG_ERR("Read DATA Packet failed\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- return;
- }
-
- usbd_core_cfg.ep0_data_buf += chunk;
- usbd_core_cfg.ep0_data_buf_residue -= chunk;
-
- if (usbd_core_cfg.ep0_data_buf_residue == 0) {
- /* Received all, send data to handler */
- usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
-
- if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
- USB_LOG_ERR("usbd_setup_request_handler1 failed\r\n");
- usbd_ep_set_stall(USB_CONTROL_IN_EP0);
- return;
- }
-
- /*Send status to host*/
- usbd_send_to_host(setup->wLength);
- } else {
- USB_LOG_ERR("ep0_data_buf_residue is not zero\r\n");
- }
-}
-
-static void usbd_ep0_in_handler(void)
-{
- struct usb_setup_packet *setup = &usbd_core_cfg.setup;
-
- /* Send more data if available */
- if (usbd_core_cfg.ep0_data_buf_residue != 0 || usbd_core_cfg.zlp_flag == true) {
- usbd_send_to_host(setup->wLength);
- } else {
- /*ep0 tx has completed,and no data to send,so do nothing*/
- }
-}
-
-static void usbd_ep_out_handler(uint8_t ep)
-{
-#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_LIST_SEARCH
- usb_slist_t *i, *j, *k;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- usb_slist_for_each(k, &intf->ep_list)
- {
- usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
-
- if ((ept->ep_addr == ep) && ept->ep_cb) {
- ept->ep_cb(ep);
- }
- }
- }
- }
-#else
-
- if (usbd_core_cfg.out_ep_cb[ep & 0x7f]) {
- usbd_core_cfg.out_ep_cb[ep & 0x7f](ep);
- }
-
-#endif
-}
-
-static void usbd_ep_in_handler(uint8_t ep)
-{
-#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_LIST_SEARCH
- usb_slist_t *i, *j, *k;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- usb_slist_for_each(k, &intf->ep_list)
- {
- usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
-
- if ((ept->ep_addr == ep) && ept->ep_cb) {
- ept->ep_cb(ep);
- }
- }
- }
- }
-#else
-
- if (usbd_core_cfg.in_ep_cb[ep & 0x7f]) {
- usbd_core_cfg.in_ep_cb[ep & 0x7f](ep);
- }
-
-#endif
-}
-
-static void usbd_class_event_notify_handler(uint8_t event, void *arg)
-{
- usb_slist_t *i, *j;
- usb_slist_for_each(i, &usbd_class_head)
- {
- usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
-
- usb_slist_for_each(j, &devclass->intf_list)
- {
- usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
-
- if (intf->notify_handler) {
- intf->notify_handler(event, arg);
- }
- }
- }
-}
-
-void usbd_event_notify_handler(uint8_t event, void *arg)
-{
- switch (event) {
- case USBD_EVENT_RESET:
- usbd_set_address(0);
- usbd_core_cfg.configured = 0;
- usbd_core_cfg.configuration = 0;
- struct usbd_endpoint_cfg ep0_cfg;
- ep0_cfg.ep_mps = USB_CTRL_EP_MPS;
- ep0_cfg.ep_type = USBD_EP_TYPE_CTRL;
- ep0_cfg.ep_addr = USB_CONTROL_IN_EP0;
- /*set USB_CONTROL_IN_EP0 nak*/
- usbd_ep_open(&ep0_cfg);
-
- ep0_cfg.ep_addr = USB_CONTROL_OUT_EP0;
- /*set USB_CONTROL_OUT_EP0 ack to prepare receiving setup data*/
- usbd_ep_open(&ep0_cfg);
-#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
- usbd_ep_callback_register();
-#endif
-
- case USBD_EVENT_ERROR:
- case USBD_EVENT_SOF:
- case USBD_EVENT_CONNECTED:
- case USBD_EVENT_CONFIGURED:
- case USBD_EVENT_SUSPEND:
- case USBD_EVENT_DISCONNECTED:
- case USBD_EVENT_RESUME:
- case USBD_EVENT_SET_INTERFACE:
- case USBD_EVENT_SET_REMOTE_WAKEUP:
- case USBD_EVENT_CLEAR_REMOTE_WAKEUP:
- case USBD_EVENT_SET_HALT:
- case USBD_EVENT_CLEAR_HALT:
- usbd_class_event_notify_handler(event, arg);
- break;
-
- case USBD_EVENT_SETUP_NOTIFY:
- usbd_ep0_setup_handler();
- break;
-
- case USBD_EVENT_EP0_IN_NOTIFY:
- usbd_ep0_in_handler();
- break;
-
- case USBD_EVENT_EP0_OUT_NOTIFY:
- usbd_ep0_out_handler();
- break;
-
- case USBD_EVENT_EP_IN_NOTIFY:
- usbd_ep_in_handler((uint32_t)arg);
- break;
-
- case USBD_EVENT_EP_OUT_NOTIFY:
- usbd_ep_out_handler((uint32_t)arg);
- break;
-
- default:
- USB_LOG_ERR("USB unknown event: %d\r\n", event);
- break;
- }
-}
-
-void usbd_desc_register(const uint8_t *desc)
-{
- usbd_core_cfg.descriptors = desc;
-}
-/* Register MS OS Descriptors version 1 */
-void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc)
-{
- msosv1_desc = desc;
-}
-
-/* Register MS OS Descriptors version 2 */
-void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc)
-{
- msosv2_desc = desc;
-}
-
-void usbd_bos_desc_register(struct usb_bos_descriptor *desc)
-{
- bos_desc = desc;
-}
-
-void usbd_class_register(usbd_class_t *devclass)
-{
- usb_slist_add_tail(&usbd_class_head, &devclass->list);
- usb_slist_init(&devclass->intf_list);
-}
-
-void usbd_class_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
-{
- static uint8_t intf_offset = 0;
- intf->intf_num = intf_offset;
- usb_slist_add_tail(&devclass->intf_list, &intf->list);
- usb_slist_init(&intf->ep_list);
- intf_offset++;
-}
-
-void usbd_interface_add_endpoint(usbd_interface_t *intf, usbd_endpoint_t *ep)
-{
- usb_slist_add_tail(&intf->ep_list, &ep->list);
-}
-
-bool usb_device_is_configured(void)
-{
- return usbd_core_cfg.configured;
-}
+/**
+ * @file usbd_core.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbd_core.h"
+
+#define USBD_EP_CALLBACK_LIST_SEARCH 0
+#define USBD_EP_CALLBACK_ARR_SEARCH 1
+#define USBD_EP_CALLBACK_SEARCH_METHOD USBD_EP_CALLBACK_ARR_SEARCH
+
+/* general descriptor field offsets */
+#define DESC_bLength 0 /** Length offset */
+#define DESC_bDescriptorType 1 /** Descriptor type offset */
+
+/* config descriptor field offsets */
+#define CONF_DESC_wTotalLength 2 /** Total length offset */
+#define CONF_DESC_bConfigurationValue 5 /** Configuration value offset */
+#define CONF_DESC_bmAttributes 7 /** configuration characteristics */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+#define USB_REQUEST_BUFFER_SIZE 256
+#define USB_EP_OUT_NUM 8
+#define USB_EP_IN_NUM 8
+
+static struct usbd_core_cfg_priv {
+ /** Setup packet */
+ struct usb_setup_packet setup;
+ /** Pointer to data buffer */
+ uint8_t *ep0_data_buf;
+ /** Remaining bytes in buffer */
+ uint32_t ep0_data_buf_residue;
+ /** Total length of control transfer */
+ uint32_t ep0_data_buf_len;
+ /** Zero length packet flag of control transfer */
+ bool zlp_flag;
+ /** Pointer to registered descriptors */
+ const uint8_t *descriptors;
+ /* Buffer used for storing standard, class and vendor request data */
+ uint8_t req_data[USB_REQUEST_BUFFER_SIZE];
+
+#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
+ usbd_endpoint_callback in_ep_cb[USB_EP_IN_NUM];
+ usbd_endpoint_callback out_ep_cb[USB_EP_OUT_NUM];
+#endif
+ /** Variable to check whether the usb has been configured */
+ bool configured;
+ /** Currently selected configuration */
+ uint8_t configuration;
+ /** Remote wakeup feature status */
+ uint16_t remote_wakeup;
+ uint8_t reserved;
+} usbd_core_cfg;
+
+static usb_slist_t usbd_class_head = USB_SLIST_OBJECT_INIT(usbd_class_head);
+static struct usb_msosv1_descriptor *msosv1_desc;
+static struct usb_msosv2_descriptor *msosv2_desc;
+static struct usb_bos_descriptor *bos_desc;
+
+/**
+ * @brief print the contents of a setup packet
+ *
+ * @param [in] setup The setup packet
+ *
+ */
+static void usbd_print_setup(struct usb_setup_packet *setup)
+{
+ USB_LOG_INFO("Setup: "
+ "bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\r\n",
+ setup->bmRequestType,
+ setup->bRequest,
+ setup->wValue,
+ setup->wIndex,
+ setup->wLength);
+}
+
+/**
+ * @brief Check if the device is in Configured state
+ *
+ * @return true if Configured, false otherwise.
+ */
+static bool is_device_configured(void)
+{
+ return (usbd_core_cfg.configuration != 0);
+}
+/**
+ * @brief Check if the interface of given number is valid
+ *
+ * @param [in] interface Number of the addressed interface
+ *
+ * This function searches through descriptor and checks
+ * is the Host has addressed valid interface.
+ *
+ * @return true if interface exists - valid
+ */
+static bool is_interface_valid(uint8_t interface)
+{
+ const uint8_t *p = (uint8_t *)usbd_core_cfg.descriptors;
+ const struct usb_configuration_descriptor *cfg_descr;
+
+ /* Search through descriptor for matching interface */
+ while (p[DESC_bLength] != 0U) {
+ if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_CONFIGURATION) {
+ cfg_descr = (const struct usb_configuration_descriptor *)p;
+
+ if (interface < cfg_descr->bNumInterfaces) {
+ return true;
+ }
+ }
+
+ p += p[DESC_bLength];
+ }
+
+ return false;
+}
+/**
+ * @brief Check if the endpoint of given address is valid
+ *
+ * @param [in] ep Address of the Endpoint
+ *
+ * This function checks if the Endpoint of given address
+ * is valid for the configured device. Valid Endpoint is
+ * either Control Endpoint or one used by the device.
+ *
+ * @return true if endpoint exists - valid
+ */
+static bool is_ep_valid(uint8_t ep)
+{
+ /* Check if its Endpoint 0 */
+ if ((ep & 0x7f) == 0) {
+ return true;
+ }
+
+ return true;
+}
+#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
+static void usbd_ep_callback_register(void)
+{
+ usb_slist_t *i, *j, *k;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ usb_slist_for_each(k, &intf->ep_list)
+ {
+ usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
+
+ if (ept->ep_cb) {
+ if (ept->ep_addr & 0x80) {
+ usbd_core_cfg.in_ep_cb[ept->ep_addr & 0x7f] = ept->ep_cb;
+ } else {
+ usbd_core_cfg.out_ep_cb[ept->ep_addr & 0x7f] = ept->ep_cb;
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+/**
+ * @brief configure and enable endpoint
+ *
+ * This function sets endpoint configuration according to one specified in USB
+ * endpoint descriptor and then enables it for data transfers.
+ *
+ * @param [in] ep_desc Endpoint descriptor byte array
+ *
+ * @return true if successfully configured and enabled
+ */
+static bool usbd_set_endpoint(const struct usb_endpoint_descriptor *ep_desc)
+{
+ struct usbd_endpoint_cfg ep_cfg;
+
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USBD_EP_TYPE_MASK;
+
+ USB_LOG_INFO("Open endpoint:0x%x type:%u mps:%u\r\n",
+ ep_cfg.ep_addr, ep_cfg.ep_type, ep_cfg.ep_mps);
+
+ usbd_ep_open(&ep_cfg);
+ usbd_core_cfg.configured = true;
+
+ return true;
+}
+/**
+ * @brief Disable endpoint for transferring data
+ *
+ * This function cancels transfers that are associated with endpoint and
+ * disabled endpoint itself.
+ *
+ * @param [in] ep_desc Endpoint descriptor byte array
+ *
+ * @return true if successfully deconfigured and disabled
+ */
+static bool usbd_reset_endpoint(const struct usb_endpoint_descriptor *ep_desc)
+{
+ struct usbd_endpoint_cfg ep_cfg;
+
+ ep_cfg.ep_addr = ep_desc->bEndpointAddress;
+ ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
+ ep_cfg.ep_type = ep_desc->bmAttributes & USBD_EP_TYPE_MASK;
+
+ USB_LOG_INFO("Close endpoint:0x%x type:%u\r\n",
+ ep_cfg.ep_addr, ep_cfg.ep_type);
+
+ usbd_ep_close(ep_cfg.ep_addr);
+
+ return true;
+}
+
+/**
+ * @brief get specified USB descriptor
+ *
+ * This function parses the list of installed USB descriptors and attempts
+ * to find the specified USB descriptor.
+ *
+ * @param [in] type_index Type and index of the descriptor
+ * @param [out] data Descriptor data
+ * @param [out] len Descriptor length
+ *
+ * @return true if the descriptor was found, false otherwise
+ */
+static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *len)
+{
+ uint8_t type = 0U;
+ uint8_t index = 0U;
+ uint8_t *p = NULL;
+ uint32_t cur_index = 0U;
+ bool found = false;
+
+ type = GET_DESC_TYPE(type_index);
+ index = GET_DESC_INDEX(type_index);
+
+ if ((type == USB_DESCRIPTOR_TYPE_STRING) && (index == USB_OSDESC_STRING_DESC_INDEX)) {
+ USB_LOG_INFO("read MS OS 2.0 descriptor string\r\n");
+
+ if (!msosv1_desc) {
+ return false;
+ }
+
+ *data = (uint8_t *)msosv1_desc->string;
+ *len = msosv1_desc->string_len;
+
+ return true;
+ } else if (type == USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE) {
+ USB_LOG_INFO("read BOS descriptor string\r\n");
+
+ if (!bos_desc) {
+ return false;
+ }
+
+ *data = bos_desc->string;
+ *len = bos_desc->string_len;
+ return true;
+ }
+ /*
+ * Invalid types of descriptors,
+ * see USB Spec. Revision 2.0, 9.4.3 Get Descriptor
+ */
+ else if ((type == USB_DESCRIPTOR_TYPE_INTERFACE) || (type == USB_DESCRIPTOR_TYPE_ENDPOINT) ||
+#ifndef CONFIG_USB_HS
+ (type > USB_DESCRIPTOR_TYPE_ENDPOINT)) {
+#else
+ (type > USB_DESCRIPTOR_TYPE_OTHER_SPEED)) {
+#endif
+ return false;
+ }
+
+ p = (uint8_t *)usbd_core_cfg.descriptors;
+
+ cur_index = 0U;
+
+ while (p[DESC_bLength] != 0U) {
+ if (p[DESC_bDescriptorType] == type) {
+ if (cur_index == index) {
+ found = true;
+ break;
+ }
+
+ cur_index++;
+ }
+
+ /* skip to next descriptor */
+ p += p[DESC_bLength];
+ }
+
+ if (found) {
+ /* set data pointer */
+ *data = p;
+
+ /* get length from structure */
+ if (type == USB_DESCRIPTOR_TYPE_CONFIGURATION) {
+ /* configuration descriptor is an
+ * exception, length is at offset
+ * 2 and 3
+ */
+ *len = (p[CONF_DESC_wTotalLength]) |
+ (p[CONF_DESC_wTotalLength + 1] << 8);
+ } else {
+ /* normally length is at offset 0 */
+ *len = p[DESC_bLength];
+ }
+ } else {
+ /* nothing found */
+ USB_LOG_ERR("descriptor <type:%x,index:%x> not found!\r\n", type, index);
+ }
+
+ return found;
+}
+
+/**
+ * @brief set USB configuration
+ *
+ * This function configures the device according to the specified configuration
+ * index and alternate setting by parsing the installed USB descriptor list.
+ * A configuration index of 0 unconfigures the device.
+ *
+ * @param [in] config_index Configuration index
+ * @param [in] alt_setting Alternate setting number
+ *
+ * @return true if successfully configured false if error or unconfigured
+ */
+static bool usbd_set_configuration(uint8_t config_index, uint8_t alt_setting)
+{
+ uint8_t *p = (uint8_t *)usbd_core_cfg.descriptors;
+ uint8_t cur_alt_setting = 0xFF;
+ uint8_t cur_config = 0xFF;
+ bool found = false;
+
+ if (config_index == 0U) {
+ /* TODO: unconfigure device */
+ USB_LOG_ERR("Device not configured - invalid configuration\r\n");
+ return true;
+ }
+
+ /* configure endpoints for this configuration/altsetting */
+ while (p[DESC_bLength] != 0U) {
+ switch (p[DESC_bDescriptorType]) {
+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+ /* remember current configuration index */
+ cur_config = p[CONF_DESC_bConfigurationValue];
+
+ if (cur_config == config_index) {
+ found = true;
+ }
+
+ break;
+
+ case USB_DESCRIPTOR_TYPE_INTERFACE:
+ /* remember current alternate setting */
+ cur_alt_setting =
+ p[INTF_DESC_bAlternateSetting];
+ break;
+
+ case USB_DESCRIPTOR_TYPE_ENDPOINT:
+ if ((cur_config != config_index) ||
+ (cur_alt_setting != alt_setting)) {
+ break;
+ }
+
+ found = usbd_set_endpoint((struct usb_endpoint_descriptor *)p);
+ break;
+
+ default:
+ break;
+ }
+
+ /* skip to next descriptor */
+ p += p[DESC_bLength];
+ }
+
+ return found;
+}
+
+/**
+ * @brief set USB interface
+ *
+ * @param [in] iface Interface index
+ * @param [in] alt_setting Alternate setting number
+ *
+ * @return true if successfully configured false if error or unconfigured
+ */
+static bool usbd_set_interface(uint8_t iface, uint8_t alt_setting)
+{
+ const uint8_t *p = usbd_core_cfg.descriptors;
+ const uint8_t *if_desc = NULL;
+ struct usb_endpoint_descriptor *ep_desc;
+ uint8_t cur_alt_setting = 0xFF;
+ uint8_t cur_iface = 0xFF;
+ bool ret = false;
+
+ USB_LOG_DBG("iface %u alt_setting %u\r\n", iface, alt_setting);
+
+ while (p[DESC_bLength] != 0U) {
+ switch (p[DESC_bDescriptorType]) {
+ case USB_DESCRIPTOR_TYPE_INTERFACE:
+ /* remember current alternate setting */
+ cur_alt_setting = p[INTF_DESC_bAlternateSetting];
+ cur_iface = p[INTF_DESC_bInterfaceNumber];
+
+ if (cur_iface == iface &&
+ cur_alt_setting == alt_setting) {
+ if_desc = (void *)p;
+ }
+
+ USB_LOG_DBG("Current iface %u alt setting %u",
+ cur_iface, cur_alt_setting);
+ break;
+
+ case USB_DESCRIPTOR_TYPE_ENDPOINT:
+ if (cur_iface == iface) {
+ ep_desc = (struct usb_endpoint_descriptor *)p;
+
+ if (cur_alt_setting != alt_setting) {
+ ret = usbd_reset_endpoint(ep_desc);
+ } else {
+ ret = usbd_set_endpoint(ep_desc);
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /* skip to next descriptor */
+ p += p[DESC_bLength];
+ }
+
+ usbd_event_notify_handler(USBD_EVENT_SET_INTERFACE, (void *)if_desc);
+
+ return ret;
+}
+
+/**
+ * @brief handle a standard device request
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usbd_std_device_req_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ uint16_t value = setup->wValue;
+ // uint16_t index = setup->wIndex;
+ bool ret = true;
+
+ switch (setup->bRequest) {
+ case USB_REQUEST_GET_STATUS:
+ USB_LOG_DBG("REQ_GET_STATUS\r\n");
+ /* bit 0: self-powered */
+ /* bit 1: remote wakeup */
+ *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
+
+ *len = 2;
+ break;
+
+ case USB_REQUEST_CLEAR_FEATURE:
+ USB_LOG_DBG("REQ_CLEAR_FEATURE\r\n");
+ ret = false;
+
+ if (value == USB_FEATURE_REMOTE_WAKEUP) {
+ usbd_core_cfg.remote_wakeup = 0;
+ usbd_event_notify_handler(USBD_EVENT_CLEAR_REMOTE_WAKEUP, NULL);
+ ret = true;
+ }
+
+ break;
+
+ case USB_REQUEST_SET_FEATURE:
+ USB_LOG_DBG("REQ_SET_FEATURE\r\n");
+ ret = false;
+
+ if (value == USB_FEATURE_REMOTE_WAKEUP) {
+ usbd_core_cfg.remote_wakeup = 1;
+ usbd_event_notify_handler(USBD_EVENT_SET_REMOTE_WAKEUP, NULL);
+ ret = true;
+ }
+
+ if (value == USB_FEATURE_TEST_MODE) {
+ /* put TEST_MODE code here */
+ }
+
+ break;
+
+ case USB_REQUEST_SET_ADDRESS:
+ USB_LOG_DBG("REQ_SET_ADDRESS, addr 0x%x\r\n", value);
+ usbd_set_address(value);
+ break;
+
+ case USB_REQUEST_GET_DESCRIPTOR:
+ USB_LOG_DBG("REQ_GET_DESCRIPTOR\r\n");
+ ret = usbd_get_descriptor(value, data, len);
+ break;
+
+ case USB_REQUEST_SET_DESCRIPTOR:
+ USB_LOG_DBG("Device req 0x%02x not implemented\r\n", setup->bRequest);
+ ret = false;
+ break;
+
+ case USB_REQUEST_GET_CONFIGURATION:
+ USB_LOG_DBG("REQ_GET_CONFIGURATION\r\n");
+ /* indicate if we are configured */
+ *data = (uint8_t *)&usbd_core_cfg.configuration;
+ *len = 1;
+ break;
+
+ case USB_REQUEST_SET_CONFIGURATION:
+ value &= 0xFF;
+ USB_LOG_DBG("REQ_SET_CONFIGURATION, conf 0x%x\r\n", value);
+
+ if (!usbd_set_configuration(value, 0)) {
+ USB_LOG_DBG("USB Set Configuration failed\r\n");
+ ret = false;
+ } else {
+ /* configuration successful,
+ * update current configuration
+ */
+ usbd_core_cfg.configuration = value;
+ usbd_event_notify_handler(USBD_EVENT_CONFIGURED, NULL);
+ }
+
+ break;
+
+ case USB_REQUEST_GET_INTERFACE:
+ break;
+
+ case USB_REQUEST_SET_INTERFACE:
+ break;
+
+ default:
+ USB_LOG_ERR("Illegal device req 0x%02x\r\n", setup->bRequest);
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief handle a standard interface request
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usbd_std_interface_req_handler(struct usb_setup_packet *setup,
+ uint8_t **data, uint32_t *len)
+{
+ /** The device must be configured to accept standard interface
+ * requests and the addressed Interface must be valid.
+ */
+ if (!is_device_configured() ||
+ (!is_interface_valid((uint8_t)setup->wIndex))) {
+ return false;
+ }
+
+ switch (setup->bRequest) {
+ case USB_REQUEST_GET_STATUS:
+ /* no bits specified */
+ *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
+
+ *len = 2;
+ break;
+
+ case USB_REQUEST_CLEAR_FEATURE:
+ case USB_REQUEST_SET_FEATURE:
+ /* not defined for interface */
+ return false;
+
+ case USB_REQUEST_GET_INTERFACE:
+ /** This handler is called for classes that does not support
+ * alternate Interfaces so always return 0. Classes that
+ * support alternative interfaces handles GET_INTERFACE
+ * in custom_handler.
+ */
+ *data = (uint8_t *)&usbd_core_cfg.reserved;
+
+ *len = 1;
+ break;
+
+ case USB_REQUEST_SET_INTERFACE:
+ USB_LOG_DBG("REQ_SET_INTERFACE\r\n");
+ usbd_set_interface(setup->wIndex, setup->wValue);
+ break;
+
+ default:
+ USB_LOG_ERR("Illegal interface req 0x%02x\r\n", setup->bRequest);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief handle a standard endpoint request
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usbd_std_endpoint_req_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ uint8_t ep = (uint8_t)setup->wIndex;
+
+ /* Check if request addresses valid Endpoint */
+ if (!is_ep_valid(ep)) {
+ return false;
+ }
+
+ switch (setup->bRequest) {
+ case USB_REQUEST_GET_STATUS:
+
+ /** This request is valid for Control Endpoints when
+ * the device is not yet configured. For other
+ * Endpoints the device must be configured.
+ * Firstly check if addressed ep is Control Endpoint.
+ * If no then the device must be in Configured state
+ * to accept the request.
+ */
+ if (((ep & 0x7f) == 0) || is_device_configured()) {
+ /* bit 0 - Endpoint halted or not */
+ usbd_ep_is_stalled(ep, (uint8_t *)&usbd_core_cfg.remote_wakeup);
+ *data = (uint8_t *)&usbd_core_cfg.remote_wakeup;
+
+ *len = 2;
+ break;
+ }
+
+ return false;
+
+ case USB_REQUEST_CLEAR_FEATURE:
+ if (setup->wValue == USB_FEATURE_ENDPOINT_HALT) {
+ /** This request is valid for Control Endpoints when
+ * the device is not yet configured. For other
+ * Endpoints the device must be configured.
+ * Firstly check if addressed ep is Control Endpoint.
+ * If no then the device must be in Configured state
+ * to accept the request.
+ */
+ if (((ep & 0x7f) == 0) || is_device_configured()) {
+ USB_LOG_ERR("ep:%x clear halt\r\n", ep);
+ usbd_ep_clear_stall(ep);
+ usbd_event_notify_handler(USBD_EVENT_CLEAR_HALT, NULL);
+ break;
+ }
+ }
+
+ /* only ENDPOINT_HALT defined for endpoints */
+ return false;
+
+ case USB_REQUEST_SET_FEATURE:
+ if (setup->wValue == USB_FEATURE_ENDPOINT_HALT) {
+ /** This request is valid for Control Endpoints when
+ * the device is not yet configured. For other
+ * Endpoints the device must be configured.
+ * Firstly check if addressed ep is Control Endpoint.
+ * If no then the device must be in Configured state
+ * to accept the request.
+ */
+ if (((ep & 0x7f) == 0) || is_device_configured()) {
+ /* set HALT by stalling */
+ USB_LOG_ERR("ep:%x set halt\r\n", ep);
+ usbd_ep_set_stall(ep);
+ usbd_event_notify_handler(USBD_EVENT_SET_HALT, NULL);
+ break;
+ }
+ }
+
+ /* only ENDPOINT_HALT defined for endpoints */
+ return false;
+
+ case USB_REQUEST_SYNCH_FRAME:
+
+ /* For Synch Frame request the device must be configured */
+ if (is_device_configured()) {
+ /* Not supported, return false anyway */
+ USB_LOG_DBG("ep req 0x%02x not implemented\r\n", setup->bRequest);
+ }
+
+ return false;
+
+ default:
+ USB_LOG_ERR("Illegal ep req 0x%02x\r\n", setup->bRequest);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief default handler for standard ('chapter 9') requests
+ *
+ * If a custom request handler was installed, this handler is called first.
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static int usbd_standard_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ int rc = 0;
+
+ switch (setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) {
+ case USB_REQUEST_RECIPIENT_DEVICE:
+ if (usbd_std_device_req_handler(setup, data, len) == false) {
+ rc = -1;
+ }
+
+ break;
+
+ case USB_REQUEST_RECIPIENT_INTERFACE:
+ if (usbd_std_interface_req_handler(setup, data, len) == false) {
+ rc = -1;
+ }
+
+ break;
+
+ case USB_REQUEST_RECIPIENT_ENDPOINT:
+ if (usbd_std_endpoint_req_handler(setup, data, len) == false) {
+ rc = -1;
+ }
+
+ break;
+
+ default:
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/**
+ * @brief handler for class requests
+ *
+ * If a custom request handler was installed, this handler is called first.
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static int usbd_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("bRequest 0x%02x, wIndex 0x%04x\r\n", setup->bRequest, setup->wIndex);
+
+ if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_INTERFACE) {
+ return -1;
+ }
+
+ usb_slist_t *i, *j;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ if (intf->class_handler && (intf->intf_num == (setup->wIndex & 0xFF))) {
+ return intf->class_handler(setup, data, len);
+ }
+ }
+ }
+ return -1;
+}
+
+/**
+ * @brief handler for vendor requests
+ *
+ * If a custom request handler was installed, this handler is called first.
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static int usbd_vendor_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("bRequest 0x%02x, wValue0x%04x, wIndex 0x%04x\r\n", setup->bRequest, setup->wValue, setup->wIndex);
+
+ // if((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_DEVICE)
+ // {
+ // return -1;
+ // }
+
+ if (msosv1_desc) {
+ if (setup->bRequest == msosv1_desc->vendor_code) {
+ switch (setup->wIndex) {
+ case 0x04:
+ USB_LOG_INFO("get Compat ID\r\n");
+ *data = (uint8_t *)msosv1_desc->compat_id;
+ *len = msosv1_desc->compat_id_len;
+
+ return 0;
+ case 0x05:
+ USB_LOG_INFO("get Compat id properties\r\n");
+ *data = (uint8_t *)msosv1_desc->comp_id_property;
+ *len = msosv1_desc->comp_id_property_len;
+
+ return 0;
+ default:
+ USB_LOG_ERR("unknown vendor code\r\n");
+ return -1;
+ }
+ }
+ } else if (msosv2_desc) {
+ if (setup->bRequest == msosv2_desc->vendor_code) {
+ switch (setup->wIndex) {
+ case WINUSB_REQUEST_GET_DESCRIPTOR_SET:
+ USB_LOG_INFO("GET MS OS 2.0 Descriptor\r\n");
+ *data = (uint8_t *)msosv2_desc->compat_id;
+ *len = msosv2_desc->compat_id_len;
+ return 0;
+ default:
+ USB_LOG_ERR("unknown vendor code\r\n");
+ return -1;
+ }
+ }
+ }
+
+ usb_slist_t *i, *j;
+
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ if (intf->vendor_handler && !intf->vendor_handler(setup, data, len)) {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * @brief handler for special requests
+ *
+ * If a custom request handler was installed, this handler is called first.
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handled successfully
+ */
+static int usbd_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("bRequest 0x%02x, wIndex 0x%04x\r\n", setup->bRequest, setup->wIndex);
+
+ if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) != USB_REQUEST_RECIPIENT_INTERFACE) {
+ return -1;
+ }
+
+ usb_slist_t *i, *j;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ if (intf->custom_handler && (intf->intf_num == (setup->wIndex & 0xFF))) {
+ return intf->custom_handler(setup, data, len);
+ }
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * @brief handle a request by calling one of the installed request handlers
+ *
+ * Local function to handle a request by calling one of the installed request
+ * handlers. In case of data going from host to device, the data is at *ppbData.
+ * In case of data going from device to host, the handler can either choose to
+ * write its data at *ppbData or update the data pointer.
+ *
+ * @param [in] setup The setup packet
+ * @param [in,out] data Data buffer
+ * @param [in,out] len Pointer to data length
+ *
+ * @return true if the request was handles successfully
+ */
+static bool usbd_setup_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ uint8_t type = setup->bmRequestType & USB_REQUEST_TYPE_MASK;
+
+ if (!usbd_custom_request_handler(setup, data, len)) {
+ return true;
+ }
+
+ if (type == USB_REQUEST_STANDARD) {
+ if (usbd_standard_request_handler(setup, data, len) < 0) {
+ USB_LOG_ERR("Handler Error %d\r\n", type);
+ usbd_print_setup(setup);
+ return false;
+ }
+ } else if (type == USB_REQUEST_CLASS) {
+ if (usbd_class_request_handler(setup, data, len) < 0) {
+ USB_LOG_ERR("Handler Error %d\r\n", type);
+ usbd_print_setup(setup);
+ return false;
+ }
+ } else if (type == USB_REQUEST_VENDOR) {
+ if (usbd_vendor_request_handler(setup, data, len) < 0) {
+ USB_LOG_ERR("Handler Error %d\r\n", type);
+ usbd_print_setup(setup);
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+/**
+ * @brief send data or status to host
+ *
+ * @return N/A
+ */
+static void usbd_send_to_host(uint16_t len)
+{
+ uint32_t chunk = 0U;
+
+ if (usbd_core_cfg.zlp_flag == false) {
+ chunk = usbd_core_cfg.ep0_data_buf_residue;
+
+ if (usbd_ep_write(USB_CONTROL_IN_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue, &chunk) < 0) {
+ USB_LOG_ERR("USB write data failed\r\n");
+ return;
+ }
+
+ usbd_core_cfg.ep0_data_buf += chunk;
+ usbd_core_cfg.ep0_data_buf_residue -= chunk;
+
+ /*
+ * Set ZLP flag when host asks for a bigger length and the
+ * last chunk is wMaxPacketSize long, to indicate the last
+ * packet.
+ */
+ if ((!usbd_core_cfg.ep0_data_buf_residue) && (usbd_core_cfg.ep0_data_buf_len >= USB_CTRL_EP_MPS) && !(usbd_core_cfg.ep0_data_buf_len % USB_CTRL_EP_MPS)) {
+ /* Transfers a zero-length packet next*/
+ usbd_core_cfg.zlp_flag = true;
+ }
+ } else {
+ usbd_core_cfg.zlp_flag = false;
+ USB_LOG_DBG("send zlp\r\n");
+ if (usbd_ep_write(USB_CONTROL_IN_EP0, NULL, 0, NULL) < 0) {
+ USB_LOG_ERR("USB write zlp failed\r\n");
+ return;
+ }
+ }
+}
+
+static void usbd_ep0_setup_handler(void)
+{
+ struct usb_setup_packet *setup = &usbd_core_cfg.setup;
+
+ /*
+ * OUT transfer, Setup packet,
+ * reset request message state machine
+ */
+ if (usbd_ep_read(USB_CONTROL_OUT_EP0, (uint8_t *)setup,
+ sizeof(struct usb_setup_packet), NULL) < 0) {
+ USB_LOG_ERR("Read Setup Packet failed\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ return;
+ }
+
+ //usbd_print_setup(setup);
+
+ if (setup->wLength > USB_REQUEST_BUFFER_SIZE) {
+ if ((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT) {
+ USB_LOG_ERR("Request buffer too small\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ return;
+ }
+ }
+
+ // usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
+ usbd_core_cfg.ep0_data_buf_residue = setup->wLength;
+ usbd_core_cfg.ep0_data_buf_len = setup->wLength;
+ usbd_core_cfg.zlp_flag = false;
+
+ /* this maybe set code in class request code */
+ if (setup->wLength &&
+ (setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT) {
+ USB_LOG_DBG("prepare to out data\r\n");
+ return;
+ }
+
+ /* Ask installed handler to process request */
+ if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
+ USB_LOG_ERR("usbd_setup_request_handler failed\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ return;
+ }
+
+ /* Send smallest of requested and offered length */
+ usbd_core_cfg.ep0_data_buf_residue = MIN(usbd_core_cfg.ep0_data_buf_len,
+ setup->wLength);
+ /*Send data or status to host*/
+ usbd_send_to_host(setup->wLength);
+}
+
+static void usbd_ep0_out_handler(void)
+{
+ uint32_t chunk = 0U;
+ struct usb_setup_packet *setup = &usbd_core_cfg.setup;
+
+ /* OUT transfer, status packets */
+ if (usbd_core_cfg.ep0_data_buf_residue == 0) {
+ /* absorb zero-length status message */
+ USB_LOG_DBG("recv status\r\n");
+
+ if (usbd_ep_read(USB_CONTROL_OUT_EP0,
+ NULL,
+ 0, NULL) < 0) {
+ USB_LOG_ERR("Read DATA Packet failed\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ }
+
+ return;
+ }
+
+ usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
+
+ /* OUT transfer, data packets */
+ if (usbd_ep_read(USB_CONTROL_OUT_EP0,
+ usbd_core_cfg.ep0_data_buf,
+ usbd_core_cfg.ep0_data_buf_residue, &chunk) < 0) {
+ USB_LOG_ERR("Read DATA Packet failed\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ return;
+ }
+
+ usbd_core_cfg.ep0_data_buf += chunk;
+ usbd_core_cfg.ep0_data_buf_residue -= chunk;
+
+ if (usbd_core_cfg.ep0_data_buf_residue == 0) {
+ /* Received all, send data to handler */
+ usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
+
+ if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
+ USB_LOG_ERR("usbd_setup_request_handler1 failed\r\n");
+ usbd_ep_set_stall(USB_CONTROL_IN_EP0);
+ return;
+ }
+
+ /*Send status to host*/
+ usbd_send_to_host(setup->wLength);
+ } else {
+ USB_LOG_ERR("ep0_data_buf_residue is not zero\r\n");
+ }
+}
+
+static void usbd_ep0_in_handler(void)
+{
+ struct usb_setup_packet *setup = &usbd_core_cfg.setup;
+
+ /* Send more data if available */
+ if (usbd_core_cfg.ep0_data_buf_residue != 0 || usbd_core_cfg.zlp_flag == true) {
+ usbd_send_to_host(setup->wLength);
+ } else {
+ /*ep0 tx has completed,and no data to send,so do nothing*/
+ }
+}
+
+static void usbd_ep_out_handler(uint8_t ep)
+{
+#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_LIST_SEARCH
+ usb_slist_t *i, *j, *k;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ usb_slist_for_each(k, &intf->ep_list)
+ {
+ usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
+
+ if ((ept->ep_addr == ep) && ept->ep_cb) {
+ ept->ep_cb(ep);
+ }
+ }
+ }
+ }
+#else
+
+ if (usbd_core_cfg.out_ep_cb[ep & 0x7f]) {
+ usbd_core_cfg.out_ep_cb[ep & 0x7f](ep);
+ }
+
+#endif
+}
+
+static void usbd_ep_in_handler(uint8_t ep)
+{
+#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_LIST_SEARCH
+ usb_slist_t *i, *j, *k;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ usb_slist_for_each(k, &intf->ep_list)
+ {
+ usbd_endpoint_t *ept = usb_slist_entry(k, struct usbd_endpoint, list);
+
+ if ((ept->ep_addr == ep) && ept->ep_cb) {
+ ept->ep_cb(ep);
+ }
+ }
+ }
+ }
+#else
+
+ if (usbd_core_cfg.in_ep_cb[ep & 0x7f]) {
+ usbd_core_cfg.in_ep_cb[ep & 0x7f](ep);
+ }
+
+#endif
+}
+
+static void usbd_class_event_notify_handler(uint8_t event, void *arg)
+{
+ usb_slist_t *i, *j;
+ usb_slist_for_each(i, &usbd_class_head)
+ {
+ usbd_class_t *devclass = usb_slist_entry(i, struct usbd_class, list);
+
+ usb_slist_for_each(j, &devclass->intf_list)
+ {
+ usbd_interface_t *intf = usb_slist_entry(j, struct usbd_interface, list);
+
+ if (intf->notify_handler) {
+ intf->notify_handler(event, arg);
+ }
+ }
+ }
+}
+
+void usbd_event_notify_handler(uint8_t event, void *arg)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ usbd_set_address(0);
+ usbd_core_cfg.configured = 0;
+ usbd_core_cfg.configuration = 0;
+ struct usbd_endpoint_cfg ep0_cfg;
+ ep0_cfg.ep_mps = USB_CTRL_EP_MPS;
+ ep0_cfg.ep_type = USBD_EP_TYPE_CTRL;
+ ep0_cfg.ep_addr = USB_CONTROL_IN_EP0;
+ /*set USB_CONTROL_IN_EP0 nak*/
+ usbd_ep_open(&ep0_cfg);
+
+ ep0_cfg.ep_addr = USB_CONTROL_OUT_EP0;
+ /*set USB_CONTROL_OUT_EP0 ack to prepare receiving setup data*/
+ usbd_ep_open(&ep0_cfg);
+#if USBD_EP_CALLBACK_SEARCH_METHOD == USBD_EP_CALLBACK_ARR_SEARCH
+ usbd_ep_callback_register();
+#endif
+
+ case USBD_EVENT_ERROR:
+ case USBD_EVENT_SOF:
+ case USBD_EVENT_CONNECTED:
+ case USBD_EVENT_CONFIGURED:
+ case USBD_EVENT_SUSPEND:
+ case USBD_EVENT_DISCONNECTED:
+ case USBD_EVENT_RESUME:
+ case USBD_EVENT_SET_INTERFACE:
+ case USBD_EVENT_SET_REMOTE_WAKEUP:
+ case USBD_EVENT_CLEAR_REMOTE_WAKEUP:
+ case USBD_EVENT_SET_HALT:
+ case USBD_EVENT_CLEAR_HALT:
+ usbd_class_event_notify_handler(event, arg);
+ break;
+
+ case USBD_EVENT_SETUP_NOTIFY:
+ usbd_ep0_setup_handler();
+ break;
+
+ case USBD_EVENT_EP0_IN_NOTIFY:
+ usbd_ep0_in_handler();
+ break;
+
+ case USBD_EVENT_EP0_OUT_NOTIFY:
+ usbd_ep0_out_handler();
+ break;
+
+ case USBD_EVENT_EP_IN_NOTIFY:
+ usbd_ep_in_handler((uint32_t)arg);
+ break;
+
+ case USBD_EVENT_EP_OUT_NOTIFY:
+ usbd_ep_out_handler((uint32_t)arg);
+ break;
+
+ default:
+ USB_LOG_ERR("USB unknown event: %d\r\n", event);
+ break;
+ }
+}
+
+void usbd_desc_register(const uint8_t *desc)
+{
+ usbd_core_cfg.descriptors = desc;
+}
+/* Register MS OS Descriptors version 1 */
+void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc)
+{
+ msosv1_desc = desc;
+}
+
+/* Register MS OS Descriptors version 2 */
+void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc)
+{
+ msosv2_desc = desc;
+}
+
+void usbd_bos_desc_register(struct usb_bos_descriptor *desc)
+{
+ bos_desc = desc;
+}
+
+void usbd_class_register(usbd_class_t *devclass)
+{
+ usb_slist_add_tail(&usbd_class_head, &devclass->list);
+ usb_slist_init(&devclass->intf_list);
+}
+
+void usbd_class_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
+{
+ static uint8_t intf_offset = 0;
+ intf->intf_num = intf_offset;
+ usb_slist_add_tail(&devclass->intf_list, &intf->list);
+ usb_slist_init(&intf->ep_list);
+ intf_offset++;
+}
+
+void usbd_interface_add_endpoint(usbd_interface_t *intf, usbd_endpoint_t *ep)
+{
+ usb_slist_add_tail(&intf->ep_list, &ep->list);
+}
+
+bool usb_device_is_configured(void)
+{
+ return usbd_core_cfg.configured;
+}
diff --git a/core/usbd_core.h b/core/usbd_core.h
index 0cc33179..8213008a 100644
--- a/core/usbd_core.h
+++ b/core/usbd_core.h
@@ -1,138 +1,138 @@
-/**
- * @file usbd_core.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBD_CORE_H
-#define _USBD_CORE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "usb_util.h"
-#include "usb_def.h"
-#include "usb_dc.h"
-
-enum usbd_event_type {
- /** USB error reported by the controller */
- USBD_EVENT_ERROR,
- /** USB reset */
- USBD_EVENT_RESET,
- /** Start of Frame received */
- USBD_EVENT_SOF,
- /** USB connection established, hardware enumeration is completed */
- USBD_EVENT_CONNECTED,
- /** USB configuration done */
- USBD_EVENT_CONFIGURED,
- /** USB connection suspended by the HOST */
- USBD_EVENT_SUSPEND,
- /** USB connection lost */
- USBD_EVENT_DISCONNECTED,
- /** USB connection resumed by the HOST */
- USBD_EVENT_RESUME,
-
- /** USB interface selected */
- USBD_EVENT_SET_INTERFACE,
- /** USB interface selected */
- USBD_EVENT_SET_REMOTE_WAKEUP,
- /** USB interface selected */
- USBD_EVENT_CLEAR_REMOTE_WAKEUP,
- /** Set Feature ENDPOINT_HALT received */
- USBD_EVENT_SET_HALT,
- /** Clear Feature ENDPOINT_HALT received */
- USBD_EVENT_CLEAR_HALT,
- /** setup packet received */
- USBD_EVENT_SETUP_NOTIFY,
- /** ep0 in packet received */
- USBD_EVENT_EP0_IN_NOTIFY,
- /** ep0 out packet received */
- USBD_EVENT_EP0_OUT_NOTIFY,
- /** ep in packet except ep0 received */
- USBD_EVENT_EP_IN_NOTIFY,
- /** ep out packet except ep0 received */
- USBD_EVENT_EP_OUT_NOTIFY,
- /** Initial USB connection status */
- USBD_EVENT_UNKNOWN
-};
-
-/**
- * @brief Callback function signature for the USB Endpoint status
- */
-typedef void (*usbd_endpoint_callback)(uint8_t ep);
-
-/**
- * @brief Callback function signature for class specific requests
- *
- * Function which handles Class specific requests corresponding to an
- * interface number specified in the device descriptor table. For host
- * to device direction the 'len' and 'payload_data' contain the length
- * of the received data and the pointer to the received data respectively.
- * For device to host class requests, 'len' and 'payload_data' should be
- * set by the callback function with the length and the address of the
- * data to be transmitted buffer respectively.
- */
-typedef int (*usbd_request_handler)(struct usb_setup_packet *setup,
- uint8_t **data, uint32_t *transfer_len);
-
-/* callback function pointer structure for Application to handle events */
-typedef void (*usbd_notify_handler)(uint8_t event, void *arg);
-
-typedef struct usbd_endpoint {
- usb_slist_t list;
- uint8_t ep_addr;
- usbd_endpoint_callback ep_cb;
-} usbd_endpoint_t;
-
-typedef struct usbd_interface {
- usb_slist_t list;
- /** Handler for USB Class specific commands*/
- usbd_request_handler class_handler;
- /** Handler for USB Vendor specific commands */
- usbd_request_handler vendor_handler;
- /** Handler for USB custom specific commands */
- usbd_request_handler custom_handler;
- /** Handler for USB event notify commands */
- usbd_notify_handler notify_handler;
- uint8_t intf_num;
- usb_slist_t ep_list;
-} usbd_interface_t;
-
-typedef struct usbd_class {
- usb_slist_t list;
- const char *name;
- usb_slist_t intf_list;
-} usbd_class_t;
-
-void usbd_event_notify_handler(uint8_t event, void *arg);
-
-void usbd_desc_register(const uint8_t *desc);
-void usbd_class_register(usbd_class_t *devclass);
-void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc);
-void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc);
-void usbd_bos_desc_register(struct usb_bos_descriptor *desc);
-void usbd_class_add_interface(usbd_class_t *devclass, usbd_interface_t *intf);
-void usbd_interface_add_endpoint(usbd_interface_t *intf, usbd_endpoint_t *ep);
-bool usb_device_is_configured(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/**
+ * @file usbd_core.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBD_CORE_H
+#define _USBD_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "usb_util.h"
+#include "usb_def.h"
+#include "usb_dc.h"
+
+enum usbd_event_type {
+ /** USB error reported by the controller */
+ USBD_EVENT_ERROR,
+ /** USB reset */
+ USBD_EVENT_RESET,
+ /** Start of Frame received */
+ USBD_EVENT_SOF,
+ /** USB connection established, hardware enumeration is completed */
+ USBD_EVENT_CONNECTED,
+ /** USB configuration done */
+ USBD_EVENT_CONFIGURED,
+ /** USB connection suspended by the HOST */
+ USBD_EVENT_SUSPEND,
+ /** USB connection lost */
+ USBD_EVENT_DISCONNECTED,
+ /** USB connection resumed by the HOST */
+ USBD_EVENT_RESUME,
+
+ /** USB interface selected */
+ USBD_EVENT_SET_INTERFACE,
+ /** USB interface selected */
+ USBD_EVENT_SET_REMOTE_WAKEUP,
+ /** USB interface selected */
+ USBD_EVENT_CLEAR_REMOTE_WAKEUP,
+ /** Set Feature ENDPOINT_HALT received */
+ USBD_EVENT_SET_HALT,
+ /** Clear Feature ENDPOINT_HALT received */
+ USBD_EVENT_CLEAR_HALT,
+ /** setup packet received */
+ USBD_EVENT_SETUP_NOTIFY,
+ /** ep0 in packet received */
+ USBD_EVENT_EP0_IN_NOTIFY,
+ /** ep0 out packet received */
+ USBD_EVENT_EP0_OUT_NOTIFY,
+ /** ep in packet except ep0 received */
+ USBD_EVENT_EP_IN_NOTIFY,
+ /** ep out packet except ep0 received */
+ USBD_EVENT_EP_OUT_NOTIFY,
+ /** Initial USB connection status */
+ USBD_EVENT_UNKNOWN
+};
+
+/**
+ * @brief Callback function signature for the USB Endpoint status
+ */
+typedef void (*usbd_endpoint_callback)(uint8_t ep);
+
+/**
+ * @brief Callback function signature for class specific requests
+ *
+ * Function which handles Class specific requests corresponding to an
+ * interface number specified in the device descriptor table. For host
+ * to device direction the 'len' and 'payload_data' contain the length
+ * of the received data and the pointer to the received data respectively.
+ * For device to host class requests, 'len' and 'payload_data' should be
+ * set by the callback function with the length and the address of the
+ * data to be transmitted buffer respectively.
+ */
+typedef int (*usbd_request_handler)(struct usb_setup_packet *setup,
+ uint8_t **data, uint32_t *transfer_len);
+
+/* callback function pointer structure for Application to handle events */
+typedef void (*usbd_notify_handler)(uint8_t event, void *arg);
+
+typedef struct usbd_endpoint {
+ usb_slist_t list;
+ uint8_t ep_addr;
+ usbd_endpoint_callback ep_cb;
+} usbd_endpoint_t;
+
+typedef struct usbd_interface {
+ usb_slist_t list;
+ /** Handler for USB Class specific commands*/
+ usbd_request_handler class_handler;
+ /** Handler for USB Vendor specific commands */
+ usbd_request_handler vendor_handler;
+ /** Handler for USB custom specific commands */
+ usbd_request_handler custom_handler;
+ /** Handler for USB event notify commands */
+ usbd_notify_handler notify_handler;
+ uint8_t intf_num;
+ usb_slist_t ep_list;
+} usbd_interface_t;
+
+typedef struct usbd_class {
+ usb_slist_t list;
+ const char *name;
+ usb_slist_t intf_list;
+} usbd_class_t;
+
+void usbd_event_notify_handler(uint8_t event, void *arg);
+
+void usbd_desc_register(const uint8_t *desc);
+void usbd_class_register(usbd_class_t *devclass);
+void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc);
+void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc);
+void usbd_bos_desc_register(struct usb_bos_descriptor *desc);
+void usbd_class_add_interface(usbd_class_t *devclass, usbd_interface_t *intf);
+void usbd_interface_add_endpoint(usbd_interface_t *intf, usbd_endpoint_t *ep);
+bool usb_device_is_configured(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/core/usbh_core.c b/core/usbh_core.c
index 41def3bb..9e77739c 100644
--- a/core/usbh_core.c
+++ b/core/usbh_core.c
@@ -1,989 +1,989 @@
-/**
- * @file usbh_core.c
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "usbh_core.h"
-#include "usbh_cdc_acm.h"
-#include "usbh_hid.h"
-#include "usbh_msc.h"
-
-static const char *speed_table[] = { "error speed", "low speed", "full speed", "high speed" };
-
-static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subcalss, uint8_t protocol, uint16_t vid, uint16_t pid);
-void usbh_hport_activate(struct usbh_hubport *hport);
-void usbh_hport_deactivate(struct usbh_hubport *hport);
-
-/* general descriptor field offsets */
-#define DESC_bLength 0 /** Length offset */
-#define DESC_bDescriptorType 1 /** Descriptor type offset */
-
-#define USB_DEV_ADDR_MAX 0x7f
-#define USB_DEV_ADDR_MARK_OFFSET 5
-#define USB_DEV_ADDR_MARK_MASK 0x1f
-
-struct usbh_devaddr_priv {
- /**
- * alloctab[0]:addr from 0~31
- * alloctab[1]:addr from 32~63
- * alloctab[2]:addr from 64~95
- * alloctab[3]:addr from 96~127
- *
- */
- uint8_t next; /* Next device address */
- uint32_t alloctab[4]; /* Bit allocation table */
-};
-
-struct usbh_roothubport_priv {
- struct usbh_hubport hport; /* Common hub port definitions */
- struct usbh_devaddr_priv devgen; /* Address generation data */
-};
-
-struct usbh_core_priv {
- struct usbh_roothubport_priv rhport[CONFIG_USBHOST_RHPORTS];
- volatile struct usbh_hubport *active_hport; /* Used to pass external hub port events */
- volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */
- usb_osal_sem_t pscsem; /* Semaphore to wait for a port event */
-} usbh_core_cfg;
-
-static inline struct usbh_roothubport_priv *usbh_find_roothub_port(struct usbh_hubport *hport)
-{
- while (hport->parent != NULL) {
- hport = hport->parent->parent;
- }
- return (struct usbh_roothubport_priv *)hport;
-}
-
-static int usbh_allocate_devaddr(struct usbh_devaddr_priv *devgen)
-{
- uint8_t startaddr = devgen->next;
- uint8_t devaddr;
- int index;
- int bitno;
-
- /* Loop until we find a valid device address */
-
- for (;;) {
- /* Try the next device address */
-
- devaddr = devgen->next;
- if (devgen->next >= 0x7f) {
- devgen->next = 1;
- } else {
- devgen->next++;
- }
-
- /* Is this address already allocated? */
-
- index = devaddr >> 5;
- bitno = devaddr & 0x1f;
- if ((devgen->alloctab[index] & (1 << bitno)) == 0) {
- /* No... allocate it now */
-
- devgen->alloctab[index] |= (1 << bitno);
- return (int)devaddr;
- }
-
- /* This address has already been allocated. The following logic will
- * prevent (unexpected) infinite loops.
- */
-
- if (startaddr == devaddr) {
- /* We are back where we started... the are no free device address */
-
- return -ENOMEM;
- }
- }
-}
-
-static int usbh_free_devaddr(struct usbh_devaddr_priv *devgen, uint8_t devaddr)
-{
- int index;
- int bitno;
-
- if ((devaddr > 0) && (devaddr < USB_DEV_ADDR_MAX)) {
- index = devaddr >> USB_DEV_ADDR_MARK_OFFSET;
- bitno = devaddr & USB_DEV_ADDR_MARK_MASK;
-
- /* Free the address by clearing the associated bit in the alloctab[]; */
- if ((devgen->alloctab[index] |= (1 << bitno)) != 0) {
- devgen->alloctab[index] &= ~(1 << bitno);
- } else {
- return -1;
- }
- /* Reset the next pointer if the one just released has a lower value */
-
- if (devaddr < devgen->next) {
- devgen->next = devaddr;
- }
- }
-
- return 0;
-}
-
-static int usbh_devaddr_create(struct usbh_hubport *hport)
-{
- struct usbh_roothubport_priv *rhport;
- rhport = usbh_find_roothub_port(hport);
-
- return usbh_allocate_devaddr(&rhport->devgen);
-}
-
-static int usbh_devaddr_destroy(struct usbh_hubport *hport, uint8_t dev_addr)
-{
- struct usbh_roothubport_priv *rhport;
- rhport = usbh_find_roothub_port(hport);
-
- return usbh_free_devaddr(&rhport->devgen, dev_addr);
-}
-
-static int parse_device_descriptor(struct usbh_hubport *hport, struct usb_device_descriptor *desc, uint16_t length)
-{
- if (desc->bLength != USB_SIZEOF_DEVICE_DESC) {
- USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
- return -EINVAL;
- } else if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_DEVICE) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -EINVAL;
- } else {
- if (length <= 8) {
- return 0;
- }
-#if 0
- USB_LOG_DBG("Device Descriptor:\r\n");
- USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
- USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
- USB_LOG_DBG("bcdUSB: 0x%04x \r\n", desc->bcdUSB);
- USB_LOG_DBG("bDeviceClass: 0x%02x \r\n", desc->bDeviceClass);
- USB_LOG_DBG("bDeviceSubClass: 0x%02x \r\n", desc->bDeviceSubClass);
- USB_LOG_DBG("bDeviceProtocol: 0x%02x \r\n", desc->bDeviceProtocol);
- USB_LOG_DBG("bMaxPacketSize0: 0x%02x \r\n", desc->bMaxPacketSize0);
- USB_LOG_DBG("idVendor: 0x%04x \r\n", desc->idVendor);
- USB_LOG_DBG("idProduct: 0x%04x \r\n", desc->idProduct);
- USB_LOG_DBG("bcdDevice: 0x%04x \r\n", desc->bcdDevice);
- USB_LOG_DBG("iManufacturer: 0x%02x \r\n", desc->iManufacturer);
- USB_LOG_DBG("iProduct: 0x%02x \r\n", desc->iProduct);
- USB_LOG_DBG("iSerialNumber: 0x%02x \r\n", desc->iSerialNumber);
- USB_LOG_DBG("bNumConfigurations: 0x%02x\r\n", desc->bNumConfigurations);
-#endif
- hport->device_desc.bLength = desc->bLength;
- hport->device_desc.bDescriptorType = desc->bDescriptorType;
- hport->device_desc.bcdUSB = desc->bcdUSB;
- hport->device_desc.bDeviceClass = desc->bDeviceClass;
- hport->device_desc.bDeviceSubClass = desc->bDeviceSubClass;
- hport->device_desc.bDeviceProtocol = desc->bDeviceProtocol;
- hport->device_desc.bMaxPacketSize0 = desc->bMaxPacketSize0;
- hport->device_desc.idVendor = desc->idVendor;
- hport->device_desc.idProduct = desc->idProduct;
- hport->device_desc.bcdDevice = desc->bcdDevice;
- hport->device_desc.iManufacturer = desc->iManufacturer;
- hport->device_desc.iProduct = desc->iProduct;
- hport->device_desc.iSerialNumber = desc->iSerialNumber;
- hport->device_desc.bNumConfigurations = desc->bNumConfigurations;
- }
- return 0;
-}
-
-static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_configuration_descriptor *desc, uint16_t length)
-{
- uint32_t total_len = 0;
- uint8_t ep_num = 0;
- uint8_t intf_num = 0;
- uint8_t *p = (uint8_t *)desc;
- if (desc->bLength != USB_SIZEOF_CONFIG_DESC) {
- USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
- return -EINVAL;
- } else if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_CONFIGURATION) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -EINVAL;
- } else {
- if (length <= USB_SIZEOF_CONFIG_DESC) {
- return 0;
- }
-#if 0
- USB_LOG_DBG("Config Descriptor:\r\n");
- USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
- USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
- USB_LOG_DBG("wTotalLength: 0x%04x \r\n", desc->wTotalLength);
- USB_LOG_DBG("bNumInterfaces: 0x%02x \r\n", desc->bNumInterfaces);
- USB_LOG_DBG("bConfigurationValue: 0x%02x \r\n", desc->bConfigurationValue);
- USB_LOG_DBG("iConfiguration: 0x%02x \r\n", desc->iConfiguration);
- USB_LOG_DBG("bmAttributes: 0x%02x \r\n", desc->bmAttributes);
- USB_LOG_DBG("bMaxPower: 0x%02x \r\n", desc->bMaxPower);
-#endif
- hport->config.config_desc.bLength = desc->bLength;
- hport->config.config_desc.bDescriptorType = desc->bDescriptorType;
- hport->config.config_desc.wTotalLength = desc->wTotalLength;
- hport->config.config_desc.bNumInterfaces = desc->bNumInterfaces;
- hport->config.config_desc.bConfigurationValue = desc->bConfigurationValue;
- hport->config.config_desc.iConfiguration = desc->iConfiguration;
- hport->config.config_desc.iConfiguration = desc->iConfiguration;
- hport->config.config_desc.bmAttributes = desc->bmAttributes;
- hport->config.config_desc.bMaxPower = desc->bMaxPower;
-
- if (length > USB_SIZEOF_CONFIG_DESC) {
- while (p[DESC_bLength] && (total_len < desc->wTotalLength) && (intf_num < desc->bNumInterfaces)) {
- p += p[DESC_bLength];
- total_len += p[DESC_bLength];
- if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_INTERFACE) {
- struct usb_interface_descriptor *intf_desc = (struct usb_interface_descriptor *)p;
-#if 0
- USB_LOG_DBG("Interface Descriptor:\r\n");
- USB_LOG_DBG("bLength: 0x%02x \r\n", intf_desc->bLength);
- USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", intf_desc->bDescriptorType);
- USB_LOG_DBG("bInterfaceNumber: 0x%02x \r\n", intf_desc->bInterfaceNumber);
- USB_LOG_DBG("bAlternateSetting: 0x%02x \r\n", intf_desc->bAlternateSetting);
- USB_LOG_DBG("bNumEndpoints: 0x%02x \r\n", intf_desc->bNumEndpoints);
- USB_LOG_DBG("bInterfaceClass: 0x%02x \r\n", intf_desc->bInterfaceClass);
- USB_LOG_DBG("bInterfaceSubClass: 0x%02x \r\n", intf_desc->bInterfaceSubClass);
- USB_LOG_DBG("bInterfaceProtocol: 0x%02x \r\n", intf_desc->bInterfaceProtocol);
- USB_LOG_DBG("iInterface: 0x%02x \r\n", intf_desc->iInterface);
-#endif
- memset(&hport->config.intf[intf_num], 0, sizeof(struct usbh_interface));
-
- hport->config.intf[intf_num].intf_desc.bLength = intf_desc->bLength;
- hport->config.intf[intf_num].intf_desc.bDescriptorType = intf_desc->bDescriptorType;
- hport->config.intf[intf_num].intf_desc.bInterfaceNumber = intf_desc->bInterfaceNumber;
- hport->config.intf[intf_num].intf_desc.bAlternateSetting = intf_desc->bAlternateSetting;
- hport->config.intf[intf_num].intf_desc.bNumEndpoints = intf_desc->bNumEndpoints;
- hport->config.intf[intf_num].intf_desc.bInterfaceClass = intf_desc->bInterfaceClass;
- hport->config.intf[intf_num].intf_desc.bInterfaceSubClass = intf_desc->bInterfaceSubClass;
- hport->config.intf[intf_num].intf_desc.bInterfaceProtocol = intf_desc->bInterfaceProtocol;
- hport->config.intf[intf_num].intf_desc.iInterface = intf_desc->iInterface;
- ep_num = 0;
- while (p[DESC_bLength] && (total_len < desc->wTotalLength) && (ep_num < intf_desc->bNumEndpoints)) {
- p += p[DESC_bLength];
- total_len += p[DESC_bLength];
- if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_ENDPOINT) {
- struct usb_endpoint_descriptor *ep_desc = (struct usb_endpoint_descriptor *)p;
-#if 0
- USB_LOG_DBG("Endpoint Descriptor:\r\n");
- USB_LOG_DBG("bLength: 0x%02x \r\n", ep_desc->bLength);
- USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", ep_desc->bDescriptorType);
- USB_LOG_DBG("bEndpointAddress: 0x%02x \r\n", ep_desc->bEndpointAddress);
- USB_LOG_DBG("bmAttributes: 0x%02x \r\n", ep_desc->bmAttributes);
- USB_LOG_DBG("wMaxPacketSize: 0x%04x \r\n", ep_desc->wMaxPacketSize);
- USB_LOG_DBG("bInterval: 0x%02x \r\n", ep_desc->bInterval);
-#endif
- memset(&hport->config.intf[intf_num].ep[ep_num], 0, sizeof(struct usbh_endpoint));
-
- hport->config.intf[intf_num].ep[ep_num].ep_desc.bLength = ep_desc->bLength;
- hport->config.intf[intf_num].ep[ep_num].ep_desc.bDescriptorType = ep_desc->bDescriptorType;
- hport->config.intf[intf_num].ep[ep_num].ep_desc.bEndpointAddress = ep_desc->bEndpointAddress;
- hport->config.intf[intf_num].ep[ep_num].ep_desc.bmAttributes = ep_desc->bmAttributes;
- hport->config.intf[intf_num].ep[ep_num].ep_desc.wMaxPacketSize = ep_desc->wMaxPacketSize;
- hport->config.intf[intf_num].ep[ep_num].ep_desc.bInterval = ep_desc->bInterval;
- ep_num++;
- }
- }
- intf_num++;
- }
- }
- }
- }
- return 0;
-}
-#if 0
-static int parse_string_descriptor(struct usbh_hubport *hport, struct usb_string_descriptor *desc, uint8_t str_idx, uint16_t length)
-{
- uint8_t string[64 + 1] = { 0 };
- uint8_t *p = (uint8_t *)desc;
-
- if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_STRING) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -2;
- } else {
- p += 2;
- for (uint32_t i = 0; i < (desc->bLength - 2) / 2; i++) {
- string[i] = *p;
- p += 2;
- }
- USB_LOG_DBG("string:%s\r\n", string);
- }
- return 0;
-}
-#endif
-
-static void usbh_print_hubport_info(struct usbh_hubport *hport)
-{
- printf("Device Descriptor:\r\n");
- printf("bLength: 0x%02x \r\n", hport->device_desc.bLength);
- printf("bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
- printf("bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
- printf("bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
- printf("bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
- printf("bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
- printf("bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
- printf("idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
- printf("idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
- printf("bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
- printf("iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
- printf("iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
- printf("iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
- printf("bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
-
- printf("Config Descriptor:\r\n");
- printf("bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
- printf("bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
- printf("wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
- printf("bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
- printf("bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
- printf("iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
- printf("bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
- printf("bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
-
- for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
- printf("Interface Descriptor:\r\n");
- printf("bLength: 0x%02x \r\n", hport->config.intf[i].intf_desc.bLength);
- printf("bDescriptorType: 0x%02x \r\n", hport->config.intf[i].intf_desc.bDescriptorType);
- printf("bInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceNumber);
- printf("bAlternateSetting: 0x%02x \r\n", hport->config.intf[i].intf_desc.bAlternateSetting);
- printf("bNumEndpoints: 0x%02x \r\n", hport->config.intf[i].intf_desc.bNumEndpoints);
- printf("bInterfaceClass: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceClass);
- printf("bInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceSubClass);
- printf("bInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceProtocol);
- printf("iInterface: 0x%02x \r\n", hport->config.intf[i].intf_desc.iInterface);
-
- for (uint8_t j = 0; j < hport->config.intf[i].intf_desc.bNumEndpoints; j++) {
- printf("Endpoint Descriptor:\r\n");
- printf("bLength: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bLength);
- printf("bDescriptorType: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bDescriptorType);
- printf("bEndpointAddress: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bEndpointAddress);
- printf("bmAttributes: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bmAttributes);
- printf("wMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].ep[j].ep_desc.wMaxPacketSize);
- printf("bInterval: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bInterval);
- }
- }
-}
-
-static int usbh_enumerate(struct usbh_hubport *hport)
-{
- struct usb_interface_descriptor *intf_desc;
- struct usb_setup_packet *setup;
- uint8_t *ep0_buffer;
- uint8_t descsize;
- int dev_addr;
- uint8_t ep_mps;
- int ret;
-
-#define USB_REQUEST_BUFFER_SIZE 256
- /* Allocate buffer for setup and data buffer */
- setup = usb_iomalloc(sizeof(struct usb_setup_packet));
- if (setup == NULL) {
- USB_LOG_ERR("Fail to alloc setup\r\n");
- return -ENOMEM;
- }
-
- ep0_buffer = usb_iomalloc(USB_REQUEST_BUFFER_SIZE);
- if (ep0_buffer == NULL) {
- USB_LOG_ERR("Fail to alloc ep0_buffer\r\n");
- return -ENOMEM;
- }
-
- /* Pick an appropriate packet size for this device
- *
- * USB 2.0, Paragraph 5.5.3 "Control Transfer Packet Size Constraints"
- *
- * "An endpoint for control transfers specifies the maximum data
- * payload size that the endpoint can accept from or transmit to
- * the bus. The allowable maximum control transfer data payload
- * sizes for full-speed devices is 8, 16, 32, or 64 bytes; for
- * high-speed devices, it is 64 bytes and for low-speed devices,
- * it is 8 bytes. This maximum applies to the data payloads of the
- * Data packets following a Setup..."
- */
-
- if (hport->speed == USB_SPEED_HIGH) {
- /* For high-speed, we must use 64 bytes */
- ep_mps = 64;
- descsize = USB_SIZEOF_DEVICE_DESC;
- } else {
- /* Eight will work for both low- and full-speed */
- ep_mps = 8;
- descsize = 8;
- }
-
- /* Configure EP0 with the initial maximum packet size */
- usbh_ep0_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
-
- /* Read the first 8 bytes of the device descriptor */
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
- setup->wIndex = 0;
- setup->wLength = descsize;
-
- ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
- if (ret < 0) {
- USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_buffer, descsize);
-
- /* Extract the correct max packetsize from the device descriptor */
- ep_mps = ((struct usb_device_descriptor *)ep0_buffer)->bMaxPacketSize0;
-
- /* And reconfigure EP0 with the correct maximum packet size */
- usbh_ep0_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
-
- /* Assign a function address to the device connected to this port */
- dev_addr = usbh_devaddr_create(hport);
- if (dev_addr < 0) {
- USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- /* Set the USB device address */
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_SET_ADDRESS;
- setup->wValue = dev_addr;
- setup->wIndex = 0;
- setup->wLength = 0;
-
- ret = usbh_control_transfer(hport->ep0, setup, NULL);
- if (ret < 0) {
- USB_LOG_ERR("Failed to set devaddr,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- /* wait device address set completely */
- usb_osal_msleep(2);
-
- /* Assign the function address to the port */
- hport->dev_addr = dev_addr;
-
- /* And reconfigure EP0 with the correct address */
- usbh_ep0_reconfigure(hport->ep0, dev_addr, ep_mps, hport->speed);
-
- /* Read the full device descriptor if hport is not in high speed*/
- if (descsize < USB_SIZEOF_DEVICE_DESC) {
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
- setup->wIndex = 0;
- setup->wLength = USB_SIZEOF_DEVICE_DESC;
-
- ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
- if (ret < 0) {
- USB_LOG_ERR("Failed to get full device descriptor,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_buffer, USB_SIZEOF_DEVICE_DESC);
- }
-
- /* Read the first 9 bytes of the config descriptor */
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
- setup->wIndex = 0;
- setup->wLength = USB_SIZEOF_CONFIG_DESC;
-
- ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
- if (ret < 0) {
- USB_LOG_ERR("Failed to get config descriptor,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_buffer, USB_SIZEOF_CONFIG_DESC);
-
- /* Read the full size of the configuration data */
- uint16_t wTotalLength = ((struct usb_configuration_descriptor *)ep0_buffer)->wTotalLength;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
- setup->wIndex = 0;
- setup->wLength = wTotalLength;
-
- ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
- if (ret < 0) {
- USB_LOG_ERR("Failed to get full config descriptor,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_buffer, wTotalLength);
-
- /* Select device configuration 1 */
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_SET_CONFIGURATION;
- setup->wValue = 1;
- setup->wIndex = 0;
- setup->wLength = 0;
-
- ret = usbh_control_transfer(hport->ep0, setup, NULL);
- if (ret < 0) {
- USB_LOG_ERR("Failed to set configuration,errorcode:%d\r\n", ret);
- goto errout;
- }
-
- /*search supported class driver*/
- for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
- intf_desc = &hport->config.intf[i].intf_desc;
-
- struct usbh_class_driver *class_driver = (struct usbh_class_driver *)usbh_find_class_driver(intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol, hport->device_desc.idVendor, hport->device_desc.idProduct);
-
- if (class_driver == NULL) {
- USB_LOG_ERR("do not support Class:0x%02x,Subclass:0x%02x,Protocl:0x%02x\r\n",
- intf_desc->bInterfaceClass,
- intf_desc->bInterfaceSubClass,
- intf_desc->bInterfaceProtocol);
-
- continue;
- }
- hport->config.intf[i].class_driver = class_driver;
-
- if (hport->config.intf[i].class_driver->connect) {
- ret = CLASS_CONNECT(hport, i);
- if (ret < 0) {
- ret = CLASS_DISCONNECT(hport, i);
- goto errout;
- }
- }
- }
-
-errout:
- if (ret < 0) {
- usbh_hport_deactivate(hport);
- }
-
- if (setup) {
- usb_iofree(setup);
- }
- if (ep0_buffer) {
- usb_iofree(ep0_buffer);
- }
-
- return ret;
-}
-
-static int usbh_portchange_wait(struct usbh_hubport **hport)
-{
- struct usbh_hubport *connport = NULL;
- uint32_t flags;
- int ret;
-
- /* Loop until a change in connection state is detected */
- while (1) {
- /* Check for a change in the connection state on any root hub port */
- flags = usb_osal_enter_critical_section();
- for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- connport = &usbh_core_cfg.rhport[port - 1].hport;
-
- if (connport->port_change) {
- connport->port_change = false;
- *hport = connport;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- }
- /* Is a device connected to an external hub? */
- if (usbh_core_cfg.active_hport) {
- connport = (struct usbh_hubport *)usbh_core_cfg.active_hport;
- usbh_core_cfg.active_hport = NULL;
- *hport = connport;
- usb_osal_leave_critical_section(flags);
- return 0;
- }
- /* No changes on any port. Wait for a connection/disconnection event and check again */
- usbh_core_cfg.pscwait = true;
- usb_osal_leave_critical_section(flags);
- ret = usb_osal_sem_take(usbh_core_cfg.pscsem);
- if (ret < 0) {
- return ret;
- }
- }
-}
-
-static void usbh_portchange_detect_thread(void *argument)
-{
- struct usbh_hubport *hport = NULL;
- uint32_t flags;
-
- flags = usb_osal_enter_critical_section();
- usb_hc_init();
-
- for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- usbh_core_cfg.rhport[port - 1].hport.port = port;
- usbh_core_cfg.rhport[port - 1].devgen.next = 1;
- usbh_hport_activate(&usbh_core_cfg.rhport[port - 1].hport);
- }
-
- usb_osal_leave_critical_section(flags);
-
- while (1) {
- usbh_portchange_wait(&hport);
- if (hport->connected) {
- /*if roothub port,reset port first*/
- if (ROOTHUB(hport)) {
- /* Reset the host port */
- usbh_reset_port(hport->port);
- usb_osal_msleep(200);
- /* Get the current device speed */
- hport->speed = usbh_get_port_speed(hport->port);
- USB_LOG_INFO("Bus %u, Port %u connected, %s\r\n", 1, hport->port, speed_table[hport->speed]);
- } else {
- USB_LOG_INFO("Bus %u, Port %u connected, %s\r\n", hport->parent->index, hport->port, speed_table[hport->speed]);
- }
- usb_osal_thread_suspend(g_lpworkq.thread);
- usbh_enumerate(hport);
- usb_osal_thread_resume(g_lpworkq.thread);
- } else {
- usbh_hport_deactivate(hport);
- for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
- if (hport->config.intf[i].class_driver && hport->config.intf[i].class_driver->disconnect) {
- CLASS_DISCONNECT(hport, i);
- }
- }
-
- hport->config.config_desc.bNumInterfaces = 0;
-
- if (ROOTHUB(hport)) {
- USB_LOG_INFO("Bus %u,Port:%u disconnected\r\n", 1, hport->port);
- } else {
- USB_LOG_INFO("Bus %u,Port:%u disconnected\r\n", hport->parent->index, hport->port);
- }
- }
- }
-}
-
-void usbh_external_hport_connect(struct usbh_hubport *hport)
-{
- uint32_t flags;
-
- usbh_hport_activate(hport);
-
- flags = usb_osal_enter_critical_section();
-
- hport->connected = true;
- usbh_core_cfg.active_hport = hport;
-
- if (usbh_core_cfg.pscwait) {
- usbh_core_cfg.pscwait = false;
- usb_osal_sem_give(usbh_core_cfg.pscsem);
- }
-
- usb_osal_leave_critical_section(flags);
-}
-
-void usbh_external_hport_disconnect(struct usbh_hubport *hport)
-{
- uint32_t flags;
-
- flags = usb_osal_enter_critical_section();
- hport->connected = false;
- usbh_core_cfg.active_hport = hport;
-
- if (usbh_core_cfg.pscwait) {
- usbh_core_cfg.pscwait = false;
- usb_osal_sem_give(usbh_core_cfg.pscsem);
- }
-
- usb_osal_leave_critical_section(flags);
-}
-
-void usbh_hport_activate(struct usbh_hubport *hport)
-{
- struct usbh_endpoint_cfg ep0_cfg;
- uint32_t flags;
-
- flags = usb_osal_enter_critical_section();
- memset(&ep0_cfg, 0, sizeof(struct usbh_endpoint_cfg));
-
- ep0_cfg.ep_addr = 0x00;
- ep0_cfg.ep_interval = 0x00;
- ep0_cfg.ep_mps = 0x08;
- ep0_cfg.ep_type = USB_ENDPOINT_TYPE_CONTROL;
- ep0_cfg.hport = hport;
- /* Allocate memory for roothub port control endpoint */
- usbh_ep_alloc(&hport->ep0, &ep0_cfg);
-
- usb_osal_leave_critical_section(flags);
-}
-
-void usbh_hport_deactivate(struct usbh_hubport *hport)
-{
- uint32_t flags;
-
- flags = usb_osal_enter_critical_section();
- /* Don't free the control pipe of root hub ports! */
- if (hport->parent != NULL && hport->ep0 != NULL) {
- usb_ep_cancel(hport->ep0);
- usbh_ep_free(hport->ep0);
- hport->ep0 = NULL;
- }
- /* Free the device address if one has been assigned */
- usbh_devaddr_destroy(hport, hport->dev_addr);
- hport->dev_addr = 0;
-
- usb_osal_leave_critical_section(flags);
-}
-
-void usbh_event_notify_handler(uint8_t event, uint8_t rhport)
-{
- switch (event) {
- case USBH_EVENT_ATTACHED:
- if (!usbh_core_cfg.rhport[rhport - 1].hport.connected) {
- usbh_core_cfg.rhport[rhport - 1].hport.connected = true;
- usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
- if (usbh_core_cfg.pscwait) {
- usbh_core_cfg.pscwait = false;
- usb_osal_sem_give(usbh_core_cfg.pscsem);
- }
- }
- break;
- case USBH_EVENT_REMOVED:
- if (usbh_core_cfg.rhport[rhport - 1].hport.connected) {
- usbh_core_cfg.rhport[rhport - 1].hport.connected = false;
- usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
- if (usbh_core_cfg.pscwait) {
- usbh_core_cfg.pscwait = false;
- usb_osal_sem_give(usbh_core_cfg.pscsem);
- }
- }
- break;
- default:
- break;
- }
-}
-
-int usbh_initialize(void)
-{
- usb_osal_thread_t usb_thread;
-
- memset(&usbh_core_cfg, 0, sizeof(struct usbh_core_priv));
-
- usbh_workq_initialize();
-
- usbh_core_cfg.pscsem = usb_osal_sem_create(0);
- if (usbh_core_cfg.pscsem == NULL) {
- return -1;
- }
-
- usb_thread = usb_osal_thread_create("usbh_psc", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_portchange_detect_thread, NULL);
- if (usb_thread == NULL) {
- return -1;
- }
-
- return 0;
-}
-
-int lsusb(int argc, char **argv)
-{
- usb_slist_t *hub_list;
- uint8_t port;
-
- if (argc < 2) {
- printf("Usage: lsusb [options]...\r\n");
- printf("List USB devices\r\n");
- printf(" -v, --verbose\r\n");
- printf(" Increase verbosity (show descriptors)\r\n");
- printf(" -s [[bus]:[devnum]]\r\n");
- printf(" Show only devices with specified device and/or bus numbers (in decimal)\r\n");
- printf(" -d vendor:[product]\r\n");
- printf(" Show only devices with the specified vendor and product ID numbers (in hexadecimal)\r\n");
- printf(" -t, --tree\r\n");
- printf(" Dump the physical USB device hierachy as a tree\r\n");
- printf(" -V, --version\r\n");
- printf(" Show version of program\r\n");
- printf(" -h, --help\r\n");
- printf(" Show usage and help\r\n");
- return 0;
- }
-
- if (argc > 3) {
- return 0;
- }
-
- if (strcmp(argv[1], "-t") == 0) {
- for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- if (usbh_core_cfg.rhport[port - 1].hport.connected) {
- printf("/: Bus %02u,VID:PID 0x%04x:0x%04x\r\n", USBH_ROOT_HUB_INDEX, usbh_core_cfg.rhport[port - 1].hport.device_desc.idVendor, usbh_core_cfg.rhport[port - 1].hport.device_desc.idProduct);
-
- for (uint8_t i = 0; i < usbh_core_cfg.rhport[port - 1].hport.config.config_desc.bNumInterfaces; i++) {
- if (usbh_core_cfg.rhport[port - 1].hport.config.intf[i].class_driver->driver_name) {
- printf(" |__Port %u,Port addr:0x%02x,If %u,ClassDriver=%s\r\n", usbh_core_cfg.rhport[port - 1].hport.port, usbh_core_cfg.rhport[port - 1].hport.dev_addr,
- i, usbh_core_cfg.rhport[port - 1].hport.config.intf[i].class_driver->driver_name);
- }
- }
- }
- }
- usb_slist_for_each(hub_list, &hub_class_head)
- {
- usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
- if (hub_class->child[port - 1].connected) {
- printf("/: Bus %02u,VID:PID 0x%04x:0x%04x\r\n", hub_class->index, hub_class->child[port - 1].device_desc.idVendor, hub_class->child[port - 1].device_desc.idProduct);
-
- for (uint8_t i = 0; i < hub_class->child[port - 1].config.config_desc.bNumInterfaces; i++) {
- if (hub_class->child[port - 1].config.intf[i].class_driver->driver_name) {
- printf(" |__Port %u,Port addr:0x%02x,If %u,ClassDriver=%s\r\n", hub_class->child[port - 1].port, hub_class->child[port - 1].dev_addr,
- i, hub_class->child[port - 1].config.intf[i].class_driver->driver_name);
- }
- }
- }
- }
- }
- } else if (strcmp(argv[1], "-v") == 0) {
- for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- if (usbh_core_cfg.rhport[port - 1].hport.connected) {
- printf("Bus %02u,Port %u,Port addr:0x%02x,VID:PID 0x%04x:0x%04x\r\n", USBH_ROOT_HUB_INDEX, usbh_core_cfg.rhport[port - 1].hport.port, usbh_core_cfg.rhport[port - 1].hport.dev_addr,
- usbh_core_cfg.rhport[port - 1].hport.device_desc.idVendor, usbh_core_cfg.rhport[port - 1].hport.device_desc.idProduct);
- usbh_print_hubport_info(&usbh_core_cfg.rhport[port - 1].hport);
- }
- }
-
- usb_slist_for_each(hub_list, &hub_class_head)
- {
- usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
- if (hub_class->child[port - 1].connected) {
- printf("Bus %02u,Port %u,Port addr:0x%02x,VID:PID 0x%04x:0x%04x\r\n", hub_class->index, hub_class->child[port - 1].port, hub_class->child[port - 1].dev_addr,
- hub_class->child[port - 1].device_desc.idVendor, hub_class->child[port - 1].device_desc.idProduct);
- usbh_print_hubport_info(&hub_class->child[port - 1]);
- }
- }
- }
- }
-
- return 0;
-}
-
-struct usbh_hubport *usbh_get_hubport(uint8_t dev_addr)
-{
- usb_slist_t *hub_list;
- uint8_t port;
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- if (usbh_core_cfg.rhport[port - 1].hport.connected) {
- if (usbh_core_cfg.rhport[port - 1].hport.dev_addr == dev_addr) {
- return &usbh_core_cfg.rhport[port - 1].hport;
- }
- }
- }
- usb_slist_for_each(hub_list, &hub_class_head)
- {
- usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
- if (hub_class->child[port - 1].connected) {
- if (hub_class->child[port - 1].dev_addr == dev_addr) {
- return &hub_class->child[port - 1];
- }
- }
- }
- }
- return NULL;
-}
-
-void *usbh_get_class(uint8_t dev_addr, uint8_t intf)
-{
- usb_slist_t *hub_list;
- uint8_t port;
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
- if (usbh_core_cfg.rhport[port - 1].hport.connected) {
- if (usbh_core_cfg.rhport[port - 1].hport.dev_addr == dev_addr) {
- if (usbh_core_cfg.rhport[port - 1].hport.config.intf[intf].priv) {
- return usbh_core_cfg.rhport[port - 1].hport.config.intf[intf].priv;
- }
- }
- }
- }
- usb_slist_for_each(hub_list, &hub_class_head)
- {
- usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
-
- for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
- if (hub_class->child[port - 1].connected) {
- if (hub_class->child[port - 1].dev_addr == dev_addr) {
- if (hub_class->child[port - 1].config.intf[intf].priv) {
- return hub_class->child[port - 1].config.intf[intf].priv;
- }
- }
- }
- }
- }
- return NULL;
-}
-
-const struct usbh_class_info class_info_table[] = {
-
- { .class = USB_DEVICE_CLASS_CDC,
- .subclass = CDC_ABSTRACT_CONTROL_MODEL,
- .protocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &cdc_acm_class_driver },
- { .class = USB_DEVICE_CLASS_HID,
- .subclass = HID_SUBCLASS_BOOTIF,
- .protocol = HID_PROTOCOL_KEYBOARD,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &hid_class_driver },
- { .class = USB_DEVICE_CLASS_HID,
- .subclass = HID_SUBCLASS_BOOTIF,
- .protocol = HID_PROTOCOL_MOUSE,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &hid_class_driver },
- { .class = USB_DEVICE_CLASS_MASS_STORAGE,
- .subclass = MSC_SUBCLASS_SCSI,
- .protocol = MSC_PROTOCOL_BULK_ONLY,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &msc_class_driver },
-#ifdef CONFIG_USBHOST_HUB
- { .class = USB_DEVICE_CLASS_HUB,
- .subclass = 0,
- .protocol = 0,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &hub_class_driver },
- { .class = USB_DEVICE_CLASS_HUB,
- .subclass = 0,
- .protocol = 1,
- .vid = 0x00,
- .pid = 0x00,
- .class_driver = &hub_class_driver },
-#endif
-};
-
-static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subcalss, uint8_t protocol, uint16_t vid, uint16_t pid)
-{
- for (uint8_t i = 0; i < sizeof(class_info_table) / sizeof(class_info_table[0]); i++) {
- if (class == class_info_table[i].class &&
- subcalss == class_info_table[i].subclass &&
- protocol == class_info_table[i].protocol) {
- /* If this is a vendor-specific class ID, then the VID and PID have to match as well. */
- if (class == USB_DEVICE_CLASS_VEND_SPECIFIC) {
- if (vid == class_info_table[i].vid &&
- pid == class_info_table[i].pid) {
- return class_info_table[i].class_driver;
- }
- }
- return class_info_table[i].class_driver;
- }
- }
-
- return NULL;
-}
+/**
+ * @file usbh_core.c
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "usbh_core.h"
+#include "usbh_cdc_acm.h"
+#include "usbh_hid.h"
+#include "usbh_msc.h"
+
+static const char *speed_table[] = { "error speed", "low speed", "full speed", "high speed" };
+
+static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subcalss, uint8_t protocol, uint16_t vid, uint16_t pid);
+void usbh_hport_activate(struct usbh_hubport *hport);
+void usbh_hport_deactivate(struct usbh_hubport *hport);
+
+/* general descriptor field offsets */
+#define DESC_bLength 0 /** Length offset */
+#define DESC_bDescriptorType 1 /** Descriptor type offset */
+
+#define USB_DEV_ADDR_MAX 0x7f
+#define USB_DEV_ADDR_MARK_OFFSET 5
+#define USB_DEV_ADDR_MARK_MASK 0x1f
+
+struct usbh_devaddr_priv {
+ /**
+ * alloctab[0]:addr from 0~31
+ * alloctab[1]:addr from 32~63
+ * alloctab[2]:addr from 64~95
+ * alloctab[3]:addr from 96~127
+ *
+ */
+ uint8_t next; /* Next device address */
+ uint32_t alloctab[4]; /* Bit allocation table */
+};
+
+struct usbh_roothubport_priv {
+ struct usbh_hubport hport; /* Common hub port definitions */
+ struct usbh_devaddr_priv devgen; /* Address generation data */
+};
+
+struct usbh_core_priv {
+ struct usbh_roothubport_priv rhport[CONFIG_USBHOST_RHPORTS];
+ volatile struct usbh_hubport *active_hport; /* Used to pass external hub port events */
+ volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */
+ usb_osal_sem_t pscsem; /* Semaphore to wait for a port event */
+} usbh_core_cfg;
+
+static inline struct usbh_roothubport_priv *usbh_find_roothub_port(struct usbh_hubport *hport)
+{
+ while (hport->parent != NULL) {
+ hport = hport->parent->parent;
+ }
+ return (struct usbh_roothubport_priv *)hport;
+}
+
+static int usbh_allocate_devaddr(struct usbh_devaddr_priv *devgen)
+{
+ uint8_t startaddr = devgen->next;
+ uint8_t devaddr;
+ int index;
+ int bitno;
+
+ /* Loop until we find a valid device address */
+
+ for (;;) {
+ /* Try the next device address */
+
+ devaddr = devgen->next;
+ if (devgen->next >= 0x7f) {
+ devgen->next = 1;
+ } else {
+ devgen->next++;
+ }
+
+ /* Is this address already allocated? */
+
+ index = devaddr >> 5;
+ bitno = devaddr & 0x1f;
+ if ((devgen->alloctab[index] & (1 << bitno)) == 0) {
+ /* No... allocate it now */
+
+ devgen->alloctab[index] |= (1 << bitno);
+ return (int)devaddr;
+ }
+
+ /* This address has already been allocated. The following logic will
+ * prevent (unexpected) infinite loops.
+ */
+
+ if (startaddr == devaddr) {
+ /* We are back where we started... the are no free device address */
+
+ return -ENOMEM;
+ }
+ }
+}
+
+static int usbh_free_devaddr(struct usbh_devaddr_priv *devgen, uint8_t devaddr)
+{
+ int index;
+ int bitno;
+
+ if ((devaddr > 0) && (devaddr < USB_DEV_ADDR_MAX)) {
+ index = devaddr >> USB_DEV_ADDR_MARK_OFFSET;
+ bitno = devaddr & USB_DEV_ADDR_MARK_MASK;
+
+ /* Free the address by clearing the associated bit in the alloctab[]; */
+ if ((devgen->alloctab[index] |= (1 << bitno)) != 0) {
+ devgen->alloctab[index] &= ~(1 << bitno);
+ } else {
+ return -1;
+ }
+ /* Reset the next pointer if the one just released has a lower value */
+
+ if (devaddr < devgen->next) {
+ devgen->next = devaddr;
+ }
+ }
+
+ return 0;
+}
+
+static int usbh_devaddr_create(struct usbh_hubport *hport)
+{
+ struct usbh_roothubport_priv *rhport;
+ rhport = usbh_find_roothub_port(hport);
+
+ return usbh_allocate_devaddr(&rhport->devgen);
+}
+
+static int usbh_devaddr_destroy(struct usbh_hubport *hport, uint8_t dev_addr)
+{
+ struct usbh_roothubport_priv *rhport;
+ rhport = usbh_find_roothub_port(hport);
+
+ return usbh_free_devaddr(&rhport->devgen, dev_addr);
+}
+
+static int parse_device_descriptor(struct usbh_hubport *hport, struct usb_device_descriptor *desc, uint16_t length)
+{
+ if (desc->bLength != USB_SIZEOF_DEVICE_DESC) {
+ USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
+ return -EINVAL;
+ } else if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_DEVICE) {
+ USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+ return -EINVAL;
+ } else {
+ if (length <= 8) {
+ return 0;
+ }
+#if 0
+ USB_LOG_DBG("Device Descriptor:\r\n");
+ USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
+ USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
+ USB_LOG_DBG("bcdUSB: 0x%04x \r\n", desc->bcdUSB);
+ USB_LOG_DBG("bDeviceClass: 0x%02x \r\n", desc->bDeviceClass);
+ USB_LOG_DBG("bDeviceSubClass: 0x%02x \r\n", desc->bDeviceSubClass);
+ USB_LOG_DBG("bDeviceProtocol: 0x%02x \r\n", desc->bDeviceProtocol);
+ USB_LOG_DBG("bMaxPacketSize0: 0x%02x \r\n", desc->bMaxPacketSize0);
+ USB_LOG_DBG("idVendor: 0x%04x \r\n", desc->idVendor);
+ USB_LOG_DBG("idProduct: 0x%04x \r\n", desc->idProduct);
+ USB_LOG_DBG("bcdDevice: 0x%04x \r\n", desc->bcdDevice);
+ USB_LOG_DBG("iManufacturer: 0x%02x \r\n", desc->iManufacturer);
+ USB_LOG_DBG("iProduct: 0x%02x \r\n", desc->iProduct);
+ USB_LOG_DBG("iSerialNumber: 0x%02x \r\n", desc->iSerialNumber);
+ USB_LOG_DBG("bNumConfigurations: 0x%02x\r\n", desc->bNumConfigurations);
+#endif
+ hport->device_desc.bLength = desc->bLength;
+ hport->device_desc.bDescriptorType = desc->bDescriptorType;
+ hport->device_desc.bcdUSB = desc->bcdUSB;
+ hport->device_desc.bDeviceClass = desc->bDeviceClass;
+ hport->device_desc.bDeviceSubClass = desc->bDeviceSubClass;
+ hport->device_desc.bDeviceProtocol = desc->bDeviceProtocol;
+ hport->device_desc.bMaxPacketSize0 = desc->bMaxPacketSize0;
+ hport->device_desc.idVendor = desc->idVendor;
+ hport->device_desc.idProduct = desc->idProduct;
+ hport->device_desc.bcdDevice = desc->bcdDevice;
+ hport->device_desc.iManufacturer = desc->iManufacturer;
+ hport->device_desc.iProduct = desc->iProduct;
+ hport->device_desc.iSerialNumber = desc->iSerialNumber;
+ hport->device_desc.bNumConfigurations = desc->bNumConfigurations;
+ }
+ return 0;
+}
+
+static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_configuration_descriptor *desc, uint16_t length)
+{
+ uint32_t total_len = 0;
+ uint8_t ep_num = 0;
+ uint8_t intf_num = 0;
+ uint8_t *p = (uint8_t *)desc;
+ if (desc->bLength != USB_SIZEOF_CONFIG_DESC) {
+ USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
+ return -EINVAL;
+ } else if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_CONFIGURATION) {
+ USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+ return -EINVAL;
+ } else {
+ if (length <= USB_SIZEOF_CONFIG_DESC) {
+ return 0;
+ }
+#if 0
+ USB_LOG_DBG("Config Descriptor:\r\n");
+ USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
+ USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
+ USB_LOG_DBG("wTotalLength: 0x%04x \r\n", desc->wTotalLength);
+ USB_LOG_DBG("bNumInterfaces: 0x%02x \r\n", desc->bNumInterfaces);
+ USB_LOG_DBG("bConfigurationValue: 0x%02x \r\n", desc->bConfigurationValue);
+ USB_LOG_DBG("iConfiguration: 0x%02x \r\n", desc->iConfiguration);
+ USB_LOG_DBG("bmAttributes: 0x%02x \r\n", desc->bmAttributes);
+ USB_LOG_DBG("bMaxPower: 0x%02x \r\n", desc->bMaxPower);
+#endif
+ hport->config.config_desc.bLength = desc->bLength;
+ hport->config.config_desc.bDescriptorType = desc->bDescriptorType;
+ hport->config.config_desc.wTotalLength = desc->wTotalLength;
+ hport->config.config_desc.bNumInterfaces = desc->bNumInterfaces;
+ hport->config.config_desc.bConfigurationValue = desc->bConfigurationValue;
+ hport->config.config_desc.iConfiguration = desc->iConfiguration;
+ hport->config.config_desc.iConfiguration = desc->iConfiguration;
+ hport->config.config_desc.bmAttributes = desc->bmAttributes;
+ hport->config.config_desc.bMaxPower = desc->bMaxPower;
+
+ if (length > USB_SIZEOF_CONFIG_DESC) {
+ while (p[DESC_bLength] && (total_len < desc->wTotalLength) && (intf_num < desc->bNumInterfaces)) {
+ p += p[DESC_bLength];
+ total_len += p[DESC_bLength];
+ if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_INTERFACE) {
+ struct usb_interface_descriptor *intf_desc = (struct usb_interface_descriptor *)p;
+#if 0
+ USB_LOG_DBG("Interface Descriptor:\r\n");
+ USB_LOG_DBG("bLength: 0x%02x \r\n", intf_desc->bLength);
+ USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", intf_desc->bDescriptorType);
+ USB_LOG_DBG("bInterfaceNumber: 0x%02x \r\n", intf_desc->bInterfaceNumber);
+ USB_LOG_DBG("bAlternateSetting: 0x%02x \r\n", intf_desc->bAlternateSetting);
+ USB_LOG_DBG("bNumEndpoints: 0x%02x \r\n", intf_desc->bNumEndpoints);
+ USB_LOG_DBG("bInterfaceClass: 0x%02x \r\n", intf_desc->bInterfaceClass);
+ USB_LOG_DBG("bInterfaceSubClass: 0x%02x \r\n", intf_desc->bInterfaceSubClass);
+ USB_LOG_DBG("bInterfaceProtocol: 0x%02x \r\n", intf_desc->bInterfaceProtocol);
+ USB_LOG_DBG("iInterface: 0x%02x \r\n", intf_desc->iInterface);
+#endif
+ memset(&hport->config.intf[intf_num], 0, sizeof(struct usbh_interface));
+
+ hport->config.intf[intf_num].intf_desc.bLength = intf_desc->bLength;
+ hport->config.intf[intf_num].intf_desc.bDescriptorType = intf_desc->bDescriptorType;
+ hport->config.intf[intf_num].intf_desc.bInterfaceNumber = intf_desc->bInterfaceNumber;
+ hport->config.intf[intf_num].intf_desc.bAlternateSetting = intf_desc->bAlternateSetting;
+ hport->config.intf[intf_num].intf_desc.bNumEndpoints = intf_desc->bNumEndpoints;
+ hport->config.intf[intf_num].intf_desc.bInterfaceClass = intf_desc->bInterfaceClass;
+ hport->config.intf[intf_num].intf_desc.bInterfaceSubClass = intf_desc->bInterfaceSubClass;
+ hport->config.intf[intf_num].intf_desc.bInterfaceProtocol = intf_desc->bInterfaceProtocol;
+ hport->config.intf[intf_num].intf_desc.iInterface = intf_desc->iInterface;
+ ep_num = 0;
+ while (p[DESC_bLength] && (total_len < desc->wTotalLength) && (ep_num < intf_desc->bNumEndpoints)) {
+ p += p[DESC_bLength];
+ total_len += p[DESC_bLength];
+ if (p[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_ENDPOINT) {
+ struct usb_endpoint_descriptor *ep_desc = (struct usb_endpoint_descriptor *)p;
+#if 0
+ USB_LOG_DBG("Endpoint Descriptor:\r\n");
+ USB_LOG_DBG("bLength: 0x%02x \r\n", ep_desc->bLength);
+ USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", ep_desc->bDescriptorType);
+ USB_LOG_DBG("bEndpointAddress: 0x%02x \r\n", ep_desc->bEndpointAddress);
+ USB_LOG_DBG("bmAttributes: 0x%02x \r\n", ep_desc->bmAttributes);
+ USB_LOG_DBG("wMaxPacketSize: 0x%04x \r\n", ep_desc->wMaxPacketSize);
+ USB_LOG_DBG("bInterval: 0x%02x \r\n", ep_desc->bInterval);
+#endif
+ memset(&hport->config.intf[intf_num].ep[ep_num], 0, sizeof(struct usbh_endpoint));
+
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.bLength = ep_desc->bLength;
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.bDescriptorType = ep_desc->bDescriptorType;
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.bEndpointAddress = ep_desc->bEndpointAddress;
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.bmAttributes = ep_desc->bmAttributes;
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.wMaxPacketSize = ep_desc->wMaxPacketSize;
+ hport->config.intf[intf_num].ep[ep_num].ep_desc.bInterval = ep_desc->bInterval;
+ ep_num++;
+ }
+ }
+ intf_num++;
+ }
+ }
+ }
+ }
+ return 0;
+}
+#if 0
+static int parse_string_descriptor(struct usbh_hubport *hport, struct usb_string_descriptor *desc, uint8_t str_idx, uint16_t length)
+{
+ uint8_t string[64 + 1] = { 0 };
+ uint8_t *p = (uint8_t *)desc;
+
+ if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_STRING) {
+ USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+ return -2;
+ } else {
+ p += 2;
+ for (uint32_t i = 0; i < (desc->bLength - 2) / 2; i++) {
+ string[i] = *p;
+ p += 2;
+ }
+ USB_LOG_DBG("string:%s\r\n", string);
+ }
+ return 0;
+}
+#endif
+
+static void usbh_print_hubport_info(struct usbh_hubport *hport)
+{
+ printf("Device Descriptor:\r\n");
+ printf("bLength: 0x%02x \r\n", hport->device_desc.bLength);
+ printf("bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
+ printf("bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
+ printf("bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
+ printf("bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
+ printf("bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
+ printf("bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
+ printf("idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
+ printf("idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
+ printf("bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
+ printf("iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
+ printf("iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
+ printf("iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
+ printf("bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
+
+ printf("Config Descriptor:\r\n");
+ printf("bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
+ printf("bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
+ printf("wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
+ printf("bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
+ printf("bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
+ printf("iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
+ printf("bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
+ printf("bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
+
+ for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
+ printf("Interface Descriptor:\r\n");
+ printf("bLength: 0x%02x \r\n", hport->config.intf[i].intf_desc.bLength);
+ printf("bDescriptorType: 0x%02x \r\n", hport->config.intf[i].intf_desc.bDescriptorType);
+ printf("bInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceNumber);
+ printf("bAlternateSetting: 0x%02x \r\n", hport->config.intf[i].intf_desc.bAlternateSetting);
+ printf("bNumEndpoints: 0x%02x \r\n", hport->config.intf[i].intf_desc.bNumEndpoints);
+ printf("bInterfaceClass: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceClass);
+ printf("bInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceSubClass);
+ printf("bInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].intf_desc.bInterfaceProtocol);
+ printf("iInterface: 0x%02x \r\n", hport->config.intf[i].intf_desc.iInterface);
+
+ for (uint8_t j = 0; j < hport->config.intf[i].intf_desc.bNumEndpoints; j++) {
+ printf("Endpoint Descriptor:\r\n");
+ printf("bLength: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bLength);
+ printf("bDescriptorType: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bDescriptorType);
+ printf("bEndpointAddress: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bEndpointAddress);
+ printf("bmAttributes: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bmAttributes);
+ printf("wMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].ep[j].ep_desc.wMaxPacketSize);
+ printf("bInterval: 0x%02x \r\n", hport->config.intf[i].ep[j].ep_desc.bInterval);
+ }
+ }
+}
+
+static int usbh_enumerate(struct usbh_hubport *hport)
+{
+ struct usb_interface_descriptor *intf_desc;
+ struct usb_setup_packet *setup;
+ uint8_t *ep0_buffer;
+ uint8_t descsize;
+ int dev_addr;
+ uint8_t ep_mps;
+ int ret;
+
+#define USB_REQUEST_BUFFER_SIZE 256
+ /* Allocate buffer for setup and data buffer */
+ setup = usb_iomalloc(sizeof(struct usb_setup_packet));
+ if (setup == NULL) {
+ USB_LOG_ERR("Fail to alloc setup\r\n");
+ return -ENOMEM;
+ }
+
+ ep0_buffer = usb_iomalloc(USB_REQUEST_BUFFER_SIZE);
+ if (ep0_buffer == NULL) {
+ USB_LOG_ERR("Fail to alloc ep0_buffer\r\n");
+ return -ENOMEM;
+ }
+
+ /* Pick an appropriate packet size for this device
+ *
+ * USB 2.0, Paragraph 5.5.3 "Control Transfer Packet Size Constraints"
+ *
+ * "An endpoint for control transfers specifies the maximum data
+ * payload size that the endpoint can accept from or transmit to
+ * the bus. The allowable maximum control transfer data payload
+ * sizes for full-speed devices is 8, 16, 32, or 64 bytes; for
+ * high-speed devices, it is 64 bytes and for low-speed devices,
+ * it is 8 bytes. This maximum applies to the data payloads of the
+ * Data packets following a Setup..."
+ */
+
+ if (hport->speed == USB_SPEED_HIGH) {
+ /* For high-speed, we must use 64 bytes */
+ ep_mps = 64;
+ descsize = USB_SIZEOF_DEVICE_DESC;
+ } else {
+ /* Eight will work for both low- and full-speed */
+ ep_mps = 8;
+ descsize = 8;
+ }
+
+ /* Configure EP0 with the initial maximum packet size */
+ usbh_ep0_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
+
+ /* Read the first 8 bytes of the device descriptor */
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
+ setup->wIndex = 0;
+ setup->wLength = descsize;
+
+ ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_buffer, descsize);
+
+ /* Extract the correct max packetsize from the device descriptor */
+ ep_mps = ((struct usb_device_descriptor *)ep0_buffer)->bMaxPacketSize0;
+
+ /* And reconfigure EP0 with the correct maximum packet size */
+ usbh_ep0_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
+
+ /* Assign a function address to the device connected to this port */
+ dev_addr = usbh_devaddr_create(hport);
+ if (dev_addr < 0) {
+ USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ /* Set the USB device address */
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_SET_ADDRESS;
+ setup->wValue = dev_addr;
+ setup->wIndex = 0;
+ setup->wLength = 0;
+
+ ret = usbh_control_transfer(hport->ep0, setup, NULL);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to set devaddr,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ /* wait device address set completely */
+ usb_osal_msleep(2);
+
+ /* Assign the function address to the port */
+ hport->dev_addr = dev_addr;
+
+ /* And reconfigure EP0 with the correct address */
+ usbh_ep0_reconfigure(hport->ep0, dev_addr, ep_mps, hport->speed);
+
+ /* Read the full device descriptor if hport is not in high speed*/
+ if (descsize < USB_SIZEOF_DEVICE_DESC) {
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
+ setup->wIndex = 0;
+ setup->wLength = USB_SIZEOF_DEVICE_DESC;
+
+ ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to get full device descriptor,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_buffer, USB_SIZEOF_DEVICE_DESC);
+ }
+
+ /* Read the first 9 bytes of the config descriptor */
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
+ setup->wIndex = 0;
+ setup->wLength = USB_SIZEOF_CONFIG_DESC;
+
+ ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to get config descriptor,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_buffer, USB_SIZEOF_CONFIG_DESC);
+
+ /* Read the full size of the configuration data */
+ uint16_t wTotalLength = ((struct usb_configuration_descriptor *)ep0_buffer)->wTotalLength;
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
+ setup->wIndex = 0;
+ setup->wLength = wTotalLength;
+
+ ret = usbh_control_transfer(hport->ep0, setup, ep0_buffer);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to get full config descriptor,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_buffer, wTotalLength);
+
+ /* Select device configuration 1 */
+ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_SET_CONFIGURATION;
+ setup->wValue = 1;
+ setup->wIndex = 0;
+ setup->wLength = 0;
+
+ ret = usbh_control_transfer(hport->ep0, setup, NULL);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to set configuration,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ /*search supported class driver*/
+ for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
+ intf_desc = &hport->config.intf[i].intf_desc;
+
+ struct usbh_class_driver *class_driver = (struct usbh_class_driver *)usbh_find_class_driver(intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol, hport->device_desc.idVendor, hport->device_desc.idProduct);
+
+ if (class_driver == NULL) {
+ USB_LOG_ERR("do not support Class:0x%02x,Subclass:0x%02x,Protocl:0x%02x\r\n",
+ intf_desc->bInterfaceClass,
+ intf_desc->bInterfaceSubClass,
+ intf_desc->bInterfaceProtocol);
+
+ continue;
+ }
+ hport->config.intf[i].class_driver = class_driver;
+
+ if (hport->config.intf[i].class_driver->connect) {
+ ret = CLASS_CONNECT(hport, i);
+ if (ret < 0) {
+ ret = CLASS_DISCONNECT(hport, i);
+ goto errout;
+ }
+ }
+ }
+
+errout:
+ if (ret < 0) {
+ usbh_hport_deactivate(hport);
+ }
+
+ if (setup) {
+ usb_iofree(setup);
+ }
+ if (ep0_buffer) {
+ usb_iofree(ep0_buffer);
+ }
+
+ return ret;
+}
+
+static int usbh_portchange_wait(struct usbh_hubport **hport)
+{
+ struct usbh_hubport *connport = NULL;
+ uint32_t flags;
+ int ret;
+
+ /* Loop until a change in connection state is detected */
+ while (1) {
+ /* Check for a change in the connection state on any root hub port */
+ flags = usb_osal_enter_critical_section();
+ for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ connport = &usbh_core_cfg.rhport[port - 1].hport;
+
+ if (connport->port_change) {
+ connport->port_change = false;
+ *hport = connport;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ }
+ /* Is a device connected to an external hub? */
+ if (usbh_core_cfg.active_hport) {
+ connport = (struct usbh_hubport *)usbh_core_cfg.active_hport;
+ usbh_core_cfg.active_hport = NULL;
+ *hport = connport;
+ usb_osal_leave_critical_section(flags);
+ return 0;
+ }
+ /* No changes on any port. Wait for a connection/disconnection event and check again */
+ usbh_core_cfg.pscwait = true;
+ usb_osal_leave_critical_section(flags);
+ ret = usb_osal_sem_take(usbh_core_cfg.pscsem);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+}
+
+static void usbh_portchange_detect_thread(void *argument)
+{
+ struct usbh_hubport *hport = NULL;
+ uint32_t flags;
+
+ flags = usb_osal_enter_critical_section();
+ usb_hc_init();
+
+ for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ usbh_core_cfg.rhport[port - 1].hport.port = port;
+ usbh_core_cfg.rhport[port - 1].devgen.next = 1;
+ usbh_hport_activate(&usbh_core_cfg.rhport[port - 1].hport);
+ }
+
+ usb_osal_leave_critical_section(flags);
+
+ while (1) {
+ usbh_portchange_wait(&hport);
+ if (hport->connected) {
+ /*if roothub port,reset port first*/
+ if (ROOTHUB(hport)) {
+ /* Reset the host port */
+ usbh_reset_port(hport->port);
+ usb_osal_msleep(200);
+ /* Get the current device speed */
+ hport->speed = usbh_get_port_speed(hport->port);
+ USB_LOG_INFO("Bus %u, Port %u connected, %s\r\n", 1, hport->port, speed_table[hport->speed]);
+ } else {
+ USB_LOG_INFO("Bus %u, Port %u connected, %s\r\n", hport->parent->index, hport->port, speed_table[hport->speed]);
+ }
+ usb_osal_thread_suspend(g_lpworkq.thread);
+ usbh_enumerate(hport);
+ usb_osal_thread_resume(g_lpworkq.thread);
+ } else {
+ usbh_hport_deactivate(hport);
+ for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
+ if (hport->config.intf[i].class_driver && hport->config.intf[i].class_driver->disconnect) {
+ CLASS_DISCONNECT(hport, i);
+ }
+ }
+
+ hport->config.config_desc.bNumInterfaces = 0;
+
+ if (ROOTHUB(hport)) {
+ USB_LOG_INFO("Bus %u,Port:%u disconnected\r\n", 1, hport->port);
+ } else {
+ USB_LOG_INFO("Bus %u,Port:%u disconnected\r\n", hport->parent->index, hport->port);
+ }
+ }
+ }
+}
+
+void usbh_external_hport_connect(struct usbh_hubport *hport)
+{
+ uint32_t flags;
+
+ usbh_hport_activate(hport);
+
+ flags = usb_osal_enter_critical_section();
+
+ hport->connected = true;
+ usbh_core_cfg.active_hport = hport;
+
+ if (usbh_core_cfg.pscwait) {
+ usbh_core_cfg.pscwait = false;
+ usb_osal_sem_give(usbh_core_cfg.pscsem);
+ }
+
+ usb_osal_leave_critical_section(flags);
+}
+
+void usbh_external_hport_disconnect(struct usbh_hubport *hport)
+{
+ uint32_t flags;
+
+ flags = usb_osal_enter_critical_section();
+ hport->connected = false;
+ usbh_core_cfg.active_hport = hport;
+
+ if (usbh_core_cfg.pscwait) {
+ usbh_core_cfg.pscwait = false;
+ usb_osal_sem_give(usbh_core_cfg.pscsem);
+ }
+
+ usb_osal_leave_critical_section(flags);
+}
+
+void usbh_hport_activate(struct usbh_hubport *hport)
+{
+ struct usbh_endpoint_cfg ep0_cfg;
+ uint32_t flags;
+
+ flags = usb_osal_enter_critical_section();
+ memset(&ep0_cfg, 0, sizeof(struct usbh_endpoint_cfg));
+
+ ep0_cfg.ep_addr = 0x00;
+ ep0_cfg.ep_interval = 0x00;
+ ep0_cfg.ep_mps = 0x08;
+ ep0_cfg.ep_type = USB_ENDPOINT_TYPE_CONTROL;
+ ep0_cfg.hport = hport;
+ /* Allocate memory for roothub port control endpoint */
+ usbh_ep_alloc(&hport->ep0, &ep0_cfg);
+
+ usb_osal_leave_critical_section(flags);
+}
+
+void usbh_hport_deactivate(struct usbh_hubport *hport)
+{
+ uint32_t flags;
+
+ flags = usb_osal_enter_critical_section();
+ /* Don't free the control pipe of root hub ports! */
+ if (hport->parent != NULL && hport->ep0 != NULL) {
+ usb_ep_cancel(hport->ep0);
+ usbh_ep_free(hport->ep0);
+ hport->ep0 = NULL;
+ }
+ /* Free the device address if one has been assigned */
+ usbh_devaddr_destroy(hport, hport->dev_addr);
+ hport->dev_addr = 0;
+
+ usb_osal_leave_critical_section(flags);
+}
+
+void usbh_event_notify_handler(uint8_t event, uint8_t rhport)
+{
+ switch (event) {
+ case USBH_EVENT_ATTACHED:
+ if (!usbh_core_cfg.rhport[rhport - 1].hport.connected) {
+ usbh_core_cfg.rhport[rhport - 1].hport.connected = true;
+ usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
+ if (usbh_core_cfg.pscwait) {
+ usbh_core_cfg.pscwait = false;
+ usb_osal_sem_give(usbh_core_cfg.pscsem);
+ }
+ }
+ break;
+ case USBH_EVENT_REMOVED:
+ if (usbh_core_cfg.rhport[rhport - 1].hport.connected) {
+ usbh_core_cfg.rhport[rhport - 1].hport.connected = false;
+ usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
+ if (usbh_core_cfg.pscwait) {
+ usbh_core_cfg.pscwait = false;
+ usb_osal_sem_give(usbh_core_cfg.pscsem);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int usbh_initialize(void)
+{
+ usb_osal_thread_t usb_thread;
+
+ memset(&usbh_core_cfg, 0, sizeof(struct usbh_core_priv));
+
+ usbh_workq_initialize();
+
+ usbh_core_cfg.pscsem = usb_osal_sem_create(0);
+ if (usbh_core_cfg.pscsem == NULL) {
+ return -1;
+ }
+
+ usb_thread = usb_osal_thread_create("usbh_psc", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_portchange_detect_thread, NULL);
+ if (usb_thread == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int lsusb(int argc, char **argv)
+{
+ usb_slist_t *hub_list;
+ uint8_t port;
+
+ if (argc < 2) {
+ printf("Usage: lsusb [options]...\r\n");
+ printf("List USB devices\r\n");
+ printf(" -v, --verbose\r\n");
+ printf(" Increase verbosity (show descriptors)\r\n");
+ printf(" -s [[bus]:[devnum]]\r\n");
+ printf(" Show only devices with specified device and/or bus numbers (in decimal)\r\n");
+ printf(" -d vendor:[product]\r\n");
+ printf(" Show only devices with the specified vendor and product ID numbers (in hexadecimal)\r\n");
+ printf(" -t, --tree\r\n");
+ printf(" Dump the physical USB device hierachy as a tree\r\n");
+ printf(" -V, --version\r\n");
+ printf(" Show version of program\r\n");
+ printf(" -h, --help\r\n");
+ printf(" Show usage and help\r\n");
+ return 0;
+ }
+
+ if (argc > 3) {
+ return 0;
+ }
+
+ if (strcmp(argv[1], "-t") == 0) {
+ for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ if (usbh_core_cfg.rhport[port - 1].hport.connected) {
+ printf("/: Bus %02u,VID:PID 0x%04x:0x%04x\r\n", USBH_ROOT_HUB_INDEX, usbh_core_cfg.rhport[port - 1].hport.device_desc.idVendor, usbh_core_cfg.rhport[port - 1].hport.device_desc.idProduct);
+
+ for (uint8_t i = 0; i < usbh_core_cfg.rhport[port - 1].hport.config.config_desc.bNumInterfaces; i++) {
+ if (usbh_core_cfg.rhport[port - 1].hport.config.intf[i].class_driver->driver_name) {
+ printf(" |__Port %u,Port addr:0x%02x,If %u,ClassDriver=%s\r\n", usbh_core_cfg.rhport[port - 1].hport.port, usbh_core_cfg.rhport[port - 1].hport.dev_addr,
+ i, usbh_core_cfg.rhport[port - 1].hport.config.intf[i].class_driver->driver_name);
+ }
+ }
+ }
+ }
+ usb_slist_for_each(hub_list, &hub_class_head)
+ {
+ usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
+ if (hub_class->child[port - 1].connected) {
+ printf("/: Bus %02u,VID:PID 0x%04x:0x%04x\r\n", hub_class->index, hub_class->child[port - 1].device_desc.idVendor, hub_class->child[port - 1].device_desc.idProduct);
+
+ for (uint8_t i = 0; i < hub_class->child[port - 1].config.config_desc.bNumInterfaces; i++) {
+ if (hub_class->child[port - 1].config.intf[i].class_driver->driver_name) {
+ printf(" |__Port %u,Port addr:0x%02x,If %u,ClassDriver=%s\r\n", hub_class->child[port - 1].port, hub_class->child[port - 1].dev_addr,
+ i, hub_class->child[port - 1].config.intf[i].class_driver->driver_name);
+ }
+ }
+ }
+ }
+ }
+ } else if (strcmp(argv[1], "-v") == 0) {
+ for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ if (usbh_core_cfg.rhport[port - 1].hport.connected) {
+ printf("Bus %02u,Port %u,Port addr:0x%02x,VID:PID 0x%04x:0x%04x\r\n", USBH_ROOT_HUB_INDEX, usbh_core_cfg.rhport[port - 1].hport.port, usbh_core_cfg.rhport[port - 1].hport.dev_addr,
+ usbh_core_cfg.rhport[port - 1].hport.device_desc.idVendor, usbh_core_cfg.rhport[port - 1].hport.device_desc.idProduct);
+ usbh_print_hubport_info(&usbh_core_cfg.rhport[port - 1].hport);
+ }
+ }
+
+ usb_slist_for_each(hub_list, &hub_class_head)
+ {
+ usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
+ if (hub_class->child[port - 1].connected) {
+ printf("Bus %02u,Port %u,Port addr:0x%02x,VID:PID 0x%04x:0x%04x\r\n", hub_class->index, hub_class->child[port - 1].port, hub_class->child[port - 1].dev_addr,
+ hub_class->child[port - 1].device_desc.idVendor, hub_class->child[port - 1].device_desc.idProduct);
+ usbh_print_hubport_info(&hub_class->child[port - 1]);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+struct usbh_hubport *usbh_get_hubport(uint8_t dev_addr)
+{
+ usb_slist_t *hub_list;
+ uint8_t port;
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ if (usbh_core_cfg.rhport[port - 1].hport.connected) {
+ if (usbh_core_cfg.rhport[port - 1].hport.dev_addr == dev_addr) {
+ return &usbh_core_cfg.rhport[port - 1].hport;
+ }
+ }
+ }
+ usb_slist_for_each(hub_list, &hub_class_head)
+ {
+ usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
+ if (hub_class->child[port - 1].connected) {
+ if (hub_class->child[port - 1].dev_addr == dev_addr) {
+ return &hub_class->child[port - 1];
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void *usbh_get_class(uint8_t dev_addr, uint8_t intf)
+{
+ usb_slist_t *hub_list;
+ uint8_t port;
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+ if (usbh_core_cfg.rhport[port - 1].hport.connected) {
+ if (usbh_core_cfg.rhport[port - 1].hport.dev_addr == dev_addr) {
+ if (usbh_core_cfg.rhport[port - 1].hport.config.intf[intf].priv) {
+ return usbh_core_cfg.rhport[port - 1].hport.config.intf[intf].priv;
+ }
+ }
+ }
+ }
+ usb_slist_for_each(hub_list, &hub_class_head)
+ {
+ usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
+
+ for (port = USBH_HUB_PORT_START_INDEX; port <= hub_class->nports; port++) {
+ if (hub_class->child[port - 1].connected) {
+ if (hub_class->child[port - 1].dev_addr == dev_addr) {
+ if (hub_class->child[port - 1].config.intf[intf].priv) {
+ return hub_class->child[port - 1].config.intf[intf].priv;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const struct usbh_class_info class_info_table[] = {
+
+ { .class = USB_DEVICE_CLASS_CDC,
+ .subclass = CDC_ABSTRACT_CONTROL_MODEL,
+ .protocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &cdc_acm_class_driver },
+ { .class = USB_DEVICE_CLASS_HID,
+ .subclass = HID_SUBCLASS_BOOTIF,
+ .protocol = HID_PROTOCOL_KEYBOARD,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &hid_class_driver },
+ { .class = USB_DEVICE_CLASS_HID,
+ .subclass = HID_SUBCLASS_BOOTIF,
+ .protocol = HID_PROTOCOL_MOUSE,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &hid_class_driver },
+ { .class = USB_DEVICE_CLASS_MASS_STORAGE,
+ .subclass = MSC_SUBCLASS_SCSI,
+ .protocol = MSC_PROTOCOL_BULK_ONLY,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &msc_class_driver },
+#ifdef CONFIG_USBHOST_HUB
+ { .class = USB_DEVICE_CLASS_HUB,
+ .subclass = 0,
+ .protocol = 0,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &hub_class_driver },
+ { .class = USB_DEVICE_CLASS_HUB,
+ .subclass = 0,
+ .protocol = 1,
+ .vid = 0x00,
+ .pid = 0x00,
+ .class_driver = &hub_class_driver },
+#endif
+};
+
+static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subcalss, uint8_t protocol, uint16_t vid, uint16_t pid)
+{
+ for (uint8_t i = 0; i < sizeof(class_info_table) / sizeof(class_info_table[0]); i++) {
+ if (class == class_info_table[i].class &&
+ subcalss == class_info_table[i].subclass &&
+ protocol == class_info_table[i].protocol) {
+ /* If this is a vendor-specific class ID, then the VID and PID have to match as well. */
+ if (class == USB_DEVICE_CLASS_VEND_SPECIFIC) {
+ if (vid == class_info_table[i].vid &&
+ pid == class_info_table[i].pid) {
+ return class_info_table[i].class_driver;
+ }
+ }
+ return class_info_table[i].class_driver;
+ }
+ }
+
+ return NULL;
+}
diff --git a/core/usbh_core.h b/core/usbh_core.h
index ee74e352..740c5380 100644
--- a/core/usbh_core.h
+++ b/core/usbh_core.h
@@ -1,128 +1,128 @@
-/**
- * @file usbh_core.h
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _USBH_CORE_H
-#define _USBH_CORE_H
-
-#include "usb_util.h"
-#include "usb_def.h"
-#include "usb_hc.h"
-#include "usb_osal.h"
-#include "usb_workq.h"
-#include "usbh_hub.h"
-#include "usb_config.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define USBH_ROOT_HUB_INDEX 1 /* roothub index*/
-#define USBH_EX_HUB_INDEX 2 /* external hub index */
-#define USBH_HUB_PORT_START_INDEX 1 /* first hub port index */
-
-#ifdef CONFIG_USBHOST_HUB
-#define ROOTHUB(hport) ((hport)->parent == NULL)
-#else
-#define ROOTHUB(hport) true
-#endif
-
-#define CLASS_CONNECT(hport,i) ((hport)->config.intf[i].class_driver->connect(hport, i))
-#define CLASS_DISCONNECT(hport,i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
-
-enum usbh_event_type {
- USBH_EVENT_ATTACHED,
- USBH_EVENT_REMOVED,
-};
-
-struct usbh_class_info {
- uint8_t class; /* Base device class code */
- uint8_t subclass; /* Sub-class, depends on base class. Eg. */
- uint8_t protocol; /* Protocol, depends on base class. Eg. */
- uint16_t vid; /* Vendor ID (for vendor/product specific devices) */
- uint16_t pid; /* Product ID (for vendor/product specific devices) */
- const struct usbh_class_driver *class_driver;
-};
-
-struct usbh_hubport;
-struct usbh_class_driver {
- const char *driver_name;
- int (*connect)(struct usbh_hubport *hport, uint8_t intf);
- int (*disconnect)(struct usbh_hubport *hport, uint8_t intf);
-};
-
-typedef struct usbh_endpoint {
- struct usb_endpoint_descriptor ep_desc;
-} usbh_endpoint_t;
-
-typedef struct usbh_interface {
- struct usb_interface_descriptor intf_desc;
- struct usbh_endpoint ep[CONFIG_USBHOST_EP_NUM];
- struct usbh_class_driver *class_driver;
- void *priv;
-} usbh_interface_t;
-
-typedef struct usbh_configuration {
- struct usb_configuration_descriptor config_desc;
- struct usbh_interface intf[CONFIG_USBHOST_INTF_NUM];
-} usbh_configuration_t;
-
-typedef struct usbh_hubport {
- bool connected; /* True: device connected; false: disconnected */
- bool port_change; /* True: port changed; false: port do not change */
- uint8_t port; /* Hub port index */
- uint8_t dev_addr; /* device address */
- uint8_t speed; /* device speed */
- usbh_epinfo_t ep0; /* control ep info */
- struct usb_device_descriptor device_desc;
- struct usbh_configuration config;
-#if 0
- uint8_t* config_desc;
-#endif
- struct usbh_hub *parent; /*if NULL, is roothub*/
-} usbh_hubport_t;
-
-typedef struct usbh_hub {
- usb_slist_t list;
- uint8_t index; /* Hub index */
- uint8_t nports; /* Hub port number */
- uint8_t dev_addr; /* Hub device address */
- usbh_epinfo_t intin;
- uint8_t *int_buffer;
- struct usb_setup_packet *setup;
- struct hub_port_status *port_status;
- struct usb_hub_descriptor hub_desc;
- struct usbh_hubport child[CONFIG_USBHOST_EHPORTS];
- struct usbh_hubport *parent; /* Parent hub port */
- struct usb_work work;
-} usbh_hub_t;
-
-void usbh_event_notify_handler(uint8_t event, uint8_t rhport);
-
-int usbh_initialize(void);
-int lsusb(int argc, char **argv);
-struct usbh_hubport *usbh_get_hubport(uint8_t dev_addr);
-void *usbh_get_class(uint8_t dev_addr, uint8_t intf);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/**
+ * @file usbh_core.h
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _USBH_CORE_H
+#define _USBH_CORE_H
+
+#include "usb_util.h"
+#include "usb_def.h"
+#include "usb_hc.h"
+#include "usb_osal.h"
+#include "usb_workq.h"
+#include "usbh_hub.h"
+#include "usb_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define USBH_ROOT_HUB_INDEX 1 /* roothub index*/
+#define USBH_EX_HUB_INDEX 2 /* external hub index */
+#define USBH_HUB_PORT_START_INDEX 1 /* first hub port index */
+
+#ifdef CONFIG_USBHOST_HUB
+#define ROOTHUB(hport) ((hport)->parent == NULL)
+#else
+#define ROOTHUB(hport) true
+#endif
+
+#define CLASS_CONNECT(hport,i) ((hport)->config.intf[i].class_driver->connect(hport, i))
+#define CLASS_DISCONNECT(hport,i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
+
+enum usbh_event_type {
+ USBH_EVENT_ATTACHED,
+ USBH_EVENT_REMOVED,
+};
+
+struct usbh_class_info {
+ uint8_t class; /* Base device class code */
+ uint8_t subclass; /* Sub-class, depends on base class. Eg. */
+ uint8_t protocol; /* Protocol, depends on base class. Eg. */
+ uint16_t vid; /* Vendor ID (for vendor/product specific devices) */
+ uint16_t pid; /* Product ID (for vendor/product specific devices) */
+ const struct usbh_class_driver *class_driver;
+};
+
+struct usbh_hubport;
+struct usbh_class_driver {
+ const char *driver_name;
+ int (*connect)(struct usbh_hubport *hport, uint8_t intf);
+ int (*disconnect)(struct usbh_hubport *hport, uint8_t intf);
+};
+
+typedef struct usbh_endpoint {
+ struct usb_endpoint_descriptor ep_desc;
+} usbh_endpoint_t;
+
+typedef struct usbh_interface {
+ struct usb_interface_descriptor intf_desc;
+ struct usbh_endpoint ep[CONFIG_USBHOST_EP_NUM];
+ struct usbh_class_driver *class_driver;
+ void *priv;
+} usbh_interface_t;
+
+typedef struct usbh_configuration {
+ struct usb_configuration_descriptor config_desc;
+ struct usbh_interface intf[CONFIG_USBHOST_INTF_NUM];
+} usbh_configuration_t;
+
+typedef struct usbh_hubport {
+ bool connected; /* True: device connected; false: disconnected */
+ bool port_change; /* True: port changed; false: port do not change */
+ uint8_t port; /* Hub port index */
+ uint8_t dev_addr; /* device address */
+ uint8_t speed; /* device speed */
+ usbh_epinfo_t ep0; /* control ep info */
+ struct usb_device_descriptor device_desc;
+ struct usbh_configuration config;
+#if 0
+ uint8_t* config_desc;
+#endif
+ struct usbh_hub *parent; /*if NULL, is roothub*/
+} usbh_hubport_t;
+
+typedef struct usbh_hub {
+ usb_slist_t list;
+ uint8_t index; /* Hub index */
+ uint8_t nports; /* Hub port number */
+ uint8_t dev_addr; /* Hub device address */
+ usbh_epinfo_t intin;
+ uint8_t *int_buffer;
+ struct usb_setup_packet *setup;
+ struct hub_port_status *port_status;
+ struct usb_hub_descriptor hub_desc;
+ struct usbh_hubport child[CONFIG_USBHOST_EHPORTS];
+ struct usbh_hubport *parent; /* Parent hub port */
+ struct usb_work work;
+} usbh_hub_t;
+
+void usbh_event_notify_handler(uint8_t event, uint8_t rhport);
+
+int usbh_initialize(void);
+int lsusb(int argc, char **argv);
+struct usbh_hubport *usbh_get_hubport(uint8_t dev_addr);
+void *usbh_get_class(uint8_t dev_addr, uint8_t intf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usb_config.h b/usb_config.h
index 9715686a..c36ee8e9 100644
--- a/usb_config.h
+++ b/usb_config.h
@@ -1,46 +1,46 @@
-#ifndef _USB_CONFIG_H
-#define _USB_CONFIG_H
-
-/* USB DEVICE Configuration */
-
-/* USB HOST Configuration */
-#ifndef CONFIG_USBHOST_RHPORTS
-#define CONFIG_USBHOST_RHPORTS 1
-#endif
-
-#ifndef CONFIG_USBHOST_EHPORTS
-#define CONFIG_USBHOST_EHPORTS 4
-#endif
-
-#ifndef CONFIG_USBHOST_INTF_NUM
-#define CONFIG_USBHOST_INTF_NUM 6
-#endif
-
-#ifndef CONFIG_USBHOST_EP_NUM
-#define CONFIG_USBHOST_EP_NUM 2
-#endif
-
-#ifndef CONFIG_USBHOST_HPWORKQ_PRIO
-#define CONFIG_USBHOST_HPWORKQ_PRIO 5
-#endif
-#ifndef CONFIG_USBHOST_HPWORKQ_STACKSIZE
-#define CONFIG_USBHOST_HPWORKQ_STACKSIZE 2048
-#endif
-
-#ifndef CONFIG_USBHOST_LPWORKQ_PRIO
-#define CONFIG_USBHOST_LPWORKQ_PRIO 1
-#endif
-#ifndef CONFIG_USBHOST_LPWORKQ_STACKSIZE
-#define CONFIG_USBHOST_LPWORKQ_STACKSIZE 2048
-#endif
-
-#ifndef CONFIG_USBHOST_PSC_PRIO
-#define CONFIG_USBHOST_PSC_PRIO 4
-#endif
-#ifndef CONFIG_USBHOST_PSC_STACKSIZE
-#define CONFIG_USBHOST_PSC_STACKSIZE 2048
-#endif
-
-#define CONFIG_USBHOST_ASYNCH
-
+#ifndef _USB_CONFIG_H
+#define _USB_CONFIG_H
+
+/* USB DEVICE Configuration */
+
+/* USB HOST Configuration */
+#ifndef CONFIG_USBHOST_RHPORTS
+#define CONFIG_USBHOST_RHPORTS 1
+#endif
+
+#ifndef CONFIG_USBHOST_EHPORTS
+#define CONFIG_USBHOST_EHPORTS 4
+#endif
+
+#ifndef CONFIG_USBHOST_INTF_NUM
+#define CONFIG_USBHOST_INTF_NUM 6
+#endif
+
+#ifndef CONFIG_USBHOST_EP_NUM
+#define CONFIG_USBHOST_EP_NUM 2
+#endif
+
+#ifndef CONFIG_USBHOST_HPWORKQ_PRIO
+#define CONFIG_USBHOST_HPWORKQ_PRIO 5
+#endif
+#ifndef CONFIG_USBHOST_HPWORKQ_STACKSIZE
+#define CONFIG_USBHOST_HPWORKQ_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_LPWORKQ_PRIO
+#define CONFIG_USBHOST_LPWORKQ_PRIO 1
+#endif
+#ifndef CONFIG_USBHOST_LPWORKQ_STACKSIZE
+#define CONFIG_USBHOST_LPWORKQ_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 4
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#endif
+
+#define CONFIG_USBHOST_ASYNCH
+
#endif \ No newline at end of file