diff options
author | AJM <poslathian@poslathian.(none)> | 2010-04-20 14:35:58 -0400 |
---|---|---|
committer | bnewbold <bnewbold@robocracy.org> | 2010-05-20 22:09:15 -0400 |
commit | bfb86b6c2ac84c691c150e20adcc1b77d57efd10 (patch) | |
tree | feb5286f411417d6832a417e02e07fe1c775f4e7 /core/usb/usb.c | |
parent | 0db5696149d8f01275955c94ec55c9c43d7ca390 (diff) | |
download | librambutan-bfb86b6c2ac84c691c150e20adcc1b77d57efd10.tar.gz librambutan-bfb86b6c2ac84c691c150e20adcc1b77d57efd10.zip |
finished the entire low level usb app for virtual com minus the precise handling of get/send data callbacks and toggle line state. completely undebugged for now.
Diffstat (limited to 'core/usb/usb.c')
-rw-r--r-- | core/usb/usb.c | 368 |
1 files changed, 307 insertions, 61 deletions
diff --git a/core/usb/usb.c b/core/usb/usb.c index 8826858..2f458cc 100644 --- a/core/usb/usb.c +++ b/core/usb/usb.c @@ -1,85 +1,331 @@ -#include "libmaple.h" +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * 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. + * ****************************************************************************/ + +/** + * @file usb.c + * + * @brief usb-specific hardware setup, NVIC, clocks, and usb activities + * in the pre-attached state. includes some of the lower level callbacks + * needed by the usb library, like suspend,resume,init,etc + */ + #include "usb.h" -#include "usb_regs.h" -#include "bootVect.h" +#include "gpio.h" +#include "usb_callbacks.h" + +/* persistent usb structs */ +volatile uint32 bDeviceState = UNCONNECTED; +volatile uint16 wIstr = 0; +volatile bIntPackSOF = 0; + +DEVICE Device_Table = + { + NUM_ENDPTS, + 1 + }; + +DEVICE_PROP Device_Property = + { + usbInit, + usbReset, + usbStatusIn, + usbStatusOut, + usbDataSetup, + usbNoDataSetup, + usbGetInterfaceSetting, + usbGetDeviceDescriptor, + usbGetInterfaceDescriptor, + usbGetConfigDescriptor, + usbGetStringDescriptor, + usbGetFunctionalDescriptor, + 0, + bMaxPacketSize + }; + +USER_STANDARD_REQUESTS User_Standard_Requests = + { + usbGetConfiguration, + usbSetConfiguration, + usbGetInterface, + usbSetInterface, + usbGetStatus, + usbClearFeature, + usbSetEndpointFeature, + usbSetDeviceFeature, + usbSetDeviceAddress + }; + +void (*pEpInt_IN[7])(void) = +{ + vcomManagementCb, + vcomDataTxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, +}; -void usb_lpIRQHandler(void) +void (*pEpInt_OUT[7])(void) = { - typedef void (*funcPtr)(void); - - const uint32_t usbIsrAddr = *(uint32_t*)(USB_ISR_ADDR); - void (*ptrToUsbISR)(void) = (funcPtr) usbIsrAddr; - ptrToUsbISR(); -} + NOP_Process, + NOP_Process, + vcomDataRxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, +}; -void usb_userToPMABufferCopy(uint8 *pbUsrBuf, uint16 wPMABufAddr, uint16 wNBytes) +struct { - uint32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ - uint32 i, temp1, temp2; - uint16 *pdwVal; - pdwVal = (uint16 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - temp1 = (uint16) * pbUsrBuf; - pbUsrBuf++; - temp2 = temp1 | (uint16) * pbUsrBuf << 8; - *pdwVal++ = temp2; - pdwVal++; - pbUsrBuf++; - } + volatile RESUME_STATE eState; + volatile uint8 bESOFcnt; +} ResumeS; + +void setupUSB (void) { + gpio_set_mode(USB_DISC_BANK, + USB_DISC_PIN, + GPIO_MODE_OUTPUT_PP); + + /* setup the apb1 clock for USB */ + pRCC->APB1ENR |= 0x00800000; + + /* initialize the usb application */ + gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,0); /* present ourselves to the host */ + USB_Init(); /* low level init routine provided by st lib */ + } -void usb_PMAToUserBufferCopy(uint8 *pbUsrBuf, uint16 wPMABufAddr, uint16 wNBytes) -{ - uint32 n = (wNBytes + 1) >> 1;/* /2*/ - uint32 i; - uint32 *pdwVal; - pdwVal = (uint32 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - *(uint16*)pbUsrBuf++ = *pdwVal++; - pbUsrBuf++; - } +void usbSuspend(void) { + u16 wCNTR; + wCNTR = _GetCNTR(); + wCNTR |= CNTR_FSUSP | CNTR_LPMODE; + _SetCNTR(wCNTR); + + /* run any power reduction handlers */ + bDeviceState = SUSPENDED; } -void usb_serialWriteStr(const char* outStr) { - uint8 offset=0; - BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); +void usbResumeInit(void) { + u16 wCNTR; - while ((outStr[offset] != '\0') - && (offset < USB_SERIAL_BUF_SIZE)) { - offset++; - } + /* restart any clocks that had been stopped */ + + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_LPMODE); + _SetCNTR(wCNTR); + + /* undo power reduction handlers here */ - delay(offset*1); + _SetCNTR(ISR_MSK); - bootVector->serial_count_in = (uint32*) &offset; - usb_userToPMABufferCopy((uint8*)outStr,USB_SERIAL_ENDP_TXADDR,offset); - _SetEPTxCount(USB_SERIAL_ENDP_TX,offset); - _SetEPTxValid(USB_SERIAL_ENDP_TX); +} + +void usbResume(RESUME_STATE eResumeSetVal) { + u16 wCNTR; + if (eResumeSetVal != RESUME_ESOF) + ResumeS.eState = eResumeSetVal; + + switch (ResumeS.eState) + { + case RESUME_EXTERNAL: + usbResumeInit(); + ResumeS.eState = RESUME_OFF; + break; + case RESUME_INTERNAL: + usbResumeInit(); + ResumeS.eState = RESUME_START; + break; + case RESUME_LATER: + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; + case RESUME_WAIT: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + ResumeS.eState = RESUME_START; + break; + case RESUME_START: + wCNTR = _GetCNTR(); + wCNTR |= CNTR_RESUME; + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; + case RESUME_ON: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + { + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_RESUME); + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_OFF; + } + break; + case RESUME_OFF: + case RESUME_ESOF: + default: + ResumeS.eState = RESUME_OFF; + break; + } } -void usb_serialWriteChar(unsigned char ch) { - BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); +RESULT usbPowerOn(void) { + u16 wRegVal; + + wRegVal = CNTR_FRES; + _SetCNTR(wRegVal); + + wInterrupt_Mask = 0; + _SetCNTR(wInterrupt_Mask); + _SetISTR(0); + wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; /* the bare minimum */ + _SetCNTR(wInterrupt_Mask); - delay(1); + return USB_SUCCESS; +} + +RESULT usbPowerOff(void) { + _SetCNTR(CNTR_FRES); + _SetISTR(0); + _SetCNTR(CNTR_FRES + CNTR_PDWN); - *(bootVector->serial_count_in) = 1; - usb_userToPMABufferCopy((uint8*)(&ch),USB_SERIAL_ENDP_TXADDR,1); - _SetEPTxCount(USB_SERIAL_ENDP_TX,1); - _SetEPTxValid(USB_SERIAL_ENDP_TX); + /* note that all weve done here is powerdown the + usb peripheral. we have no disabled the clocks, + pulled the usb_disc pin back up, or reset the + application state machines */ + return USB_SUCCESS; } -uint8 usb_serialGetRecvLen() { - uint8 count_out =_GetEPRxCount(USB_SERIAL_ENDP_RX); - return count_out; +void usbEnbISR(void) { + NVIC_InitTypeDef NVIC_InitStructure; + + + NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = TRUE; + nvicInit(&NVIC_InitStructure); } -void usb_copyRecvBuffer(unsigned char* dest, uint8 len) { - ASSERT(len < USB_SERIAL_BUF_SIZE); - usb_PMAToUserBufferCopy((uint8*)(dest),USB_SERIAL_ENDP_RXADDR,len); - _SetEPRxValid(USB_SERIAL_ENDP_RX); +void usbDsbISR(void) { + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE; + nvicInit(&NVIC_InitStructure); } +/* overloaded ISR routine, this is the main usb ISR */ +void usb_lpIRQHandler(void); +wIstr = _GetISTR(); + +/* go nuts with the preproc switches since this is an ISTR and must be FAST */ +#if (ISR_MSK & ISTR_RESET) +if (wIstr & ISTR_RESET & wInterrupt_Mask) + { + _SetISTR((u16)CLR_RESET); + Device_Property.Reset(); + } +#endif + + +#if (ISR_MSK & ISTR_DOVR) +if (wIstr & ISTR_DOVR & wInterrupt_Mask) + { + _SetISTR((u16)CLR_DOVR); + } +#endif + + +#if (ISR_MSK & ISTR_ERR) +if (wIstr & ISTR_ERR & wInterrupt_Mask) + { + _SetISTR((u16)CLR_ERR); + } +#endif + + +#if (ISR_MSK & ISTR_WKUP) +if (wIstr & ISTR_WKUP & wInterrupt_Mask) + { + _SetISTR((u16)CLR_WKUP); + usbResume(RESUME_EXTERNAL); + } +#endif + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (ISR_MSK & ISTR_SUSP) +if (wIstr & ISTR_SUSP & wInterrupt_Mask) + { + + /* check if SUSPEND is possible */ + if (F_SUSPEND_ENABLED) + { + usbSuspend(); + } + else + { + /* if not possible then resume after xx ms */ + usbResume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + _SetISTR((u16)CLR_SUSP); + } +#endif + + +#if (ISR_MSK & ISTR_SOF) +if (wIstr & ISTR_SOF & wInterrupt_Mask) + { + _SetISTR((u16)CLR_SOF); + bIntPackSOF++; + } +#endif + + +#if (ISR_MSK & ISTR_ESOF) +if (wIstr & ISTR_ESOF & wInterrupt_Mask) + { + _SetISTR((u16)CLR_ESOF); + /* resume handling timing is made with ESOFs */ + usbResume(RESUME_ESOF); /* request without change of the machine state */ + } +#endif + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (ISR_MSK & ISTR_CTR) +if (wIstr & ISTR_CTR & wInterrupt_Mask) + { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + CTR_LP(); /* low priority ISR defined in the usb core lib */ + } +#endif + +} |