rt-thread/bsp/phytium/libraries/standalone/drivers/usb/fusb_dev.c

447 lines
13 KiB
C
Raw Normal View History

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fusb_dev.c
* Date: 2022-02-11 13:33:11
* LastEditTime: 2022-02-18 09:18:45
* Description:  This files is for USB device function implementation
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 zhugengyu 2022/2/7 init commit
*/
#include <string.h>
#include "fdebug.h"
#include "fusb_private.h"
#define FUSB_DEBUG_TAG "FUSB-DEV"
#define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
#define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
#define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
#define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
#define FUSB_DR_DESC FUsbGenerateReqType(FUSB_REQ_DEVICE_TO_HOST, FUSB_REQ_TYPE_STANDARD, FUSB_REQ_RECP_DEV)
#define FUSB_SKIP_BYTES(desc, bytes) ((FUsbDescriptor *) ((u8 *) (desc) + (bytes)))
#define FUSB_CONFIG_DESC_SIZE 512 /* best guess */
static void FUsbNopDevDestory(FUsbDev *dev)
{
FUsbNopDevInit(dev);
dev->address = FUSB_NO_DEV_ADDR;
dev->hub = FUSB_NO_HUB;
dev->port = FUSB_NO_PORT;
}
static void FUsbNopDevPoll(FUsbDev *dev)
{
return;
}
/**
* @name: FUsbNopDevInit
* @msg: USB设备初始化函数
* @return {*}
* @param {FUsbDev} *dev, USB设备实例
*/
void FUsbNopDevInit(FUsbDev *dev)
{
dev->descriptor = NULL;
dev->configuration = NULL;
dev->destroy = FUsbNopDevDestory;
dev->poll = FUsbNopDevPoll;
}
static inline boolean FUsbParserIsValid(const FUsbConfigParser *parser)
{
FASSERT(parser);
return parser->is_valid;
}
static FError FUsbParserDescriptor(FUsbConfigParser *parser)
{
FASSERT(parser && parser->buf);
const FUsbDescriptor *cur_pos = parser->buf;
const FUsbDescriptor *desc_end;
FUsbDescriptorType last_desc_type = FUSB_DESC_TYPE_NONE;
FUsbDescriptorType desc_type;
u8 desc_len, exp_len, alt_len;
FError ret = FUSB_SUCCESS;
while (FUSB_SKIP_BYTES(cur_pos, FUSB_DESCRIPTOR_HEADER_SIZE) < parser->end_pos)
{
/* get length and type of descriptor */
desc_len = cur_pos->header.len;
desc_type = cur_pos->header.type;
desc_end = FUSB_SKIP_BYTES(cur_pos, desc_len);
if (desc_end > parser->end_pos)
{
FUSB_ERROR("Parse descriptor out of boundary !!!");
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
exp_len = 0;
alt_len = 0;
switch (desc_type)
{
case FUSB_DESC_TYPE_CONFIG:
if (FUSB_DESC_TYPE_NONE != last_desc_type)
{
FUSB_ERROR("Configuration descriptor must be the first !!!");
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
exp_len = sizeof(FUsbConfigurationDescriptor);
break;
case FUSB_DESC_TYPE_INTERFACE:
if (FUSB_DESC_TYPE_NONE == last_desc_type)
{
FUSB_ERROR("Interface descriptor must not be the first !!!");
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
exp_len = sizeof(FUsbInterfaceDescriptor);
break;
case FUSB_DESC_TYPE_ENDPOINT:
if ((FUSB_DESC_TYPE_NONE == last_desc_type) ||
(FUSB_DESC_TYPE_CONFIG == last_desc_type))
{
FUSB_ERROR("Endpoint descriptor must follow interface descriptor !!!");
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
break;
default:
FUSB_DEBUG("Descriptor %d not handled !!!", desc_type);
break;
}
if (((exp_len != 0) && (desc_len != exp_len)) &&
((alt_len == 0) || (desc_len != alt_len)))
{
FUSB_ERROR("Descriptor %d invalid !!!", desc_type);
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
last_desc_type = desc_type;
cur_pos = desc_end;
}
if (cur_pos != parser->end_pos)
{
parser->err_pos = cur_pos;
ret = FUSB_ERR_DESC_PARSE_ERR;
goto err_handle;
}
err_handle:
if (FUSB_SUCCESS == ret)
{
parser->is_valid = TRUE;
}
return ret;
}
/**
* @name: FUsbSetupConfigParser
* @msg: USB配置描述符解析器
* @return {*}
* @param {FUsbDev} *dev, USB设备实例
* @param {void} *buf,
* @param {u32} buf_len,
*/
FError FUsbSetupConfigParser(FUsbDev *dev, const void *buf, u32 buf_len)
{
FASSERT(dev && buf && (buf_len > 0));
const FUsbConfigurationDescriptor *config_desc;
FUsbConfigParser *parser = &dev->config_parser;
memset(parser, 0, sizeof(*parser));
parser->buf = buf;
parser->buf_len = buf_len;
parser->is_valid = FALSE;
parser->end_pos = FUSB_SKIP_BYTES(parser->buf, parser->buf_len);
parser->next_pos = parser->buf;
parser->cur_desc = NULL;
parser->err_pos = parser->buf;
if ((parser->buf_len < sizeof(u32)) || (parser->buf_len > FUSB_CONFIG_DESC_SIZE))
{
FUSB_ERROR("Invalid buffer length !!!");
return FUSB_ERR_INVALID_DATA;
}
/* input buffer must start with config desc */
config_desc = (FUsbConfigurationDescriptor *)parser->buf;
if ((config_desc->bLength != sizeof(FUsbConfigurationDescriptor)) ||
(config_desc->bDescriptorType != FUSB_DESC_TYPE_CONFIG) ||
(config_desc->wTotalLength > parser->buf_len))
{
FUSB_ERROR("Invalid configuration descriptor !!!");
return FUSB_ERR_INVALID_DATA;
}
/* adjust end position */
if (config_desc->wTotalLength < parser->buf_len)
{
parser->end_pos = FUSB_SKIP_BYTES(parser->buf, config_desc->wTotalLength);
}
return FUsbParserDescriptor(parser);
}
/**
* @name: FUsbRevokeConfigParser
* @msg: USB配置描述符解析器
* @return {*}
* @param {FUsbDev} *dev, USB设备实例
*/
void FUsbRevokeConfigParser(FUsbDev *dev)
{
FASSERT(dev);
memset(&dev->config_parser, 0, sizeof(dev->config_parser));
return;
}
/**
* @name: FUsbGetDescriptorFromParser
* @msg: /
* @return {const FUsbDescriptor *}
* @param {FUsbConfigParser} *parser,
* @param {FUsbDescriptorType} type,
*/
const FUsbDescriptor *FUsbGetDescriptorFromParser(FUsbConfigParser *parser, FUsbDescriptorType type)
{
FASSERT(parser);
if (!FUsbParserIsValid(parser))
{
FUSB_ERROR("Config parse is not valid !!!");
return NULL;
}
const FUsbDescriptor *result = NULL;
FUsbDescriptorType desc_type;
u8 desc_len;
const FUsbDescriptor *desc_end;
/* travesal all descriptors */
while (parser->next_pos < parser->end_pos)
{
desc_len = parser->next_pos->header.len;
desc_type = parser->next_pos->header.type;
desc_end = FUSB_SKIP_BYTES(parser->next_pos, desc_len);
if (desc_end > parser->end_pos)
{
break;
}
if ((FUSB_DESC_TYPE_ENDPOINT == type) &&
(FUSB_DESC_TYPE_INTERFACE == desc_type))
{
break; /* there is no chance to find endpoint desc after interface desc */
}
if (type == desc_type)
{
/* target desc found !!! */
result = parser->next_pos;
parser->next_pos = desc_end;
break;
}
parser->next_pos = desc_end;/* check next one */
}
if (NULL != result)
{
parser->err_pos = result;
}
parser->cur_desc = result;
return result;
}
/**
* @name: FUsbSetupStringParser
* @msg:
* @return {*}
* @param {FUsbDev} *dev, USB设备实例
*/
void FUsbSetupStringParser(FUsbDev *dev)
{
FASSERT(dev);
FUsbStringParser *parser = &dev->string_parser;
if (NULL != parser->usb_str)
{
FUSB_WARN("String descriptor exists, might cause memory leakage !!!");
}
parser->usb_str = NULL;
memset(parser->str_buf, 0, sizeof(parser->str_buf));
return;
}
/**
* @name: FUsbRevokeStringParser
* @msg:
* @return {*}
* @param {FUsbDev} *dev, USB设备实例
*/
void FUsbRevokeStringParser(FUsbDev *dev)
{
FASSERT(dev);
FUsbStringParser *parser = &dev->string_parser;
FASSERT(dev->controller && dev->controller->usb);
FUsb *instance = dev->controller->usb;
if (NULL != parser->usb_str)
{
FUSB_FREE(instance, parser->usb_str);
parser->usb_str = NULL;
}
return;
}
/**
* @name: FUsbSearchStringDescriptor
* @msg: FUsbStringParser结构中
* @return {*}
* @param {FUsb} *instance, USB实例
* @param {FUsbDev} *dev, USB设备实例
* @param {u8} id, ID
*/
FError FUsbSearchStringDescriptor(FUsb *instance, FUsbDev *dev, u8 id)
{
FASSERT(instance && dev);
FUsbStringParser *parser = &dev->string_parser;
const FUsbStringDescriptor *usb_str = NULL;
u8 total_len;
u8 char_num;
u16 character;
/* re-malloc usb string desc buffer with length 4 */
if (NULL != parser->usb_str)
{
FUSB_FREE(instance, parser->usb_str);
parser->usb_str = NULL;
}
parser->usb_str = FUSB_ALLOCATE(instance, FUSB_USBSTR_MIN_LEN, FUSB_DEFAULT_ALIGN);
if (NULL == parser->usb_str)
{
return FUSB_ERR_ALLOCATE_FAIL;
}
/* get header of string for the full length */
if (FUsbGetStringDescriptor(dev, FUSB_DR_DESC, FUSB_DESC_TYPE_STRING, id, FUSB_DEFAULT_LANG_ID,
parser->usb_str, FUSB_USBSTR_MIN_LEN) < 0)
{
FUSB_ERROR("Parse string descriptor failed (len: %d) !!!", FUSB_USBSTR_MIN_LEN);
return FUSB_ERR_DESC_PARSE_ERR;
}
/* check if string descriptor header is valid */
total_len = parser->usb_str->len;
if ((total_len < FUSB_DESCRIPTOR_HEADER_SIZE) ||
((total_len & 1) != 0) ||
(parser->usb_str->type != FUSB_DESC_TYPE_STRING))
{
FUSB_ERROR("Get invalid string descriptor (len: %d) !!!", FUSB_USBSTR_MIN_LEN);
return FUSB_ERR_DESC_PARSE_ERR;
}
/* return if no need to get more */
if (total_len <= FUSB_USBSTR_MIN_LEN)
{
return FUSB_SUCCESS;
}
/* re-malloc usb string desc buffer with full length */
FASSERT(parser->usb_str);
FUSB_FREE(instance, parser->usb_str);
parser->usb_str = NULL;
parser->usb_str = FUSB_ALLOCATE(instance, total_len, FUSB_DEFAULT_ALIGN);
if (NULL == parser->usb_str)
{
return FUSB_ERR_ALLOCATE_FAIL;
}
/* get the whole string descriptor */
if (FUsbGetStringDescriptor(dev, FUSB_DR_DESC, FUSB_DESC_TYPE_STRING, id, FUSB_DEFAULT_LANG_ID,
parser->usb_str, total_len) < 0)
{
FUSB_ERROR("Parse string descriptor failed (len: %d)!!!", total_len);
return FUSB_ERR_DESC_PARSE_ERR;
}
if ((parser->usb_str->len < FUSB_DESCRIPTOR_HEADER_SIZE) ||
((parser->usb_str->len & 1) != 0) ||
(parser->usb_str->type != FUSB_DESC_TYPE_STRING))
{
FUSB_ERROR("Get invalid string descriptor (len: %d) !!!", total_len);
return FUSB_ERR_DESC_PARSE_ERR;
}
/* convert into ASCII string */
usb_str = parser->usb_str;
char_num = (usb_str->len - FUSB_DESCRIPTOR_HEADER_SIZE) / 2; /* in 16-bit way */
if (char_num >= FUSB_STRDESC_BUF_MAX - 1)
{
return FUSB_ERR_NOT_SUPPORT;
}
for (u8 i = 0; i < char_num; i++)
{
character = usb_str->string[i];
if (character < ' ' /* 0x20 */
|| character > '~') /* 0x7E */
{
character = '_';
}
parser->str_buf[i] = (char)character;
}
parser->str_buf[char_num] = '\0';
return FUSB_SUCCESS;
}
/**
* @name: FUsbGetString
* @msg:
* @return {const char *},
* @param {FUsbDev} *dev, USB设备实例
*/
const char *FUsbGetString(const FUsbDev *const dev)
{
FASSERT(dev);
return (const char *)dev->string_parser.str_buf;
}