Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBDevice by
Revision 2:9fdd29bb0d95, committed 2012-11-07
- Comitter:
- hase
- Date:
- Wed Nov 07 09:31:53 2012 +0000
- Parent:
- 1:f6a91be12476
- Commit message:
- test NGprogram
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBDescriptor.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,74 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +/* Standard descriptor types */ +#define DEVICE_DESCRIPTOR (1) +#define CONFIGURATION_DESCRIPTOR (2) +#define STRING_DESCRIPTOR (3) +#define INTERFACE_DESCRIPTOR (4) +#define ENDPOINT_DESCRIPTOR (5) +#define QUALIFIER_DESCRIPTOR (6) + +/* Standard descriptor lengths */ +#define DEVICE_DESCRIPTOR_LENGTH (0x12) +#define CONFIGURATION_DESCRIPTOR_LENGTH (0x09) +#define INTERFACE_DESCRIPTOR_LENGTH (0x09) +#define ENDPOINT_DESCRIPTOR_LENGTH (0x07) + + +/*string offset*/ +#define STRING_OFFSET_LANGID (0) +#define STRING_OFFSET_IMANUFACTURER (1) +#define STRING_OFFSET_IPRODUCT (2) +#define STRING_OFFSET_ISERIAL (3) +#define STRING_OFFSET_ICONFIGURATION (4) +#define STRING_OFFSET_IINTERFACE (5) + +/* USB Specification Release Number */ +#define USB_VERSION_2_0 (0x0200) + +/* Least/Most significant byte of short integer */ +#define LSB(n) ((n)&0xff) +#define MSB(n) (((n)&0xff00)>>8) + +/* Convert physical endpoint number to descriptor endpoint number */ +#define PHY_TO_DESC(endpoint) (((endpoint)>>1) | (((endpoint) & 1) ? 0x80:0)) + +/* bmAttributes in configuration descriptor */ +/* C_RESERVED must always be set */ +#define C_RESERVED (1U<<7) +#define C_SELF_POWERED (1U<<6) +#define C_REMOTE_WAKEUP (1U<<5) + +/* bMaxPower in configuration descriptor */ +#define C_POWER(mA) ((mA)/2) + +/* bmAttributes in endpoint descriptor */ +#define E_CONTROL (0x00) +#define E_ISOCHRONOUS (0x01) +#define E_BULK (0x02) +#define E_INTERRUPT (0x03) + +/* For isochronous endpoints only: */ +#define E_NO_SYNCHRONIZATION (0x00) +#define E_ASYNCHRONOUS (0x04) +#define E_ADAPTIVE (0x08) +#define E_SYNCHRONOUS (0x0C) +#define E_DATA (0x00) +#define E_FEEDBACK (0x10) +#define E_IMPLICIT_FEEDBACK (0x20)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBDevice.cpp Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,976 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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 "stdint.h" + +#include "USBEndpoints.h" +#include "USBDevice.h" +#include "USBDescriptor.h" + +//#define DEBUG + +/* Device status */ +#define DEVICE_STATUS_SELF_POWERED (1U<<0) +#define DEVICE_STATUS_REMOTE_WAKEUP (1U<<1) + +/* Endpoint status */ +#define ENDPOINT_STATUS_HALT (1U<<0) + +/* Standard feature selectors */ +#define DEVICE_REMOTE_WAKEUP (1) +#define ENDPOINT_HALT (0) + +/* Macro to convert wIndex endpoint number to physical endpoint number */ +#define WINDEX_TO_PHYSICAL(endpoint) (((endpoint & 0x0f) << 1) + \ + ((endpoint & 0x80) ? 1 : 0)) + + +bool USBDevice::requestGetDescriptor(void) +{ + bool success = false; +#ifdef DEBUG + printf("get descr: type: %d\r\n", DESCRIPTOR_TYPE(transfer.setup.wValue)); +#endif + switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) + { + case DEVICE_DESCRIPTOR: + if (deviceDesc() != NULL) + { + if ((deviceDesc()[0] == DEVICE_DESCRIPTOR_LENGTH) \ + && (deviceDesc()[1] == DEVICE_DESCRIPTOR)) + { +#ifdef DEBUG + printf("device descr\r\n"); +#endif + transfer.remaining = DEVICE_DESCRIPTOR_LENGTH; + transfer.ptr = deviceDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + } + } + break; + case CONFIGURATION_DESCRIPTOR: + if (configurationDesc() != NULL) + { + if ((configurationDesc()[0] == CONFIGURATION_DESCRIPTOR_LENGTH) \ + && (configurationDesc()[1] == CONFIGURATION_DESCRIPTOR)) + { +#ifdef DEBUG + printf("conf descr request\r\n"); +#endif + /* Get wTotalLength */ + transfer.remaining = configurationDesc()[2] \ + | (configurationDesc()[3] << 8); + + transfer.ptr = configurationDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + } + } + break; + case STRING_DESCRIPTOR: +#ifdef DEBUG + printf("str descriptor\r\n"); +#endif + switch (DESCRIPTOR_INDEX(transfer.setup.wValue)) + { + case STRING_OFFSET_LANGID: +#ifdef DEBUG + printf("1\r\n"); +#endif + transfer.remaining = stringLangidDesc()[0]; + transfer.ptr = stringLangidDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_OFFSET_IMANUFACTURER: +#ifdef DEBUG + printf("2\r\n"); +#endif + transfer.remaining = stringImanufacturerDesc()[0]; + transfer.ptr = stringImanufacturerDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_OFFSET_IPRODUCT: +#ifdef DEBUG + printf("3\r\n"); +#endif + transfer.remaining = stringIproductDesc()[0]; + transfer.ptr = stringIproductDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_OFFSET_ISERIAL: +#ifdef DEBUG + printf("4\r\n"); +#endif + transfer.remaining = stringIserialDesc()[0]; + transfer.ptr = stringIserialDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_OFFSET_ICONFIGURATION: +#ifdef DEBUG + printf("5\r\n"); +#endif + transfer.remaining = stringIConfigurationDesc()[0]; + transfer.ptr = stringIConfigurationDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_OFFSET_IINTERFACE: +#ifdef DEBUG + printf("6\r\n"); +#endif + transfer.remaining = stringIinterfaceDesc()[0]; + transfer.ptr = stringIinterfaceDesc(); + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + } + break; + case INTERFACE_DESCRIPTOR: +#ifdef DEBUG + printf("interface descr\r\n"); +#endif + case ENDPOINT_DESCRIPTOR: +#ifdef DEBUG + printf("endpoint descr\r\n"); +#endif + /* TODO: Support is optional, not implemented here */ + break; + default: +#ifdef DEBUG + printf("ERROR\r\n"); +#endif + break; + } + + return success; +} + +void USBDevice::decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet) +{ + /* Fill in the elements of a SETUP_PACKET structure from raw data */ + packet->bmRequestType.dataTransferDirection = (data[0] & 0x80) >> 7; + packet->bmRequestType.Type = (data[0] & 0x60) >> 5; + packet->bmRequestType.Recipient = data[0] & 0x1f; + packet->bRequest = data[1]; + packet->wValue = (data[2] | (uint16_t)data[3] << 8); + packet->wIndex = (data[4] | (uint16_t)data[5] << 8); + packet->wLength = (data[6] | (uint16_t)data[7] << 8); +} + + +bool USBDevice::controlOut(void) +{ + /* Control transfer data OUT stage */ + uint8_t buffer[MAX_PACKET_SIZE_EP0]; + uint32_t packetSize; + + /* Check we should be transferring data OUT */ + if (transfer.direction != HOST_TO_DEVICE) + { + return false; + } + + /* Read from endpoint */ + packetSize = EP0getReadResult(buffer); + + /* Check if transfer size is valid */ + if (packetSize > transfer.remaining) + { + /* Too big */ + return false; + } + + /* Update transfer */ + transfer.ptr += packetSize; + transfer.remaining -= packetSize; + + /* Check if transfer has completed */ + if (transfer.remaining == 0) + { + /* Transfer completed */ + if (transfer.notify) + { + /* Notify class layer. */ + USBCallback_requestCompleted(buffer, packetSize); + transfer.notify = false; + } + /* Status stage */ + EP0write(NULL, 0); + } + else + { + EP0read(); + } + + return true; +} + +bool USBDevice::controlIn(void) +{ + /* Control transfer data IN stage */ + uint32_t packetSize; + + /* Check if transfer has completed (status stage transactions */ + /* also have transfer.remaining == 0) */ + if (transfer.remaining == 0) + { + if (transfer.zlp) + { + /* Send zero length packet */ + EP0write(NULL, 0); + transfer.zlp = false; + } + + /* Transfer completed */ + if (transfer.notify) + { + /* Notify class layer. */ + USBCallback_requestCompleted(NULL, 0); + transfer.notify = false; + } + + EP0read(); + + /* Completed */ + return true; + } + + /* Check we should be transferring data IN */ + if (transfer.direction != DEVICE_TO_HOST) + { + return false; + } + + packetSize = transfer.remaining; + + if (packetSize > MAX_PACKET_SIZE_EP0) + { + packetSize = MAX_PACKET_SIZE_EP0; + } + + /* Write to endpoint */ + EP0write(transfer.ptr, packetSize); + + /* Update transfer */ + transfer.ptr += packetSize; + transfer.remaining -= packetSize; + + return true; +} + +bool USBDevice::requestSetAddress(void) +{ + /* Set the device address */ + setAddress(transfer.setup.wValue); + + if (transfer.setup.wValue == 0) + { + device.state = DEFAULT; + } + else + { + device.state = ADDRESS; + } + + return true; +} + +bool USBDevice::requestSetConfiguration(void) +{ + + device.configuration = transfer.setup.wValue; + /* Set the device configuration */ + if (device.configuration == 0) + { + /* Not configured */ + unconfigureDevice(); + device.state = ADDRESS; + } + else + { + if (USBCallback_setConfiguration(device.configuration)) + { + /* Valid configuration */ + configureDevice(); + device.state = CONFIGURED; + } + else + { + return false; + } + } + + return true; +} + +bool USBDevice::requestGetConfiguration(void) +{ + /* Send the device configuration */ + transfer.ptr = &device.configuration; + transfer.remaining = sizeof(device.configuration); + transfer.direction = DEVICE_TO_HOST; + return true; +} + +bool USBDevice::requestGetInterface(void) +{ + /* Return the selected alternate setting for an interface */ + + if (device.state != CONFIGURED) + { + return false; + } + + /* Send the alternate setting */ + transfer.setup.wIndex = currentInterface; + transfer.ptr = ¤tAlternate; + transfer.remaining = sizeof(currentAlternate); + transfer.direction = DEVICE_TO_HOST; + return true; +} + +bool USBDevice::requestSetInterface(void) +{ + bool success = false; + if(USBCallback_setInterface(transfer.setup.wIndex, transfer.setup.wValue)) + { + success = true; + currentInterface = transfer.setup.wIndex; + currentAlternate = transfer.setup.wValue; + } + return success; +} + +bool USBDevice::requestSetFeature() +{ + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + { + return false; + } + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Remote wakeup feature not supported */ + break; + case ENDPOINT_RECIPIENT: + if (transfer.setup.wValue == ENDPOINT_HALT) + { + /* TODO: We should check that the endpoint number is valid */ + stallEndpoint( + WINDEX_TO_PHYSICAL(transfer.setup.wIndex)); + success = true; + } + break; + default: + break; + } + + return success; +} + +bool USBDevice::requestClearFeature() +{ + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + { + return false; + } + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Remote wakeup feature not supported */ + break; + case ENDPOINT_RECIPIENT: + /* TODO: We should check that the endpoint number is valid */ + if (transfer.setup.wValue == ENDPOINT_HALT) + { + unstallEndpoint( WINDEX_TO_PHYSICAL(transfer.setup.wIndex)); + success = true; + } + break; + default: + break; + } + + return success; +} + +bool USBDevice::requestGetStatus(void) +{ + static uint16_t status; + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + { + return false; + } + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Currently only supports self powered devices */ + status = DEVICE_STATUS_SELF_POWERED; + success = true; + break; + case INTERFACE_RECIPIENT: + status = 0; + success = true; + break; + case ENDPOINT_RECIPIENT: + /* TODO: We should check that the endpoint number is valid */ + if (getEndpointStallState( + WINDEX_TO_PHYSICAL(transfer.setup.wIndex))) + { + status = ENDPOINT_STATUS_HALT; + } + else + { + status = 0; + } + success = true; + break; + default: + break; + } + + if (success) + { + /* Send the status */ + transfer.ptr = (uint8_t *)&status; /* Assumes little endian */ + transfer.remaining = sizeof(status); + transfer.direction = DEVICE_TO_HOST; + } + + return success; +} + +bool USBDevice::requestSetup(void) +{ + bool success = false; + + /* Process standard requests */ + if ((transfer.setup.bmRequestType.Type == STANDARD_TYPE)) + { + switch (transfer.setup.bRequest) + { + case GET_STATUS: + success = requestGetStatus(); + break; + case CLEAR_FEATURE: + success = requestClearFeature(); + break; + case SET_FEATURE: + success = requestSetFeature(); + break; + case SET_ADDRESS: + success = requestSetAddress(); + break; + case GET_DESCRIPTOR: + success = requestGetDescriptor(); + break; + case SET_DESCRIPTOR: + /* TODO: Support is optional, not implemented here */ + success = false; + break; + case GET_CONFIGURATION: + success = requestGetConfiguration(); + break; + case SET_CONFIGURATION: + success = requestSetConfiguration(); + break; + case GET_INTERFACE: + success = requestGetInterface(); + break; + case SET_INTERFACE: + success = requestSetInterface(); + break; + default: + break; + } + } + + return success; +} + +bool USBDevice::controlSetup(void) +{ + bool success = false; + + /* Control transfer setup stage */ + uint8_t buffer[MAX_PACKET_SIZE_EP0]; + + EP0setup(buffer); + + /* Initialise control transfer state */ + decodeSetupPacket(buffer, &transfer.setup); + transfer.ptr = NULL; + transfer.remaining = 0; + transfer.direction = 0; + transfer.zlp = false; + transfer.notify = false; + +#ifdef DEBUG + printf("dataTransferDirection: %d\r\nType: %d\r\nRecipient: %d\r\nbRequest: %d\r\nwValue: %d\r\nwIndex: %d\r\nwLength: %d\r\n",transfer.setup.bmRequestType.dataTransferDirection, + transfer.setup.bmRequestType.Type, + transfer.setup.bmRequestType.Recipient, + transfer.setup.bRequest, + transfer.setup.wValue, + transfer.setup.wIndex, + transfer.setup.wLength); +#endif + + /* Class / vendor specific */ + success = USBCallback_request(); + + if (!success) + { + /* Standard requests */ + if (!requestSetup()) + { +#ifdef DEBUG + printf("fail!!!!\r\n"); +#endif + return false; + } + } + + /* Check transfer size and direction */ + if (transfer.setup.wLength>0) + { + if (transfer.setup.bmRequestType.dataTransferDirection \ + == DEVICE_TO_HOST) + { + /* IN data stage is required */ + if (transfer.direction != DEVICE_TO_HOST) + { + return false; + } + + /* Transfer must be less than or equal to the size */ + /* requested by the host */ + if (transfer.remaining > transfer.setup.wLength) + { + transfer.remaining = transfer.setup.wLength; + } + } + else + { + + /* OUT data stage is required */ + if (transfer.direction != HOST_TO_DEVICE) + { + return false; + } + + /* Transfer must be equal to the size requested by the host */ + if (transfer.remaining != transfer.setup.wLength) + { + return false; + } + } + } + else + { + /* No data stage; transfer size must be zero */ + if (transfer.remaining != 0) + { + return false; + } + } + + /* Data or status stage if applicable */ + if (transfer.setup.wLength>0) + { + if (transfer.setup.bmRequestType.dataTransferDirection \ + == DEVICE_TO_HOST) + { + /* Check if we'll need to send a zero length packet at */ + /* the end of this transfer */ + if (transfer.setup.wLength > transfer.remaining) + { + /* Device wishes to transfer less than host requested */ + if ((transfer.remaining % MAX_PACKET_SIZE_EP0) == 0) + { + /* Transfer is a multiple of EP0 max packet size */ + transfer.zlp = true; + } + } + + /* IN stage */ + controlIn(); + } + else + { + /* OUT stage */ + EP0read(); + } + } + else + { + /* Status stage */ + EP0write(NULL, 0); + } + + return true; +} + +void USBDevice::busReset(void) +{ + device.state = DEFAULT; + device.configuration = 0; + device.suspended = false; + + /* Call class / vendor specific busReset function */ + USBCallback_busReset(); +} + +void USBDevice::EP0setupCallback(void) +{ + /* Endpoint 0 setup event */ + if (!controlSetup()) + { + /* Protocol stall */ + EP0stall(); + } + + /* Return true if an OUT data stage is expected */ +} + +void USBDevice::EP0out(void) +{ + /* Endpoint 0 OUT data event */ + if (!controlOut()) + { + /* Protocol stall; this will stall both endpoints */ + EP0stall(); + } +} + +void USBDevice::EP0in(void) +{ +#ifdef DEBUG + printf("EP0IN\r\n"); +#endif + /* Endpoint 0 IN data event */ + if (!controlIn()) + { + /* Protocol stall; this will stall both endpoints */ + EP0stall(); + } +} + +bool USBDevice::configured(void) +{ + /* Returns true if device is in the CONFIGURED state */ + return (device.state == CONFIGURED); +} + +void USBDevice::connect(void) +{ + /* Connect device */ + USBHAL::connect(); + /* Block if not configured */ + while (!configured()); +} + +void USBDevice::disconnect(void) +{ + /* Disconnect device */ + USBHAL::disconnect(); +} + +CONTROL_TRANSFER * USBDevice::getTransferPtr(void) +{ + return &transfer; +} + +bool USBDevice::addEndpoint(uint8_t endpoint, uint32_t maxPacket) +{ + return realiseEndpoint(endpoint, maxPacket, 0); +} + +bool USBDevice::addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket) +{ + /* For interrupt endpoints only */ + return realiseEndpoint(endpoint, maxPacket, RATE_FEEDBACK_MODE); +} + +uint8_t * USBDevice::findDescriptor(uint8_t descriptorType) +{ + /* Find a descriptor within the list of descriptors */ + /* following a configuration descriptor. */ + uint16_t wTotalLength; + uint8_t *ptr; + + if (configurationDesc() == NULL) + { + return NULL; + } + + /* Check this is a configuration descriptor */ + if ((configurationDesc()[0] != CONFIGURATION_DESCRIPTOR_LENGTH) \ + || (configurationDesc()[1] != CONFIGURATION_DESCRIPTOR)) + { + return NULL; + } + + wTotalLength = configurationDesc()[2] | (configurationDesc()[3] << 8); + + /* Check there are some more descriptors to follow */ + if (wTotalLength <= (CONFIGURATION_DESCRIPTOR_LENGTH+2)) + /* +2 is for bLength and bDescriptorType of next descriptor */ + { + return false; + } + + /* Start at first descriptor after the configuration descriptor */ + ptr = &(configurationDesc()[CONFIGURATION_DESCRIPTOR_LENGTH]); + + do { + if (ptr[1] /* bDescriptorType */ == descriptorType) + { + /* Found */ + return ptr; + } + + /* Skip to next descriptor */ + ptr += ptr[0]; /* bLength */ + } while (ptr < (configurationDesc() + wTotalLength)); + + /* Reached end of the descriptors - not found */ + return NULL; +} + + +void USBDevice::connectStateChanged(unsigned int connected) +{ +} + +void USBDevice::suspendStateChanged(unsigned int suspended) +{ +} + + +USBDevice::USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release){ + VENDOR_ID = vendor_id; + PRODUCT_ID = product_id; + PRODUCT_RELEASE = product_release; + + /* Set initial device state */ + device.state = POWERED; + device.configuration = 0; + device.suspended = false; +}; + + +bool USBDevice::readStart(uint8_t endpoint, uint32_t maxSize) +{ + return endpointRead(endpoint, maxSize) == EP_PENDING; +} + + +bool USBDevice::write(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize) +{ + EP_STATUS result; + + if (size > maxSize) + { + return false; + } + + + if(!configured()) { + return false; + } + + /* Send report */ + result = endpointWrite(endpoint, buffer, size); + + if (result != EP_PENDING) + { + return false; + } + + /* Wait for completion */ + do { + result = endpointWriteResult(endpoint); + } while ((result == EP_PENDING) && configured()); + + return (result == EP_COMPLETED); +} + + +bool USBDevice::writeNB(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize) +{ + EP_STATUS result; + + if (size > maxSize) + { + return false; + } + + if(!configured()) { + return false; + } + + /* Send report */ + result = endpointWrite(endpoint, buffer, size); + + if (result != EP_PENDING) + { + return false; + } + + result = endpointWriteResult(endpoint); + + return (result == EP_COMPLETED); +} + + + +bool USBDevice::readEP(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize) +{ + EP_STATUS result; + + if(!configured()) { + return false; + } + + /* Wait for completion */ + do { + result = endpointReadResult(endpoint, buffer, size); + } while ((result == EP_PENDING) && configured()); + + return (result == EP_COMPLETED); +} + + +bool USBDevice::readEP_NB(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize) +{ + EP_STATUS result; + + if(!configured()) { + return false; + } + + result = endpointReadResult(endpoint, buffer, size); + + return (result == EP_COMPLETED); +} + + + +uint8_t * USBDevice::deviceDesc() { + static uint8_t deviceDescriptor[] = { + DEVICE_DESCRIPTOR_LENGTH, /* bLength */ + DEVICE_DESCRIPTOR, /* bDescriptorType */ + LSB(USB_VERSION_2_0), /* bcdUSB (LSB) */ + MSB(USB_VERSION_2_0), /* bcdUSB (MSB) */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceprotocol */ + MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */ + LSB(VENDOR_ID), /* idVendor (LSB) */ + MSB(VENDOR_ID), /* idVendor (MSB) */ + LSB(PRODUCT_ID), /* idProduct (LSB) */ + MSB(PRODUCT_ID), /* idProduct (MSB) */ + LSB(PRODUCT_RELEASE), /* bcdDevice (LSB) */ + MSB(PRODUCT_RELEASE), /* bcdDevice (MSB) */ + STRING_OFFSET_IMANUFACTURER, /* iManufacturer */ + STRING_OFFSET_IPRODUCT, /* iProduct */ + STRING_OFFSET_ISERIAL, /* iSerialNumber */ + 0x01 /* bNumConfigurations */ + }; + return deviceDescriptor; +} + +uint8_t * USBDevice::stringLangidDesc() { + static uint8_t stringLangidDescriptor[] = { + 0x04, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + 0x09,0x00, /*bString Lang ID - 0x009 - English*/ + }; + return stringLangidDescriptor; +} + +uint8_t * USBDevice::stringImanufacturerDesc() { + static uint8_t stringImanufacturerDescriptor[] = { + 0x12, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + 'm',0,'b',0,'e',0,'d',0,'.',0,'o',0,'r',0,'g',0, /*bString iManufacturer - mbed.org*/ + }; + return stringImanufacturerDescriptor; +} + +uint8_t * USBDevice::stringIserialDesc() { + static uint8_t stringIserialDescriptor[] = { + 0x16, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + '0',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0, /*bString iSerial - 0123456789*/ + }; + return stringIserialDescriptor; +} + +uint8_t * USBDevice::stringIConfigurationDesc() { + static uint8_t stringIconfigurationDescriptor[] = { + 0x06, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + '0',0,'1',0, /*bString iConfiguration - 01*/ + }; + return stringIconfigurationDescriptor; +} + +uint8_t * USBDevice::stringIinterfaceDesc() { + static uint8_t stringIinterfaceDescriptor[] = { + 0x08, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + 'U',0,'S',0,'B',0, /*bString iInterface - USB*/ + }; + return stringIinterfaceDescriptor; +} + +uint8_t * USBDevice::stringIproductDesc() { + static uint8_t stringIproductDescriptor[] = { + 0x16, /*bLength*/ + STRING_DESCRIPTOR, /*bDescriptorType 0x03*/ + 'U',0,'S',0,'B',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 /*bString iProduct - USB DEVICE*/ + }; + return stringIproductDescriptor; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBDevice.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,269 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifndef USBDEVICE_H +#define USBDEVICE_H + +#include "mbed.h" +#include "USBDevice_Types.h" +#include "USBHAL.h" + +class USBDevice: public USBHAL +{ +public: + USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release); + + /* + * Check if the device is configured + * + * @returns true if configured, false otherwise + */ + bool configured(void); + + /* + * Connect a device + */ + void connect(void); + + /* + * Disconnect a device + */ + void disconnect(void); + + /* + * Add an endpoint + * + * @param endpoint endpoint which will be added + * @param maxPacket Maximum size of a packet which can be sent for this endpoint + * @returns true if successful, false otherwise + */ + bool addEndpoint(uint8_t endpoint, uint32_t maxPacket); + + /* + * Start a reading on a certain endpoint. + * You can access the result of the reading by USBDevice_read + * + * @param endpoint endpoint which will be read + * @param maxSize the maximum length that can be read + * @return true if successful + */ + bool readStart(uint8_t endpoint, uint32_t maxSize); + + /* + * Read a certain endpoint. Before calling this function, USBUSBDevice_readStart + * must be called. + * + * Warning: blocking + * + * @param endpoint endpoint which will be read + * @param buffer buffer will be filled with the data received + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize); + + /* + * Read a certain endpoint. + * + * Warning: non blocking + * + * @param endpoint endpoint which will be read + * @param buffer buffer will be filled with the data received (if data are available) + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP_NB(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize); + + /* + * Write a certain endpoint. + * + * Warning: blocking + * + * @param endpoint endpoint to write + * @param buffer data contained in buffer will be write + * @param size the number of bytes to write + * @param maxSize the maximum length that can be written on this endpoint + */ + bool write(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize); + + + /* + * Write a certain endpoint. + * + * Warning: non blocking + * + * @param endpoint endpoint to write + * @param buffer data contained in buffer will be write + * @param size the number of bytes to write + * @param maxSize the maximum length that can be written on this endpoint + */ + bool writeNB(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize); + + + /* + * Called by USBDevice layer on bus reset. Warning: Called in ISR context + * + * May be used to reset state + */ + virtual void USBCallback_busReset(void) {}; + + /* + * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context + * This is used to handle extensions to standard requests + * and class specific requests + * + * @returns true if class handles this request + */ + virtual bool USBCallback_request() { return false; }; + + /* + * Called by USBDevice on Endpoint0 request completion + * if the 'notify' flag has been set to true. Warning: Called in ISR context + * + * In this case it is used to indicate that a HID report has + * been received from the host on endpoint 0 + * + * @param buf buffer received on endpoint 0 + * @param length length of this buffer + */ + virtual void USBCallback_requestCompleted(uint8_t * buf, uint32_t length) {}; + + /* + * Called by USBDevice layer. Set configuration of the device. + * For instance, you can add all endpoints that you need on this function. + * + * @param configuration Number of the configuration + */ + virtual bool USBCallback_setConfiguration(uint8_t configuration) { return false; }; + + /* + * Called by USBDevice layer. Set interface/alternate of the device. + * + * @param interface Number of the interface to be configured + * @param alternate Number of the alternate to be configured + * @returns true if class handles this request + */ + virtual bool USBCallback_setInterface(uint16_t interface, uint8_t alternate) { return false; }; + + /* + * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength. + * + * @returns pointer to the device descriptor + */ + virtual uint8_t * deviceDesc(); + + /* + * Get configuration descriptor + * + * @returns pointer to the configuration descriptor + */ + virtual uint8_t * configurationDesc(){return NULL;}; + + /* + * Get string lang id descriptor + * + * @return pointer to the string lang id descriptor + */ + virtual uint8_t * stringLangidDesc(); + + /* + * Get string manufacturer descriptor + * + * @returns pointer to the string manufacturer descriptor + */ + virtual uint8_t * stringImanufacturerDesc(); + + /* + * Get string product descriptor + * + * @returns pointer to the string product descriptor + */ + virtual uint8_t * stringIproductDesc(); + + /* + * Get string serial descriptor + * + * @returns pointer to the string serial descriptor + */ + virtual uint8_t * stringIserialDesc(); + + /* + * Get string configuration descriptor + * + * @returns pointer to the string configuration descriptor + */ + virtual uint8_t * stringIConfigurationDesc(); + + /* + * Get string interface descriptor + * + * @returns pointer to the string interface descriptor + */ + virtual uint8_t * stringIinterfaceDesc(); + + /* + * Get the length of the report descriptor + * + * @returns length of the report descriptor + */ + virtual uint16_t reportDescLength() { return 0; }; + + + +protected: + virtual void busReset(void); + virtual void EP0setupCallback(void); + virtual void EP0out(void); + virtual void EP0in(void); + virtual void connectStateChanged(unsigned int connected); + virtual void suspendStateChanged(unsigned int suspended); + uint8_t * findDescriptor(uint8_t descriptorType); + CONTROL_TRANSFER * getTransferPtr(void); + + uint16_t VENDOR_ID; + uint16_t PRODUCT_ID; + uint16_t PRODUCT_RELEASE; + +private: + bool addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket); + bool requestGetDescriptor(void); + bool controlOut(void); + bool controlIn(void); + bool requestSetAddress(void); + bool requestSetConfiguration(void); + bool requestSetFeature(void); + bool requestClearFeature(void); + bool requestGetStatus(void); + bool requestSetup(void); + bool controlSetup(void); + void decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet); + bool requestGetConfiguration(void); + bool requestGetInterface(void); + bool requestSetInterface(void); + + CONTROL_TRANSFER transfer; + USB_DEVICE device; + + uint16_t currentInterface; + uint8_t currentAlternate; +}; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBDevice_Types.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,83 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifndef USBDEVICE_TYPES_H +#define USBDEVICE_TYPES_H + +/* Standard requests */ +#define GET_STATUS (0) +#define CLEAR_FEATURE (1) +#define SET_FEATURE (3) +#define SET_ADDRESS (5) +#define GET_DESCRIPTOR (6) +#define SET_DESCRIPTOR (7) +#define GET_CONFIGURATION (8) +#define SET_CONFIGURATION (9) +#define GET_INTERFACE (10) +#define SET_INTERFACE (11) + +/* bmRequestType.dataTransferDirection */ +#define HOST_TO_DEVICE (0) +#define DEVICE_TO_HOST (1) + +/* bmRequestType.Type*/ +#define STANDARD_TYPE (0) +#define CLASS_TYPE (1) +#define VENDOR_TYPE (2) +#define RESERVED_TYPE (3) + +/* bmRequestType.Recipient */ +#define DEVICE_RECIPIENT (0) +#define INTERFACE_RECIPIENT (1) +#define ENDPOINT_RECIPIENT (2) +#define OTHER_RECIPIENT (3) + +/* Descriptors */ +#define DESCRIPTOR_TYPE(wValue) (wValue >> 8) +#define DESCRIPTOR_INDEX(wValue) (wValue & 0xf) + +typedef struct { + struct { + uint8_t dataTransferDirection; + uint8_t Type; + uint8_t Recipient; + } bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} SETUP_PACKET; + +typedef struct { + SETUP_PACKET setup; + uint8_t *ptr; + uint32_t remaining; + uint8_t direction; + bool zlp; + bool notify; +} CONTROL_TRANSFER; + +typedef enum {ATTACHED, POWERED, DEFAULT, ADDRESS, CONFIGURED} DEVICE_STATE; + +typedef struct { + volatile DEVICE_STATE state; + uint8_t configuration; + bool suspended; +} USB_DEVICE; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBEndpoints.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,48 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifndef USBENDPOINTS_H +#define USBENDPOINTS_H + +/* SETUP packet size */ +#define SETUP_PACKET_SIZE (8) + +/* Options flags for configuring endpoints */ +#define DEFAULT_OPTIONS (0) +#define SINGLE_BUFFERED (1U << 0) +#define ISOCHRONOUS (1U << 1) +#define RATE_FEEDBACK_MODE (1U << 2) /* Interrupt endpoints only */ + +/* Endpoint transfer status, for endpoints > 0 */ +typedef enum { + EP_COMPLETED, /* Transfer completed */ + EP_PENDING, /* Transfer in progress */ + EP_INVALID, /* Invalid parameter */ + EP_STALLED, /* Endpoint stalled */ +} EP_STATUS; + +/* Include configuration for specific target */ +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) +#include "USBEndpoints_LPC17_LPC23.h" +#elif defined(TARGET_LPC11U24) +#include "USBEndpoints_LPC11U.h" +#else +#error "Unknown target type" +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBEndpoints_LPC11U.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,65 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#define NUMBER_OF_LOGICAL_ENDPOINTS (5) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) + +/* Define physical endpoint numbers */ + +/* Endpoint No. Type(s) MaxPacket DoubleBuffer */ +/* ---------------- ------------ ---------- --- */ +#define EP0OUT (0) /* Control 64 No */ +#define EP0IN (1) /* Control 64 No */ +#define EP1OUT (2) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP1IN (3) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP2OUT (4) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP2IN (5) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP3OUT (6) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP3IN (7) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP4OUT (8) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP4IN (9) /* Int/Bulk/Iso 64/64/1023 Yes */ + +/* Maximum Packet sizes */ + +#define MAX_PACKET_SIZE_EP0 (64) +#define MAX_PACKET_SIZE_EP1 (64) /* Int/Bulk */ +#define MAX_PACKET_SIZE_EP2 (64) /* Int/Bulk */ +#define MAX_PACKET_SIZE_EP3 (64) /* Int/Bulk */ +#define MAX_PACKET_SIZE_EP4 (64) /* Int/Bulk */ + +#define MAX_PACKET_SIZE_EP1_ISO (1023) /* Isochronous */ +#define MAX_PACKET_SIZE_EP2_ISO (1023) /* Isochronous */ +#define MAX_PACKET_SIZE_EP3_ISO (1023) /* Isochronous */ +#define MAX_PACKET_SIZE_EP4_ISO (1023) /* Isochronous */ + +/* Generic endpoints - intended to be portable accross devices */ +/* and be suitable for simple USB devices. */ + +/* Bulk endpoint */ +#define EPBULK_OUT (EP2OUT) +#define EPBULK_IN (EP2IN) +/* Interrupt endpoint */ +#define EPINT_OUT (EP1OUT) +#define EPINT_IN (EP1IN) +/* Isochronous endpoint */ +#define EPISO_OUT (EP3OUT) +#define EPISO_IN (EP3IN) + +#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) +#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) +#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3_ISO)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBEndpoints_LPC17_LPC23.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,93 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#define NUMBER_OF_LOGICAL_ENDPOINTS (16) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) + +/* Define physical endpoint numbers */ + +/* Endpoint No. Type(s) MaxPacket DoubleBuffer */ +/* ---------------- ------------ ---------- --- */ +#define EP0OUT (0) /* Control 64 No */ +#define EP0IN (1) /* Control 64 No */ +#define EP1OUT (2) /* Interrupt 64 No */ +#define EP1IN (3) /* Interrupt 64 No */ +#define EP2OUT (4) /* Bulk 64 Yes */ +#define EP2IN (5) /* Bulk 64 Yes */ +#define EP3OUT (6) /* Isochronous 1023 Yes */ +#define EP3IN (7) /* Isochronous 1023 Yes */ +#define EP4OUT (8) /* Interrupt 64 No */ +#define EP4IN (9) /* Interrupt 64 No */ +#define EP5OUT (10) /* Bulk 64 Yes */ +#define EP5IN (11) /* Bulk 64 Yes */ +#define EP6OUT (12) /* Isochronous 1023 Yes */ +#define EP6IN (13) /* Isochronous 1023 Yes */ +#define EP7OUT (14) /* Interrupt 64 No */ +#define EP7IN (15) /* Interrupt 64 No */ +#define EP8OUT (16) /* Bulk 64 Yes */ +#define EP8IN (17) /* Bulk 64 Yes */ +#define EP9OUT (18) /* Isochronous 1023 Yes */ +#define EP9IN (19) /* Isochronous 1023 Yes */ +#define EP10OUT (20) /* Interrupt 64 No */ +#define EP10IN (21) /* Interrupt 64 No */ +#define EP11OUT (22) /* Bulk 64 Yes */ +#define EP11IN (23) /* Bulk 64 Yes */ +#define EP12OUT (24) /* Isochronous 1023 Yes */ +#define EP12IN (25) /* Isochronous 1023 Yes */ +#define EP13OUT (26) /* Interrupt 64 No */ +#define EP13IN (27) /* Interrupt 64 No */ +#define EP14OUT (28) /* Bulk 64 Yes */ +#define EP14IN (29) /* Bulk 64 Yes */ +#define EP15OUT (30) /* Bulk 64 Yes */ +#define EP15IN (31) /* Bulk 64 Yes */ + +/* Maximum Packet sizes */ + +#define MAX_PACKET_SIZE_EP0 (64) +#define MAX_PACKET_SIZE_EP1 (64) +#define MAX_PACKET_SIZE_EP2 (64) +#define MAX_PACKET_SIZE_EP3 (1023) +#define MAX_PACKET_SIZE_EP4 (64) +#define MAX_PACKET_SIZE_EP5 (64) +#define MAX_PACKET_SIZE_EP6 (1023) +#define MAX_PACKET_SIZE_EP7 (64) +#define MAX_PACKET_SIZE_EP8 (64) +#define MAX_PACKET_SIZE_EP9 (1023) +#define MAX_PACKET_SIZE_EP10 (64) +#define MAX_PACKET_SIZE_EP11 (64) +#define MAX_PACKET_SIZE_EP12 (1023) +#define MAX_PACKET_SIZE_EP13 (64) +#define MAX_PACKET_SIZE_EP14 (64) +#define MAX_PACKET_SIZE_EP15 (64) + +/* Generic endpoints - intended to be portable accross devices */ +/* and be suitable for simple USB devices. */ + +/* Bulk endpoints */ +#define EPBULK_OUT (EP2OUT) +#define EPBULK_IN (EP2IN) +/* Interrupt endpoints */ +#define EPINT_OUT (EP1OUT) +#define EPINT_IN (EP1IN) +/* Isochronous endpoints */ +#define EPISO_OUT (EP3OUT) +#define EPISO_IN (EP3IN) + +#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) +#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) +#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBHAL.h Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,77 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifndef USBBUSINTERFACE_H +#define USBBUSINTERFACE_H + +#include "mbed.h" +#include "USBEndpoints.h" + +class USBHAL { +public: + /* Configuration */ + USBHAL(); + ~USBHAL(); + void connect(void); + void disconnect(void); + void configureDevice(void); + void unconfigureDevice(void); + void setAddress(uint8_t address); + void remoteWakeup(void); + + /* Endpoint 0 */ + void EP0setup(uint8_t *buffer); + void EP0read(void); + uint32_t EP0getReadResult(uint8_t *buffer); + void EP0write(uint8_t *buffer, uint32_t size); + void EP0getWriteResult(void); + void EP0stall(void); + + /* Other endpoints */ + EP_STATUS endpointRead(uint8_t endpoint, uint32_t maximumSize); + EP_STATUS endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead); + EP_STATUS endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size); + EP_STATUS endpointWriteResult(uint8_t endpoint); + void stallEndpoint(uint8_t endpoint); + void unstallEndpoint(uint8_t endpoint); + bool realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options); + bool getEndpointStallState(unsigned char endpoint); + uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer); + +protected: + virtual void busReset(void){}; + virtual void EP0setupCallback(void){}; + virtual void EP0out(void){}; + virtual void EP0in(void){}; + virtual void connectStateChanged(unsigned int connected){}; + virtual void suspendStateChanged(unsigned int suspended){}; + virtual void SOF(int frameNumber){}; + virtual bool EP1_OUT_callback(){return false;}; + virtual bool EP1_IN_callback(){return false;}; + virtual bool EP2_OUT_callback(){return false;}; + virtual bool EP2_IN_callback(){return false;}; + virtual bool EP3_OUT_callback(){return false;}; + virtual bool EP3_IN_callback(){return false;}; + +private: + void usbisr(void); + static void _usbisr(void); + static USBHAL * instance; +}; +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBHAL_LPC11U.cpp Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,712 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifdef TARGET_LPC11U24 + +#include "USBHAL.h" + +USBHAL * USBHAL::instance; + + +// Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1) +#define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1) + +// Convert physical endpoint number to register bit +#define EP(endpoint) (1UL<<endpoint) + +// Convert physical to logical +#define PHY_TO_LOG(endpoint) ((endpoint)>>1) + +// Get endpoint direction +#define IN_EP(endpoint) ((endpoint) & 1U ? true : false) +#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true) + +// USB RAM +#define USB_RAM_START (0x20004000) +#define USB_RAM_SIZE (0x00000800) + +// SYSAHBCLKCTRL +#define CLK_USB (1UL<<14) +#define CLK_USBRAM (1UL<<27) + +// USB Information register +#define FRAME_NR(a) ((a) & 0x7ff) // Frame number + +// USB Device Command/Status register +#define DEV_ADDR_MASK (0x7f) // Device address +#define DEV_ADDR(a) ((a) & DEV_ADDR_MASK) +#define DEV_EN (1UL<<7) // Device enable +#define SETUP (1UL<<8) // SETUP token received +#define PLL_ON (1UL<<9) // PLL enabled in suspend +#define DCON (1UL<<16) // Device status - connect +#define DSUS (1UL<<17) // Device status - suspend +#define DCON_C (1UL<<24) // Connect change +#define DSUS_C (1UL<<25) // Suspend change +#define DRES_C (1UL<<26) // Reset change +#define VBUSDEBOUNCED (1UL<<28) // Vbus detected + +// Endpoint Command/Status list +#define CMDSTS_A (1UL<<31) // Active +#define CMDSTS_D (1UL<<30) // Disable +#define CMDSTS_S (1UL<<29) // Stall +#define CMDSTS_TR (1UL<<28) // Toggle Reset +#define CMDSTS_RF (1UL<<27) // Rate Feedback mode +#define CMDSTS_TV (1UL<<27) // Toggle Value +#define CMDSTS_T (1UL<<26) // Endpoint Type +#define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes +#define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address + +#define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer + +// USB Non-endpoint interrupt sources +#define FRAME_INT (1UL<<30) +#define DEV_INT (1UL<<31) + +static volatile int epComplete = 0; + +// One entry for a double-buffered logical endpoint in the endpoint +// command/status list. Endpoint 0 is single buffered, out[1] is used +// for the SETUP packet and in[1] is not used +typedef __packed struct { + uint32_t out[2]; + uint32_t in[2]; +} EP_COMMAND_STATUS; + +typedef __packed struct { + uint8_t out[MAX_PACKET_SIZE_EP0]; + uint8_t in[MAX_PACKET_SIZE_EP0]; + uint8_t setup[SETUP_PACKET_SIZE]; +} CONTROL_TRANSFER; + +typedef __packed struct { + uint32_t maxPacket; + uint32_t buffer[2]; + uint32_t options; +} EP_STATE; + +static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS]; + +// Pointer to the endpoint command/status list +static EP_COMMAND_STATUS *ep = NULL; + +// Pointer to endpoint 0 data (IN/OUT and SETUP) +static CONTROL_TRANSFER *ct = NULL; + +// Shadow DEVCMDSTAT register to avoid accidentally clearing flags or +// initiating a remote wakeup event. +static volatile uint32_t devCmdStat; + +// Pointers used to allocate USB RAM +static uint32_t usbRamPtr = USB_RAM_START; +static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here + +#define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m)) + +void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size); +void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) { + if (size > 0) { + do { + *dst++ = *src++; + } while (--size > 0); + } +} + + +USBHAL::USBHAL(void) { + NVIC_DisableIRQ(USB_IRQn); + + // nUSB_CONNECT output + LPC_IOCON->PIO0_6 = 0x00000001; + + // Enable clocks (USB registers, USB RAM) + LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM; + + // Ensure device disconnected (DCON not set) + LPC_USB->DEVCMDSTAT = 0; + + // to ensure that the USB host sees the device as + // disconnected if the target CPU is reset. + wait(0.3); + + // Reserve space in USB RAM for endpoint command/status list + // Must be 256 byte aligned + usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256); + ep = (EP_COMMAND_STATUS *)usbRamPtr; + usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS); + LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00; + + // Reserve space in USB RAM for Endpoint 0 + // Must be 64 byte aligned + usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64); + ct = (CONTROL_TRANSFER *)usbRamPtr; + usbRamPtr += sizeof(CONTROL_TRANSFER); + LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000; + + // Setup command/status list for EP0 + ep[0].out[0] = 0; + ep[0].in[0] = 0; + ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup); + + // Route all interrupts to IRQ, some can be routed to + // USB_FIQ if you wish. + LPC_USB->INTROUTING = 0; + + // Set device address 0, enable USB device, no remote wakeup + devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS; + LPC_USB->DEVCMDSTAT = devCmdStat; + + // Enable interrupts for device events and EP0 + LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT; + instance = this; + + //attach IRQ handler and enable interrupts + NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); + NVIC_EnableIRQ(USB_IRQn); +} + +USBHAL::~USBHAL(void) { + // Ensure device disconnected (DCON not set) + LPC_USB->DEVCMDSTAT = 0; + + // Disable USB interrupts + NVIC_DisableIRQ(USB_IRQn); +} + +void USBHAL::connect(void) { + devCmdStat |= DCON; + LPC_USB->DEVCMDSTAT = devCmdStat; +} + +void USBHAL::disconnect(void) { + devCmdStat &= ~DCON; + LPC_USB->DEVCMDSTAT = devCmdStat; +} + +void USBHAL::configureDevice(void) { +} + +void USBHAL::unconfigureDevice(void) { +} + +void USBHAL::EP0setup(uint8_t *buffer) { + // Copy setup packet data + USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE); +} + +void USBHAL::EP0read(void) { + // Start an endpoint 0 read + + // The USB ISR will call USBDevice_EP0out() when a packet has been read, + // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to + // read the data. + + ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \ + | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out); +} + +uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) { + // Complete an endpoint 0 read + uint32_t bytesRead; + + // Find how many bytes were read + bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]); + + // Copy data + USBMemCopy(buffer, ct->out, bytesRead); + return bytesRead; +} + +void USBHAL::EP0write(uint8_t *buffer, uint32_t size) { + // Start and endpoint 0 write + + // The USB ISR will call USBDevice_EP0in() when the data has + // been written, the USBDevice layer then calls + // USBBusInterface_EP0getWriteResult() to complete the transaction. + + // Copy data + USBMemCopy(ct->in, buffer, size); + + // Start transfer + ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \ + | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in); +} + + +EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) { + uint8_t bf = 0; + uint32_t flags = 0; + + //check which buffer must be filled + if (LPC_USB->EPBUFCFG & EP(endpoint)) { + // Double buffered + if (LPC_USB->EPINUSE & EP(endpoint)) { + bf = 1; + } else { + bf = 0; + } + } + + // if isochronous endpoint, T = 1 + if(endpointState[endpoint].options & ISOCHRONOUS) + { + flags |= CMDSTS_T; + } + + //Active the endpoint for reading + ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \ + | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags; + return EP_PENDING; +} + +EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) { + + uint8_t bf = 0; + + if (!(epComplete & EP(endpoint))) + return EP_PENDING; + else { + epComplete &= ~EP(endpoint); + + //check which buffer has been filled + if (LPC_USB->EPBUFCFG & EP(endpoint)) { + // Double buffered (here we read the previous buffer which was used) + if (LPC_USB->EPINUSE & EP(endpoint)) { + bf = 0; + } else { + bf = 1; + } + } + + // Find how many bytes were read + *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf])); + + // Copy data + USBMemCopy(data, ct->out, *bytesRead); + return EP_COMPLETED; + } +} + +void USBHAL::EP0getWriteResult(void) { + // Complete an endpoint 0 write + + // Nothing required for this target + return; +} + +void USBHAL::EP0stall(void) { + ep[0].in[0] = CMDSTS_S; + ep[0].out[0] = CMDSTS_S; +} + +void USBHAL::setAddress(uint8_t address) { + devCmdStat &= ~DEV_ADDR_MASK; + devCmdStat |= DEV_ADDR(address); + LPC_USB->DEVCMDSTAT = devCmdStat; +} + +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { + uint32_t flags = 0; + uint32_t bf; + + // Validate parameters + if (data == NULL) { + return EP_INVALID; + } + + if (endpoint > LAST_PHYSICAL_ENDPOINT) { + return EP_INVALID; + } + + if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { + return EP_INVALID; + } + + if (size > endpointState[endpoint].maxPacket) { + return EP_INVALID; + } + + if (LPC_USB->EPBUFCFG & EP(endpoint)) { + // Double buffered + if (LPC_USB->EPINUSE & EP(endpoint)) { + bf = 1; + } else { + bf = 0; + } + } else { + // Single buffered + bf = 0; + } + + // Check if already active + if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { + return EP_INVALID; + } + + // Check if stalled + if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { + return EP_STALLED; + } + + // Copy data to USB RAM + USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size); + + // Add options + if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) { + flags |= CMDSTS_RF; + } + + if (endpointState[endpoint].options & ISOCHRONOUS) { + flags |= CMDSTS_T; + } + + // Add transfer + ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \ + endpointState[endpoint].buffer[bf]) \ + | CMDSTS_NBYTES(size) | CMDSTS_A | flags; + + return EP_PENDING; +} + +EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) { + uint32_t bf; + // Validate parameters + + if (endpoint > LAST_PHYSICAL_ENDPOINT) { + return EP_INVALID; + } + + if (OUT_EP(endpoint)) { + return EP_INVALID; + } + + if (LPC_USB->EPBUFCFG & EP(endpoint)) { + // Double buffered // TODO: FIX THIS + if (LPC_USB->EPINUSE & EP(endpoint)) { + bf = 1; + } else { + bf = 0; + } + } else { + // Single buffered + bf = 0; + } + + // Check if endpoint still active + if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { + return EP_PENDING; + } + + // Check if stalled + if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { + return EP_STALLED; + } + + return EP_COMPLETED; +} + +void USBHAL::stallEndpoint(uint8_t endpoint) { + + // TODO: should this clear active bit? + + if (IN_EP(endpoint)) { + ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S; + ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S; + } else { + ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S; + ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S; + } +} + +void USBHAL::unstallEndpoint(uint8_t endpoint) { + if (LPC_USB->EPBUFCFG & EP(endpoint)) { + // Double buffered + if (IN_EP(endpoint)) { + ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0 + ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0 + + if (LPC_USB->EPINUSE & EP(endpoint)) { + ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0 + } else { + ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0 + } + } else { + ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0 + ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0 + + if (LPC_USB->EPINUSE & EP(endpoint)) { + ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0 + } else { + ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0 + } + } + } else { + // Single buffered + if (IN_EP(endpoint)) { + ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0 + } else { + ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0 + } + } +} + +bool USBHAL::getEndpointStallState(unsigned char endpoint) { + if (IN_EP(endpoint)) { + if (LPC_USB->EPINUSE & EP(endpoint)) { + if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) { + return true; + } + } else { + if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) { + return true; + } + } + } else { + if (LPC_USB->EPINUSE & EP(endpoint)) { + if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) { + return true; + } + } else { + if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) { + return true; + } + } + } + + return false; +} + +bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) { + uint32_t tmpEpRamPtr; + + if (endpoint > LAST_PHYSICAL_ENDPOINT) { + return false; + } + + // Not applicable to the control endpoints + if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { + return false; + } + + // Allocate buffers in USB RAM + tmpEpRamPtr = epRamPtr; + + // Must be 64 byte aligned + tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); + + if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { + // Out of memory + return false; + } + + // Allocate first buffer + endpointState[endpoint].buffer[0] = tmpEpRamPtr; + tmpEpRamPtr += maxPacket; + + if (!(options & SINGLE_BUFFERED)) { + // Must be 64 byte aligned + tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); + + if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { + // Out of memory + return false; + } + + // Allocate second buffer + endpointState[endpoint].buffer[1] = tmpEpRamPtr; + tmpEpRamPtr += maxPacket; + } + + // Commit to this USB RAM allocation + epRamPtr = tmpEpRamPtr; + + // Remaining endpoint state values + endpointState[endpoint].maxPacket = maxPacket; + endpointState[endpoint].options = options; + + // Enable double buffering if required + if (options & SINGLE_BUFFERED) { + LPC_USB->EPBUFCFG &= ~EP(endpoint); + } else { + // Double buffered + LPC_USB->EPBUFCFG |= EP(endpoint); + } + + // Enable interrupt + LPC_USB->INTEN |= EP(endpoint); + + // Enable endpoint + unstallEndpoint(endpoint); + return true; +} + +void USBHAL::remoteWakeup(void) { + // Clearing DSUS bit initiates a remote wakeup if the + // device is currently enabled and suspended - otherwise + // it has no effect. + LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS; +} + + +static void disableEndpoints(void) { + uint32_t logEp; + + // Ref. Table 158 "When a bus reset is received, software + // must set the disable bit of all endpoints to 1". + + for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) { + ep[logEp].out[0] = CMDSTS_D; + ep[logEp].out[1] = CMDSTS_D; + ep[logEp].in[0] = CMDSTS_D; + ep[logEp].in[1] = CMDSTS_D; + } + + // Start of USB RAM for endpoints > 0 + epRamPtr = usbRamPtr; +} + + + +void USBHAL::_usbisr(void) { + instance->usbisr(); +} + +void USBHAL::usbisr(void) { + // Start of frame + if (LPC_USB->INTSTAT & FRAME_INT) { + // Clear SOF interrupt + LPC_USB->INTSTAT = FRAME_INT; + + // SOF event, read frame number + SOF(FRAME_NR(LPC_USB->INFO)); + } + + // Device state + if (LPC_USB->INTSTAT & DEV_INT) { + LPC_USB->INTSTAT = DEV_INT; + + if (LPC_USB->DEVCMDSTAT & DSUS_C) { + // Suspend status changed + LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C; + if((LPC_USB->DEVCMDSTAT & DSUS) != 0) { + suspendStateChanged(1); + } + } + + if (LPC_USB->DEVCMDSTAT & DRES_C) { + // Bus reset + LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C; + + suspendStateChanged(0); + + // Disable endpoints > 0 + disableEndpoints(); + + // Bus reset event + busReset(); + } + } + + // Endpoint 0 + if (LPC_USB->INTSTAT & EP(EP0OUT)) { + // Clear EP0OUT/SETUP interrupt + LPC_USB->INTSTAT = EP(EP0OUT); + + // Check if SETUP + if (LPC_USB->DEVCMDSTAT & SETUP) { + // Clear Active and Stall bits for EP0 + // Documentation does not make it clear if we must use the + // EPSKIP register to achieve this, Fig. 16 and NXP reference + // code suggests we can just clear the Active bits - check with + // NXP to be sure. + ep[0].in[0] = 0; + ep[0].out[0] = 0; + + // Clear EP0IN interrupt + LPC_USB->INTSTAT = EP(EP0IN); + + // Clear SETUP (and INTONNAK_CI/O) in device status register + LPC_USB->DEVCMDSTAT = devCmdStat | SETUP; + + // EP0 SETUP event (SETUP data received) + EP0setupCallback(); + } else { + // EP0OUT ACK event (OUT data received) + EP0out(); + } + } + + if (LPC_USB->INTSTAT & EP(EP0IN)) { + // Clear EP0IN interrupt + LPC_USB->INTSTAT = EP(EP0IN); + + // EP0IN ACK event (IN data sent) + EP0in(); + } + + if (LPC_USB->INTSTAT & EP(EP1IN)) { + // Clear EP1IN interrupt + LPC_USB->INTSTAT = EP(EP1IN); + epComplete |= EP(EP1IN); + if (EP1_IN_callback()) + epComplete &= ~EP(EP1IN); + } + + if (LPC_USB->INTSTAT & EP(EP1OUT)) { + // Clear EP1OUT interrupt + LPC_USB->INTSTAT = EP(EP1OUT); + epComplete |= EP(EP1OUT); + if (EP1_OUT_callback()) + epComplete &= ~EP(EP1OUT); + } + + if (LPC_USB->INTSTAT & EP(EP2IN)) { + // Clear EPBULK_IN interrupt + LPC_USB->INTSTAT = EP(EP2IN); + epComplete |= EP(EP2IN); + if (EP2_IN_callback()) + epComplete &= ~EP(EP2IN); + } + + if (LPC_USB->INTSTAT & EP(EP2OUT)) { + // Clear EPBULK_OUT interrupt + LPC_USB->INTSTAT = EP(EP2OUT); + epComplete |= EP(EP2OUT); + //Call callback function. If true, clear epComplete + if (EP2_OUT_callback()) + epComplete &= ~EP(EP2OUT); + } + + if (LPC_USB->INTSTAT & EP(EP3IN)) { + // Clear EP3_IN interrupt + LPC_USB->INTSTAT = EP(EP3IN); + epComplete |= EP(EP3IN); + if (EP3_IN_callback()) + epComplete &= ~EP(EP3IN); + } + + if (LPC_USB->INTSTAT & EP(EP3OUT)) { + // Clear EP3_OUT interrupt + LPC_USB->INTSTAT = EP(EP3OUT); + epComplete |= EP(EP3OUT); + //Call callback function. If true, clear epComplete + if (EP3_OUT_callback()) + epComplete &= ~EP(EP3OUT); + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBHAL_LPC17.cpp Wed Nov 07 09:31:53 2012 +0000 @@ -0,0 +1,644 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* 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. +*/ + +#ifdef TARGET_LPC1768 + +#include "USBHAL.h" + + +// Get endpoint direction +#define IN_EP(endpoint) ((endpoint) & 1U ? true : false) +#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true) + +// Convert physical endpoint number to register bit +#define EP(endpoint) (1UL<<endpoint) + +// Power Control for Peripherals register +#define PCUSB (1UL<<31) + +// USB Clock Control register +#define DEV_CLK_EN (1UL<<1) +#define AHB_CLK_EN (1UL<<4) + +// USB Clock Status register +#define DEV_CLK_ON (1UL<<1) +#define AHB_CLK_ON (1UL<<4) + +// USB Device Interupt registers +#define FRAME (1UL<<0) +#define EP_FAST (1UL<<1) +#define EP_SLOW (1UL<<2) +#define DEV_STAT (1UL<<3) +#define CCEMPTY (1UL<<4) +#define CDFULL (1UL<<5) +#define RxENDPKT (1UL<<6) +#define TxENDPKT (1UL<<7) +#define EP_RLZED (1UL<<8) +#define ERR_INT (1UL<<9) + +// USB Control register +#define RD_EN (1<<0) +#define WR_EN (1<<1) +#define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2) + +// USB Receive Packet Length register +#define DV (1UL<<10) +#define PKT_RDY (1UL<<11) +#define PKT_LNGTH_MASK (0x3ff) + +// Serial Interface Engine (SIE) +#define SIE_WRITE (0x01) +#define SIE_READ (0x02) +#define SIE_COMMAND (0x05) +#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16)) + +// SIE Command codes +#define SIE_CMD_SET_ADDRESS (0xD0) +#define SIE_CMD_CONFIGURE_DEVICE (0xD8) +#define SIE_CMD_SET_MODE (0xF3) +#define SIE_CMD_READ_FRAME_NUMBER (0xF5) +#define SIE_CMD_READ_TEST_REGISTER (0xFD) +#define SIE_CMD_SET_DEVICE_STATUS (0xFE) +#define SIE_CMD_GET_DEVICE_STATUS (0xFE) +#define SIE_CMD_GET_ERROR_CODE (0xFF) +#define SIE_CMD_READ_ERROR_STATUS (0xFB) + +#define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint) +#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint) +#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint) + +#define SIE_CMD_CLEAR_BUFFER (0xF2) +#define SIE_CMD_VALIDATE_BUFFER (0xFA) + +// SIE Device Status register +#define SIE_DS_CON (1<<0) +#define SIE_DS_CON_CH (1<<1) +#define SIE_DS_SUS (1<<2) +#define SIE_DS_SUS_CH (1<<3) +#define SIE_DS_RST (1<<4) + +// SIE Device Set Address register +#define SIE_DSA_DEV_EN (1<<7) + +// SIE Configue Device register +#define SIE_CONF_DEVICE (1<<0) + +// Select Endpoint register +#define SIE_SE_FE (1<<0) +#define SIE_SE_ST (1<<1) +#define SIE_SE_STP (1<<2) +#define SIE_SE_PO (1<<3) +#define SIE_SE_EPN (1<<4) +#define SIE_SE_B_1_FULL (1<<5) +#define SIE_SE_B_2_FULL (1<<6) + +// Set Endpoint Status command +#define SIE_SES_ST (1<<0) +#define SIE_SES_DA (1<<5) +#define SIE_SES_RF_MO (1<<6) +#define SIE_SES_CND_ST (1<<7) + + +USBHAL * USBHAL::instance; + +volatile int epComplete; +uint32_t endpointStallState; + +static void SIECommand(uint32_t command) { + // The command phase of a SIE transaction + LPC_USB->USBDevIntClr = CCEMPTY; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command); + while (!(LPC_USB->USBDevIntSt & CCEMPTY)); +} + +static void SIEWriteData(uint8_t data) { + // The data write phase of a SIE transaction + LPC_USB->USBDevIntClr = CCEMPTY; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data); + while (!(LPC_USB->USBDevIntSt & CCEMPTY)); +} + +static uint8_t SIEReadData(uint32_t command) { + // The data read phase of a SIE transaction + LPC_USB->USBDevIntClr = CDFULL; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command); + while (!(LPC_USB->USBDevIntSt & CDFULL)); + return (uint8_t)LPC_USB->USBCmdData; +} + +static void SIEsetDeviceStatus(uint8_t status) { + // Write SIE device status register + SIECommand(SIE_CMD_SET_DEVICE_STATUS); + SIEWriteData(status); +} + +static uint8_t SIEgetDeviceStatus(void) { + // Read SIE device status register + SIECommand(SIE_CMD_GET_DEVICE_STATUS); + return SIEReadData(SIE_CMD_GET_DEVICE_STATUS); +} + +void SIEsetAddress(uint8_t address) { + // Write SIE device address register + SIECommand(SIE_CMD_SET_ADDRESS); + SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN); +} + +static uint8_t SIEselectEndpoint(uint8_t endpoint) { + // SIE select endpoint command + SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint)); + return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint)); +} + +static uint8_t SIEclearBuffer(void) { + // SIE clear buffer command + SIECommand(SIE_CMD_CLEAR_BUFFER); + return SIEReadData(SIE_CMD_CLEAR_BUFFER); +} + +static void SIEvalidateBuffer(void) { + // SIE validate buffer command + SIECommand(SIE_CMD_VALIDATE_BUFFER); +} + +static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status) { + // SIE set endpoint status command + SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint)); + SIEWriteData(status); +} + +static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused)); +static uint16_t SIEgetFrameNumber(void) { + // Read current frame number + uint16_t lowByte; + uint16_t highByte; + + SIECommand(SIE_CMD_READ_FRAME_NUMBER); + lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER); + highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER); + + return (highByte << 8) | lowByte; +} + +static void SIEconfigureDevice(void) { + // SIE Configure device command + SIECommand(SIE_CMD_CONFIGURE_DEVICE); + SIEWriteData(SIE_CONF_DEVICE); +} + +static void SIEunconfigureDevice(void) { + // SIE Configure device command + SIECommand(SIE_CMD_CONFIGURE_DEVICE); + SIEWriteData(0); +} + +static void SIEconnect(void) { + // Connect USB device + uint8_t status; + + status = SIEgetDeviceStatus(); + SIEsetDeviceStatus(status | SIE_DS_CON); +} + + +static void SIEdisconnect(void) { + // Disconnect USB device + uint8_t status; + + status = SIEgetDeviceStatus(); + SIEsetDeviceStatus(status & ~SIE_DS_CON); +} + + +static uint8_t selectEndpointClearInterrupt(uint8_t endpoint) { + // Implemented using using EP_INT_CLR. + LPC_USB->USBEpIntClr = EP(endpoint); + while (!(LPC_USB->USBDevIntSt & CDFULL)); + return (uint8_t)LPC_USB->USBCmdData; +} + + + + + +static void enableEndpointEvent(uint8_t endpoint) { + // Enable an endpoint interrupt + LPC_USB->USBEpIntEn |= EP(endpoint); +} + +static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused)); +static void disableEndpointEvent(uint8_t endpoint) { + // Disable an endpoint interrupt + LPC_USB->USBEpIntEn &= ~EP(endpoint); +} + +static volatile uint32_t __attribute__((used)) dummyRead; + + +uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) { + // Read from an OUT endpoint + uint32_t size; + uint32_t i; + uint32_t data = 0; + uint8_t offset; + + LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN; + while (!(LPC_USB->USBRxPLen & PKT_RDY)); + + size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK; + + offset = 0; + + if (size > 0) { + for (i=0; i<size; i++) { + if (offset==0) { + // Fetch up to four bytes of data as a word + data = LPC_USB->USBRxData; + } + + // extract a byte + *buffer = (data>>offset) & 0xff; + buffer++; + + // move on to the next byte + offset = (offset + 8) % 32; + } + } else { + dummyRead = LPC_USB->USBRxData; + } + + LPC_USB->USBCtrl = 0; + + if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) { + SIEselectEndpoint(endpoint); + SIEclearBuffer(); + } + + return size; +} + +static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size) { + // Write to an IN endpoint + uint32_t temp, data; + uint8_t offset; + + LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN; + + LPC_USB->USBTxPLen = size; + offset = 0; + data = 0; + + if (size>0) { + do { + // Fetch next data byte into a word-sized temporary variable + temp = *buffer++; + + // Add to current data word + temp = temp << offset; + data = data | temp; + + // move on to the next byte + offset = (offset + 8) % 32; + size--; + + if ((offset==0) || (size==0)) { + // Write the word to the endpoint + LPC_USB->USBTxData = data; + data = 0; + } + } while (size>0); + } else { + LPC_USB->USBTxData = 0; + } + + // Clear WR_EN to cover zero length packet case + LPC_USB->USBCtrl=0; + + SIEselectEndpoint(endpoint); + SIEvalidateBuffer(); +} + + + + + + + +USBHAL::USBHAL(void) { + // Disable IRQ + NVIC_DisableIRQ(USB_IRQn); + + // Enable power to USB device controller + LPC_SC->PCONP |= PCUSB; + + // Enable USB clocks + LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN; + while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); + + // Configure pins P0.29 and P0.30 to be USB D+ and USB D- + LPC_PINCON->PINSEL1 &= 0xc3ffffff; + LPC_PINCON->PINSEL1 |= 0x14000000; + + // Disconnect USB device + SIEdisconnect(); + + // Configure pin P2.9 to be Connect + LPC_PINCON->PINSEL4 &= 0xfffcffff; + LPC_PINCON->PINSEL4 |= 0x00040000; + + // Connect must be low for at least 2.5uS + wait(0.3); + + // Set the maximum packet size for the control endpoints + realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0); + realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0); + + // Attach IRQ + instance = this; + NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); + NVIC_EnableIRQ(USB_IRQn); + + // Enable interrupts for device events and EP0 + LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME; + enableEndpointEvent(EP0IN); + enableEndpointEvent(EP0OUT); +} + +USBHAL::~USBHAL(void) { + // Ensure device disconnected + SIEdisconnect(); + + // Disable USB interrupts + NVIC_DisableIRQ(USB_IRQn); +} + +void USBHAL::connect(void) { + // Connect USB device + SIEconnect(); +} + +void USBHAL::disconnect(void) { + // Disconnect USB device + SIEdisconnect(); +} + +void USBHAL::configureDevice(void) { + SIEconfigureDevice(); +} + +void USBHAL::unconfigureDevice(void) { + SIEunconfigureDevice(); +} + +void USBHAL::setAddress(uint8_t address) { + SIEsetAddress(address); +} + +void USBHAL::EP0setup(uint8_t *buffer) { + endpointReadcore(EP0OUT, buffer); +} + +void USBHAL::EP0read(void) { + // Not required +} + +uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) { + return endpointReadcore(EP0OUT, buffer); +} + +void USBHAL::EP0write(uint8_t *buffer, uint32_t size) { + endpointWritecore(EP0IN, buffer, size); +} + +void USBHAL::EP0getWriteResult(void) { + // Not required +} + +void USBHAL::EP0stall(void) { + // This will stall both control endpoints + stallEndpoint(EP0OUT); +} + +EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) { + return EP_PENDING; +} + +EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) { + + //for isochronous endpoint, we don't wait an interrupt + if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) { + if (!(epComplete & EP(endpoint))) + return EP_PENDING; + } + + *bytesRead = endpointReadcore(endpoint, buffer); + epComplete &= ~EP(endpoint); + return EP_COMPLETED; +} + +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { + if (getEndpointStallState(endpoint)) { + return EP_STALLED; + } + + epComplete &= ~EP(endpoint); + + endpointWritecore(endpoint, data, size); + return EP_PENDING; +} + +EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) { + if (epComplete & EP(endpoint)) { + epComplete &= ~EP(endpoint); + return EP_COMPLETED; + } + + return EP_PENDING; +} + +bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) { + // Realise an endpoint + LPC_USB->USBDevIntClr = EP_RLZED; + LPC_USB->USBReEp |= EP(endpoint); + LPC_USB->USBEpInd = endpoint; + LPC_USB->USBMaxPSize = maxPacket; + + while (!(LPC_USB->USBDevIntSt & EP_RLZED)); + LPC_USB->USBDevIntClr = EP_RLZED; + + // Clear stall state + endpointStallState &= ~EP(endpoint); + + enableEndpointEvent(endpoint); + return true; +} + +void USBHAL::stallEndpoint(uint8_t endpoint) { + // Stall an endpoint + if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) { + // Conditionally stall both control endpoints + SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST); + } else { + SIEsetEndpointStatus(endpoint, SIE_SES_ST); + + // Update stall state + endpointStallState |= EP(endpoint); + } +} + +void USBHAL::unstallEndpoint(uint8_t endpoint) { + // Unstall an endpoint. The endpoint will also be reinitialised + SIEsetEndpointStatus(endpoint, 0); + + // Update stall state + endpointStallState &= ~EP(endpoint); +} + +bool USBHAL::getEndpointStallState(uint8_t endpoint) { + // Returns true if endpoint stalled + return endpointStallState & EP(endpoint); +} + +void USBHAL::remoteWakeup(void) { + // Remote wakeup + uint8_t status; + + // Enable USB clocks + LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN; + while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); + + status = SIEgetDeviceStatus(); + SIEsetDeviceStatus(status & ~SIE_DS_SUS); +} + + + + + +void USBHAL::_usbisr(void) { + instance->usbisr(); +} + + +void USBHAL::usbisr(void) { + uint8_t devStat; + + if (LPC_USB->USBDevIntSt & FRAME) { + // Start of frame event + SOF(SIEgetFrameNumber()); + // Clear interrupt status flag + LPC_USB->USBDevIntClr = FRAME; + } + + if (LPC_USB->USBDevIntSt & DEV_STAT) { + // Device Status interrupt + // Must clear the interrupt status flag before reading the device status from the SIE + LPC_USB->USBDevIntClr = DEV_STAT; + + // Read device status from SIE + devStat = SIEgetDeviceStatus(); + //printf("devStat: %d\r\n", devStat); + + if (devStat & SIE_DS_SUS_CH) { + // Suspend status changed + if((devStat & SIE_DS_SUS) != 0) { + suspendStateChanged(0); + } + } + + if (devStat & SIE_DS_RST) { + // Bus reset + if((devStat & SIE_DS_SUS) == 0) { + suspendStateChanged(1); + } + busReset(); + } + } + + if (LPC_USB->USBDevIntSt & EP_SLOW) { + // (Slow) Endpoint Interrupt + + // Process each endpoint interrupt + if (LPC_USB->USBEpIntSt & EP(EP0OUT)) { + if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) { + // this is a setup packet + EP0setupCallback(); + } else { + EP0out(); + } + LPC_USB->USBDevIntClr = EP_SLOW; + } + + if (LPC_USB->USBEpIntSt & EP(EP0IN)) { + selectEndpointClearInterrupt(EP0IN); + LPC_USB->USBDevIntClr = EP_SLOW; + EP0in(); + } + + // TODO: This should cover all endpoints, not just EP1,2,3: + if (LPC_USB->USBEpIntSt & EP(EP1IN)) { + selectEndpointClearInterrupt(EP1IN); + epComplete |= EP(EP1IN); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP1_IN_callback()) + epComplete &= ~EP(EP1IN); + } + + if (LPC_USB->USBEpIntSt & EP(EP1OUT)) { + selectEndpointClearInterrupt(EP1OUT); + epComplete |= EP(EP1OUT); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP1_OUT_callback()) + epComplete &= ~EP(EP1OUT); + } + + if (LPC_USB->USBEpIntSt & EP(EP2IN)) { + selectEndpointClearInterrupt(EP2IN); + epComplete |= EP(EP2IN); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP2_IN_callback()) + epComplete &= ~EP(EP2IN); + } + + if (LPC_USB->USBEpIntSt & EP(EP2OUT)) { + selectEndpointClearInterrupt(EP2OUT); + epComplete |= EP(EP2OUT); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP2_OUT_callback()) + epComplete &= ~EP(EP2OUT); + } + + if (LPC_USB->USBEpIntSt & EP(EP3IN)) { + selectEndpointClearInterrupt(EP3IN); + epComplete |= EP(EP3IN); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP3_IN_callback()) + epComplete &= ~EP(EP3IN); + } + + if (LPC_USB->USBEpIntSt & EP(EP3OUT)) { + selectEndpointClearInterrupt(EP3OUT); + epComplete |= EP(EP3OUT); + LPC_USB->USBDevIntClr = EP_SLOW; + if (EP3_OUT_callback()) + epComplete &= ~EP(EP3OUT); + } + } +} + +#endif