1beacf11bSopenharmony_ci/* ---------------------------------------------------------------------------- 2beacf11bSopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved. 3beacf11bSopenharmony_ci * Description: LiteOS USB Driver UAC Protocol 4beacf11bSopenharmony_ci * Author: huangjieliang 5beacf11bSopenharmony_ci * Create: 2017-12-12 6beacf11bSopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 7beacf11bSopenharmony_ci * are permitted provided that the following conditions are met: 8beacf11bSopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of 9beacf11bSopenharmony_ci * conditions and the following disclaimer. 10beacf11bSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11beacf11bSopenharmony_ci * of conditions and the following disclaimer in the documentation and/or other materials 12beacf11bSopenharmony_ci * provided with the distribution. 13beacf11bSopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used 14beacf11bSopenharmony_ci * to endorse or promote products derived from this software without specific prior written 15beacf11bSopenharmony_ci * permission. 16beacf11bSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17beacf11bSopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18beacf11bSopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19beacf11bSopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20beacf11bSopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21beacf11bSopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22beacf11bSopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23beacf11bSopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24beacf11bSopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25beacf11bSopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26beacf11bSopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27beacf11bSopenharmony_ci * --------------------------------------------------------------------------- */ 28beacf11bSopenharmony_ci/* ---------------------------------------------------------------------------- 29beacf11bSopenharmony_ci * Notice of Export Control Law 30beacf11bSopenharmony_ci * =============================================== 31beacf11bSopenharmony_ci * Huawei LiteOS may be subject to applicable export control laws and regulations, which might 32beacf11bSopenharmony_ci * include those applicable to Huawei LiteOS of U.S. and the country in which you are located. 33beacf11bSopenharmony_ci * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such 34beacf11bSopenharmony_ci * applicable export control laws and regulations. 35beacf11bSopenharmony_ci * --------------------------------------------------------------------------- */ 36beacf11bSopenharmony_ci 37beacf11bSopenharmony_ci#include "gadget/f_uac.h" 38beacf11bSopenharmony_ci#include "gadget/usbd_audio.h" 39beacf11bSopenharmony_ci#include "controller/usb_device/dwc_otg_pcd.h" 40beacf11bSopenharmony_ci#include "implementation/global_implementation.h" 41beacf11bSopenharmony_ci 42beacf11bSopenharmony_ci#ifdef __cplusplus 43beacf11bSopenharmony_ci#if __cplusplus 44beacf11bSopenharmony_ciextern "C" { 45beacf11bSopenharmony_ci#endif /* __cplusplus */ 46beacf11bSopenharmony_ci#endif /* __cplusplus */ 47beacf11bSopenharmony_ci 48beacf11bSopenharmony_ciint usbdev_uac_initialize(struct module *mod, int n, void *arg); 49beacf11bSopenharmony_ci 50beacf11bSopenharmony_ci/* device driver structure definition */ 51beacf11bSopenharmony_ci 52beacf11bSopenharmony_cistatic const driver_t g_fuac_driver = 53beacf11bSopenharmony_ci{ 54beacf11bSopenharmony_ci .name = "fuac", 55beacf11bSopenharmony_ci .methods = NULL, 56beacf11bSopenharmony_ci .size = sizeof(struct uac_softc) 57beacf11bSopenharmony_ci}; 58beacf11bSopenharmony_ci 59beacf11bSopenharmony_ci/* private device class information */ 60beacf11bSopenharmony_ci 61beacf11bSopenharmony_cistatic devclass_t g_fuac_devclass; 62beacf11bSopenharmony_ciDRIVER_MODULE(fuac, simple, g_fuac_driver, g_fuac_devclass, usbdev_uac_initialize, 0); 63beacf11bSopenharmony_ci 64beacf11bSopenharmony_cistatic int usbclass_uac_bind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev); 65beacf11bSopenharmony_cistatic int usbclass_uac_unbind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev); 66beacf11bSopenharmony_cistatic int usbclass_uac_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev, 67beacf11bSopenharmony_ci const struct usb_device_request *ctrl, uint8_t *dataout, size_t outlen); 68beacf11bSopenharmony_cistatic void usbclass_uac_disconnect(struct usbdevclass_driver_s *driver, struct usbdev_s *dev); 69beacf11bSopenharmony_ci 70beacf11bSopenharmony_ci/* USB driver operations */ 71beacf11bSopenharmony_ci 72beacf11bSopenharmony_cistatic const struct usbdevclass_driverops_s g_uac_driverops = 73beacf11bSopenharmony_ci{ 74beacf11bSopenharmony_ci usbclass_uac_bind, 75beacf11bSopenharmony_ci usbclass_uac_unbind, 76beacf11bSopenharmony_ci usbclass_uac_setup, 77beacf11bSopenharmony_ci usbclass_uac_disconnect, 78beacf11bSopenharmony_ci NULL, 79beacf11bSopenharmony_ci NULL 80beacf11bSopenharmony_ci}; 81beacf11bSopenharmony_ci 82beacf11bSopenharmony_cistatic const char g_fuac_str_lang[] = 83beacf11bSopenharmony_ci{ 84beacf11bSopenharmony_ci 4, UDESC_STRING, 85beacf11bSopenharmony_ci 0x09, 0x04 86beacf11bSopenharmony_ci}; 87beacf11bSopenharmony_ci 88beacf11bSopenharmony_ci#define STR_AC_IF 4 89beacf11bSopenharmony_cistatic const char g_fuac_str_ac_if[] = 90beacf11bSopenharmony_ci{ 91beacf11bSopenharmony_ci 38, UDESC_STRING, 92beacf11bSopenharmony_ci 'H', 0, 'i', 0, 's', 0, 'i', 0, 'l', 0, 'i', 0, 'c', 0, 'o', 0, 'n', 0, 93beacf11bSopenharmony_ci ' ', 0, 'H', 0, 'D', 0, ' ', 0, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 94beacf11bSopenharmony_ci}; 95beacf11bSopenharmony_ci 96beacf11bSopenharmony_cistatic const char g_fuac_str_manufacturer[] = 97beacf11bSopenharmony_ci{ 98beacf11bSopenharmony_ci 14, UDESC_STRING, 99beacf11bSopenharmony_ci 'H', 0, 'U', 0, 'A', 0, 'W', 0, 'E', 0, 'I', 0 100beacf11bSopenharmony_ci}; 101beacf11bSopenharmony_ci 102beacf11bSopenharmony_ci#define UAC_STR_IDX_PRODUCT 2 103beacf11bSopenharmony_cistatic const char g_fuac_str_product[] = 104beacf11bSopenharmony_ci{ 105beacf11bSopenharmony_ci 48, UDESC_STRING, 106beacf11bSopenharmony_ci 'L', 0, 'i', 0, 't', 0, 'e', 0, 'O', 0, 'S', 0, ' ', 0, 'U', 0, 'S', 0, 107beacf11bSopenharmony_ci 'B', 0, ' ', 0, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 0, 'G', 0, 108beacf11bSopenharmony_ci 'a', 0, 'd', 0, 'g', 0, 'e', 0, 't', 0 109beacf11bSopenharmony_ci}; 110beacf11bSopenharmony_ci 111beacf11bSopenharmony_ci#define UAC_IN_TERMINAL 8 112beacf11bSopenharmony_cistatic const char g_fuac_input_terminal[] = 113beacf11bSopenharmony_ci{ 114beacf11bSopenharmony_ci 46, UDESC_STRING, 115beacf11bSopenharmony_ci 'C', 0, 'a', 0, 'p', 0, 't', 0, 'u', 0, 'r', 0, 'e', 0, ' ', 0, 'I', 0, 116beacf11bSopenharmony_ci 'n', 0, 'p', 0, 'u', 0, 't', 0, ' ', 0, 't', 0, 'e', 0, 'r', 0, 'm', 0, 117beacf11bSopenharmony_ci 'i', 0, 'n', 0, 'a', 0, 'l', 0 118beacf11bSopenharmony_ci}; 119beacf11bSopenharmony_ci 120beacf11bSopenharmony_cistatic const char g_fuac_output_terminal[] = 121beacf11bSopenharmony_ci{ 122beacf11bSopenharmony_ci 48, UDESC_STRING, 123beacf11bSopenharmony_ci 'C', 0, 'a', 0, 'p', 0, 't', 0, 'u', 0, 'r', 0, 'e', 0, ' ', 0, 'O', 0, 124beacf11bSopenharmony_ci 'u', 0, 't', 0, 'p', 0, 'u', 0, 't', 0, ' ', 0, 't', 0, 'e', 0, 'r', 0, 125beacf11bSopenharmony_ci 'm', 0, 'i', 0, 'n', 0, 'a', 0, 'l', 0 126beacf11bSopenharmony_ci}; 127beacf11bSopenharmony_ci 128beacf11bSopenharmony_ci#define ISO_DATA_SIZE 200 129beacf11bSopenharmony_cisize_t g_uac_iso_data_size = 16; 130beacf11bSopenharmony_ci 131beacf11bSopenharmony_ci#define UAC_DEF_CCHMASK 0x3 132beacf11bSopenharmony_ci#define UAC_DEF_CSRATE 48000 133beacf11bSopenharmony_ci#define UAC_DEF_CSSIZE 2 134beacf11bSopenharmony_ci#define UAC_DEF_PCHMASK 0x3 /* Playback support dual channel. */ 135beacf11bSopenharmony_ci#define UAC_DEF_PSRATE 8000 136beacf11bSopenharmony_ci#define UAC_DEF_PSSIZE 2 137beacf11bSopenharmony_ci 138beacf11bSopenharmony_cistruct uac_opts g_uac_opts = 139beacf11bSopenharmony_ci{ 140beacf11bSopenharmony_ci UAC_DEF_CCHMASK, UAC_DEF_CSRATE, UAC_DEF_CSSIZE, 141beacf11bSopenharmony_ci UAC_DEF_PCHMASK, UAC_DEF_PSRATE, UAC_DEF_PSSIZE 142beacf11bSopenharmony_ci}; 143beacf11bSopenharmony_ci 144beacf11bSopenharmony_cistatic uint32_t fuac_channel_num_get(uint32_t channel_mask) 145beacf11bSopenharmony_ci{ 146beacf11bSopenharmony_ci uint32_t num = 0; 147beacf11bSopenharmony_ci 148beacf11bSopenharmony_ci while (channel_mask) 149beacf11bSopenharmony_ci { 150beacf11bSopenharmony_ci if (channel_mask & 1) 151beacf11bSopenharmony_ci { 152beacf11bSopenharmony_ci num++; 153beacf11bSopenharmony_ci } 154beacf11bSopenharmony_ci channel_mask >>= 1; 155beacf11bSopenharmony_ci } 156beacf11bSopenharmony_ci 157beacf11bSopenharmony_ci return num; 158beacf11bSopenharmony_ci} 159beacf11bSopenharmony_ci 160beacf11bSopenharmony_ciint fuac_opts_set(struct uac_opts *opts) 161beacf11bSopenharmony_ci{ 162beacf11bSopenharmony_ci if (opts == NULL) 163beacf11bSopenharmony_ci { 164beacf11bSopenharmony_ci usb_err("opts is NULL\n"); 165beacf11bSopenharmony_ci return -1; 166beacf11bSopenharmony_ci } 167beacf11bSopenharmony_ci 168beacf11bSopenharmony_ci (void)memcpy_s(&g_uac_opts, sizeof(g_uac_opts), opts, sizeof(struct uac_opts)); 169beacf11bSopenharmony_ci 170beacf11bSopenharmony_ci return 0; 171beacf11bSopenharmony_ci} 172beacf11bSopenharmony_ci 173beacf11bSopenharmony_cistatic size_t g_uac_rate = 0; 174beacf11bSopenharmony_ciuint32_t fuac_rate_get(void) 175beacf11bSopenharmony_ci{ 176beacf11bSopenharmony_ci if (g_uac_rate != 0) 177beacf11bSopenharmony_ci { 178beacf11bSopenharmony_ci return g_uac_rate; 179beacf11bSopenharmony_ci } 180beacf11bSopenharmony_ci 181beacf11bSopenharmony_ci return 0; 182beacf11bSopenharmony_ci} 183beacf11bSopenharmony_ci 184beacf11bSopenharmony_cistatic const struct usb_device_descriptor g_fuac_device_desc __attribute__((aligned(4))) = 185beacf11bSopenharmony_ci{ 186beacf11bSopenharmony_ci .bLength = sizeof(struct usb_device_descriptor), 187beacf11bSopenharmony_ci .bDescriptorType = UDESC_DEVICE, /* Constant for device descriptor */ 188beacf11bSopenharmony_ci HSETW(.bcdUSB, UD_BCD_USB), /* USB version required: 2.0 */ 189beacf11bSopenharmony_ci .bDeviceClass = UICLASS_IAD, /* Miscellaneous Device Class */ 190beacf11bSopenharmony_ci .bDeviceSubClass = 0x2, /* Common Class */ 191beacf11bSopenharmony_ci .bDeviceProtocol = 0x1, /* Interface Association Descriptor */ 192beacf11bSopenharmony_ci .bMaxPacketSize = 64, /* Control Endpoint packet size */ 193beacf11bSopenharmony_ci HSETW(.idVendor, 0x1d6b), /* Vendor ID of Huawei Technologies */ 194beacf11bSopenharmony_ci HSETW(.idProduct, 0x0101), /* Product ID, webcamera ? */ 195beacf11bSopenharmony_ci HSETW(.bcdDevice, 0x318), /* Device release code */ 196beacf11bSopenharmony_ci .iManufacturer = 1, /* Manufacturer name, string index */ 197beacf11bSopenharmony_ci .iProduct = 2, /* Product name, string index */ 198beacf11bSopenharmony_ci .iSerialNumber = 0, /* Not Used */ 199beacf11bSopenharmony_ci .bNumConfigurations = 1 /* One Configuration */ 200beacf11bSopenharmony_ci}; 201beacf11bSopenharmony_ci 202beacf11bSopenharmony_cistatic struct usb_config_descriptor g_fuac_config_desc = 203beacf11bSopenharmony_ci{ 204beacf11bSopenharmony_ci .bLength = sizeof(struct usb_config_descriptor), 205beacf11bSopenharmony_ci .bDescriptorType = UDESC_CONFIG, 206beacf11bSopenharmony_ci HSETW(.wTotalLength, 0x006c), /* Size of all descriptors, set later */ 207beacf11bSopenharmony_ci .bNumInterface = 0x2, /* Two Interfaces */ 208beacf11bSopenharmony_ci .bConfigurationValue = 0x1, /* ID of this configuration */ 209beacf11bSopenharmony_ci .iConfiguration = 0x0, /* Index of string descriptor */ 210beacf11bSopenharmony_ci .bmAttributes = 0xc0, /* Self-powered */ 211beacf11bSopenharmony_ci .bMaxPower = 0x1 /* Maximum power consumption from the bus */ 212beacf11bSopenharmony_ci}; 213beacf11bSopenharmony_ci 214beacf11bSopenharmony_cistatic struct usb_interface_assoc_descriptor g_fuac_iad = 215beacf11bSopenharmony_ci{ 216beacf11bSopenharmony_ci .bLength = sizeof(struct usb_interface_assoc_descriptor), 217beacf11bSopenharmony_ci .bDescriptorType = UDESC_IFACE_ASSOC, 218beacf11bSopenharmony_ci .bFirstInterface = 0, /* Interface number of VideoControl interface */ 219beacf11bSopenharmony_ci .bInterfaceCount = 2, /* Number of contiguous Video interfaces */ 220beacf11bSopenharmony_ci .bFunctionClass = UICLASS_AUDIO, 221beacf11bSopenharmony_ci .bFunctionSubClass = 0, 222beacf11bSopenharmony_ci .bFunctionProtocol = 0, 223beacf11bSopenharmony_ci .iFunction = STR_AC_IF /* index of string descriptor */ 224beacf11bSopenharmony_ci}; 225beacf11bSopenharmony_ci 226beacf11bSopenharmony_cistatic struct usb_interface_descriptor g_fuac_ac_intf_desc = 227beacf11bSopenharmony_ci{ 228beacf11bSopenharmony_ci .bLength = sizeof(struct usb_interface_descriptor), 229beacf11bSopenharmony_ci .bDescriptorType = UDESC_INTERFACE, 230beacf11bSopenharmony_ci .bInterfaceNumber = 0, /* index number of this interface */ 231beacf11bSopenharmony_ci .bAlternateSetting = 0, /* index of this settings */ 232beacf11bSopenharmony_ci .bNumEndpoints = 0, /* one endpoint */ 233beacf11bSopenharmony_ci .bInterfaceClass = UICLASS_AUDIO, 234beacf11bSopenharmony_ci .bInterfaceSubClass = 1, 235beacf11bSopenharmony_ci .bInterfaceProtocol = 0, 236beacf11bSopenharmony_ci .iInterface = STR_AC_IF /* index of string descriptor */ 237beacf11bSopenharmony_ci}; 238beacf11bSopenharmony_ci 239beacf11bSopenharmony_cistatic struct uac_ac_header_descriptor g_fuac_ac_head_desc = 240beacf11bSopenharmony_ci{ 241beacf11bSopenharmony_ci .bLength = sizeof(struct uac_ac_header_descriptor), 242beacf11bSopenharmony_ci .bDescriptorType = UAC_CS_INTERFACE, 243beacf11bSopenharmony_ci .bDescriptorSubtype = UAC_HEADER, 244beacf11bSopenharmony_ci .bcdADC = 0x0100, /* UAC specification version, 1.0 */ 245beacf11bSopenharmony_ci .wTotalLength = 0x1e, /* total length, currently not set */ 246beacf11bSopenharmony_ci .bInCollection = 1, /* Number of streaming interfaces */ 247beacf11bSopenharmony_ci .baInterfaceNr = {0x01} /* Associated Audio Streaming Interface */ 248beacf11bSopenharmony_ci}; 249beacf11bSopenharmony_ci 250beacf11bSopenharmony_cistatic const struct uac1_input_terminal_descriptor g_fuac_input_terminal_desc = 251beacf11bSopenharmony_ci{ 252beacf11bSopenharmony_ci .bLength = sizeof(struct uac1_input_terminal_descriptor), 253beacf11bSopenharmony_ci .bDescriptorType = UAC_CS_INTERFACE, 254beacf11bSopenharmony_ci .bDescriptorSubtype = UAC_INPUT_TERMINAL, 255beacf11bSopenharmony_ci .bTerminalID = 0x03, 256beacf11bSopenharmony_ci .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE, 257beacf11bSopenharmony_ci .bAssocTerminal = 0, 258beacf11bSopenharmony_ci .bNrChannels = 0x1, 259beacf11bSopenharmony_ci .wChannelConfig = 0x0001, 260beacf11bSopenharmony_ci .iChannelNames = 0x10, 261beacf11bSopenharmony_ci .iTerminal = 0x8, 262beacf11bSopenharmony_ci}; 263beacf11bSopenharmony_ci 264beacf11bSopenharmony_cistatic const struct uac_output_terminal_descriptor g_fuac_output_terminal_desc = 265beacf11bSopenharmony_ci{ 266beacf11bSopenharmony_ci .bLength = sizeof(struct uac_output_terminal_descriptor), 267beacf11bSopenharmony_ci .bDescriptorType = UAC_CS_INTERFACE, 268beacf11bSopenharmony_ci .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 269beacf11bSopenharmony_ci .bTerminalID = 4, 270beacf11bSopenharmony_ci .wTerminalType = 0x101, 271beacf11bSopenharmony_ci .bAssocTerminal = 0, 272beacf11bSopenharmony_ci .bSourceID = 3, 273beacf11bSopenharmony_ci .iTerminal = 0xb, 274beacf11bSopenharmony_ci}; 275beacf11bSopenharmony_ci 276beacf11bSopenharmony_cistatic struct usb_interface_descriptor g_fuac_as_interface_alt_0_desc = 277beacf11bSopenharmony_ci{ 278beacf11bSopenharmony_ci .bLength = sizeof(struct usb_interface_descriptor), 279beacf11bSopenharmony_ci .bDescriptorType = UDESC_INTERFACE, 280beacf11bSopenharmony_ci .bInterfaceNumber = 1, 281beacf11bSopenharmony_ci .bAlternateSetting = 0, 282beacf11bSopenharmony_ci .bNumEndpoints = 0, 283beacf11bSopenharmony_ci .bInterfaceClass = UICLASS_AUDIO, 284beacf11bSopenharmony_ci .bInterfaceSubClass = 2, 285beacf11bSopenharmony_ci .bInterfaceProtocol = 0, 286beacf11bSopenharmony_ci .iInterface = 0, 287beacf11bSopenharmony_ci}; 288beacf11bSopenharmony_ci 289beacf11bSopenharmony_cistatic struct usb_interface_descriptor g_fuac_as_interface_alt_1_desc = 290beacf11bSopenharmony_ci{ 291beacf11bSopenharmony_ci .bLength = sizeof(struct usb_interface_descriptor), 292beacf11bSopenharmony_ci .bDescriptorType = UDESC_INTERFACE, 293beacf11bSopenharmony_ci .bInterfaceNumber = 1, 294beacf11bSopenharmony_ci .bAlternateSetting = 1, 295beacf11bSopenharmony_ci .bNumEndpoints = 1, 296beacf11bSopenharmony_ci .bInterfaceClass = UICLASS_AUDIO, 297beacf11bSopenharmony_ci .bInterfaceSubClass = 2, 298beacf11bSopenharmony_ci .bInterfaceProtocol = 0, 299beacf11bSopenharmony_ci .iInterface = 0, 300beacf11bSopenharmony_ci}; 301beacf11bSopenharmony_ci 302beacf11bSopenharmony_cistatic const struct uac_as_header_descriptor g_fuac_as_head_desc = 303beacf11bSopenharmony_ci{ 304beacf11bSopenharmony_ci .bLength = sizeof(struct uac_as_header_descriptor), 305beacf11bSopenharmony_ci .bDescriptorType = UAC_CS_INTERFACE, 306beacf11bSopenharmony_ci .bDescriptorSubtype = UAC_HEADER, 307beacf11bSopenharmony_ci .bTerminalLink = 4, 308beacf11bSopenharmony_ci .bDelay = 0, 309beacf11bSopenharmony_ci .wFormatTag = 1, 310beacf11bSopenharmony_ci}; 311beacf11bSopenharmony_ci 312beacf11bSopenharmony_cistatic const struct uac_format_type_i_discrete_descriptor g_fuac_as_type_i_desc = 313beacf11bSopenharmony_ci{ 314beacf11bSopenharmony_ci .bLength = sizeof(struct uac_format_type_i_discrete_descriptor), 315beacf11bSopenharmony_ci .bDescriptorType = UAC_CS_INTERFACE, 316beacf11bSopenharmony_ci .bDescriptorSubtype = UAC_FORMAT_TYPE, 317beacf11bSopenharmony_ci .bFormatType = 1, 318beacf11bSopenharmony_ci .bNrChannels = 1, 319beacf11bSopenharmony_ci .bSubframeSize = 2, 320beacf11bSopenharmony_ci .bBitResolution = 16, 321beacf11bSopenharmony_ci .bSamFreqType = 4, 322beacf11bSopenharmony_ci HSETM(.tSamFreq[0], 0x001f40), 323beacf11bSopenharmony_ci HSETM(.tSamFreq[1], 0x003e80), 324beacf11bSopenharmony_ci HSETM(.tSamFreq[2], 0x007d00), 325beacf11bSopenharmony_ci HSETM(.tSamFreq[3], 0x00bb80) 326beacf11bSopenharmony_ci}; 327beacf11bSopenharmony_ci 328beacf11bSopenharmony_ci/* Standard ISO OUT Endpoint Descriptor */ 329beacf11bSopenharmony_ci 330beacf11bSopenharmony_cistatic struct uac_endpoint_descriptor g_fuac_as_out_ep_desc = 331beacf11bSopenharmony_ci{ 332beacf11bSopenharmony_ci .bLength = sizeof(struct uac_endpoint_descriptor), 333beacf11bSopenharmony_ci .bDescriptorType = UDESC_ENDPOINT, 334beacf11bSopenharmony_ci .bEndpointAddress = 0, 335beacf11bSopenharmony_ci .bmAttributes = 0x0d, 336beacf11bSopenharmony_ci HSETW(.wMaxPacketSize, ISO_DATA_SIZE), 337beacf11bSopenharmony_ci .bInterval = 4, 338beacf11bSopenharmony_ci .bRefresh = 0, 339beacf11bSopenharmony_ci .bSynchAddress = 0, 340beacf11bSopenharmony_ci}; 341beacf11bSopenharmony_ci 342beacf11bSopenharmony_ci/* Standard ISO IN Endpoint Descriptor */ 343beacf11bSopenharmony_ci 344beacf11bSopenharmony_cistruct uac_endpoint_descriptor g_fuac_as_in_ep_desc = 345beacf11bSopenharmony_ci{ 346beacf11bSopenharmony_ci .bLength = sizeof(struct uac_endpoint_descriptor), 347beacf11bSopenharmony_ci .bDescriptorType = UDESC_ENDPOINT, 348beacf11bSopenharmony_ci 349beacf11bSopenharmony_ci /* Hi3516ev200 platform needs to specify endpoint number, otherwise the camera audio works abnormally. 350beacf11bSopenharmony_ci * This way is compatible with other platforms. 351beacf11bSopenharmony_ci */ 352beacf11bSopenharmony_ci 353beacf11bSopenharmony_ci .bEndpointAddress = UE_DIR_IN | 0x1, 354beacf11bSopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_XFER_SYNC, 355beacf11bSopenharmony_ci HSETW(.wMaxPacketSize, ISO_DATA_SIZE), 356beacf11bSopenharmony_ci .bInterval = 4, 357beacf11bSopenharmony_ci .bRefresh = 0, 358beacf11bSopenharmony_ci .bSynchAddress = 0, 359beacf11bSopenharmony_ci}; 360beacf11bSopenharmony_ci 361beacf11bSopenharmony_cistatic const struct uac2_iso_endpoint_descriptor g_fuac_as_iso_in_desc = 362beacf11bSopenharmony_ci{ 363beacf11bSopenharmony_ci .bLength = sizeof(struct uac2_iso_endpoint_descriptor), 364beacf11bSopenharmony_ci .bDescriptorType = UDESC_CS_ENDPOINT, 365beacf11bSopenharmony_ci 366beacf11bSopenharmony_ci .bDescriptorSubtype = 1, 367beacf11bSopenharmony_ci .bmAttributes = 1, 368beacf11bSopenharmony_ci .bmControls = 0, 369beacf11bSopenharmony_ci .bLockDelayUnits = 0, 370beacf11bSopenharmony_ci .wLockDelay = 0, 371beacf11bSopenharmony_ci}; 372beacf11bSopenharmony_ci 373beacf11bSopenharmony_ciconst uint8_t *g_fuac_descriptors_array[] = 374beacf11bSopenharmony_ci{ 375beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_config_desc, 376beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_iad, 377beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_ac_intf_desc, 378beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_ac_head_desc, 379beacf11bSopenharmony_ci 380beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_input_terminal_desc, 381beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_output_terminal_desc, 382beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_interface_alt_0_desc, 383beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_interface_alt_1_desc, 384beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_head_desc, 385beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_type_i_desc, 386beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_in_ep_desc, 387beacf11bSopenharmony_ci (const uint8_t *)&g_fuac_as_iso_in_desc, 388beacf11bSopenharmony_ci NULL, 389beacf11bSopenharmony_ci}; 390beacf11bSopenharmony_ci 391beacf11bSopenharmony_ciuint8_t *link_fuac_descriptors(uint8_t *prefer, uint16_t ps, uint16_t *total_size) 392beacf11bSopenharmony_ci{ 393beacf11bSopenharmony_ci int i; 394beacf11bSopenharmony_ci uint8_t *des; 395beacf11bSopenharmony_ci uint8_t *pdes; 396beacf11bSopenharmony_ci uint16_t cs; 397beacf11bSopenharmony_ci errno_t err; 398beacf11bSopenharmony_ci uint16_t ds = 0; 399beacf11bSopenharmony_ci 400beacf11bSopenharmony_ci (void)prefer; 401beacf11bSopenharmony_ci (void)ps; 402beacf11bSopenharmony_ci 403beacf11bSopenharmony_ci /* Add the length of descriptors one by one */ 404beacf11bSopenharmony_ci 405beacf11bSopenharmony_ci for (i = 0; g_fuac_descriptors_array[i]; ++i) 406beacf11bSopenharmony_ci { 407beacf11bSopenharmony_ci ds += (uint16_t)(*g_fuac_descriptors_array[i]); 408beacf11bSopenharmony_ci } 409beacf11bSopenharmony_ci 410beacf11bSopenharmony_ci if (total_size != NULL) 411beacf11bSopenharmony_ci { 412beacf11bSopenharmony_ci *total_size = ds; 413beacf11bSopenharmony_ci } 414beacf11bSopenharmony_ci 415beacf11bSopenharmony_ci des = memalign(64, SKB_DATA_ALIGN(ds)); 416beacf11bSopenharmony_ci if (des == NULL) 417beacf11bSopenharmony_ci { 418beacf11bSopenharmony_ci usb_err("System out of memory! Descriptors length: %u\n", ds); 419beacf11bSopenharmony_ci return NULL; 420beacf11bSopenharmony_ci } 421beacf11bSopenharmony_ci (void)memset_s(des, SKB_DATA_ALIGN(ds), 0, SKB_DATA_ALIGN(ds)); 422beacf11bSopenharmony_ci 423beacf11bSopenharmony_ci pdes = des; 424beacf11bSopenharmony_ci 425beacf11bSopenharmony_ci /* configuration descriptor needs to have the full length of rest of descriptors */ 426beacf11bSopenharmony_ci 427beacf11bSopenharmony_ci g_fuac_config_desc.wTotalLength[0] = (uint8_t)ds; 428beacf11bSopenharmony_ci g_fuac_config_desc.wTotalLength[1] = (uint8_t)(ds >> 8); 429beacf11bSopenharmony_ci 430beacf11bSopenharmony_ci /* Add the length of audio control descriptors */ 431beacf11bSopenharmony_ci 432beacf11bSopenharmony_ci cs = (uint32_t)g_fuac_ac_head_desc.bLength; 433beacf11bSopenharmony_ci cs += (uint32_t)g_fuac_input_terminal_desc.bLength; 434beacf11bSopenharmony_ci cs += (uint32_t)g_fuac_output_terminal_desc.bLength; 435beacf11bSopenharmony_ci 436beacf11bSopenharmony_ci g_fuac_ac_head_desc.wTotalLength = (uint16_t)cs; 437beacf11bSopenharmony_ci 438beacf11bSopenharmony_ci for (i = 0; g_fuac_descriptors_array[i]; ++i) 439beacf11bSopenharmony_ci { 440beacf11bSopenharmony_ci const u8 *des_src = g_fuac_descriptors_array[i]; 441beacf11bSopenharmony_ci u8 des_len = *des_src; 442beacf11bSopenharmony_ci err = memcpy_s(pdes, des_len, des_src, des_len); 443beacf11bSopenharmony_ci if (err != EOK) 444beacf11bSopenharmony_ci { 445beacf11bSopenharmony_ci usb_err("memcpy fail!\n"); 446beacf11bSopenharmony_ci free(des); 447beacf11bSopenharmony_ci return NULL; 448beacf11bSopenharmony_ci } 449beacf11bSopenharmony_ci pdes += des_len; 450beacf11bSopenharmony_ci } 451beacf11bSopenharmony_ci 452beacf11bSopenharmony_ci return des; 453beacf11bSopenharmony_ci} 454beacf11bSopenharmony_ci 455beacf11bSopenharmony_cistatic void fuac_request_complete(struct usbdev_ep_s *ep, struct usbdev_req_s *req) 456beacf11bSopenharmony_ci{ 457beacf11bSopenharmony_ci struct uac_dev_s *uac = (struct uac_dev_s *)req->priv; 458beacf11bSopenharmony_ci volatile uint32_t rate; 459beacf11bSopenharmony_ci 460beacf11bSopenharmony_ci (void) ep; /* ignored */ 461beacf11bSopenharmony_ci switch (uac->control) 462beacf11bSopenharmony_ci { 463beacf11bSopenharmony_ci case ~0u: 464beacf11bSopenharmony_ci break; 465beacf11bSopenharmony_ci 466beacf11bSopenharmony_ci case UAC_VS_COMMIT_CONTROL: 467beacf11bSopenharmony_ci spin_lock(&uac->lock); 468beacf11bSopenharmony_ci uac->connected = 0x1; 469beacf11bSopenharmony_ci spin_unlock(&uac->lock); 470beacf11bSopenharmony_ci uac->control = ~0; 471beacf11bSopenharmony_ci break; 472beacf11bSopenharmony_ci 473beacf11bSopenharmony_ci case UAC_SETCUR_COMPLETE: 474beacf11bSopenharmony_ci rate = (((uint8_t *)req->buf)[0] | (((uint8_t *)req->buf)[1] << 8) | 475beacf11bSopenharmony_ci (((uint8_t *)req->buf)[2] << 16)); 476beacf11bSopenharmony_ci 477beacf11bSopenharmony_ci if (uac->count == 0 || rate != g_uac_rate) 478beacf11bSopenharmony_ci { 479beacf11bSopenharmony_ci uac->count = 1; 480beacf11bSopenharmony_ci spin_lock(&uac->lock); 481beacf11bSopenharmony_ci uac_queue_free(uac); 482beacf11bSopenharmony_ci uac->busy_flag = 0; 483beacf11bSopenharmony_ci uac->connected = 1; 484beacf11bSopenharmony_ci spin_unlock(&uac->lock); 485beacf11bSopenharmony_ci g_uac_iso_data_size = (rate / 1000) * g_uac_opts.p_ssize * fuac_channel_num_get(g_uac_opts.p_chmask); 486beacf11bSopenharmony_ci g_uac_rate = rate; 487beacf11bSopenharmony_ci PRINTK("<<<rate:%u, size:%u>>>\n", rate, g_uac_iso_data_size); 488beacf11bSopenharmony_ci (void)EP_DISABLE(uac->in_ep); 489beacf11bSopenharmony_ci (void)EP_FLUSH(uac->in_ep); 490beacf11bSopenharmony_ci (void)EP_CONFIGURE(uac->in_ep, (const usb_endpoint_descriptor_t *)&g_fuac_as_in_ep_desc, 0); 491beacf11bSopenharmony_ci } 492beacf11bSopenharmony_ci uac->control = ~0; 493beacf11bSopenharmony_ci break; 494beacf11bSopenharmony_ci 495beacf11bSopenharmony_ci default: 496beacf11bSopenharmony_ci uac->control = ~0; 497beacf11bSopenharmony_ci break; 498beacf11bSopenharmony_ci } 499beacf11bSopenharmony_ci} 500beacf11bSopenharmony_ci 501beacf11bSopenharmony_cistatic void fuac_output_request_complete(struct usbdev_ep_s *ep, 502beacf11bSopenharmony_ci struct usbdev_req_s *req) 503beacf11bSopenharmony_ci{ 504beacf11bSopenharmony_ci (void)ep; 505beacf11bSopenharmony_ci (void)req; 506beacf11bSopenharmony_ci} 507beacf11bSopenharmony_ci 508beacf11bSopenharmony_civoid fuac_input_req_complete(struct usbdev_ep_s *ep, struct usbdev_req_s *req) 509beacf11bSopenharmony_ci{ 510beacf11bSopenharmony_ci struct uac_dev_s *uac = &((struct uac_softc *)(ep->priv))->dev; 511beacf11bSopenharmony_ci struct uac_queue_node *node_tx; 512beacf11bSopenharmony_ci struct usbdev_req_s *req_temp = &uac->inputreq; 513beacf11bSopenharmony_ci 514beacf11bSopenharmony_ci spin_lock(&uac->lock); 515beacf11bSopenharmony_ci if (req->result != 0) 516beacf11bSopenharmony_ci { 517beacf11bSopenharmony_ci uac_queue_free(uac); 518beacf11bSopenharmony_ci spin_unlock(&uac->lock); 519beacf11bSopenharmony_ci return; 520beacf11bSopenharmony_ci } 521beacf11bSopenharmony_ci 522beacf11bSopenharmony_ci if (uac->cur_node != NULL) 523beacf11bSopenharmony_ci { 524beacf11bSopenharmony_ci node_tx = uac->cur_node; 525beacf11bSopenharmony_ci if (node_tx->buf_len == 0) 526beacf11bSopenharmony_ci { 527beacf11bSopenharmony_ci uac_queue_node_free(node_tx); 528beacf11bSopenharmony_ci uac->cur_node = NULL; 529beacf11bSopenharmony_ci } 530beacf11bSopenharmony_ci else 531beacf11bSopenharmony_ci { 532beacf11bSopenharmony_ci uac_send_data_sub(uac); 533beacf11bSopenharmony_ci spin_unlock(&uac->lock); 534beacf11bSopenharmony_ci return; 535beacf11bSopenharmony_ci } 536beacf11bSopenharmony_ci } 537beacf11bSopenharmony_ci 538beacf11bSopenharmony_ci if (!list_empty(&uac->uac_queue)) 539beacf11bSopenharmony_ci { 540beacf11bSopenharmony_ci node_tx = list_first_entry(&uac->uac_queue, struct uac_queue_node, irqqueue); 541beacf11bSopenharmony_ci uac->cur_node = node_tx; 542beacf11bSopenharmony_ci list_del_init(&node_tx->irqqueue); 543beacf11bSopenharmony_ci uac->uac_queue_len--; 544beacf11bSopenharmony_ci uac_send_data_sub(uac); 545beacf11bSopenharmony_ci } 546beacf11bSopenharmony_ci else 547beacf11bSopenharmony_ci { 548beacf11bSopenharmony_ci req_temp->len = 0; 549beacf11bSopenharmony_ci (void)EP_SUBMIT(uac->in_ep, req_temp); 550beacf11bSopenharmony_ci } 551beacf11bSopenharmony_ci spin_unlock(&uac->lock); 552beacf11bSopenharmony_ci} 553beacf11bSopenharmony_ci 554beacf11bSopenharmony_cistatic int audio_set_endpoint_req(struct usbdev_s *dev, struct usbdev_req_s *req, 555beacf11bSopenharmony_ci const struct usb_device_request *ctrl) 556beacf11bSopenharmony_ci{ 557beacf11bSopenharmony_ci uint8_t request = ctrl->bRequest; 558beacf11bSopenharmony_ci uint8_t new_req = 0; 559beacf11bSopenharmony_ci switch (request) 560beacf11bSopenharmony_ci { 561beacf11bSopenharmony_ci case SET_CUR_UAC: 562beacf11bSopenharmony_ci case SET_MIN_UAC: 563beacf11bSopenharmony_ci case SET_MAX_UAC: 564beacf11bSopenharmony_ci case SET_RES_UAC: 565beacf11bSopenharmony_ci req->len = UGETW(ctrl->wLength); 566beacf11bSopenharmony_ci new_req++; 567beacf11bSopenharmony_ci break; 568beacf11bSopenharmony_ci 569beacf11bSopenharmony_ci default: 570beacf11bSopenharmony_ci PRINT_ERR("Unknown index in [%s]: %#x\n", __FUNCTION__, (uint8_t)request); 571beacf11bSopenharmony_ci break; 572beacf11bSopenharmony_ci } 573beacf11bSopenharmony_ci 574beacf11bSopenharmony_ci if (new_req) 575beacf11bSopenharmony_ci { 576beacf11bSopenharmony_ci (void)EP_SUBMIT(dev->ep0, req); 577beacf11bSopenharmony_ci } 578beacf11bSopenharmony_ci return 0; 579beacf11bSopenharmony_ci} 580beacf11bSopenharmony_ci 581beacf11bSopenharmony_cistatic int audio_get_endpoint_req(struct usbdev_s *dev, struct usbdev_req_s *req, 582beacf11bSopenharmony_ci const struct usb_device_request *ctrl) 583beacf11bSopenharmony_ci{ 584beacf11bSopenharmony_ci uint8_t request = ctrl->bRequest; 585beacf11bSopenharmony_ci uint8_t new_req = 0; 586beacf11bSopenharmony_ci uint8_t *buf = (uint8_t *)req->buf; 587beacf11bSopenharmony_ci 588beacf11bSopenharmony_ci switch (request) 589beacf11bSopenharmony_ci { 590beacf11bSopenharmony_ci case GET_CUR_UAC: 591beacf11bSopenharmony_ci case GET_MIN_UAC: 592beacf11bSopenharmony_ci case GET_MAX_UAC: 593beacf11bSopenharmony_ci case GET_RES_UAC: 594beacf11bSopenharmony_ci req->len = UGETW(ctrl->wLength); 595beacf11bSopenharmony_ci buf[0] = (uint8_t)g_uac_rate; 596beacf11bSopenharmony_ci buf[1] = (uint8_t)(g_uac_rate >> 8); 597beacf11bSopenharmony_ci buf[2] = (uint8_t)(g_uac_rate >> 16); 598beacf11bSopenharmony_ci new_req++; 599beacf11bSopenharmony_ci break; 600beacf11bSopenharmony_ci 601beacf11bSopenharmony_ci case GET_MEM_UAC: 602beacf11bSopenharmony_ci break; 603beacf11bSopenharmony_ci 604beacf11bSopenharmony_ci default: 605beacf11bSopenharmony_ci PRINT_ERR("Unknown index in [%s]: %#x\n", __FUNCTION__, request); 606beacf11bSopenharmony_ci break; 607beacf11bSopenharmony_ci } 608beacf11bSopenharmony_ci if (new_req) 609beacf11bSopenharmony_ci { 610beacf11bSopenharmony_ci (void)EP_SUBMIT(dev->ep0, req); 611beacf11bSopenharmony_ci } 612beacf11bSopenharmony_ci return 0; 613beacf11bSopenharmony_ci} 614beacf11bSopenharmony_ci 615beacf11bSopenharmony_cistatic void fuac_source_free(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) 616beacf11bSopenharmony_ci{ 617beacf11bSopenharmony_ci struct uac_driver_s *drvr; 618beacf11bSopenharmony_ci struct uac_dev_s *uac; 619beacf11bSopenharmony_ci 620beacf11bSopenharmony_ci drvr = (struct uac_driver_s *)driver; 621beacf11bSopenharmony_ci uac = drvr->dev; 622beacf11bSopenharmony_ci if (uac == NULL) 623beacf11bSopenharmony_ci { 624beacf11bSopenharmony_ci return; 625beacf11bSopenharmony_ci } 626beacf11bSopenharmony_ci 627beacf11bSopenharmony_ci DEV_FREEEP(dev, uac->out_ep); 628beacf11bSopenharmony_ci DEV_FREEEP(dev, uac->in_ep); 629beacf11bSopenharmony_ci} 630beacf11bSopenharmony_ci 631beacf11bSopenharmony_cistatic int usbclass_uac_bind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) 632beacf11bSopenharmony_ci{ 633beacf11bSopenharmony_ci struct usbdev_ep_s *ep; 634beacf11bSopenharmony_ci struct uac_driver_s *drvr; 635beacf11bSopenharmony_ci struct composite_dev_s *cdev; 636beacf11bSopenharmony_ci struct uac_dev_s *uac; 637beacf11bSopenharmony_ci struct composite_devobj_s *devobj; 638beacf11bSopenharmony_ci struct usbdev_devinfo_s *devinfo; 639beacf11bSopenharmony_ci 640beacf11bSopenharmony_ci if (driver == NULL || dev == NULL) 641beacf11bSopenharmony_ci { 642beacf11bSopenharmony_ci return -1; 643beacf11bSopenharmony_ci } 644beacf11bSopenharmony_ci 645beacf11bSopenharmony_ci cdev = dev->ep0->priv; 646beacf11bSopenharmony_ci drvr = (struct uac_driver_s *)driver; 647beacf11bSopenharmony_ci uac = drvr->dev; 648beacf11bSopenharmony_ci if (uac == NULL) 649beacf11bSopenharmony_ci { 650beacf11bSopenharmony_ci return -1; 651beacf11bSopenharmony_ci } 652beacf11bSopenharmony_ci 653beacf11bSopenharmony_ci INIT_LIST_HEAD(&uac->uac_queue); 654beacf11bSopenharmony_ci uac->busy_flag = 0; 655beacf11bSopenharmony_ci uac->uac_queue_len = 0; 656beacf11bSopenharmony_ci uac->cur_node = NULL; 657beacf11bSopenharmony_ci uac->count = 0; 658beacf11bSopenharmony_ci spin_lock_init(&uac->lock); 659beacf11bSopenharmony_ci 660beacf11bSopenharmony_ci devobj = usbclass_devobj_get(cdev, DEV_UAC); 661beacf11bSopenharmony_ci if (devobj == NULL) 662beacf11bSopenharmony_ci { 663beacf11bSopenharmony_ci return -1; 664beacf11bSopenharmony_ci } 665beacf11bSopenharmony_ci devinfo = &devobj->compdesc.devinfo; 666beacf11bSopenharmony_ci 667beacf11bSopenharmony_ci /* initialize control endpoint */ 668beacf11bSopenharmony_ci 669beacf11bSopenharmony_ci ep = DEV_ALLOCEP(dev, g_fuac_as_out_ep_desc.bEndpointAddress, 670beacf11bSopenharmony_ci (struct usb_endpoint_descriptor *)&g_fuac_as_out_ep_desc); 671beacf11bSopenharmony_ci if (ep == NULL) 672beacf11bSopenharmony_ci { 673beacf11bSopenharmony_ci return -1; 674beacf11bSopenharmony_ci } 675beacf11bSopenharmony_ci ep->priv = (void *)uac; 676beacf11bSopenharmony_ci (void)memset_s(&(uac->outputreq), sizeof(struct usbdev_req_s), 0, sizeof(struct usbdev_req_s)); 677beacf11bSopenharmony_ci uac->outputreq.callback = fuac_output_request_complete; 678beacf11bSopenharmony_ci uac->outputreq.priv = (void *)uac; 679beacf11bSopenharmony_ci ep->handle_req = &uac->outputreq; 680beacf11bSopenharmony_ci uac->out_ep = ep; 681beacf11bSopenharmony_ci devinfo->epno[0] = ep->eplog; 682beacf11bSopenharmony_ci 683beacf11bSopenharmony_ci /* initialize AudioStreaming endpoint */ 684beacf11bSopenharmony_ci 685beacf11bSopenharmony_ci ep = DEV_ALLOCEP(dev, g_fuac_as_in_ep_desc.bEndpointAddress, 686beacf11bSopenharmony_ci (struct usb_endpoint_descriptor *)&g_fuac_as_in_ep_desc); 687beacf11bSopenharmony_ci if (ep == NULL) 688beacf11bSopenharmony_ci { 689beacf11bSopenharmony_ci goto fail; 690beacf11bSopenharmony_ci } 691beacf11bSopenharmony_ci (void)memset_s(&uac->inputreq, sizeof(struct usbdev_req_s), 0, sizeof(struct usbdev_req_s)); 692beacf11bSopenharmony_ci uac->inputreq.callback = fuac_input_req_complete; 693beacf11bSopenharmony_ci uac->inputreq.priv = (void *)uac; 694beacf11bSopenharmony_ci uac->inputreq.buf = NULL; 695beacf11bSopenharmony_ci ep->priv = (void *)uac; 696beacf11bSopenharmony_ci ep->handle_req = &uac->inputreq; 697beacf11bSopenharmony_ci uac->in_ep = ep; 698beacf11bSopenharmony_ci devinfo->epno[1] = ep->eplog; 699beacf11bSopenharmony_ci uac->control = ~0; 700beacf11bSopenharmony_ci 701beacf11bSopenharmony_ci return 0; 702beacf11bSopenharmony_cifail: 703beacf11bSopenharmony_ci (void)usbclass_uac_unbind(driver, dev); 704beacf11bSopenharmony_ci return -1; 705beacf11bSopenharmony_ci} 706beacf11bSopenharmony_ci 707beacf11bSopenharmony_cistatic int usbclass_uac_unbind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) 708beacf11bSopenharmony_ci{ 709beacf11bSopenharmony_ci struct composite_dev_s *cdev; 710beacf11bSopenharmony_ci struct composite_devobj_s *devobj; 711beacf11bSopenharmony_ci struct usbdev_devinfo_s *devinfo; 712beacf11bSopenharmony_ci 713beacf11bSopenharmony_ci if (driver == NULL || dev == NULL) 714beacf11bSopenharmony_ci { 715beacf11bSopenharmony_ci return -1; 716beacf11bSopenharmony_ci } 717beacf11bSopenharmony_ci 718beacf11bSopenharmony_ci usbclass_uac_disconnect(driver, dev); 719beacf11bSopenharmony_ci 720beacf11bSopenharmony_ci cdev = dev->ep0->priv; 721beacf11bSopenharmony_ci if (cdev == NULL) 722beacf11bSopenharmony_ci { 723beacf11bSopenharmony_ci return -1; 724beacf11bSopenharmony_ci } 725beacf11bSopenharmony_ci 726beacf11bSopenharmony_ci devobj = usbclass_devobj_get(cdev, DEV_UAC); 727beacf11bSopenharmony_ci if (devobj == NULL) 728beacf11bSopenharmony_ci { 729beacf11bSopenharmony_ci return -1; 730beacf11bSopenharmony_ci } 731beacf11bSopenharmony_ci devinfo = &devobj->compdesc.devinfo; 732beacf11bSopenharmony_ci (void)memset_s(devinfo, sizeof(struct usbdev_devinfo_s), 0, sizeof(struct usbdev_devinfo_s)); 733beacf11bSopenharmony_ci 734beacf11bSopenharmony_ci fuac_source_free(driver, dev); 735beacf11bSopenharmony_ci return 0; 736beacf11bSopenharmony_ci} 737beacf11bSopenharmony_ci 738beacf11bSopenharmony_cistatic int usbclass_uac_set_alt(struct uac_dev_s *dev, unsigned intf, unsigned alt) 739beacf11bSopenharmony_ci{ 740beacf11bSopenharmony_ci (void)intf; 741beacf11bSopenharmony_ci (void)alt; 742beacf11bSopenharmony_ci 743beacf11bSopenharmony_ci dev->busy_flag = 0; 744beacf11bSopenharmony_ci if (dev->in_ep_enabled == true) 745beacf11bSopenharmony_ci { 746beacf11bSopenharmony_ci (void)EP_DISABLE(dev->in_ep); 747beacf11bSopenharmony_ci dev->in_ep_enabled = false; 748beacf11bSopenharmony_ci } 749beacf11bSopenharmony_ci 750beacf11bSopenharmony_ci (void)EP_CONFIGURE(dev->in_ep, (const usb_endpoint_descriptor_t *)&g_fuac_as_in_ep_desc, 0); 751beacf11bSopenharmony_ci dev->in_ep_enabled = true; 752beacf11bSopenharmony_ci 753beacf11bSopenharmony_ci return 0; 754beacf11bSopenharmony_ci} 755beacf11bSopenharmony_ci 756beacf11bSopenharmony_cistatic int usbclass_uac_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev, 757beacf11bSopenharmony_ci const struct usb_device_request *ctrl, uint8_t *dataout, size_t outlen) 758beacf11bSopenharmony_ci{ 759beacf11bSopenharmony_ci uint8_t req_type; 760beacf11bSopenharmony_ci struct uac_dev_s *uac; 761beacf11bSopenharmony_ci struct uac_driver_s *drvr; 762beacf11bSopenharmony_ci struct usbdev_req_s *req; 763beacf11bSopenharmony_ci 764beacf11bSopenharmony_ci (void)dataout; 765beacf11bSopenharmony_ci (void)outlen; 766beacf11bSopenharmony_ci 767beacf11bSopenharmony_ci if (dev == NULL || driver == NULL || ctrl == NULL) 768beacf11bSopenharmony_ci { 769beacf11bSopenharmony_ci return -1; 770beacf11bSopenharmony_ci } 771beacf11bSopenharmony_ci 772beacf11bSopenharmony_ci drvr = (struct uac_driver_s *)driver; 773beacf11bSopenharmony_ci uac = drvr->dev; 774beacf11bSopenharmony_ci if (uac == NULL) 775beacf11bSopenharmony_ci { 776beacf11bSopenharmony_ci return -1; 777beacf11bSopenharmony_ci } 778beacf11bSopenharmony_ci 779beacf11bSopenharmony_ci req = dev->ep0->handle_req; 780beacf11bSopenharmony_ci req_type = ctrl->bmRequestType; 781beacf11bSopenharmony_ci req->callback = fuac_request_complete; 782beacf11bSopenharmony_ci req->priv = uac; 783beacf11bSopenharmony_ci 784beacf11bSopenharmony_ci if (UT_GET_TYPE(req_type) == UT_STANDARD) 785beacf11bSopenharmony_ci { 786beacf11bSopenharmony_ci switch (ctrl->bRequest) 787beacf11bSopenharmony_ci { 788beacf11bSopenharmony_ci case USB_REQ_SET_CONFIGURATION: 789beacf11bSopenharmony_ci case USB_REQ_SET_INTERFACE: 790beacf11bSopenharmony_ci (void)usbclass_uac_set_alt(uac, UGETW(ctrl->wIndex), UGETW(ctrl->wValue)); 791beacf11bSopenharmony_ci break; 792beacf11bSopenharmony_ci 793beacf11bSopenharmony_ci default: 794beacf11bSopenharmony_ci break; 795beacf11bSopenharmony_ci } 796beacf11bSopenharmony_ci } 797beacf11bSopenharmony_ci else 798beacf11bSopenharmony_ci { 799beacf11bSopenharmony_ci switch (req_type) 800beacf11bSopenharmony_ci { 801beacf11bSopenharmony_ci case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: 802beacf11bSopenharmony_ci (void)audio_set_endpoint_req(dev, req, ctrl); 803beacf11bSopenharmony_ci uac->control = UAC_SETCUR_COMPLETE; 804beacf11bSopenharmony_ci break; 805beacf11bSopenharmony_ci 806beacf11bSopenharmony_ci case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER: 807beacf11bSopenharmony_ci case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER: 808beacf11bSopenharmony_ci case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: 809beacf11bSopenharmony_ci case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE: 810beacf11bSopenharmony_ci break; 811beacf11bSopenharmony_ci 812beacf11bSopenharmony_ci case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: 813beacf11bSopenharmony_ci (void)audio_get_endpoint_req(dev, req, ctrl); 814beacf11bSopenharmony_ci break; 815beacf11bSopenharmony_ci 816beacf11bSopenharmony_ci default: 817beacf11bSopenharmony_ci break; 818beacf11bSopenharmony_ci } 819beacf11bSopenharmony_ci } 820beacf11bSopenharmony_ci return 0; 821beacf11bSopenharmony_ci} 822beacf11bSopenharmony_ci 823beacf11bSopenharmony_cistatic void usbclass_uac_disconnect(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) 824beacf11bSopenharmony_ci{ 825beacf11bSopenharmony_ci struct uac_driver_s *uac_drvr; 826beacf11bSopenharmony_ci struct uac_dev_s *uac_dev; 827beacf11bSopenharmony_ci 828beacf11bSopenharmony_ci uac_drvr = (struct uac_driver_s *)driver; 829beacf11bSopenharmony_ci uac_dev = uac_drvr->dev; 830beacf11bSopenharmony_ci if (uac_dev == NULL) 831beacf11bSopenharmony_ci { 832beacf11bSopenharmony_ci return; 833beacf11bSopenharmony_ci } 834beacf11bSopenharmony_ci 835beacf11bSopenharmony_ci if (uac_dev->in_ep_enabled == true) 836beacf11bSopenharmony_ci { 837beacf11bSopenharmony_ci (void)EP_DISABLE(uac_dev->in_ep); 838beacf11bSopenharmony_ci uac_dev->in_ep_enabled = false; 839beacf11bSopenharmony_ci } 840beacf11bSopenharmony_ci} 841beacf11bSopenharmony_ci 842beacf11bSopenharmony_cistruct usbd_string g_fuac_device_strings[7] = 843beacf11bSopenharmony_ci{ 844beacf11bSopenharmony_ci { 0, g_fuac_str_lang }, 845beacf11bSopenharmony_ci { 1, g_fuac_str_manufacturer }, 846beacf11bSopenharmony_ci { 2, g_fuac_str_product }, 847beacf11bSopenharmony_ci { 4, g_fuac_str_ac_if }, 848beacf11bSopenharmony_ci { 8, g_fuac_input_terminal }, 849beacf11bSopenharmony_ci { 11, g_fuac_output_terminal }, 850beacf11bSopenharmony_ci USBD_DEVICE_STRINGS_END 851beacf11bSopenharmony_ci}; 852beacf11bSopenharmony_ci 853beacf11bSopenharmony_civoid uac_mkdevdesc(uint8_t *buf) 854beacf11bSopenharmony_ci{ 855beacf11bSopenharmony_ci errno_t ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, &g_fuac_device_desc, sizeof(g_fuac_device_desc)); 856beacf11bSopenharmony_ci if (ret != EOK) 857beacf11bSopenharmony_ci { 858beacf11bSopenharmony_ci usb_err("memcpy_s fail!, ret:%d\n", ret); 859beacf11bSopenharmony_ci return; 860beacf11bSopenharmony_ci } 861beacf11bSopenharmony_ci} 862beacf11bSopenharmony_ci 863beacf11bSopenharmony_ciint16_t uac_mkcfgdesc(uint8_t *buf, struct usbdev_devinfo_s *devinfo) 864beacf11bSopenharmony_ci{ 865beacf11bSopenharmony_ci uint16_t total_len; 866beacf11bSopenharmony_ci uint8_t *des; 867beacf11bSopenharmony_ci errno_t ret; 868beacf11bSopenharmony_ci 869beacf11bSopenharmony_ci g_fuac_iad.bFirstInterface = devinfo->ifnobase; 870beacf11bSopenharmony_ci g_fuac_ac_intf_desc.bInterfaceNumber = devinfo->ifnobase; 871beacf11bSopenharmony_ci g_fuac_as_interface_alt_0_desc.bInterfaceNumber = devinfo->ifnobase + 1; 872beacf11bSopenharmony_ci g_fuac_as_interface_alt_1_desc.bInterfaceNumber = devinfo->ifnobase + 1; 873beacf11bSopenharmony_ci g_fuac_ac_head_desc.baInterfaceNr[0] = devinfo->ifnobase + 1; 874beacf11bSopenharmony_ci 875beacf11bSopenharmony_ci des = link_fuac_descriptors(NULL, 0, &total_len); 876beacf11bSopenharmony_ci if (des != NULL) 877beacf11bSopenharmony_ci { 878beacf11bSopenharmony_ci ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, des, total_len); 879beacf11bSopenharmony_ci if (ret != EOK) 880beacf11bSopenharmony_ci { 881beacf11bSopenharmony_ci usb_err("memcpy_s fail!, ret:%d\n", ret); 882beacf11bSopenharmony_ci free(des); 883beacf11bSopenharmony_ci return 0; 884beacf11bSopenharmony_ci } 885beacf11bSopenharmony_ci free(des); 886beacf11bSopenharmony_ci } 887beacf11bSopenharmony_ci 888beacf11bSopenharmony_ci return (int16_t)total_len; 889beacf11bSopenharmony_ci} 890beacf11bSopenharmony_ci 891beacf11bSopenharmony_ciint uac_mkstrdesc(uint8_t id, uint8_t *buf) 892beacf11bSopenharmony_ci{ 893beacf11bSopenharmony_ci errno_t ret; 894beacf11bSopenharmony_ci const char *str; 895beacf11bSopenharmony_ci int i; 896beacf11bSopenharmony_ci 897beacf11bSopenharmony_ci for (i = 0; g_fuac_device_strings[i].s != NULL; i++) 898beacf11bSopenharmony_ci { 899beacf11bSopenharmony_ci str = g_fuac_device_strings[i].s; 900beacf11bSopenharmony_ci if (g_fuac_device_strings[i].id == id) 901beacf11bSopenharmony_ci { 902beacf11bSopenharmony_ci ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, str, str[0]); 903beacf11bSopenharmony_ci if (ret != EOK) 904beacf11bSopenharmony_ci { 905beacf11bSopenharmony_ci usb_err("memcpy_s failed, ret = %d\n", ret); 906beacf11bSopenharmony_ci return -1; 907beacf11bSopenharmony_ci } 908beacf11bSopenharmony_ci return str[0]; 909beacf11bSopenharmony_ci } 910beacf11bSopenharmony_ci } 911beacf11bSopenharmony_ci 912beacf11bSopenharmony_ci usb_err("Can not find the id = %u of string\n", id); 913beacf11bSopenharmony_ci return -1; 914beacf11bSopenharmony_ci} 915beacf11bSopenharmony_ci 916beacf11bSopenharmony_ci#define UAC_NCONFIGS 1 917beacf11bSopenharmony_ci#define UAC_CONFIGID 0 918beacf11bSopenharmony_ci#define UAC_NINTERFACES 2 919beacf11bSopenharmony_ci#define UAC_NSTRIDS 6 920beacf11bSopenharmony_ci#define UAC_NUM_EPS 2 921beacf11bSopenharmony_civoid uac_get_composite_devdesc(struct composite_devdesc_s *dev) 922beacf11bSopenharmony_ci{ 923beacf11bSopenharmony_ci (void)memset_s(dev, sizeof(struct composite_devdesc_s), 0, sizeof(struct composite_devdesc_s)); 924beacf11bSopenharmony_ci 925beacf11bSopenharmony_ci dev->mkdevdesc = uac_mkdevdesc; 926beacf11bSopenharmony_ci dev->mkconfdesc = uac_mkcfgdesc; 927beacf11bSopenharmony_ci dev->mkstrdesc = uac_mkstrdesc; 928beacf11bSopenharmony_ci 929beacf11bSopenharmony_ci dev->nconfigs = UAC_NCONFIGS; /* Number of configurations supported */ 930beacf11bSopenharmony_ci dev->configid = UAC_CONFIGID; /* The only supported configuration ID */ 931beacf11bSopenharmony_ci 932beacf11bSopenharmony_ci /* Interfaces. 933beacf11bSopenharmony_ci * 934beacf11bSopenharmony_ci * ifnobase must be provided by board-specific logic 935beacf11bSopenharmony_ci */ 936beacf11bSopenharmony_ci 937beacf11bSopenharmony_ci dev->devinfo.ninterfaces = UAC_NINTERFACES; /* Number of interfaces in the configuration */ 938beacf11bSopenharmony_ci 939beacf11bSopenharmony_ci /* Strings. 940beacf11bSopenharmony_ci * 941beacf11bSopenharmony_ci * strbase must be provided by board-specific logic 942beacf11bSopenharmony_ci */ 943beacf11bSopenharmony_ci 944beacf11bSopenharmony_ci dev->devinfo.nstrings = UAC_NSTRIDS; /* Number of Strings */ 945beacf11bSopenharmony_ci 946beacf11bSopenharmony_ci /* Endpoints. 947beacf11bSopenharmony_ci * 948beacf11bSopenharmony_ci * Endpoint numbers must be provided by board-specific logic. 949beacf11bSopenharmony_ci */ 950beacf11bSopenharmony_ci 951beacf11bSopenharmony_ci dev->devinfo.nendpoints = UAC_NUM_EPS; 952beacf11bSopenharmony_ci} 953beacf11bSopenharmony_ci 954beacf11bSopenharmony_ciint uac_classobject(int minor, struct usbdev_devinfo_s *devinfo, 955beacf11bSopenharmony_ci struct usbdevclass_driver_s **classdev) 956beacf11bSopenharmony_ci{ 957beacf11bSopenharmony_ci struct uac_softc *uac_s; 958beacf11bSopenharmony_ci struct uac_dev_s *priv; 959beacf11bSopenharmony_ci struct uac_driver_s *drvr; 960beacf11bSopenharmony_ci 961beacf11bSopenharmony_ci (void)minor; 962beacf11bSopenharmony_ci (void)devinfo; 963beacf11bSopenharmony_ci 964beacf11bSopenharmony_ci /* Allocate the structures needed */ 965beacf11bSopenharmony_ci 966beacf11bSopenharmony_ci uac_s = (struct uac_softc *)malloc(sizeof(struct uac_softc)); 967beacf11bSopenharmony_ci if (uac_s == NULL) 968beacf11bSopenharmony_ci { 969beacf11bSopenharmony_ci return -1; 970beacf11bSopenharmony_ci } 971beacf11bSopenharmony_ci 972beacf11bSopenharmony_ci /* Convenience pointers into the allocated blob */ 973beacf11bSopenharmony_ci 974beacf11bSopenharmony_ci priv = &uac_s->dev; 975beacf11bSopenharmony_ci drvr = &uac_s->drvr; 976beacf11bSopenharmony_ci 977beacf11bSopenharmony_ci /* Initialize the USB serial driver structure */ 978beacf11bSopenharmony_ci 979beacf11bSopenharmony_ci (void)memset_s(priv, sizeof(struct uac_dev_s), 0, sizeof(struct uac_dev_s)); 980beacf11bSopenharmony_ci 981beacf11bSopenharmony_ci /* Initialize the USB class driver structure */ 982beacf11bSopenharmony_ci 983beacf11bSopenharmony_ci drvr->drvr.speed = USB_SPEED_HIGH; 984beacf11bSopenharmony_ci drvr->drvr.ops = &g_uac_driverops; 985beacf11bSopenharmony_ci drvr->dev = priv; 986beacf11bSopenharmony_ci 987beacf11bSopenharmony_ci *classdev = &drvr->drvr; 988beacf11bSopenharmony_ci return 0; 989beacf11bSopenharmony_ci} 990beacf11bSopenharmony_ci 991beacf11bSopenharmony_civoid uac_uninitialize(struct usbdevclass_driver_s *classdev) 992beacf11bSopenharmony_ci{ 993beacf11bSopenharmony_ci struct uac_driver_s *uac_drvr = (struct uac_driver_s *)classdev; 994beacf11bSopenharmony_ci struct uac_dev_s *priv; 995beacf11bSopenharmony_ci struct uac_softc *uac_s; 996beacf11bSopenharmony_ci 997beacf11bSopenharmony_ci if (uac_drvr == NULL) 998beacf11bSopenharmony_ci { 999beacf11bSopenharmony_ci return; 1000beacf11bSopenharmony_ci } 1001beacf11bSopenharmony_ci 1002beacf11bSopenharmony_ci priv = uac_drvr->dev; 1003beacf11bSopenharmony_ci if (priv == NULL) 1004beacf11bSopenharmony_ci { 1005beacf11bSopenharmony_ci return; 1006beacf11bSopenharmony_ci } 1007beacf11bSopenharmony_ci 1008beacf11bSopenharmony_ci uac_s = container_of(uac_drvr, struct uac_softc, drvr); 1009beacf11bSopenharmony_ci free(uac_s); 1010beacf11bSopenharmony_ci} 1011beacf11bSopenharmony_ci 1012beacf11bSopenharmony_civoid usbdev_uac_initialize_sub(struct composite_devdesc_s *dev, int ifnobase, int minor) 1013beacf11bSopenharmony_ci{ 1014beacf11bSopenharmony_ci /* Ask the UAC driver to fill in the constants we didn't 1015beacf11bSopenharmony_ci * know here. 1016beacf11bSopenharmony_ci */ 1017beacf11bSopenharmony_ci 1018beacf11bSopenharmony_ci uac_get_composite_devdesc(dev); 1019beacf11bSopenharmony_ci 1020beacf11bSopenharmony_ci /* Overwrite and correct some values... */ 1021beacf11bSopenharmony_ci /* The callback functions for the UAC class */ 1022beacf11bSopenharmony_ci 1023beacf11bSopenharmony_ci dev->classobject = uac_classobject; 1024beacf11bSopenharmony_ci dev->uninitialize = uac_uninitialize; 1025beacf11bSopenharmony_ci 1026beacf11bSopenharmony_ci /* Interfaces */ 1027beacf11bSopenharmony_ci 1028beacf11bSopenharmony_ci dev->devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ 1029beacf11bSopenharmony_ci dev->minor = minor; /* The minor interface number */ 1030beacf11bSopenharmony_ci 1031beacf11bSopenharmony_ci /* Strings */ 1032beacf11bSopenharmony_ci 1033beacf11bSopenharmony_ci dev->devinfo.strbase = 0; /* Offset to String Numbers */ 1034beacf11bSopenharmony_ci} 1035beacf11bSopenharmony_ci 1036beacf11bSopenharmony_ciint usbdev_uac_initialize(struct module *mod, int n, void *arg) 1037beacf11bSopenharmony_ci{ 1038beacf11bSopenharmony_ci struct composite_softc *com_s = (struct composite_softc *)arg; 1039beacf11bSopenharmony_ci struct composite_devdesc_s dev; 1040beacf11bSopenharmony_ci int ret; 1041beacf11bSopenharmony_ci 1042beacf11bSopenharmony_ci (void)mod; 1043beacf11bSopenharmony_ci (void)n; 1044beacf11bSopenharmony_ci if (com_s == NULL) 1045beacf11bSopenharmony_ci { 1046beacf11bSopenharmony_ci return -1; 1047beacf11bSopenharmony_ci } 1048beacf11bSopenharmony_ci 1049beacf11bSopenharmony_ci usbdev_uac_initialize_sub(&dev, 0, DEV_UAC); 1050beacf11bSopenharmony_ci 1051beacf11bSopenharmony_ci ret = composite_initialize(com_s, 1, &dev); 1052beacf11bSopenharmony_ci if (ret < 0) 1053beacf11bSopenharmony_ci { 1054beacf11bSopenharmony_ci return -1; 1055beacf11bSopenharmony_ci } 1056beacf11bSopenharmony_ci 1057beacf11bSopenharmony_ci PRINTK(" ** uac device initialized successfully! **\n"); 1058beacf11bSopenharmony_ci return 0; 1059beacf11bSopenharmony_ci} 1060beacf11bSopenharmony_ci 1061beacf11bSopenharmony_ci#ifdef __cplusplus 1062beacf11bSopenharmony_ci#if __cplusplus 1063beacf11bSopenharmony_ci} 1064beacf11bSopenharmony_ci#endif /* __cplusplus */ 1065beacf11bSopenharmony_ci#endif /* __cplusplus */