/* * Copyright (c) 2022 OpenLuat & AirM2M * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "user.h" enum { DEVICE_INTERFACE_HID_SN, DEVICE_INTERFACE_MSC_SN, DEVICE_INTERFACE_SERIAL_SN, DEVICE_INTERFACE_MAX, USB_HW_ACTION = USB_APP_EVENT_ID_START + 1, USBD_MSC_CB, }; #define DEVICE_HID_KEYBOARD_EP_IN (0x01) #define DEVICE_HID_KEYBOARD_EP_OUT (0x01) #define DEVICE_MASS_STORAGE_EP_IN (0x02) #define DEVICE_MASS_STORAGE_EP_OUT (0x02) #define DEVICE_GENERIC_SERIAL_EP_IN (0x03) #define DEVICE_GENERIC_SERIAL_EP_OUT (0x03) #define VIRTUAL_SERIAL_BUFFER_LEN (8192) #define VIRTUAL_VHID_BUFFER_LEN (2048) #define VIRTUAL_UDISK_BLOCKS_LEN (512) #define VIRTUAL_UDISK_BLOCKS_NUMS (32) #define VIRTUAL_UDISK_LEN (VIRTUAL_UDISK_BLOCKS_NUMS * VIRTUAL_UDISK_BLOCKS_LEN) //#define TEST_SPEED typedef struct { uint32_t CurAddress; uint32_t BlockNums; uint32_t BlockSize; uint32_t BlockTotalNums; uint8_t *VirtualData; }Virtual_UDiskCtrlStruct; typedef struct { Buffer_Struct TxBuf; Buffer_Struct TxCacheBuf; // 缓存下次发送的数据 CBFuncEx_t CB; uint8_t USB_ID; uint8_t IsReady; uint8_t ToHostEpIndex; }Virtual_HIDCtrlStruct; typedef struct { Buffer_Struct TxBuf; Buffer_Struct TxCacheBuf; // 缓存下次发送的数据 Buffer_Struct RxBuf; CBFuncEx_t CB; Timer_t *RxTimer; uint32_t RxTimeoutUS; uint8_t *TxData; uint8_t USBOnOff; uint8_t UartOnOff; uint8_t USB_ID; uint8_t ToHostEpIndex; uint8_t ToDeviceEpIndex; }Virtual_UartCtrlStruct; typedef struct { MSC_SCSICtrlStruct tSCSI; Virtual_UDiskCtrlStruct tUDisk; DBuffer_Struct DataBuf; SDHC_SPICtrlStruct *pSDHC; HANDLE hTaskHandle; uint8_t *pHIDReport; uint16_t HIDReportLen; }USB_AppCtrlStruct; static const uint8_t prvCore_StandardInquiryData[STANDARD_INQUIRY_DATA_LEN] = { 0x00, //磁盘设备 0x00, //其中最高位D7为RMB。RMB=0,表示不可移除设备。如果RMB=1,则为可移除设备。 0x02, //各种版本号 0x02, //数据响应格式 0x02 0x1F, //附加数据长度,为31字节 0x00, //保留 0x00, //保留 0x00, //保留 'A','I','R','M','2','M',' ',' ', 'L','U','A','T','O','S','-','S','O','C',' ','U','S','B',' ',' ', '1','.','0','0' }; const uint8_t prvCore_MSCPage00InquiryData[LENGTH_INQUIRY_PAGE00] = { 0x00, 0x00, 0x00, (LENGTH_INQUIRY_PAGE00 - 4U), 0x00, 0x80 }; /* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */ const uint8_t prvCore_MSCPage80InquiryData[LENGTH_INQUIRY_PAGE80] = { 0x00, 0x80, 0x00, LENGTH_INQUIRY_PAGE80, 0x20, /* Put Product Serial number */ 0x20, 0x20, 0x20 }; /* USB Mass storage sense 6 Data */ const uint8_t prvCore_MSCModeSense6data[MODE_SENSE6_LEN] = { 0x22, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* USB Mass storage sense 10 Data */ const uint8_t prvCore_MSCModeSense10data[MODE_SENSE10_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 }; static USB_AppCtrlStruct prvUSBApp; static Virtual_HIDCtrlStruct prvLuatOS_VirtualHID; static Virtual_UartCtrlStruct prvLuatOS_VirtualUart[VIRTUAL_UART_MAX]; /* LangID = 0x0409: U.S. English */ static const char prvCore_StringManufacturer[] = "airm2m"; static const char prvCore_StringProduct[] = "air105 usb device"; static const char prvCore_StringSerial[] = "00001"; static const char prvCore_StringConfig[] = "luatos"; static const char *prvCore_StringInterface[3] = { "virtual Mass Storage Device", "virtual HID Keyboard", "virtual Serial" }; static const usb_device_descriptor_t prvCore_DeviceDesc = { .bLength = USB_LEN_DEV_DESC, .bDescriptorType = UDESC_DEVICE, .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_IN_INTERFACE, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize = 0x40, .idVendor = {0x82, 0x17}, .idProduct = {0x00, 0x4e}, // .idVendor = {0x83, 0x04}, // .idProduct = {0x20, 0x57}, .bcdDevice = {0x00, 0x02}, .iManufacturer = USBD_IDX_MANUFACTURER_STR, .iProduct = USBD_IDX_PRODUCT_STR, .iSerialNumber = 0, .bNumConfigurations = 1, }; static const usb_device_qualifier_t prvCore_QualifierDesc = { .bLength = USB_LEN_DEV_QUALIFIER_DESC, /* bLength */ .bDescriptorType = UDESC_DEVICE_QUALIFIER, /* bDescriptorType */ .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_IN_INTERFACE, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 0x40, .bNumConfigurations = 1, .bReserved = 0 }; static const usb_config_descriptor_t prvCore_ConfigDesc = { .bLength = USB_LEN_CFG_DESC, .bDescriptorType = UDESC_CONFIG, .wTotalLength = {0x00, 0x00}, .bNumInterface = DEVICE_INTERFACE_MAX, .bConfigurationValue = 1, .iConfiguration = USBD_IDX_CONFIG_STR, .bmAttributes = UC_SELF_POWERED|UC_BUS_POWERED, .bMaxPower = (USB_MIN_POWER >> 1), }; static const usb_interface_assoc_descriptor_t prvCore_AssocInterfaceDesc = { .bLength = USB_LEN_ASSOC_IF_DESC, .bDescriptorType = UDESC_IFACE_ASSOC, .bFirstInterface = 0, .bInterfaceCount = 1, // .bFunctionClass = UICLASS_MASS, // .bFunctionSubClass = UISUBCLASS_SCSI, // .bFunctionProtocol = UIPROTO_MASS_BBB, // .bFunctionClass = 0, // .bFunctionSubClass = 0, // .bFunctionProtocol = 0, .bFunctionClass = UICLASS_HID, .bFunctionSubClass = 0, .bFunctionProtocol = UIPROTO_BOOT_KEYBOARD, .iFunction = USBD_IDX_INTERFACE0_STR, }; static const usb_interface_descriptor_t prvCore_MassStorgeInterfaceDesc = { .bLength = USB_LEN_IF_DESC, .bDescriptorType = UDESC_INTERFACE, .bInterfaceNumber = DEVICE_INTERFACE_MSC_SN, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = UICLASS_MASS, .bInterfaceSubClass = UISUBCLASS_SCSI, .bInterfaceProtocol = UIPROTO_MASS_BBB, .iInterface = USBD_IDX_INTERFACE0_STR, }; static const usb_endpoint_descriptor_t prvCore_MassStorgeEndpointDesc[2] = { { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_IN|DEVICE_MASS_STORAGE_EP_IN, .bmAttributes = UE_BULK, .wMaxPacketSize = {0x40,0x00}, .bInterval = 10, }, { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_OUT|DEVICE_MASS_STORAGE_EP_OUT, .bmAttributes = UE_BULK, .wMaxPacketSize = {0x40,0x00}, .bInterval = 10, } }; static const usb_interface_descriptor_t prvCore_HIDInterfaceDesc = { .bLength = USB_LEN_IF_DESC, .bDescriptorType = UDESC_INTERFACE, .bInterfaceNumber = DEVICE_INTERFACE_HID_SN, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = UICLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USBD_IDX_INTERFACE0_STR + 1, }; static const usb_endpoint_descriptor_t prvCore_HIDEndpointDesc[2] = { { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_IN|DEVICE_HID_KEYBOARD_EP_IN, .bmAttributes = UE_INTERRUPT, .wMaxPacketSize = {0x08,0x00}, .bInterval = 10, }, { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_OUT|DEVICE_HID_KEYBOARD_EP_OUT, .bmAttributes = UE_INTERRUPT, .wMaxPacketSize = {0x08,0x00}, .bInterval = 10, }, }; static const usb_interface_descriptor_t prvCore_SerialInterfaceDesc = { .bLength = USB_LEN_IF_DESC, .bDescriptorType = UDESC_INTERFACE, .bInterfaceNumber = DEVICE_INTERFACE_SERIAL_SN, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = UICLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USBD_IDX_INTERFACE0_STR + 2, }; static const usb_endpoint_descriptor_t prvCore_SerialEndpointDesc[2] = { { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_IN|DEVICE_GENERIC_SERIAL_EP_IN, .bmAttributes = UE_BULK, .wMaxPacketSize = {0x40,0x00}, .bInterval = 10, }, { .bLength = USB_LEN_EP_DESC, .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_OUT|DEVICE_GENERIC_SERIAL_EP_OUT, .bmAttributes = UE_BULK, .wMaxPacketSize = {0x40,0x00}, .bInterval = 10, } }; static const usb_hid_descriptor_t prvCore_HIDDesc = { .bLength = 9, .bDescriptorType = USB_HID_DESCRIPTOR_TYPE, .bcdHID = {0x11, 0x01}, .bCountryCode = 0x21, .bNumDescriptors = 1, .bReportDescriptorType = USB_HID_REPORT_DESC, .wDescriptorLength = {63,0}, }; static const char prvCore_HIDCustomReportDescriptor[34] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1) 0x09, 0x00, // USAGE (Undefined) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x00, // USAGE (Undefined) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x08, // REPORT_COUNT (8) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x00, // USAGE (Undefined) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x95, 0x08, // REPORT_COUNT (8) 0x75, 0x08, // REPORT_SIZE (8) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; static const char prvCore_HIDKeyboardReportDesc[64] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 0x29, 0x05, // USAGE_MAXIMUM (Kana) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0x00, 0xff, // LOGICAL_MAXIMUM (255) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0 // END_COLLECTION }; static int32_t prvCore_GetHIDDesc(void *pData, void *pParam) { usb_hid_descriptor_t HIDDesc; if (pData) { HIDDesc = prvCore_HIDDesc; BytesPutLe16(HIDDesc.wDescriptorLength, prvUSBApp.HIDReportLen); memcpy(pData, &HIDDesc, sizeof(usb_hid_descriptor_t)); } return sizeof(usb_hid_descriptor_t); } static usb_full_interface_t prvCore_InterfaceList[3] = { { &prvCore_HIDInterfaceDesc, prvCore_HIDEndpointDesc, NULL, prvCore_GetHIDDesc, 2, }, { &prvCore_MassStorgeInterfaceDesc, prvCore_MassStorgeEndpointDesc, NULL, NULL, 2, }, { &prvCore_SerialInterfaceDesc, prvCore_SerialEndpointDesc, NULL, NULL, 2, }, }; static const usb_full_config_t prvCore_Config = { .pConfigDesc = &prvCore_ConfigDesc, .pInterfaceAssocDesc = &prvCore_AssocInterfaceDesc, .pInterfaceFullDesc = prvCore_InterfaceList, .InterfaceNum = 3, }; static const USB_FullConfigStruct prvCore_FullConfig = { .pQualifierDesc = NULL, .pFullConfig = {&prvCore_Config, NULL, NULL}, }; static int32_t prvCore_SCSIInit(uint8_t LUN, void *pUserData) { return 0; } static int32_t prvCore_SCSIGetCapacity(uint8_t LUN, uint32_t *BlockNum, uint32_t *BlockSize, void *pUserData) { *BlockNum = prvUSBApp.tUDisk.BlockTotalNums; *BlockSize = prvUSBApp.tUDisk.BlockSize; return 0; } static int32_t prvCore_SCSIIsReady(uint8_t LUN, void *pUserData) { return 0; } static int32_t prvCore_SCSIIsWriteProtected(uint8_t LUN, void *pUserData) { return 0; } static int32_t prvCore_SCSIPreRead(uint8_t LUN, uint32_t BlockAddress, uint32_t BlockNums, void *pUserData) { if ((BlockAddress + BlockNums) * prvUSBApp.tUDisk.BlockSize > VIRTUAL_UDISK_LEN) { return -1; } prvUSBApp.tUDisk.CurAddress = BlockAddress * prvUSBApp.tUDisk.BlockSize; return 0; } static int32_t prvCore_SCSIRead(uint8_t LUN, uint32_t Len, uint8_t **pOutData, uint32_t *OutLen, void *pUserData) { if (Len + prvUSBApp.tUDisk.CurAddress > VIRTUAL_UDISK_LEN) { return -1; } *pOutData = &prvUSBApp.tUDisk.VirtualData[prvUSBApp.tUDisk.CurAddress]; *OutLen = Len; prvUSBApp.tUDisk.CurAddress += Len; return 0; } static int32_t prvCore_SCSIReadNext(uint8_t LUN, void *pUserData) { return 0; } static int32_t prvCore_SCSIPreWrite(uint8_t LUN, uint32_t BlockAddress, uint32_t BlockNums, void *pUserData) { if ((BlockAddress + BlockNums) * prvUSBApp.tUDisk.BlockSize > VIRTUAL_UDISK_LEN) { return -1; } prvUSBApp.tUDisk.CurAddress = BlockAddress * prvUSBApp.tUDisk.BlockSize; return 0; } static int32_t prvCore_SCSIWrite(uint8_t LUN, uint8_t *Data, uint32_t Len, void *pUserData) { if (Len + prvUSBApp.tUDisk.CurAddress > VIRTUAL_UDISK_LEN) { return -1; } memcpy(&prvUSBApp.tUDisk.VirtualData[prvUSBApp.tUDisk.CurAddress], Data, Len); prvUSBApp.tUDisk.CurAddress += Len; return 0; } static int32_t prvCore_SCSIDoWrite(uint8_t LUN, void *pUserData) { return 0; } static int32_t prvCore_SCSIUserCmd(USB_EndpointDataStruct *pEpData, MSC_SCSICtrlStruct *pMSC) { return -1; } static int32_t prvCore_SCSIGetMaxLUN(uint8_t *LUN, void *pUserData) { *LUN = 0; } static const USB_StorageSCSITypeDef prvCore_SCSIFun = { prvCore_SCSIGetMaxLUN, prvCore_SCSIInit, prvCore_SCSIGetCapacity, prvCore_SCSIIsReady, prvCore_SCSIIsWriteProtected, prvCore_SCSIPreRead, prvCore_SCSIRead, prvCore_SCSIReadNext, prvCore_SCSIPreWrite, prvCore_SCSIWrite, prvCore_SCSIDoWrite, prvCore_SCSIUserCmd, &prvCore_StandardInquiryData, &prvCore_MSCPage00InquiryData, &prvCore_MSCPage80InquiryData, &prvCore_MSCModeSense6data, &prvCore_MSCModeSense10data, }; static void prvCore_VUartOpen(Virtual_UartCtrlStruct *pVUart, uint8_t UartID) { pVUart->USBOnOff = 1; if (pVUart->TxBuf.Data) { DBG("send last data %ubyte", pVUart->TxBuf.MaxLen); USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0); } else if (pVUart->TxCacheBuf.Pos) { DBG("send cache data %ubyte", pVUart->TxCacheBuf.Pos); Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos); OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN); USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0); } pVUart->CB(UartID, UART_CB_CONNECTED); } static int32_t prvCore_VUartRxTimeoutCB(void *pData, void *pParam) { uint32_t UartID = (uint32_t)pParam; prvLuatOS_VirtualUart[UartID].CB(UartID, UART_CB_RX_TIMEOUT); } static int32_t prvCore_VHIDDummyCB(void *pData, void *pParam) { return 0; } static int32_t prvCore_VUartDummyCB(void *pData, void *pParam) { return 0; } static int32_t prvCore_VMSCDummyCB(void *pData, void *pParam) { return 0; } static void prvCore_VHIDSetReady(uint8_t OnOff) { if (prvLuatOS_VirtualHID.IsReady != OnOff) { prvLuatOS_VirtualHID.IsReady = OnOff; prvLuatOS_VirtualHID.CB(prvLuatOS_VirtualHID.USB_ID, prvLuatOS_VirtualHID.IsReady); } } static int32_t prvCore_USBEp0CB(void *pData, void *pParam) { int32_t Result = -ERROR_CMD_NOT_SUPPORT; USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData; USB_StorageSCSITypeDef *pUserFun = (USB_StorageSCSITypeDef *)prvUSBApp.tSCSI.pSCSIUserFunList; uint16_t wLength, wValue; Virtual_UartCtrlStruct *pVUart; // DBG("%d,%d,%d,%d", pEpData->USB_ID, pEpData->EpIndex, pEpData->IsToDevice, pEpData->Len); if (!pEpData->IsDataStage) { wLength = BytesGetLe16(pEpData->pLastRequest->wLength); if (pEpData->IsToDevice) { switch (pEpData->pLastRequest->bRequest) { case UCDC_SET_CONTROL_LINE_STATE: pVUart = &prvLuatOS_VirtualUart[pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN]; switch (pEpData->pLastRequest->wValue[0]) { case 0: //close serial pVUart->USBOnOff = 0; pVUart->CB(pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN, UART_CB_ERROR); break; case 1: case 3: //open serial prvCore_VUartOpen(pVUart, pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN); prvLuatOS_VirtualUart[pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN].USBOnOff = 1; break; } Result = ERROR_NONE; break; case USB_HID_REQ_SET_IDLE: prvCore_VHIDSetReady(1); Result = ERROR_NONE; break; case UR_GET_DESCRIPTOR: switch(pEpData->pLastRequest->wValue[1]) { case USB_HID_REPORT_DESC: USB_StackTxEpData(pEpData->USB_ID, pEpData->EpIndex, prvUSBApp.pHIDReport, prvUSBApp.HIDReportLen, wLength, 1); Result = ERROR_NONE; break; } break; case MSC_GET_MAX_LUN: pUserFun->GetMaxLUN(&prvUSBApp.tSCSI.LogicalUnitNum, prvUSBApp.tSCSI.pUserData); USB_StackTxEpData(pEpData->USB_ID, pEpData->EpIndex, &prvUSBApp.tSCSI.LogicalUnitNum, 1, wLength, 1); Result = ERROR_NONE; break; case MSC_RESET: Result = ERROR_NONE; break; } } } return Result; } static int32_t prvCore_MSCCB(void *pData, void *pParam) { USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData; USB_EndpointDataStruct *pEpDataSave; switch(prvUSBApp.tSCSI.BotState) { case USB_MSC_BOT_STATE_DATA_OUT_TO_DEVICE: case USB_MSC_BOT_STATE_DATA_IN_TO_HOST: goto MSC_RUN_IN_TASK; break; default: if (pEpData->IsToDevice && pEpData->Data) { switch(pEpData->Data[15]) { case SCSI_READ10: case SCSI_READ12: case SCSI_READ16: goto MSC_RUN_IN_TASK; break; } } break; } USB_MSCHandle(pEpData, &prvUSBApp.tSCSI); return ERROR_NONE; MSC_RUN_IN_TASK: pEpDataSave = malloc(sizeof(USB_EndpointDataStruct)); memcpy(pEpDataSave, pEpData, sizeof(USB_EndpointDataStruct)); if (pEpData->Data && pEpData->Len) { pEpDataSave->Data = malloc(pEpData->Len); memcpy(pEpDataSave->Data, pEpData->Data, pEpData->Len); } else { pEpDataSave->Data = NULL; pEpDataSave->Len = 0; } Task_SendEvent(prvUSBApp.hTaskHandle, USBD_MSC_CB, pEpDataSave, &prvUSBApp.tSCSI, pParam); return ERROR_NONE; } static int32_t prvCore_HIDCB(void *pData, void *pParam) { USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData; uint32_t USB_ID = (uint32_t)pParam; Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID; Buffer_Struct Buf; if (pEpData->IsToDevice) { prvCore_VHIDSetReady(1); Buf.Data = pEpData->Data; Buf.Pos = pEpData->Len; pVHID->CB(prvLuatOS_VirtualHID.USB_ID, &Buf); } else { OS_DeInitBuffer(&pVHID->TxBuf); if (pVHID->TxCacheBuf.Pos) { Buffer_StaticInit(&pVHID->TxBuf, pVHID->TxCacheBuf.Data, pVHID->TxCacheBuf.Pos); OS_InitBuffer(&pVHID->TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN); USB_StackTxEpData(pVHID->USB_ID, pVHID->ToHostEpIndex, pVHID->TxBuf.Data, pVHID->TxBuf.MaxLen, pVHID->TxBuf.MaxLen, 1); } else { pVHID->CB(USB_ID, USB_HID_SEND_DONE); } } return ERROR_NONE; } static int32_t prvCore_SerialCB(void *pData, void *pParam) { USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData; uint32_t UartID = (uint32_t)pParam; Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; if (pEpData->IsToDevice) { //open serial if (!pVUart->USBOnOff) { prvCore_VUartOpen(pVUart, UartID); } if (pEpData->Data && pEpData->Len) { if ((pVUart->RxBuf.Pos + pEpData->Len) >= pVUart->RxBuf.MaxLen) { OS_ReSizeBuffer(&pVUart->RxBuf, pVUart->RxBuf.MaxLen * 2); } OS_BufferWrite(&pVUart->RxBuf, pEpData->Data, pEpData->Len); if (pEpData->IsDataStage && pVUart->RxTimeoutUS) { Timer_StartUS(pVUart->RxTimer, pVUart->RxTimeoutUS, 0); } else { Timer_Stop(pVUart->RxTimer); pVUart->CB(UartID, UART_CB_RX_NEW); } } } else { OS_DeInitBuffer(&pVUart->TxBuf); if (pVUart->TxCacheBuf.Pos) { Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos); OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN); USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0); } else { pVUart->CB(UartID, UART_CB_TX_ALL_DONE); } } return ERROR_NONE; } static int32_t prvCore_USBStateCB(void *pData, void *pParam) { PV_Union uPV; uint8_t i; uPV.p = pData; switch(uPV.u8[1]) { case USBD_BUS_TYPE_DISCONNECT: prvCore_VHIDSetReady(0); USB_MSCReset(&prvUSBApp.tSCSI); for(i = 0; i < VIRTUAL_UART_MAX; i++) { prvLuatOS_VirtualUart[i].USBOnOff = 0; prvLuatOS_VirtualUart[i].CB(i, UART_CB_ERROR); } break; case USBD_BUS_TYPE_ENABLE_CONNECT: USB_StackStartDevice(uPV.u8[0]); break; } } void Core_USBDefaultDeviceStart(uint8_t USB_ID) { uint8_t langid[2] = {0x09, 0x04}; int i; prvLuatOS_VirtualHID.USB_ID = USB_ID; prvLuatOS_VirtualHID.IsReady = 0; prvLuatOS_VirtualHID.ToHostEpIndex = DEVICE_HID_KEYBOARD_EP_IN; prvUSBApp.tUDisk.BlockTotalNums = VIRTUAL_UDISK_BLOCKS_NUMS; prvUSBApp.tUDisk.BlockSize = VIRTUAL_UDISK_BLOCKS_LEN; prvUSBApp.tSCSI.LogicalUnitNum = 0; prvUSBApp.tSCSI.ToHostEpIndex = DEVICE_MASS_STORAGE_EP_IN; prvUSBApp.tSCSI.ToDeviceEpIndex = DEVICE_MASS_STORAGE_EP_OUT; if (!prvUSBApp.pHIDReport) { prvUSBApp.pHIDReport = &prvCore_HIDKeyboardReportDesc; prvUSBApp.HIDReportLen = sizeof(prvCore_HIDKeyboardReportDesc); } if (!prvUSBApp.tSCSI.pSCSIUserFunList) { prvUSBApp.tSCSI.pSCSIUserFunList = &prvCore_SCSIFun; } if (!prvLuatOS_VirtualHID.CB) { prvLuatOS_VirtualHID.CB = prvCore_VHIDDummyCB; } OS_ReInitBuffer(&prvLuatOS_VirtualHID.TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN); USB_StackPowerOnOff(USB_ID, 1); USB_StackStop(USB_ID); USB_StackClearSetup(USB_ID); USB_StackSetDeviceBusPower(USB_ID, 1); USB_StackSetEpCB(USB_ID, 0, prvCore_USBEp0CB, NULL); USB_StackSetEpCB(USB_ID, DEVICE_HID_KEYBOARD_EP_IN, prvCore_HIDCB, USB_ID); USB_StackSetEpCB(USB_ID, DEVICE_HID_KEYBOARD_EP_OUT, prvCore_HIDCB, USB_ID); USB_StackSetEpCB(USB_ID, DEVICE_MASS_STORAGE_EP_IN, prvCore_MSCCB, USB_ID); USB_StackSetEpCB(USB_ID, DEVICE_MASS_STORAGE_EP_OUT, prvCore_MSCCB, USB_ID); USB_StackSetEpCB(USB_ID, DEVICE_GENERIC_SERIAL_EP_IN, prvCore_SerialCB, VIRTUAL_UART0); USB_StackSetEpCB(USB_ID, DEVICE_GENERIC_SERIAL_EP_OUT, prvCore_SerialCB, VIRTUAL_UART0); USB_StackSetDeviceConfig(USB_ID, &prvCore_DeviceDesc, &prvCore_FullConfig, 1, USBD_IDX_INTERFACE0_STR + 3, prvCore_USBStateCB, NULL); USB_StackSetCharString(USB_ID, USBD_IDX_LANGID_STR, langid, 2); USB_StackSetCharString(USB_ID, USBD_IDX_MANUFACTURER_STR, prvCore_StringManufacturer, sizeof(prvCore_StringManufacturer)); USB_StackSetCharString(USB_ID, USBD_IDX_PRODUCT_STR, prvCore_StringProduct, sizeof(prvCore_StringProduct)); USB_StackSetCharString(USB_ID, USBD_IDX_SERIAL_STR, prvCore_StringSerial, sizeof(prvCore_StringSerial)); USB_StackSetCharString(USB_ID, USBD_IDX_CONFIG_STR, prvCore_StringConfig, sizeof(prvCore_StringConfig)); for(i = 0; i < 3; i++) { USB_StackSetCharString(USB_ID, USBD_IDX_INTERFACE0_STR + i, prvCore_StringInterface[i], strlen(prvCore_StringInterface[i])); } for(i = 0; i < VIRTUAL_UART_MAX; i++) { prvLuatOS_VirtualUart[i].USBOnOff = 0; prvLuatOS_VirtualUart[i].USB_ID = USB_ID; if (!prvLuatOS_VirtualUart[i].RxTimer) { prvLuatOS_VirtualUart[i].RxTimer = Timer_Create(prvCore_VUartRxTimeoutCB, i, NULL); } if (!prvLuatOS_VirtualUart[i].CB) { prvLuatOS_VirtualUart[i].CB = prvCore_VUartDummyCB; } prvLuatOS_VirtualUart[i].RxTimeoutUS = 150; OS_ReInitBuffer(&prvLuatOS_VirtualUart[i].TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN); OS_ReInitBuffer(&prvLuatOS_VirtualUart[i].RxBuf, VIRTUAL_SERIAL_BUFFER_LEN); } prvLuatOS_VirtualUart[VIRTUAL_UART0].ToDeviceEpIndex = DEVICE_GENERIC_SERIAL_EP_IN; prvLuatOS_VirtualUart[VIRTUAL_UART0].ToHostEpIndex = DEVICE_GENERIC_SERIAL_EP_OUT; prvUSBApp.tUDisk.VirtualData = prvLuatOS_VirtualUart[0].TxCacheBuf.Data; USB_MSCReset(&prvUSBApp.tSCSI); USB_StackStartDevice(USB_ID); } void Core_VHIDInit(uint8_t USB_ID, CBFuncEx_t CB) { if (CB) { prvLuatOS_VirtualHID.CB = CB; } else { prvLuatOS_VirtualHID.CB = prvCore_VHIDDummyCB; } } void Core_VUartInit(uint8_t UartID, uint32_t BaudRate, uint8_t IsRxCacheEnable, uint8_t DataBits, uint8_t Parity, uint8_t StopBits, CBFuncEx_t CB) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; // switch(UartID) // { // case VIRTUAL_UART0: // if (!prvService.IsUSBOpen) // { // Core_USBDefaultDeviceStart(USB_ID0); // prvService.IsUSBOpen = 1; // } // break; // } if (CB) { pVUart->CB = CB; } else { pVUart->CB = prvCore_VUartDummyCB; } pVUart->UartOnOff = 1; } void Core_VUartDeInit(uint8_t UartID) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; pVUart->UartOnOff = 0; } void Core_VUartSetRxTimeout(uint8_t UartID, uint32_t TimeoutUS) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; pVUart->RxTimeoutUS = TimeoutUS; } void Core_VUartSetCb(uint8_t UartID, CBFuncEx_t CB) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; if (CB) { pVUart->CB = CB; } else { pVUart->CB = prvCore_VUartDummyCB; } } uint32_t Core_VUartRxBufferRead(uint8_t UartID, uint8_t *Data, uint32_t Len) { uint32_t ReadLen; Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; switch(UartID) { case VIRTUAL_UART0: USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToDeviceEpIndex, 1, 0); break; } if (!Len) { ReadLen = pVUart->RxBuf.Pos; goto READ_END; } ReadLen = (pVUart->RxBuf.Pos < Len)?pVUart->RxBuf.Pos:Len; memcpy(Data, pVUart->RxBuf.Data, ReadLen); OS_BufferRemove(&pVUart->RxBuf, ReadLen); if (!pVUart->RxBuf.Pos && pVUart->RxBuf.MaxLen > VIRTUAL_SERIAL_BUFFER_LEN) { OS_ReInitBuffer(&pVUart->RxBuf, VIRTUAL_SERIAL_BUFFER_LEN); } READ_END: switch(UartID) { case VIRTUAL_UART0: USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToDeviceEpIndex, 1, 1); break; } return ReadLen; } int32_t Core_VUartBufferTx(uint8_t UartID, const uint8_t *Data, uint32_t Len) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; switch(UartID) { case VIRTUAL_UART0: if (!pVUart->USBOnOff) { return -1; } USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 0); break; } if (Data && Len) { OS_BufferWrite(&pVUart->TxCacheBuf, Data, Len); } if (pVUart->TxBuf.Data || pVUart->TxBuf.MaxLen) { goto TX_END; } // 把缓存的Tx指针交给发送的Tx指针,缓存的Tx指针重新建立一个 Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos); OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN); USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0); TX_END: switch(UartID) { case VIRTUAL_UART0: USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 1); break; } return 0; } void Core_VUartBufferTxStop(uint8_t UartID) { Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID]; switch(UartID) { case VIRTUAL_UART0: USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 0); break; } OS_DeInitBuffer(&pVUart->TxBuf); pVUart->TxCacheBuf.Pos = 0; USB_StackStopDeviceTx(pVUart->USB_ID, pVUart->ToHostEpIndex, 0); switch(UartID) { case VIRTUAL_UART0: USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 1); break; } } void Core_VHIDUploadData(uint8_t USB_ID, uint8_t *Data, uint16_t Len) { if (!prvLuatOS_VirtualHID.IsReady) return; USB_HIDKeyValue HIDKey; USB_HIDKeyBoradKeyStruct HIDKeyBoard; uint16_t Pos; volatile uint8_t IsShift, i, LastValue; Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID; USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 0); if (Data && Len) { if ((Len*16 + pVHID->TxCacheBuf.Pos) > pVHID->TxCacheBuf.MaxLen) { OS_ReSizeBuffer(&pVHID->TxCacheBuf, Len*16 + pVHID->TxCacheBuf.Pos); } Pos = 0; while(Pos < Len) { memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct)); HIDKey = USB_HIDGetValueFromAscii(Data[Pos]); Pos++; IsShift = HIDKey.Shift; LastValue = HIDKey.Value; HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift; HIDKeyBoard.PressKey[0] = HIDKey.Value; // DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift); ADD_REST: for(i = 1; i < 6; i++) { HIDKey = USB_HIDGetValueFromAscii(Data[Pos]); Pos++; if ((IsShift != HIDKey.Shift) || (LastValue == HIDKey.Value) || (LastValue == '\r') || (LastValue == '\n')) { OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct)); //加入一个抬起的data OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); IsShift = HIDKey.Shift; LastValue = HIDKey.Value; HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift; HIDKeyBoard.PressKey[0] = HIDKey.Value; // DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift); if (Pos < Len) { goto ADD_REST; } else { break; } } // else if // { // OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); // memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct)); // //加入一个抬起的data // OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); // IsShift = HIDKey.Shift; // LastValue = HIDKey.Value; // HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift; // HIDKeyBoard.PressKey[0] = HIDKey.Value; //// DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift); // if (Pos < Len) // { // goto ADD_REST; // } // else // { // break; // } // } else { LastValue = HIDKey.Value; HIDKeyBoard.PressKey[i] = HIDKey.Value; // DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], i, HIDKey.Value, HIDKey.Shift); if (Pos >= Len) { break; } } } OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); //加入一个抬起的data memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct)); OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); } //加入一个抬起的data memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct)); OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard)); } // pVHID->TxCacheBuf.Pos = 0; // return; if (pVHID->TxBuf.Data || pVHID->TxBuf.MaxLen) { goto UPLOAD_END; } // 把缓存的Tx指针交给发送的Tx指针,缓存的Tx指针重新建立一个 Buffer_StaticInit(&pVHID->TxBuf, pVHID->TxCacheBuf.Data, pVHID->TxCacheBuf.Pos); OS_InitBuffer(&pVHID->TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN); USB_StackTxEpData(pVHID->USB_ID, pVHID->ToHostEpIndex, pVHID->TxBuf.Data, pVHID->TxBuf.MaxLen, pVHID->TxBuf.MaxLen, 1); UPLOAD_END: USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 1); } void Core_VHIDSendRawData(uint8_t USB_ID, uint8_t *Data, uint16_t Len) { if (!prvLuatOS_VirtualHID.IsReady) return; USB_HIDKeyValue HIDKey; Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID; USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 0); OS_BufferWrite(&pVHID->TxCacheBuf, Data, Len); Buffer_StaticInit(&pVHID->TxBuf, pVHID->TxCacheBuf.Data, pVHID->TxCacheBuf.Pos); OS_InitBuffer(&pVHID->TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN); USB_StackTxEpData(pVHID->USB_ID, pVHID->ToHostEpIndex, pVHID->TxBuf.Data, pVHID->TxBuf.MaxLen, pVHID->TxBuf.MaxLen, 1); USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 1); } void Core_VHIDUploadStop(uint8_t USB_ID) { Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID; USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 0); OS_DeInitBuffer(&pVHID->TxBuf); pVHID->TxCacheBuf.Pos = 0; USB_StackStopDeviceTx(pVHID->USB_ID, pVHID->ToHostEpIndex, 0); USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 1); } #ifdef __BUILD_OS__ static void prvCore_USBAppTask(void *pParam) { OS_EVENT Event; USB_EndpointDataStruct *pEpData; while(1) { Task_GetEventByMS(prvUSBApp.hTaskHandle, CORE_EVENT_ID_ANY, &Event, NULL, 0); switch(Event.ID) { case USB_HW_ACTION: switch (Event.Param2) { case SERV_USB_RESET_END: DBG("USB%d reset", Event.Param1); Task_DelayMS(1); USB_StackDeviceAfterDisconnect(Event.Param1); break; case SERV_USB_RESUME_END: Task_DelayMS(20); USB_ResumeEnd(Event.Param3); break; case SERV_USB_SUSPEND: DBG("USB%d suspend", Event.Param1); break; case SERV_USB_RESUME: break; } break; case USBD_MSC_CB: pEpData = (USB_EndpointDataStruct *)Event.Param1; // DBG("%d,%d,%d,%d", pEpData->USB_ID, pEpData->EpIndex, pEpData->IsToDevice, pEpData->Len); USB_MSCHandle(pEpData, Event.Param2); free(pEpData->Data); free(Event.Param1); WDT_Feed(); break; } } } void Core_USBAction(uint8_t USB_ID, uint8_t Action, void *pParam) { Task_SendEvent(prvUSBApp.hTaskHandle, USB_HW_ACTION, USB_ID, Action, pParam); } extern const USB_StorageSCSITypeDef prvSDHC_SCSIFun; void Core_UDiskAttachSDHC(uint8_t USB_ID, void *pCtrl) { if (!prvUSBApp.pSDHC) { prvUSBApp.pSDHC = malloc(sizeof(SDHC_SPICtrlStruct)); } memcpy(prvUSBApp.pSDHC, pCtrl, sizeof(SDHC_SPICtrlStruct)); prvUSBApp.tSCSI.pSCSIUserFunList = &prvSDHC_SCSIFun; prvUSBApp.tSCSI.pUserData = prvUSBApp.pSDHC; DBuffer_ReInit(&prvUSBApp.DataBuf, 8 * 1024); prvUSBApp.pSDHC->SCSIDataBuf = &prvUSBApp.DataBuf; } void Core_UDiskDetachSDHC(uint8_t USB_ID) { prvUSBApp.tSCSI.pSCSIUserFunList = &prvCore_SCSIFun; prvUSBApp.tSCSI.pUserData = NULL; free(prvUSBApp.pSDHC); prvUSBApp.pSDHC = NULL; DBuffer_DeInit(&prvUSBApp.DataBuf); } void Core_USBAppGlobalInit(void) { prvUSBApp.hTaskHandle = Task_Create(prvCore_USBAppTask, NULL,2 * 1024, USB_TASK_PRO, "usb app"); } INIT_TASK_EXPORT(Core_USBAppGlobalInit, "2"); #endif