diff options
| author | sakimisu <[email protected]> | 2022-02-08 11:44:46 +0800 |
|---|---|---|
| committer | sakimisu <[email protected]> | 2022-02-08 11:44:46 +0800 |
| commit | 1edbae8e07ddb7c03d97d455cee8c091c81ce986 (patch) | |
| tree | 1367990e7a9c104ba3bbf3592239a82cf3de8eda | |
| parent | feb5a8fb52326b5306c10b7a9c4838411af06b7c (diff) | |
format codes
| -rw-r--r-- | class/audio/usbd_audio.c | 272 | ||||
| -rw-r--r-- | class/cdc/usbd_cdc.c | 342 | ||||
| -rw-r--r-- | class/cdc/usbh_cdc_acm.c | 670 | ||||
| -rw-r--r-- | class/cdc/usbh_cdc_acm.h | 102 | ||||
| -rw-r--r-- | class/hid/usbd_hid.c | 572 | ||||
| -rw-r--r-- | class/hid/usbh_hid.c | 548 | ||||
| -rw-r--r-- | class/hid/usbh_hid.h | 88 | ||||
| -rw-r--r-- | class/hub/usbh_hub.c | 992 | ||||
| -rw-r--r-- | class/hub/usbh_hub.h | 84 | ||||
| -rw-r--r-- | class/msc/usbd_msc.c | 1984 | ||||
| -rw-r--r-- | class/msc/usbh_msc.c | 874 | ||||
| -rw-r--r-- | class/msc/usbh_msc.h | 96 | ||||
| -rw-r--r-- | class/video/usbd_video.c | 266 | ||||
| -rw-r--r-- | common/usb_dc.h | 400 | ||||
| -rw-r--r-- | common/usb_def.h | 1342 | ||||
| -rw-r--r-- | common/usb_util.h | 600 | ||||
| -rw-r--r-- | core/usbd_core.c | 2598 | ||||
| -rw-r--r-- | core/usbd_core.h | 276 | ||||
| -rw-r--r-- | core/usbh_core.c | 1978 | ||||
| -rw-r--r-- | core/usbh_core.h | 256 | ||||
| -rw-r--r-- | usb_config.h | 90 |
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 *)¤t_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 *)¤t_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 *)¤t_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 *)¤t_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 *)¤t_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 *)¤t_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 |
