#include "terasic_includes.h" #include "bulk_device.h" #include "usb_device.h" #include "usb_protocol.h" #ifdef DEBUG_USBDEV_BULK #define DEBUG_OUT(x) {printf("[USBBULK]"); printf x;} #define DEBUG_ERR(x) {printf("[USBBULK_ERR]!!!"); printf x;} #else #define DEBUG_OUT(x) #define DEBUG_ERR(x) #endif /*--------------------------------------------------------------* * local variables declerations *--------------------------------------------------------------*/ //============================================================================= #define DC_USB_VID 0x09FB #define DC_USB_PID 0xDE30 #define DC_CTRL_MPS 0x40 #define DC_HS_CTRL_MPS 512 #define DC_BUS_NUM_CONFIG 0x01 // pipe #define DC_CONFIG_PIPE_MPS DC_CTRL_MPS #define DC_HS_CONFIG_PIPE_MPS DC_HS_CTRL_MPS #define DC_BUS_NUM_INTF 0x01 #pragma pack(1) /* Device descriptor */ unsigned char gDeviceDesc[] = { DC_DEV_DESC_LEN, /* length of this desc. */ DC_DEV_DESC_TYPE, /* DEVICE descriptor */ 0x10,0x01, /* spec rev level (BCD) */ //Complient to USB2.0 FullSpeed 0xFF, //USBCS_VENDER_SPECIFIC , richard 0x00, /* device class */ 0x00, /* device subclass */ 0x00, /* device protocol */ DC_CTRL_MPS, /* max packet size */ (DC_USB_VID & 0xFF), (DC_USB_VID >> 8), (DC_USB_PID & 0xFF), (DC_USB_PID >> 8), 0x00,0x01, /* 1761's revision ID */ 1, /* index of manuf. string */ 2, /* index of prod. string */ 3, /* index of ser. # string */ DC_BUS_NUM_CONFIG /* number of configs. */ }; /* HS Device descriptor */ unsigned char gHSDeviceDesc[] = { DC_DEV_DESC_LEN, /* length of this desc. */ DC_DEV_DESC_TYPE, /* DEVICE descriptor */ 0x00,0x02, /* spec rev level (BCD) */ 0x00, /* device class */ 0x00, /* device subclass */ 0x00, /* device protocol */ DC_CTRL_MPS, /* max packet size */ (DC_USB_VID & 0xFF), (DC_USB_VID >> 8), (DC_USB_PID & 0xFF), (DC_USB_PID >> 8), 0x00,0x01, /* 1761's revision ID */ 1, /* index of manuf. string */ 2, /* index of prod. string */ 3, /* index of ser. # string */ DC_BUS_NUM_CONFIG /* number of configs. */ }; /* configuration descriptor */ unsigned char gConfigDesc[] = { DC_CONFIG_DESC_LEN, /* length of this desc. */ DC_CONFIG_DESC_TYPE, /* CONFIGURATION descriptor */ #ifdef CONFIG_USB_OTG 0x23,0x00, /* total length returned */ #elif MTP_ENABLED 0x27,0x00, /* total length returned if device is for MTP*/ #else 0x20, 0x00, #endif /* CONFIG_USB_OTG */ DC_BUS_NUM_INTF, /* number of interfaces */ 0x01, /* number of this config */ 0x00, /* index of config. string */ 0x40,//??0xC0, /* attr.: self powered */ 0x00, //0x01, /* we take no bus power */ DC_INTF_DESC_LEN, /* length of this desc. */ DC_INTF_DESC_TYPE, /* INTERFACE descriptor */ 0x00, /* interface number */ 0x00, /* alternate setting */ #ifdef MTP_ENABLED 0x03, 0x00, 0x00, 0x00, #else 0x02, /* # of (non 0) endpoints */ 0, // richard 0x08, /* interface class (Mass Storage)*/ 0, // richard 0x06, /* interface subclass (SCSI Transparent) */ 0, // richard 0x50, /* interface protocol (BOT Protocol) */ #endif 0x00, /* index of intf. string */ /* Pipe 0 */ DC_EP_DESC_LEN, /* length of this desc. */ DC_EP_DESC_TYPE, /* ENDPOINT descriptor */ 0x81, /* address (IN) */ 0x02, /* attributes (BULK) */ (DC_CONFIG_PIPE_MPS&0xff),/* max packet size */ (DC_CONFIG_PIPE_MPS>>8), 0, /* interval (ms) */ /* Pipe 1 */ DC_EP_DESC_LEN, /* length of this desc. */ DC_EP_DESC_TYPE, /* ENDPOINT descriptor*/ 0x01, /* address (OUT) */ 0x02, /* attributes (BULK) */ (DC_CONFIG_PIPE_MPS&0xff),/* max packet size */ (DC_CONFIG_PIPE_MPS>>8), 0, /* interval (ms) */ #ifdef MTP_ENABLED /* Pipe 2 */ PDC_EP_DESC_LEN, /* length of this desc. 32*/ PDC_EP_DESC_TYPE, /* ENDPOINT descriptor 33*/ 0x83, /* address (IN) 34*/ 0x03, /* attributes (Interrupt) 35*/ (PDC_CONFIG_PIPE_MPS&0xff),/* max packet size 36*/ (PDC_CONFIG_PIPE_MPS>>8), //37 0x10, #endif #ifdef CONFIG_USB_OTG PDC_OTG_DESC_LEN, /* length of this desc. */ PDC_OTG_DESC_TYPE, /* OTG descriptor */ 0x03, /* D1: HNP Support D0:SRP Support */ #endif /* CONFIG_USB_OTG */ }; /* configuration descriptor */ unsigned char gHSConfigDesc[] = { DC_CONFIG_DESC_LEN, /* length of this desc. */ DC_CONFIG_DESC_TYPE, /* CONFIGURATION descriptor */ #ifdef CONFIG_USB_OTG 0x23,0x00, /* total length returned */ #elif MTP_ENABLED 0x27,0x00, /* total length returned if device is for MTP*/ #else 0x20, 0x00, #endif /* CONFIG_USB_OTG */ DC_BUS_NUM_INTF, /* number of interfaces */ 0x01, /* number of this config */ 0x00, /* index of config. string */ 0x40,//??0xC0, /* attr.: self powered */ 0x00, //0x01, /* we take no bus power */ DC_INTF_DESC_LEN, /* length of this desc. */ DC_INTF_DESC_TYPE, /* INTERFACE descriptor */ 0x00, /* interface number */ 0x00, /* alternate setting */ #ifdef MTP_ENABLED 0x03, 0x00, 0x00, 0x00, #else 0x02, /* # of (non 0) endpoints */ 0, // richard 0x08, /* interface class (Mass Storage)*/ 0, // richard 0x06, /* interface subclass (SCSI Transparent) */ 0, // richard 0x50, /* interface protocol (BOT Protocol) */ #endif 0x00, /* index of intf. string */ /* Pipe 0 */ DC_EP_DESC_LEN, /* length of this desc. */ DC_EP_DESC_TYPE, /* ENDPOINT descriptor */ 0x81, /* address (IN) */ 0x02, /* attributes (BULK) */ (DC_HS_CONFIG_PIPE_MPS&0xff),/* max packet size */ (DC_HS_CONFIG_PIPE_MPS>>8), 0, /* interval (ms) */ /* Pipe 1 */ DC_EP_DESC_LEN, /* length of this desc. */ DC_EP_DESC_TYPE, /* ENDPOINT descriptor*/ 0x01, /* address (OUT) */ 0x02, /* attributes (BULK) */ (DC_HS_CONFIG_PIPE_MPS&0xff),/* max packet size */ (DC_HS_CONFIG_PIPE_MPS>>8), 0, /* interval (ms) */ #ifdef MTP_ENABLED /* Pipe 2 */ PDC_EP_DESC_LEN, /* length of this desc. 32*/ PDC_EP_DESC_TYPE, /* ENDPOINT descriptor 33*/ 0x83, /* address (IN) 34*/ 0x03, /* attributes (Interrupt) 35*/ (PDC_CONFIG_PIPE_MPS&0xff),/* max packet size 36*/ (PDC_CONFIG_PIPE_MPS>>8), //37 0x10, #endif #ifdef CONFIG_USB_OTG PDC_OTG_DESC_LEN, /* length of this desc. */ PDC_OTG_DESC_TYPE, /* OTG descriptor */ 0x03, /* D1: HNP Support D0:SRP Support */ #endif /* CONFIG_USB_OTG */ }; /* Unicode descriptors for our device description */ unsigned char gUnicodeString[]= { 0x04,0x03, 0x09,0x04 /* We offer only one language: 0409, US English */ }; unsigned char gMfgString[] = { 52,3, 'T',0, 'e',0, 'r',0, 'a',0, 's',0, 'i',0, 'c',0, ' ',0, 'T',0, 'e',0, 'c',0, 'h',0, 'n',0, 'o',0, 'l',0, 'o',0, 'g',0, 'i',0, 'e',0, 's',0, ' ',0, 'I',0, 'n',0, 'c',0, '.',0 }; unsigned char gProductString[]= { 30,3, 'D',0, 'E',0, '3',0, ' ',0, 'F',0, 'P',0, 'G',0, 'A',0, ' ',0, 'B',0, 'o',0, 'a',0, 'r',0, 'd', 0 }; unsigned char gSerialString[]= { 0x0A, 0x03, '1', 0x00, '.',0x00, '0', 0x00, '0', 0x00 }; #pragma pack() //============================================================================= typedef struct{ USBDEV_HANDLE hUSbDevice; BULK_NOTIFY NotifyApp; // DEVICE_DRIVER DeviceDriver; DC_PIPE_HANDLE DataInPipe; DC_PIPE_HANDLE DataOutPipe; struct DC_URB ReadUrb; struct DC_URB WriteUrb; }BULK_DRIVER; void bulkReset(BULK_DRIVER *pBulkDrv); bool bulkReadData(BULK_DRIVER *pBulkDrv, alt_u8 *buff, alt_u32 bytes); bool bulkWriteData(BULK_DRIVER *pBulkDrv, alt_u8 *buff, alt_u32 bytes); void bulkReadUrbComplete(struct DC_URB *pUrb); void bulkWriteUrbComplete(struct DC_URB *pUrb); static bool bulkNotify(USBDEV_EVENT_CONTEXT *pEventContext, void *pPrivateData){ BULK_DRIVER *pBulkDrv = (BULK_DRIVER *)pPrivateData; bool bSuccess = TRUE; switch(pEventContext->Event){ case USBDEV_EVENT_GET_DEVICE_DESC: DEBUG_OUT(("Get Device Descriptor\n")); if (pEventContext->bHighSpeed){ DEBUG_OUT(("Response high-speed Device Descriptor\n")); pEventContext->pData = gHSDeviceDesc; }else{ DEBUG_OUT(("Response full-speed Device Descriptor\n")); pEventContext->pData = gDeviceDesc; } pEventContext->DataLen = sizeof(gDeviceDesc); break; case USBDEV_EVENT_GET_CONFIGURATION_DESC: DEBUG_OUT(("Get Configuration Descriptor\n")); if (pEventContext->bHighSpeed){ DEBUG_OUT(("Response high-speed Configuration Descriptor\n")); pEventContext->pData = gHSConfigDesc; //??? }else{ DEBUG_OUT(("Response full-speed Configuration Descriptor\n")); pEventContext->pData = gConfigDesc; } pEventContext->DataLen = sizeof(gConfigDesc); break; case USBDEV_EVENT_GET_STRING_DESC: DEBUG_OUT(("Get String Descriptor (%d)\n", pEventContext->u.GetStringID)); switch(pEventContext->u.GetStringID){ case 0: pEventContext->pData = gUnicodeString; pEventContext->DataLen = sizeof(gUnicodeString); break; case 1: pEventContext->pData = gMfgString; pEventContext->DataLen = sizeof(gMfgString); break; case 2: pEventContext->pData = gProductString; pEventContext->DataLen = sizeof(gProductString); break; case 3: pEventContext->pData = gSerialString; pEventContext->DataLen = sizeof(gSerialString); break; default: bSuccess = FALSE; } // break; case USBDEV_EVENT_SET_CONFIGURATION: DEBUG_OUT(("Set Configuration(%d)\n", pEventContext->u.SetConfigurationValue)); // create/delete none-control pipe if (pEventContext->u.SetConfigurationValue == 0){ if(pBulkDrv->ReadUrb.Status == DC_URB_PENDING) DC_CancelUrb(&pBulkDrv->ReadUrb); //if(pBulkDrv->WriteUrb.Status == DC_URB_PENDING) // DC_CancelUrb(&pBulkDrv->WriteUrb); // unconfig the device, close pipe if (pBulkDrv->DataOutPipe != DC_INVALID_PIPE_HANDLE){ DC_ClosePipe(pBulkDrv->DataOutPipe); pBulkDrv->DataOutPipe = DC_INVALID_PIPE_HANDLE; } if (pBulkDrv->DataInPipe != DC_INVALID_PIPE_HANDLE){ DC_ClosePipe(pBulkDrv->DataInPipe); pBulkDrv->DataInPipe = DC_INVALID_PIPE_HANDLE; } bulkReset(pBulkDrv); }else{ // open pipe DC_PIPE_DESC PipeDesc; DC_EP_DESC *pEpDesc = pBulkDrv->DeviceDriver.szEpDesc; bulkReset(pBulkDrv); pBulkDrv->DataInPipe = DC_INVALID_PIPE_HANDLE; pBulkDrv->DataOutPipe = DC_INVALID_PIPE_HANDLE; int i; for(i=0;iDeviceDriver.NumOfEp;i++){ if (pEpDesc->Number > 0){ PipeDesc.Ep = pEpDesc->Number; PipeDesc.Dir = pEpDesc->Dir; PipeDesc.CtrlPipeNotify = NULL; PipeDesc.Context = (alt_u32)pPrivateData; PipeDesc.pPriv = pPrivateData; if (pEpDesc->Dir == DC_EP_DIR_OUT) pBulkDrv->DataInPipe = DC_OpenPipe(&PipeDesc); else pBulkDrv->DataOutPipe = DC_OpenPipe(&PipeDesc); } pEpDesc++; } if (pBulkDrv->DataOutPipe != DC_INVALID_PIPE_HANDLE && pBulkDrv->DataInPipe != DC_INVALID_PIPE_HANDLE){ /* Start waiting for input data */ //bulkReadData(pBulkDrv, pBulkDrv->szDataIn, DATAIN_LEN); //dev->cbw,DEVMSCD_CBW_LENGTH); if (pBulkDrv->NotifyApp.DeviceReady) pBulkDrv->NotifyApp.DeviceReady(); } } break; case USBDEV_EVENT_SET_ADDRESS: DEBUG_OUT(("Set Address(%d)\n", pEventContext->u.SetAddress)); break; default: bSuccess = FALSE; } // switch return bSuccess; } BULK_HANDLE BULK_Open(BULK_NOTIFY BulkNotify){ BULK_DRIVER *pBulk; DC_EP_DESC *pEpDesc; pBulk = malloc(sizeof(BULK_DRIVER)); if (!pBulk) return pBulk; pBulk->NotifyApp = BulkNotify; pBulk->DataInPipe = DC_INVALID_PIPE_HANDLE; pBulk->DataOutPipe = DC_INVALID_PIPE_HANDLE; pBulk->DeviceDriver.DeviceNotify = bulkNotify; pBulk->DeviceDriver.pPrivateData = (void *)pBulk; pBulk->DeviceDriver.NumOfEp = 3; /* Control+Bulk In + Bulk OUT */ pEpDesc = pBulk->DeviceDriver.szEpDesc; // control in pipe pEpDesc->Number = 0; /* Control End point*/ pEpDesc->Dir = DC_EP_DIR_OUT; /* In endpoint */ pEpDesc->Type = DC_EP_CONTROL; /* Control type*/ pEpDesc->MaxPacketSize = 64; /* Maximum packet size */ // none control pipe: bulk out pEpDesc++; pEpDesc->Number = 1; /* Bulk out end point */ pEpDesc->Dir = DC_EP_DIR_OUT; /* Out endpoint */ pEpDesc->Type = DC_EP_BULK; /* Transfer type*/ pEpDesc->MaxPacketSize = 64; /* Maximum packet size */ // none control pipe: bulk in pEpDesc++; pEpDesc->Number = 2; /* Bulk out end point */ pEpDesc->Dir = DC_EP_DIR_IN; /* In endpoint */ pEpDesc->Type = DC_EP_BULK; /* Transfer type*/ pEpDesc->MaxPacketSize = 64; /* Maximum packet size */ pBulk->hUSbDevice = USBDEV_Init(&pBulk->DeviceDriver); if (!pBulk->hUSbDevice){ if (pBulk){ free(pBulk); pBulk = 0; } } return (BULK_HANDLE)pBulk; } bool BULK_Read(BULK_HANDLE hBulk, alt_u8 *buff, alt_u32 bytes){ bool bSuccess = FALSE; BULK_DRIVER *pBulkDrv = (BULK_DRIVER *)hBulk; if (pBulkDrv){ bSuccess = bulkReadData(pBulkDrv, buff, bytes); } return bSuccess; } bool BULK_Write(BULK_HANDLE hBulk, alt_u8 *buff, alt_u32 bytes){ bool bSuccess = FALSE; BULK_DRIVER *pBulkDrv = (BULK_DRIVER *)hBulk; if (pBulkDrv){ bSuccess = bulkWriteData(pBulkDrv, buff, bytes); } return bSuccess; } bool BULKD_Close(BULK_HANDLE hBulk){ BULK_DRIVER *pBulk; if (hBulk){ pBulk = (BULK_DRIVER *)hBulk; USBDEV_UnInit(pBulk->hUSbDevice); free(pBulk); } return TRUE; } void BULK_Run(void){ DC_Run(); } /*--------------------------------------------------------------* * local function definitions *--------------------------------------------------------------*/ void bulkReset(BULK_DRIVER *pBulkDrv){ DEBUG_OUT(("++ bulkReset(%p)\n",pBulkDrv)); pBulkDrv->ReadUrb.Status = DC_URB_COMPLETE; pBulkDrv->WriteUrb.Status = DC_URB_COMPLETE; } /* * Make the URB req and call the Peripheral controller driver * read function */ bool bulkReadData(BULK_DRIVER *pBulkDrv, alt_u8 *buff, alt_u32 bytes) { DEBUG_OUT(("++ bulkReadData(%p,%d)\n",buff,(int)bytes)); /* Fill the read URB */ pBulkDrv->ReadUrb.pNext = NULL; pBulkDrv->ReadUrb.Pipe = pBulkDrv->DataInPipe; pBulkDrv->ReadUrb.PipeType = DC_PIPE_BULK; pBulkDrv->ReadUrb.Operation = DC_OPR_READ; pBulkDrv->ReadUrb.Status = DC_URB_PENDING; pBulkDrv->ReadUrb.pTransferBuffer = buff; pBulkDrv->ReadUrb.TransferBufferLength = bytes; pBulkDrv->ReadUrb.ActualLength = 0x00; pBulkDrv->ReadUrb.Complete = bulkReadUrbComplete; /* call back function */ pBulkDrv->ReadUrb.pReqPriv = pBulkDrv; return DC_SubmitUrb(&pBulkDrv->ReadUrb); } /* End of devmscd_read_data */ /* * Make the URB req and call the Peripheral controller driver * write function. */ int bulkWriteData(BULK_DRIVER *pBulkDrv, alt_u8 *buff, alt_u32 bytes) { // struct pdc_urb *urb; bool bSuccess; DEBUG_OUT(("++ bulkWriteData(%p,%d)\n",buff,(int)bytes)); // if(bytes == DEVMSCD_CSW_LENGTH) urb = &csw_urb; // else urb = &write_urb; /* Fill the wrtite URB */ pBulkDrv->WriteUrb.pNext = NULL; pBulkDrv->WriteUrb.Pipe = pBulkDrv->DataOutPipe;; pBulkDrv->WriteUrb.PipeType = DC_PIPE_BULK; pBulkDrv->WriteUrb.Operation = DC_OPR_WRITE; pBulkDrv->WriteUrb.Status = DC_URB_PENDING; pBulkDrv->WriteUrb.pTransferBuffer = buff; pBulkDrv->WriteUrb.TransferBufferLength = bytes; pBulkDrv->WriteUrb.ActualLength = 0x00; pBulkDrv->WriteUrb.Complete = bulkWriteUrbComplete; pBulkDrv->WriteUrb.pReqPriv = pBulkDrv; /* transfer residue will be updated in the call back function */ bSuccess = DC_SubmitUrb(&pBulkDrv->WriteUrb); if (!bSuccess) DEBUG_ERR(("bulkWriteData fail, size=%d\n", (int)bytes)); return bSuccess; } /* End of devmscd_write_data */ /* * read URB complete function. */ void bulkReadUrbComplete(struct DC_URB *pUrb) { BULK_DRIVER *pBulkDrv = (BULK_DRIVER *)pUrb->pReqPriv; // mscd_req_t *req; DEBUG_OUT(("++ bulkReadUrbComplete(%p)\n",pUrb)); pUrb->Status = DC_URB_COMPLETE; // notify parent if (pBulkDrv->NotifyApp.DataIn) pBulkDrv->NotifyApp.DataIn(pUrb->pTransferBuffer, pUrb->ActualLength); //bulkReadData(pBulkDrv, pBulkDrv->szDataIn, DATAIN_LEN); } /* End of bulkReadUrbComplete */ /* * Call the call back function of the bridge request * If the status stage is already sent by the bridge, finish the status * stage */ void bulkWriteUrbComplete(struct DC_URB *pUrb) { BULK_DRIVER *pBulkDrv = (BULK_DRIVER *)pUrb->pReqPriv; // struct devmscd_device *dev = &devmscd_dev; // mscd_req_t *req; // struct pdc_pipe_opr bulk_pipe_opr; DEBUG_OUT(("++ bulkWriteUrbComplete(%p)\n",pUrb)); #if 0 dev->tx_residue -= urb->actual_length; if(dev->status_queue) { if(dev->tx_residue) { /* Send a stall */ bulk_pipe_opr.handle = dev->data_out_pipe; bulk_pipe_opr.context = (unsigned long) dev; bulk_pipe_opr.opr = PDC_PIPE_STALL; mdelay(3); pdc_pipe_operation(&bulk_pipe_opr); dev->csw[8] = dev->tx_residue & 0xFF; dev->csw[9] = (dev->tx_residue >> 8) & 0xFF; dev->csw[10] = (dev->tx_residue >> 16) & 0xFF; dev->csw[11] = (dev->tx_residue >> 24) & 0xFF; } /* Already status is received, so send the status */ devmscd_read_data(dev->cbw,DEVMSCD_CBW_LENGTH); devmscd_write_data(dev->csw, DEVMSCD_CSW_LENGTH); devmscd_change_state(dev, DEVMSCD_IDLE); dev->status_queue = 0; } if(devmscd_dev.state != DEVMSCD_CSW) { /* Update the transfer residue */ req = bridge_write_req; if(req) { /* call the bridge call back function */ req->res_data_len = urb->actual_length; req->status = MSCD_SUCCESS; bridge_write_req = NULL; if(req->complete) req->complete(req); } } #endif pUrb->Status = DC_URB_COMPLETE; if (pBulkDrv->NotifyApp.DataOutComplete) pBulkDrv->NotifyApp.DataOutComplete(); } /* End of devmscd_write_urb_complete */