changing circuitry to disable RTC, update initialization to match
[fw/openalt] / usb / usbcontrol.c
1 /** @file
2   Control transfer handler.
3   
4   This module handles control transfers and is normally installed on the
5   endpoint 0 callback.
6   
7   Control transfers can be of the following type:
8   0 Standard;
9   1 Class;
10   2 Vendor;
11   3 Reserved.
12
13   A callback can be installed for each of these control transfers using
14   USBRegisterRequestHandler.
15   When an OUT request arrives, data is collected in the data store provided
16   with the usbRegisterRequestHandler call. When the transfer is done, the
17   callback is called.
18   When an IN request arrives, the callback is called immediately to either
19   put the control transfer data in the data store, or to get a pointer to
20   control transfer data. The data is then packetised and sent to the host.
21 */
22
23 #include "FreeRTOS.h"
24
25 #include "usbstruct.h"
26 #include "usbapi.h"
27
28 //
29 //
30 //
31 #define MAX_CONTROL_SIZE  128 /**< maximum total size of control transfer data */
32 #define MAX_REQ_HANDLERS  4   /**< standard, class, vendor, reserved */
33
34 static TSetupPacket Setup;    /**< setup packet */
35
36 static U8  *pbData;   /**< pointer to data buffer */
37 static int iResidue;  /**< remaining bytes in buffer */
38 static int iLen;      /**< total length of control transfer */
39
40 static TFnHandleRequest *apfnReqHandlers [4] = { NULL, NULL, NULL, NULL };  // Array of installed request handler callbacks
41 static U8 *apbDataStore [4] = { NULL, NULL, NULL, NULL };                   // Array of installed request data pointers */
42
43 //
44 //  Local function to handle a request by calling one of the installed
45 //  request handlers.
46     
47 //  In case of data going from host to device, the data is at *ppbData.
48 //  In case of data going from device to host, the handler can either
49 //  choose to write its data at *ppbData or update the data pointer.
50 //
51 static BOOL _HandleRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
52 {
53   TFnHandleRequest *pfnHandler;
54   int iType;
55   
56   iType = REQTYPE_GET_TYPE (pSetup->bmRequestType);
57   pfnHandler = apfnReqHandlers [iType];
58
59   if (pfnHandler == NULL)
60     return FALSE;
61
62   return pfnHandler (pSetup, piLen, ppbData);
63 }
64
65 //
66 //  Local function to stall the control endpoint
67 //
68 static void usbStallControlPipe (U8 bEPStat __attribute__ ((unused)))
69 {
70   usbHardwareEndpointStall (0x80, TRUE);
71 }
72
73 //
74 //  Sends next chunk of data (possibly 0 bytes) to host
75 //
76 static void usbDataIn (void)
77 {
78   int iChunk;
79
80   iChunk = MIN (MAX_PACKET_SIZE0, iResidue);
81   usbHardwareEndpointWrite (0x80, pbData, iChunk);
82   pbData += iChunk;
83   iResidue -= iChunk;
84 }
85
86 //
87 //  Handles IN/OUT transfers on EP0
88 //
89 int usbHandleControlTransfer (U8 bEP, U8 bEPStat)
90 {
91   int iChunk;
92   int iType;
93
94   //
95   //  OUT transfer
96   //
97   if (bEP == 0x00) 
98   {
99     if (bEPStat & EP_STATUS_SETUP) 
100     {
101       //
102       //  Setup packet, reset request message state machine
103       //
104       usbHardwareEndpointRead (0x00, (U8 *) &Setup, sizeof (Setup));
105
106       //
107       //  Defaults for data pointer and residue
108       //
109       iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
110       pbData = apbDataStore [iType];
111       iResidue = Setup.wLength;
112       iLen = Setup.wLength;
113
114       if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) 
115       {
116         if (!_HandleRequest (&Setup, &iLen, &pbData)) 
117         {
118           usbStallControlPipe (bEPStat);
119           return pdFALSE;
120         }
121
122         iResidue = MIN (iLen, Setup.wLength);
123         usbDataIn ();
124       }
125     }
126     else 
127     {    
128       if (iResidue > 0) 
129       {
130         iChunk = usbHardwareEndpointRead (0x00, pbData, iResidue);
131
132         if (iChunk < 0) 
133         {
134           usbStallControlPipe (bEPStat);
135           return pdFALSE;
136         }
137
138         pbData += iChunk;
139         iResidue -= iChunk;
140
141         if (iResidue == 0) 
142         {
143           iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
144           pbData = apbDataStore [iType];
145
146           if (!_HandleRequest (&Setup, &iLen, &pbData)) 
147           {
148             usbStallControlPipe (bEPStat);
149             return pdFALSE;
150           }
151
152           usbDataIn ();
153         }
154       }
155       else 
156         iChunk = usbHardwareEndpointRead (0x00, NULL, 0);
157     }
158   }
159   else if (bEP == 0x80) 
160     usbDataIn ();
161
162   return pdFALSE;
163 }
164
165
166 //
167 //  Registers a callback for handling requests
168 //
169 void usbRegisterRequestHandler (int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore)
170 {
171   apfnReqHandlers [iType] = pfnHandler;
172   apbDataStore [iType] = pbDataStore;
173 }