diff options
Diffstat (limited to 'openpicc/os/usb')
| -rw-r--r-- | openpicc/os/usb/USB-CDC.c | 953 | ||||
| -rw-r--r-- | openpicc/os/usb/USB-CDC.h | 87 | ||||
| -rw-r--r-- | openpicc/os/usb/USBIsr.c | 169 | ||||
| -rw-r--r-- | openpicc/os/usb/descriptors.h | 190 | ||||
| -rw-r--r-- | openpicc/os/usb/usb.h | 146 | 
5 files changed, 1545 insertions, 0 deletions
diff --git a/openpicc/os/usb/USB-CDC.c b/openpicc/os/usb/USB-CDC.c new file mode 100644 index 0000000..4496c55 --- /dev/null +++ b/openpicc/os/usb/USB-CDC.c @@ -0,0 +1,953 @@ +/* +	FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + +	This file is part of the FreeRTOS.org distribution. + +	FreeRTOS.org is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	FreeRTOS.org is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with FreeRTOS.org; if not, write to the Free Software +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +	A special exception to the GPL can be applied should you wish to distribute +	a combined work that includes FreeRTOS.org, without being obliged to provide +	the source code for any proprietary components.  See the licensing section +	of http://www.FreeRTOS.org for full details of how and when the exception +	can be applied. + +	*************************************************************************** +	See http://www.FreeRTOS.org for documentation, latest information, license +	and contact details.  Please ensure to read the configuration and relevant +	port sections of the online documentation. + +	Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along +	with commercial development and support options. +	*************************************************************************** +*/ + +/* +	USB Communications Device Class driver. +	Implements task vUSBCDCTask and provides an Abstract Control Model serial  +	interface.  Control is through endpoint 0, device-to-host notification is  +	provided by interrupt-in endpoint 3, and raw data is transferred through  +	bulk endpoints 1 and 2. + +	- developed from original FreeRTOS HID example by Scott Miller +	- modified to support 3.2 GCC by najay +*/ + +/* Standard includes. */ +#include <string.h> +#include <stdio.h> + +/* Demo board includes. */ +#include <board.h> + +/* Scheduler includes. */ +#include <FreeRTOS.h> +#include <task.h> +#include <queue.h> + +/* Demo app includes. */ +#include <USB-CDC.h> +#include <descriptors.h> + +#define usbNO_BLOCK ( ( portTickType ) 0 ) + +/* Reset all endpoints */ +static void prvResetEndPoints (void); + +/* Clear pull up resistor to detach device from host */ +static void vDetachUSBInterface (void); + +/* Set up interface and initialize variables */ +static void vInitUSBInterface (void); + +/* Handle control endpoint events. */ +static void prvProcessEndPoint0Interrupt (xISRStatus * pxMessage); + +/* Handle standard device requests. */ +static void prvHandleStandardDeviceRequest (xUSB_REQUEST * pxRequest); + +/* Handle standard interface requests. */ +static void prvHandleStandardInterfaceRequest (xUSB_REQUEST * pxRequest); + +/* Handle endpoint requests. */ +static void prvHandleStandardEndPointRequest (xUSB_REQUEST * pxRequest); + +/* Handle class interface requests. */ +static void prvHandleClassInterfaceRequest (xUSB_REQUEST * pxRequest); + +/* Prepare control data transfer.  prvSendNextSegment starts transfer. */ +static void prvSendControlData (unsigned portCHAR * pucData, +				unsigned portSHORT usRequestedLength, +				unsigned portLONG ulLengthLeftToSend, +				portLONG lSendingDescriptor); + +/* Send next segment of data for the control transfer */ +static void prvSendNextSegment (void); + +/* Send stall - used to respond to unsupported requests */ +static void prvSendStall (void); + +/* Send a zero-length (null) packet */ +static void prvSendZLP (void); + +/* Handle requests for standard interface descriptors */ +static void prvGetStandardInterfaceDescriptor (xUSB_REQUEST * pxRequest); + +/*------------------------------------------------------------*/ + +/* File scope static variables */ +static unsigned portCHAR ucUSBConfig = (unsigned portCHAR) 0; +static unsigned portLONG ulReceivedAddress = (unsigned portLONG) 0; +static eDRIVER_STATE eDriverState = eNOTHING; + +/* Incoming and outgoing control data structures */ +static xCONTROL_MESSAGE pxControlTx; +static xCONTROL_MESSAGE pxControlRx; + +/* Queue holding pointers to pending messages */ +xQueueHandle xUSBInterruptQueue; + +/* Queues used to hold received characters, and characters waiting to be +transmitted.  Rx queue must be larger than FIFO size. */ +static xQueueHandle xRxCDC; +static xQueueHandle xTxCDC; + +/* Line coding - 115,200 baud, N-8-1 */ +static const unsigned portCHAR pxLineCoding[] = +  { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 }; + +/* Status variables. */ +static unsigned portCHAR ucControlState; +static unsigned int uiCurrentBank; + + +/*------------------------------------------------------------*/ + + +void +vUSBCDCTask (void *pvParameters) +{ +  xISRStatus *pxMessage; +  unsigned portLONG ulStatus; +  unsigned portLONG ulRxBytes; +  unsigned portCHAR ucByte; +  portBASE_TYPE xByte; + +  (void) pvParameters; + +  /* Disconnect USB device from hub.  For debugging - causes host to register reset */ +  portENTER_CRITICAL (); +  vDetachUSBInterface (); +  portEXIT_CRITICAL (); + +  vTaskDelay (portTICK_RATE_MS * 60); + +  /* Init USB interface */ +  portENTER_CRITICAL (); +  vInitUSBInterface (); +  portEXIT_CRITICAL (); + +  /* Main task loop.  Process incoming endpoint 0 interrupts, handle data transfers. */ + +  for (;;) +    { +      /* Look for data coming from the ISR. */ +      if (xQueueReceive (xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY)) +	{ +	  if (pxMessage->ulISR & AT91C_UDP_EPINT0) +	    { +	      /* All endpoint 0 interrupts are handled here. */ +	      prvProcessEndPoint0Interrupt (pxMessage); +	    } + +	  if (pxMessage->ulISR & AT91C_UDP_ENDBUSRES) +	    { +	      /* End of bus reset - reset the endpoints and de-configure. */ +	      prvResetEndPoints (); +	    } +	} + +      /* See if we're ready to send and receive data. */ +      if (eDriverState == eREADY_TO_SEND && ucControlState) +	{ +	  if ((! +	       (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] & AT91C_UDP_TXPKTRDY)) +	      && uxQueueMessagesWaiting (xTxCDC)) +	    { +	      for (xByte = 0; xByte < 64; xByte++) +		{ +		  if (!xQueueReceive (xTxCDC, &ucByte, 0)) +		    { +		      /* No data buffered to transmit. */ +		      break; +		    } + +		  /* Got a byte to transmit. */ +		  AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_2] = ucByte; +		} +	      AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] |= AT91C_UDP_TXPKTRDY; +	    } + +	  /* Check for incoming data (host-to-device) on endpoint 1. */ +	  while (AT91C_BASE_UDP-> +		 UDP_CSR[usbEND_POINT_1] & (AT91C_UDP_RX_DATA_BK0 | +					    AT91C_UDP_RX_DATA_BK1)) +	    { +	      ulRxBytes = +		(AT91C_BASE_UDP-> +		 UDP_CSR[usbEND_POINT_1] >> 16) & usbRX_COUNT_MASK; + +	      /* Only process FIFO if there's room to store it in the queue */ +	      if (ulRxBytes < +		  (USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting (xRxCDC))) +		{ +		  while (ulRxBytes--) +		    { +		      ucByte = AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_1]; +		      xQueueSend (xRxCDC, &ucByte, 0); +		    } + +		  /* Release the FIFO */ +		  portENTER_CRITICAL (); +		  { +		    ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1]; +		    usbCSR_CLEAR_BIT (&ulStatus, uiCurrentBank); +		    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] = ulStatus; +		  } +		  portEXIT_CRITICAL (); + +		  /* Re-enable endpoint 1's interrupts */ +		  AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; + +		  /* Update the current bank in use */ +		  if (uiCurrentBank == AT91C_UDP_RX_DATA_BK0) +		    { +		      uiCurrentBank = AT91C_UDP_RX_DATA_BK1; +		    } +		  else +		    { +		      uiCurrentBank = AT91C_UDP_RX_DATA_BK0; +		    } + +		} +	      else +		{ +		  break; +		} +	    } +	} +    } +} + +/*------------------------------------------------------------*/ + +void +vUSBSendByte (portCHAR cByte) +{ +  /* Queue the byte to be sent.  The USB task will send it. */ +  xQueueSend (xTxCDC, &cByte, usbNO_BLOCK); +} + +/*------------------------------------------------------------*/ + +portLONG +vUSBRecvByte (portCHAR *cByte, portLONG size, portTickType xTicksToWait) +{ +    portLONG res; +    if(size<=0 || !cByte || !xRxCDC) +        return 0; + +    res=0; +    while(size-- && xQueueReceive(xRxCDC, cByte++, xTicksToWait)) +        res++; + +    return res; +} + +/*------------------------------------------------------------*/ + +static void +prvSendZLP (void) +{ +  unsigned portLONG ulStatus; + +  /* Wait until the FIFO is free - even though we are not going to use it. +     THERE IS NO TIMEOUT HERE! */ +  while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_TXPKTRDY) +    { +      vTaskDelay (usbSHORTEST_DELAY); +    } + +  portENTER_CRITICAL (); +  { +    /* Cancel any further pending data */ +    pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex; + +    /* Set the TXPKTRDY bit to cause a transmission with no data. */ +    ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; +    usbCSR_SET_BIT (&ulStatus, AT91C_UDP_TXPKTRDY); +    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; +  } +  portEXIT_CRITICAL (); +} + +/*------------------------------------------------------------*/ + +static void +prvSendStall (void) +{ +  unsigned portLONG ulStatus; + +  portENTER_CRITICAL (); +  { +    /* Force a stall by simply setting the FORCESTALL bit in the CSR. */ +    ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; +    usbCSR_SET_BIT (&ulStatus, AT91C_UDP_FORCESTALL); +    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; +  } +  portEXIT_CRITICAL (); +} + +/*------------------------------------------------------------*/ + +static void +prvResetEndPoints (void) +{ +  unsigned portLONG ulTemp; + +  eDriverState = eJUST_RESET; +  ucControlState = 0; + +  /* Reset all the end points. */ +  AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK; +  AT91C_BASE_UDP->UDP_RSTEP = (unsigned portLONG) 0x00; + +  /* Enable data to be sent and received. */ +  AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; + +  /* Repair the configuration end point. */ +  portENTER_CRITICAL (); +  { +    ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; +    usbCSR_SET_BIT (&ulTemp, +		    ((unsigned portLONG) (AT91C_UDP_EPEDS | +					  AT91C_UDP_EPTYPE_CTRL))); +    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulTemp; +    AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0; +  } +  portEXIT_CRITICAL (); +  uiCurrentBank = AT91C_UDP_RX_DATA_BK0; +} + +/*------------------------------------------------------------*/ + +static void +prvProcessEndPoint0Interrupt (xISRStatus * pxMessage) +{ +  static xUSB_REQUEST xRequest; +  unsigned portLONG ulRxBytes; + +  /* Get number of bytes received, if any */ +  ulRxBytes = pxMessage->ulCSR0 >> 16; +  ulRxBytes &= usbRX_COUNT_MASK; + +  if (pxMessage->ulCSR0 & AT91C_UDP_TXCOMP) +    { +      /* We received a TX complete interrupt.  What we do depends on +         what we sent to get this interrupt. */ + +      if (eDriverState == eJUST_GOT_CONFIG) +	{ +	  /* We sent an acknowledgement of a SET_CONFIG request.  We +	     are now at the end of the enumeration. + +	     TODO: Config 0 sets unconfigured state, should enter Address state. +	     Request for unsupported config should stall. */ +	  AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG; + +	  /* Set up endpoints */ +	  portENTER_CRITICAL (); +	  { +	    unsigned portLONG ulTemp; + +	    /* Set endpoint 1 to bulk-out */ +	    ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1]; +	    usbCSR_SET_BIT (&ulTemp, +			    AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); +	    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] = ulTemp; +	    AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; +	    /* Set endpoint 2 to bulk-in */ +	    ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2]; +	    usbCSR_SET_BIT (&ulTemp, +			    AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); +	    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] = ulTemp; +	    AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2; +	    /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */ +	    ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3]; +	    usbCSR_SET_BIT (&ulTemp, +			    AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); +	    AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3] = ulTemp; +	    /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 );                                */ +	  } +	  portEXIT_CRITICAL (); + +	  eDriverState = eREADY_TO_SEND; +	} +      else if (eDriverState == eJUST_GOT_ADDRESS) +	{ +	  /* We sent an acknowledgement of a SET_ADDRESS request.  Move +	     to the addressed state. */ +	  if (ulReceivedAddress != (unsigned portLONG) 0) +	    { +	      AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; +	    } +	  else +	    { +	      AT91C_BASE_UDP->UDP_GLBSTATE = 0; +	    } + +	  AT91C_BASE_UDP->UDP_FADDR = (AT91C_UDP_FEN | ulReceivedAddress); +	  eDriverState = eNOTHING; +	} +      else +	{ +	  /* The TXCOMP was not for any special type of transmission.  See +	     if there is any more data to send. */ +	  prvSendNextSegment (); +	} +    } + +  if (pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0) +    { +      /* Received a control data packet.  May be a 0-length ACK or a data stage. */ +      unsigned portCHAR ucBytesToGet; + +      /* Got data.  Cancel any outgoing data. */ +      pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength; + +      /* Determine how many bytes we need to receive. */ +      ucBytesToGet = +	pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex; +      if (ucBytesToGet > ulRxBytes) +	{ +	  ucBytesToGet = ulRxBytes; +	} + +      /* If we're not expecting any data, it's an ack - just quit now. */ +      if (!ucBytesToGet) +	{ +	  return; +	} + +      /* Get the required data and update the index. */ +      memcpy (pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet); +      pxControlRx.ulNextCharIndex += ucBytesToGet; +    } + +  if (pxMessage->ulCSR0 & AT91C_UDP_RXSETUP) +    { +      /* Received a SETUP packet.  May be followed by data packets. */ + +      if (ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES) +	{ +	  /* Create an xUSB_REQUEST variable from the raw bytes array. */ + +	  xRequest.ucReqType = pxMessage->ucFifoData[usbREQUEST_TYPE_INDEX]; +	  xRequest.ucRequest = pxMessage->ucFifoData[usbREQUEST_INDEX]; + +	  xRequest.usValue = pxMessage->ucFifoData[usbVALUE_HIGH_BYTE]; +	  xRequest.usValue <<= 8; +	  xRequest.usValue |= pxMessage->ucFifoData[usbVALUE_LOW_BYTE]; + +	  xRequest.usIndex = pxMessage->ucFifoData[usbINDEX_HIGH_BYTE]; +	  xRequest.usIndex <<= 8; +	  xRequest.usIndex |= pxMessage->ucFifoData[usbINDEX_LOW_BYTE]; + +	  xRequest.usLength = pxMessage->ucFifoData[usbLENGTH_HIGH_BYTE]; +	  xRequest.usLength <<= 8; +	  xRequest.usLength |= pxMessage->ucFifoData[usbLENGTH_LOW_BYTE]; + +	  pxControlRx.ulNextCharIndex = 0; +	  if (!(xRequest.ucReqType & 0x80))	/* Host-to-Device transfer, may need to get data first */ +	    { +	      if (xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE) +		{ +		  /* Too big!  No space for control data, stall and abort. */ +		  prvSendStall (); +		  return; +		} + +	      pxControlRx.ulTotalDataLength = xRequest.usLength; +	    } +	  else +	    { +	      /* We're sending the data, don't wait for any. */ +	      pxControlRx.ulTotalDataLength = 0; +	    } +	} +    } + +  /* See if we've got a pending request and all its associated data ready */ +  if ((pxMessage->ulCSR0 & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP)) +      && (pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength)) +    { +      unsigned portCHAR ucRequest; + +      /* Manipulate the ucRequestType and the ucRequest parameters to  +         generate a zero based request selection.  This is just done to  +         break up the requests into subsections for clarity.  The  +         alternative would be to have more huge switch statement that would +         be difficult to optimise. */ +      ucRequest = ((xRequest.ucReqType & 0x60) >> 3); +      ucRequest |= (xRequest.ucReqType & 0x03); + +      switch (ucRequest) +	{ +	case usbSTANDARD_DEVICE_REQUEST: +	  /* Standard Device request */ +	  prvHandleStandardDeviceRequest (&xRequest); +	  break; + +	case usbSTANDARD_INTERFACE_REQUEST: +	  /* Standard Interface request */ +	  prvHandleStandardInterfaceRequest (&xRequest); +	  break; + +	case usbSTANDARD_END_POINT_REQUEST: +	  /* Standard Endpoint request */ +	  prvHandleStandardEndPointRequest (&xRequest); +	  break; + +	case usbCLASS_INTERFACE_REQUEST: +	  /* Class Interface request */ +	  prvHandleClassInterfaceRequest (&xRequest); +	  break; + +	default:		/* This is not something we want to respond to. */ +	  prvSendStall (); +	} +    } +} + +/*------------------------------------------------------------*/ + +static void +prvGetStandardDeviceDescriptor (xUSB_REQUEST * pxRequest) +{ +  /* The type is in the high byte.  Return whatever has been requested. */ +  switch ((pxRequest->usValue & 0xff00) >> 8) +    { +    case usbDESCRIPTOR_TYPE_DEVICE: +      prvSendControlData ((unsigned portCHAR *) &pxDeviceDescriptor, +			  pxRequest->usLength, sizeof (pxDeviceDescriptor), +			  pdTRUE); +      break; + +    case usbDESCRIPTOR_TYPE_CONFIGURATION: +      prvSendControlData ((unsigned portCHAR *) &(pxConfigDescriptor), +			  pxRequest->usLength, sizeof (pxConfigDescriptor), +			  pdTRUE); +      break; + +    case usbDESCRIPTOR_TYPE_STRING: + +      /* The index to the string descriptor is the lower byte. */ +      switch (pxRequest->usValue & 0xff) +	{ +	case usbLANGUAGE_STRING: +	  prvSendControlData ((unsigned portCHAR *) +			      &pxLanguageStringDescriptor, +			      pxRequest->usLength, +			      sizeof (pxLanguageStringDescriptor), pdTRUE); +	  break; + +	case usbMANUFACTURER_STRING: +	  prvSendControlData ((unsigned portCHAR *) +			      &pxManufacturerStringDescriptor, +			      pxRequest->usLength, +			      sizeof (pxManufacturerStringDescriptor), +			      pdTRUE); +	  break; + +	case usbPRODUCT_STRING: +	  prvSendControlData ((unsigned portCHAR *) +			      &pxProductStringDescriptor, pxRequest->usLength, +			      sizeof (pxProductStringDescriptor), pdTRUE); +	  break; + +	default: +	  prvSendStall (); +	  break; +	} +      break; + +    default: +      prvSendStall (); +      break; +    } +} + +/*------------------------------------------------------------*/ + +static void +prvHandleStandardDeviceRequest (xUSB_REQUEST * pxRequest) +{ +  unsigned portSHORT usStatus = 0; + +  switch (pxRequest->ucRequest) +    { +    case usbGET_STATUS_REQUEST: +      /* Just send two byte dummy status. */ +      prvSendControlData ((unsigned portCHAR *) &usStatus, sizeof (usStatus), +			  sizeof (usStatus), pdFALSE); +      break; + +    case usbGET_DESCRIPTOR_REQUEST: +      /* Send device descriptor */ +      prvGetStandardDeviceDescriptor (pxRequest); +      break; + +    case usbGET_CONFIGURATION_REQUEST: +      /* Send selected device configuration */ +      prvSendControlData ((unsigned portCHAR *) &ucUSBConfig, +			  sizeof (ucUSBConfig), sizeof (ucUSBConfig), +			  pdFALSE); +      break; + +    case usbSET_FEATURE_REQUEST: +      prvSendZLP (); +      break; + +    case usbSET_ADDRESS_REQUEST: +      /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */ +      prvSendZLP (); +      eDriverState = eJUST_GOT_ADDRESS; +      ulReceivedAddress = (unsigned portLONG) pxRequest->usValue; +      break; + +    case usbSET_CONFIGURATION_REQUEST: +      /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */ +      ucUSBConfig = (unsigned portCHAR) (pxRequest->usValue & 0xff); +      eDriverState = eJUST_GOT_CONFIG; +      prvSendZLP (); +      break; + +    default: +      /* Any unsupported request results in a STALL response. */ +      prvSendStall (); +      break; +    } +} + +/*------------------------------------------------------------*/ + +static void +prvHandleClassInterfaceRequest (xUSB_REQUEST * pxRequest) +{ +  switch (pxRequest->ucRequest) +    { +    case usbSEND_ENCAPSULATED_COMMAND: +      prvSendStall (); +      break; + +    case usbGET_ENCAPSULATED_RESPONSE: +      prvSendStall (); +      break; + +    case usbSET_LINE_CODING: +      /* Set line coding - baud rate, data bits, parity, stop bits */ +      prvSendZLP (); +      memcpy ((void *) pxLineCoding, pxControlRx.ucBuffer, +	      sizeof (pxLineCoding)); +      break; + +    case usbGET_LINE_CODING: +      /* Get line coding */ +      prvSendControlData ((unsigned portCHAR *) &pxLineCoding, +			  pxRequest->usLength, sizeof (pxLineCoding), +			  pdFALSE); +      break; + +    case usbSET_CONTROL_LINE_STATE: +      /* D0: 1=DTR, 0=No DTR,  D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */ +      prvSendZLP (); +      ucControlState = pxRequest->usValue; +      break; + +    default: +      prvSendStall (); +      break; +    } +} + +/*------------------------------------------------------------*/ + +static void +prvGetStandardInterfaceDescriptor (xUSB_REQUEST * pxRequest) +{ +  switch ((pxRequest->usValue & (unsigned portSHORT) 0xff00) >> 8) +    { +    default: +      prvSendStall (); +      break; +    } +} + +/*-----------------------------------------------------------*/ + +static void +prvHandleStandardInterfaceRequest (xUSB_REQUEST * pxRequest) +{ +  unsigned portSHORT usStatus = 0; + +  switch (pxRequest->ucRequest) +    { +    case usbGET_STATUS_REQUEST: +      /* Send dummy 2 bytes. */ +      prvSendControlData ((unsigned portCHAR *) &usStatus, sizeof (usStatus), +			  sizeof (usStatus), pdFALSE); +      break; + +    case usbGET_DESCRIPTOR_REQUEST: +      prvGetStandardInterfaceDescriptor (pxRequest); +      break; + +      /* This minimal implementation does not respond to these. */ +    case usbGET_INTERFACE_REQUEST: +    case usbSET_FEATURE_REQUEST: +    case usbSET_INTERFACE_REQUEST: + +    default: +      prvSendStall (); +      break; +    } +} + +/*-----------------------------------------------------------*/ + +static void +prvHandleStandardEndPointRequest (xUSB_REQUEST * pxRequest) +{ +  switch (pxRequest->ucRequest) +    { +      /* This minimal implementation does not expect to respond to these. */ +    case usbGET_STATUS_REQUEST: +    case usbCLEAR_FEATURE_REQUEST: +    case usbSET_FEATURE_REQUEST: + +    default: +      prvSendStall (); +      break; +    } +} + +/*-----------------------------------------------------------*/ + +static void +vDetachUSBInterface (void) +{ +  /* Setup the PIO for the USB pull up resistor. */ +  AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16; +  AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16; + + +  /* Disable pull up */ +  AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16; +} + +/*-----------------------------------------------------------*/ + +static void +vInitUSBInterface (void) +{ +  extern void (vUSB_ISR) (void); + +  /* Create the queue used to communicate between the USB ISR and task. */ +  xUSBInterruptQueue = +    xQueueCreate (usbQUEUE_LENGTH + 1, sizeof (xISRStatus *)); + +  /* Create the queues used to hold Rx and Tx characters. */ +  xRxCDC = +    xQueueCreate (USB_CDC_QUEUE_SIZE, +		  (unsigned portCHAR) sizeof (signed portCHAR)); +  xTxCDC = +    xQueueCreate (USB_CDC_QUEUE_SIZE + 1, +		  (unsigned portCHAR) sizeof (signed portCHAR)); + +  if ((!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC)) +    { +      /* Not enough RAM to create queues!. */ +      return; +    } + +  /* Initialise a few state variables. */ +  pxControlTx.ulNextCharIndex = (unsigned portLONG) 0; +  pxControlRx.ulNextCharIndex = (unsigned portLONG) 0; +  ucUSBConfig = (unsigned portCHAR) 0; +  eDriverState = eNOTHING; +  ucControlState = 0; +  uiCurrentBank = AT91C_UDP_RX_DATA_BK0; + + +  /* HARDWARE SETUP */ + +  /* Set the PLL USB Divider */ +  AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; + +  /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */ +  AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; +  AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); + +  /* Setup the PIO for the USB pull up resistor. */ +  AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16; +  AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16; + + +  /* Start without the pullup - this will get set at the end of this  +     function. */ +  AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16; + + +  /* When using the USB debugger the peripheral registers do not always get +     set to the correct default values.  To make sure set the relevant registers +     manually here. */ +  AT91C_BASE_UDP->UDP_IDR = (unsigned portLONG) 0xffffffff; +  AT91C_BASE_UDP->UDP_ICR = (unsigned portLONG) 0xffffffff; +  AT91C_BASE_UDP->UDP_CSR[0] = (unsigned portLONG) 0x00; +  AT91C_BASE_UDP->UDP_CSR[1] = (unsigned portLONG) 0x00; +  AT91C_BASE_UDP->UDP_CSR[2] = (unsigned portLONG) 0x00; +  AT91C_BASE_UDP->UDP_CSR[3] = (unsigned portLONG) 0x00; +  AT91C_BASE_UDP->UDP_GLBSTATE = 0; +  AT91C_BASE_UDP->UDP_FADDR = 0; + +  /* Enable the transceiver. */ +  AT91C_UDP_TRANSCEIVER_ENABLE = 0; + +  /* Enable the USB interrupts - other interrupts get enabled as the  +     enumeration process progresses. */ +  AT91F_AIC_ConfigureIt (AT91C_ID_UDP, usbINTERRUPT_PRIORITY, +			 AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, +			 (void (*)(void)) vUSB_ISR); +  AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP; + + +  /* Wait a short while before making our presence known. */ +  vTaskDelay (usbINIT_DELAY); +  AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16; +} + +/*-----------------------------------------------------------*/ + +static void +prvSendControlData (unsigned portCHAR * pucData, +		    unsigned portSHORT usRequestedLength, +		    unsigned portLONG ulLengthToSend, +		    portLONG lSendingDescriptor) +{ +  if (((unsigned portLONG) usRequestedLength < ulLengthToSend)) +    { +      /* Cap the data length to that requested. */ +      ulLengthToSend = (unsigned portSHORT) usRequestedLength; +    } +  else if ((ulLengthToSend < (unsigned portLONG) usRequestedLength) +	   && lSendingDescriptor) +    { +      /* We are sending a descriptor.  If the descriptor is an exact  +         multiple of the FIFO length then it will have to be terminated +         with a NULL packet.  Set the state to indicate this if +         necessary. */ +      if ((ulLengthToSend % usbFIFO_LENGTH) == 0) +	{ +	  eDriverState = eSENDING_EVEN_DESCRIPTOR; +	} +    } + +  /* Here we assume that the previous message has been sent.  THERE IS NO +     BUFFER OVERFLOW PROTECTION HERE. + +     Copy the data to send into the buffer as we cannot send it all at once +     (if it is greater than 8 bytes in length). */ +  memcpy (pxControlTx.ucBuffer, pucData, ulLengthToSend); + +  /* Reinitialise the buffer index so we start sending from the start of  +     the data. */ +  pxControlTx.ulTotalDataLength = ulLengthToSend; +  pxControlTx.ulNextCharIndex = (unsigned portLONG) 0; + +  /* Send the first 8 bytes now.  The rest will get sent in response to  +     TXCOMP interrupts. */ +  prvSendNextSegment (); +} + +/*-----------------------------------------------------------*/ + +static void +prvSendNextSegment (void) +{ +  volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend; + +  /* Is there any data to send? */ +  if (pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex) +    { +      ulLengthLeftToSend = +	pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex; + +      /* We can only send 8 bytes to the fifo at a time. */ +      if (ulLengthLeftToSend > usbFIFO_LENGTH) +	{ +	  ulNextLength = usbFIFO_LENGTH; +	} +      else +	{ +	  ulNextLength = ulLengthLeftToSend; +	} + +      /* Wait until we can place data in the fifo.  THERE IS NO TIMEOUT +         HERE! */ +      while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_TXPKTRDY) +	{ +	  vTaskDelay (usbSHORTEST_DELAY); +	} + +      /* Write the data to the FIFO. */ +      while (ulNextLength > (unsigned portLONG) 0) +	{ +	  AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_0] = +	    pxControlTx.ucBuffer[pxControlTx.ulNextCharIndex]; + +	  ulNextLength--; +	  pxControlTx.ulNextCharIndex++; +	} + +      /* Start the transmission. */ +      portENTER_CRITICAL (); +      { +	ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; +	usbCSR_SET_BIT (&ulStatus, ((unsigned portLONG) 0x10)); +	AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; +      } +      portEXIT_CRITICAL (); +    } +  else +    { +      /* There is no data to send.  If we were sending a descriptor and the  +         descriptor was an exact multiple of the max packet size then we need +         to send a null to terminate the transmission. */ +      if (eDriverState == eSENDING_EVEN_DESCRIPTOR) +	{ +	  prvSendZLP (); +	  eDriverState = eNOTHING; +	} +    } +} diff --git a/openpicc/os/usb/USB-CDC.h b/openpicc/os/usb/USB-CDC.h new file mode 100644 index 0000000..894ebfb --- /dev/null +++ b/openpicc/os/usb/USB-CDC.h @@ -0,0 +1,87 @@ +/* +	FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + +	This file is part of the FreeRTOS.org distribution. + +	FreeRTOS.org is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	FreeRTOS.org is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with FreeRTOS.org; if not, write to the Free Software +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +	A special exception to the GPL can be applied should you wish to distribute +	a combined work that includes FreeRTOS.org, without being obliged to provide +	the source code for any proprietary components.  See the licensing section +	of http://www.FreeRTOS.org for full details of how and when the exception +	can be applied. + +	*************************************************************************** +	See http://www.FreeRTOS.org for documentation, latest information, license +	and contact details.  Please ensure to read the configuration and relevant +	port sections of the online documentation. + +	Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along +	with commercial development and support options. +	*************************************************************************** +*/ + +#ifndef USB_CDC_H +#define USB_CDC_H + +#include "usb.h" + +#define USB_CDC_QUEUE_SIZE    1024 + +/* Structure used to take a snapshot of the USB status from within the ISR. */ +typedef struct X_ISR_STATUS +{ +  unsigned portLONG ulISR; +  unsigned portLONG ulCSR0; +  unsigned portCHAR ucFifoData[8]; +} xISRStatus; + +/* Structure used to hold the received requests. */ +typedef struct +{ +  unsigned portCHAR ucReqType; +  unsigned portCHAR ucRequest; +  unsigned portSHORT usValue; +  unsigned portSHORT usIndex; +  unsigned portSHORT usLength; +} xUSB_REQUEST; + +typedef enum +{ +  eNOTHING, +  eJUST_RESET, +  eJUST_GOT_CONFIG, +  eJUST_GOT_ADDRESS, +  eSENDING_EVEN_DESCRIPTOR, +  eREADY_TO_SEND +} eDRIVER_STATE; + +/* Structure used to control the data being sent to the host. */ +typedef struct +{ +  unsigned portCHAR ucBuffer[usbMAX_CONTROL_MESSAGE_SIZE]; +  unsigned portLONG ulNextCharIndex; +  unsigned portLONG ulTotalDataLength; +} xCONTROL_MESSAGE; + +/*-----------------------------------------------------------*/ +void vUSBCDCTask (void *pvParameters); + +/* Send cByte down the USB port.  Characters are simply buffered and not +sent unless the port is connected. */ +void vUSBSendByte (portCHAR cByte); +portLONG vUSBRecvByte (portCHAR *cByte,portLONG size, portTickType xTicksToWait); + +#endif diff --git a/openpicc/os/usb/USBIsr.c b/openpicc/os/usb/USBIsr.c new file mode 100644 index 0000000..cbc5f85 --- /dev/null +++ b/openpicc/os/usb/USBIsr.c @@ -0,0 +1,169 @@ +/* +  FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + +  This file is part of the FreeRTOS.org distribution. + +  FreeRTOS.org is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  FreeRTOS.org is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with FreeRTOS.org; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +  A special exception to the GPL can be applied should you wish to distribute +  a combined work that includes FreeRTOS.org, without being obliged to provide +  the source code for any proprietary components.  See the licensing section  +  of http://www.FreeRTOS.org for full details of how and when the exception +  can be applied. + +  *************************************************************************** +  See http://www.FreeRTOS.org for documentation, latest information, license  +  and contact details.  Please ensure to read the configuration and relevant  +  port sections of the online documentation. +  *************************************************************************** +*/ + + +/*  +  BASIC INTERRUPT DRIVEN DRIVER FOR USB.  + +  This file contains all the usb components that must be compiled +  to ARM mode.  The components that can be compiled to either ARM or THUMB +  mode are contained in USB-CDC.c. + +*/ + +/* Scheduler includes. */ +#include <FreeRTOS.h> +#include <task.h> +#include <queue.h> + +/* Demo application includes. */ +#include <board.h> +#include <usb.h> +#include <USB-CDC.h> + +#define usbINT_CLEAR_MASK	(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 ) +/*-----------------------------------------------------------*/ + +/* Messages and queue used to communicate between the ISR and the USB task. */ +static xISRStatus xISRMessages[usbQUEUE_LENGTH + 1]; +extern xQueueHandle xUSBInterruptQueue; +/*-----------------------------------------------------------*/ + +/* The ISR can cause a context switch so is declared naked. */ +void vUSB_ISR (void) __attribute__ ((naked)); + +/*-----------------------------------------------------------*/ + + +void +vUSB_ISR (void) +{ +  /* This ISR can cause a context switch.  Therefore a call to the  +     portENTER_SWITCHING_ISR() macro is made.  This must come BEFORE any  +     stack variable declarations. */ +  portENTER_SWITCHING_ISR (); + +  /* Now variables can be declared. */ +  portCHAR cTaskWokenByPost = pdFALSE; +  static volatile unsigned portLONG ulNextMessage = 0; +  xISRStatus *pxMessage; +  unsigned portLONG ulRxBytes; +  unsigned portCHAR ucFifoIndex; + +  /* Use the next message from the array. */ +  pxMessage = &(xISRMessages[(ulNextMessage & usbQUEUE_LENGTH)]); +  ulNextMessage++; + +  /* Save UDP ISR state for task-level processing. */ +  pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR; +  pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + +  /* Clear interrupts from ICR. */ +  AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES; + + +  /* Process incoming FIFO data.  Must set DIR (if needed) and clear RXSETUP  +     before exit. */ + +  /* Read CSR and get incoming byte count. */ +  ulRxBytes = (pxMessage->ulCSR0 >> 16) & usbRX_COUNT_MASK; + +  /* Receive control transfers on endpoint 0. */ +  if (pxMessage->ulCSR0 & (AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0)) +    { +      /* Save FIFO data buffer for either a SETUP or DATA stage */ +      for (ucFifoIndex = 0; ucFifoIndex < ulRxBytes; ucFifoIndex++) +	{ +	  pxMessage->ucFifoData[ucFifoIndex] = +	    AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_0]; +	} + +      /* Set direction for data stage.  Must be done before RXSETUP is  +         cleared. */ +      if ((AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RXSETUP)) +	{ +	  if (ulRxBytes +	      && (pxMessage->ucFifoData[usbREQUEST_TYPE_INDEX] & 0x80)) +	    { +	      AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] |= AT91C_UDP_DIR; + +	      /* Might not be wise in an ISR! */ +	      while (! +		     (AT91C_BASE_UDP-> +		      UDP_CSR[usbEND_POINT_0] & AT91C_UDP_DIR)); +	    } + +	  /* Clear RXSETUP */ +	  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= ~AT91C_UDP_RXSETUP; + +	  /* Might not be wise in an ISR! */ +	  while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RXSETUP); +	} +      else +	{ +	  /* Clear RX_DATA_BK0 */ +	  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= ~AT91C_UDP_RX_DATA_BK0; + +	  /* Might not be wise in an ISR! */ +	  while (AT91C_BASE_UDP-> +		 UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RX_DATA_BK0); +	} +    } + +  /* If we received data on endpoint 1, disable its interrupts until it is  +     processed in the main loop */ +  if (AT91C_BASE_UDP-> +      UDP_CSR[usbEND_POINT_1] & (AT91C_UDP_RX_DATA_BK0 | +				 AT91C_UDP_RX_DATA_BK1)) +    { +      AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_EPINT1; +    } + +  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= +    ~(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT); + +  /* Clear interrupts for the other endpoints, retain data flags for endpoint  +     1. */ +  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] &= +    ~(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP); +  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] &= ~usbINT_CLEAR_MASK; +  AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3] &= ~usbINT_CLEAR_MASK; + +  /* Post ISR data to queue for task-level processing */ +  cTaskWokenByPost = +    xQueueSendFromISR (xUSBInterruptQueue, &pxMessage, cTaskWokenByPost); + +  /* Clear AIC to complete ISR processing */ +  AT91C_BASE_AIC->AIC_EOICR = 0; + +  /* Do a task switch if needed */ +portEXIT_SWITCHING_ISR (cTaskWokenByPost)} diff --git a/openpicc/os/usb/descriptors.h b/openpicc/os/usb/descriptors.h new file mode 100644 index 0000000..230122f --- /dev/null +++ b/openpicc/os/usb/descriptors.h @@ -0,0 +1,190 @@ +/* +	FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + +	This file is part of the FreeRTOS.org distribution. + +	FreeRTOS.org is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	FreeRTOS.org is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with FreeRTOS.org; if not, write to the Free Software +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +	A special exception to the GPL can be applied should you wish to distribute +	a combined work that includes FreeRTOS.org, without being obliged to provide +	the source code for any proprietary components.  See the licensing section +	of http://www.FreeRTOS.org for full details of how and when the exception +	can be applied. + +	*************************************************************************** +	See http://www.FreeRTOS.org for documentation, latest information, license +	and contact details.  Please ensure to read the configuration and relevant +	port sections of the online documentation. + +	Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along +	with commercial development and support options. +	*************************************************************************** +*/ + +/* +	- DESCRIPTOR DEFINITIONS - +*/ + +/* String descriptors used during the enumeration process. +These take the form: + +{ +	Length of descriptor, +	Descriptor type, +	Data +} +*/ + +const portCHAR pxLanguageStringDescriptor[] = { +  4, +  usbDESCRIPTOR_TYPE_STRING, +  0x09, 0x04 +}; + +const portCHAR pxManufacturerStringDescriptor[] = { +  28, +  usbDESCRIPTOR_TYPE_STRING, + +  'b', 0x00, 'i', 0x00, 't', 0x00, 'm', 0x00, +  'a', 0x00, 'n', 0x00, 'u', 0x00, 'f', 0x00, +  'a', 0x00, 'k', 0x00, 't', 0x00, 'u', 0x00, +  'r', 0x00 +}; + +const portCHAR pxProductStringDescriptor[] = { +  44, +  usbDESCRIPTOR_TYPE_STRING, +   +  'O', 0x00, 'p', 0x00, 'e', 0x00, 'n', 0x00, +  'B', 0x00, 'e', 0x00, 'a', 0x00, 'c', 0x00, +  'o', 0x00, 'n', 0x00, ' ', 0x00, 'U', 0x00, +  'S', 0x00, 'B', 0x00, ' ', 0x00, '2', 0x00, +  '.', 0x00, '4', 0x00, 'G', 0x00, 'H', 0x00, +  'z', 0x00 +}; + +/* Device should properly be 0x134A:0x9001, using 0x05F9:0xFFFF for Linux testing */ +const char pxDeviceDescriptor[] = { +  /* Device descriptor */ +  0x12,				/* bLength                      */ +  0x01,				/* bDescriptorType              */ +  0x10, 0x01,			/* bcdUSBL                      */ +  0x02,				/* bDeviceClass:                */ +  0x00,				/* bDeviceSubclass:             */ +  0x00,				/* bDeviceProtocol:             */ +  0x08,				/* bMaxPacketSize0              */ +  0xC0, 0x16,			/* idVendorL                    */ +  0xAC, 0x08,			/* idProductL                   */ +  0x10, 0x01,			/* bcdDeviceL                   */ +  usbMANUFACTURER_STRING,	/* iManufacturer                */ +  usbPRODUCT_STRING,		/* iProduct                     */ +  0x00,				/* SerialNumber                 */ +  0x01				/* bNumConfigs                  */ +}; + +const char pxConfigDescriptor[] = { + +  /* Configuration 1 descriptor +     Here we define two interfaces (0 and 1) and a total of 3 endpoints. +     Interface 0 is a CDC Abstract Control Model interface with one interrupt-in endpoint. +     Interface 1 is a CDC Data Interface class, with a bulk-in and bulk-out endpoint. +     Endpoint 0 gets used as the CDC management element. +   */ +  0x09,				/* CbLength                                                             */ +  0x02,				/* CbDescriptorType                                             */ +  0x43, 0x00,			/* CwTotalLength 2 EP + Control         ?       */ +  0x02,				/* CbNumInterfaces                                              */ +  0x01,				/* CbConfigurationValue                                 */ +  0x00,				/* CiConfiguration                                      */ +  usbBUS_POWERED,		/* CbmAttributes Bus powered + Remote Wakeup */ +  0x32,				/* CMaxPower: 100mA                                             */ + +  /* Communication Class Interface Descriptor Requirement         */ +  0x09,				/* bLength                                                              */ +  0x04,				/* bDescriptorType                                              */ +  0x00,				/* bInterfaceNumber                                             */ +  0x00,				/* bAlternateSetting                                    */ +  0x01,				/* bNumEndpoints                                                */ +  0x02,				/* bInterfaceClass: Comm Interface Class */ +  0x02,				/* bInterfaceSubclass: Abstract Control Model */ +  0x01,				/* bInterfaceProtocol                                   */ +  usbINTERFACE_STRING,		/* iInterface                                                       */ + +  /* Header Functional Descriptor                                                         */ +  0x05,				/* bLength                                                              */ +  0x24,				/* bDescriptor type: CS_INTERFACE               */ +  0x00,				/* bDescriptor subtype: Header Func Desc */ +  0x10, 0x01,			/* bcdCDC:1.1                                                   */ + +  /* ACM Functional Descriptor                                                            */ +  0x04,				/* bFunctionLength                                              */ +  0x24,				/* bDescriptor type: CS_INTERFACE               */ +  0x02,				/* bDescriptor subtype: ACM Func Desc   */ +  0x00,				/* bmCapabilities: We don't support squat */ + +  /* Union Functional Descriptor                                                          */ +  0x05,				/* bFunctionLength                                              */ +  0x24,				/* bDescriptor type: CS_INTERFACE               */ +  0x06,				/* bDescriptor subtype: Union Func Desc */ +  0x00,				/* bMasterInterface: CDC Interface              */ +  0x01,				/* bSlaveInterface0: Data Class Interface */ + +  /* Call Management Functional Descriptor +     0 in D1 and D0 indicates that device does not handle call management */ +  0x05,				/* bFunctionLength                                              */ +  0x24,				/* bDescriptor type: CS_INTERFACE               */ +  0x01,				/* bDescriptor subtype: Call Management Func */ +  0x00,				/* bmCapabilities: D1 + D0                              */ +  0x01,				/* bDataInterface: Data Class Interface 1 */ + +  /* CDC Control - Endpoint 3 descriptor +     This endpoint serves as a notification element.                              */ + +  0x07,				/* bLength                                                              */ +  0x05,				/* bDescriptorType                                              */ +  0x83,				/* bEndpointAddress, Endpoint 03 - IN   */ +  0x03,				/* bmAttributes   INT                                   */ +  0x08, 0x00,			/* wMaxPacketSize: 8 bytes                              */ +  0xFF,				/* bInterval                                                    */ + +  /* Data Class Interface Descriptor Requirement                          */ +  0x09,				/* bLength                                                              */ +  0x04,				/* bDescriptorType                                              */ +  0x01,				/* bInterfaceNumber                                             */ +  0x00,				/* bAlternateSetting                                    */ +  0x02,				/* bNumEndPoints                                                */ +  0x0A,				/* bInterfaceClass                                              */ +  0x00,				/* bInterfaceSubclass                                   */ +  0x00,				/* bInterfaceProtocol                                   */ +  0x00,				/* iInterface                                                   */ + +  /* CDC Data - Endpoint 1 descriptor */ +  0x07,				/* bLenght                                                              */ +  0x05,				/* bDescriptorType                                              */ +  0x01,				/* bEndPointAddress, Endpoint 01 - OUT  */ +  0x02,				/* bmAttributes BULK                                    */ +  64,				/* wMaxPacketSize                                               */ +  0x00, +  0x00,				/* bInterval                                                    */ + +  /* CDC Data - Endpoint 2 descriptor */ +  0x07,				/* bLength                                                              */ +  0x05,				/* bDescriptorType                                              */ +  0x82,				/* bEndPointAddress, Endpoint 02 - IN   */ +  0x02,				/* bmAttributes BULK                                    */ +  64,				/* wMaxPacketSize                                               */ +  0x00, +  0x00				/* bInterval                                                    */ +}; diff --git a/openpicc/os/usb/usb.h b/openpicc/os/usb/usb.h new file mode 100644 index 0000000..86d98f9 --- /dev/null +++ b/openpicc/os/usb/usb.h @@ -0,0 +1,146 @@ +/* +	FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + +	This file is part of the FreeRTOS.org distribution. + +	FreeRTOS.org is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	FreeRTOS.org is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with FreeRTOS.org; if not, write to the Free Software +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +	A special exception to the GPL can be applied should you wish to distribute +	a combined work that includes FreeRTOS.org, without being obliged to provide +	the source code for any proprietary components.  See the licensing section +	of http://www.FreeRTOS.org for full details of how and when the exception +	can be applied. + +	*************************************************************************** +	See http://www.FreeRTOS.org for documentation, latest information, license +	and contact details.  Please ensure to read the configuration and relevant +	port sections of the online documentation. + +	Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along +	with commercial development and support options. +	*************************************************************************** +*/ + +/* Descriptor type definitions. */ +#define usbDESCRIPTOR_TYPE_DEVICE			( 0x01 ) +#define usbDESCRIPTOR_TYPE_CONFIGURATION		( 0x02 ) +#define usbDESCRIPTOR_TYPE_STRING			( 0x03 ) + +/* USB request type definitions. */ +#define usbGET_REPORT_REQUEST				( 0x01 ) +#define usbGET_IDLE_REQUEST				( 0x02 ) +#define usbGET_PROTOCOL_REQUEST				( 0x03 ) +#define usbSET_REPORT_REQUEST				( 0x09 ) +#define usbSET_IDLE_REQUEST				( 0x0A ) +#define usbSET_PROTOCOL_REQUEST				( 0x0B ) +#define usbGET_CONFIGURATION_REQUEST			( 0x08 ) +#define usbGET_STATUS_REQUEST				( 0x00 ) +#define usbCLEAR_FEATURE_REQUEST			( 0x01 ) +#define usbSET_FEATURE_REQUEST				( 0x03 ) +#define usbSET_ADDRESS_REQUEST				( 0x05 ) +#define usbGET_DESCRIPTOR_REQUEST			( 0x06 ) +#define usbSET_CONFIGURATION_REQUEST			( 0x09 ) +#define usbGET_INTERFACE_REQUEST			( 0x0A ) +#define usbSET_INTERFACE_REQUEST			( 0x0B ) + +/* ACM Requests */ +#define usbSEND_ENCAPSULATED_COMMAND			( 0x00 ) +#define usbGET_ENCAPSULATED_RESPONSE			( 0x01 ) +#define usbSET_LINE_CODING				( 0x20 ) +#define usbGET_LINE_CODING				( 0x21 ) +#define usbSET_CONTROL_LINE_STATE			( 0x22 ) + +/* Misc USB definitions. */ +#define usbDEVICE_CLASS_VENDOR_SPECIFIC			( 0xFF ) +#define usbBUS_POWERED					( 0x80 ) +#define usbHID_REPORT_DESCRIPTOR			( 0x22 ) +#define AT91C_UDP_TRANSCEIVER_ENABLE		( *( ( unsigned long * ) 0xfffb0074 ) ) + +/* Index to the various string. */ +#define usbLANGUAGE_STRING				( 0 ) +#define usbMANUFACTURER_STRING				( 1 ) +#define usbPRODUCT_STRING				( 2 ) +#define usbCONFIGURATION_STRING				( 3 ) +#define usbINTERFACE_STRING				( 4 ) + +/* Defines fields of standard SETUP request.  Now in normal order. */ +#define usbREQUEST_TYPE_INDEX				( 0 ) +#define usbREQUEST_INDEX				( 1 ) +#define usbVALUE_HIGH_BYTE				( 3 ) +#define usbVALUE_LOW_BYTE				( 2 ) +#define usbINDEX_HIGH_BYTE				( 5 ) +#define usbINDEX_LOW_BYTE				( 4 ) +#define usbLENGTH_HIGH_BYTE				( 7 ) +#define usbLENGTH_LOW_BYTE				( 6 ) + +/* Misc application definitions. */ +#define usbINTERRUPT_PRIORITY				( 3 ) +#define usbQUEUE_LENGTH					( 0x3 )	/* Must have all bits set! */ +#define usbFIFO_LENGTH					( ( unsigned portLONG ) 8 ) +#define usbEND_POINT_0					( 0 ) +#define usbEND_POINT_1					( 1 ) +#define usbEND_POINT_2					( 2 ) +#define usbEND_POINT_3					( 3 ) +#define usbMAX_CONTROL_MESSAGE_SIZE			( 128 ) +#define usbRX_COUNT_MASK				( ( unsigned portLONG ) 0x7ff ) +#define usbSHORTEST_DELAY				( ( portTickType ) 1 ) +#define usbINIT_DELAY					( ( portTickType ) 1000 / portTICK_RATE_MS ) +#define usbSHORT_DELAY					( ( portTickType ) 50 / portTICK_RATE_MS ) +#define usbEND_POINT_RESET_MASK				( ( unsigned portLONG ) 0x0f ) +#define usbDATA_INC					( ( portCHAR ) 5 ) +#define usbEXPECTED_NUMBER_OF_BYTES			( ( unsigned portLONG ) 8 ) + +/* Control request types. */ +#define usbSTANDARD_DEVICE_REQUEST			( 0 ) +#define usbSTANDARD_INTERFACE_REQUEST			( 1 ) +#define usbSTANDARD_END_POINT_REQUEST			( 2 ) +#define usbCLASS_INTERFACE_REQUEST			( 5 ) + + +/* Macros to manipulate the control and status registers.  These registers  +cannot be accessed using a direct read modify write operation outside of the  +ISR as some bits are left unchanged by writing with a 0, and some are left  +unchanged by writing with a 1. */ + + +#define usbCSR_SET_BIT( pulValueNow, ulBit )											\ +{																						\ +	/* Set TXCOMP, RX_DATA_BK0, RXSETUP, */												\ +	/* STALLSENT and RX_DATA_BK1 to 1 so the */											\ +	/* write has no effect. */															\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f;		\ +																						\ +	/* Clear the FORCE_STALL and TXPKTRDY bits */										\ +	/* so the write has no effect. */													\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf;	\ +																						\ +	/* Set whichever bit we want set. */												\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( ulBit );							\ +} + +#define usbCSR_CLEAR_BIT( pulValueNow, ulBit )											\ +{																						\ +	/* Set TXCOMP, RX_DATA_BK0, RXSETUP, */												\ +	/* STALLSENT and RX_DATA_BK1 to 1 so the */											\ +	/* write has no effect. */															\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f;		\ +																						\ +	/* Clear the FORCE_STALL and TXPKTRDY bits */										\ +	/* so the write has no effect. */													\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf;	\ +																						\ +	/* Clear whichever bit we want clear. */											\ +	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( ~ulBit );						\ +}  | 
