]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LPC1768_IAR/LPCUSB/usbstdreq.c
Comment the new MicroBlaze port layer files.
[freertos] / Demo / CORTEX_LPC1768_IAR / LPCUSB / usbstdreq.c
1 /*\r
2         LPCUSB, an USB device driver for LPC microcontrollers   \r
3         Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)\r
4 \r
5         Redistribution and use in source and binary forms, with or without\r
6         modification, are permitted provided that the following conditions are met:\r
7 \r
8         1. Redistributions of source code must retain the above copyright\r
9            notice, this list of conditions and the following disclaimer.\r
10         2. Redistributions in binary form must reproduce the above copyright\r
11            notice, this list of conditions and the following disclaimer in the\r
12            documentation and/or other materials provided with the distribution.\r
13         3. The name of the author may not be used to endorse or promote products\r
14            derived from this software without specific prior written permission.\r
15 \r
16         THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
17         IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
18         OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
19         IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, \r
20         INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
21         NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
22         DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
23         THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
24         (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
25         THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
26 */\r
27 \r
28 \r
29 /** @file\r
30         Standard request handler.\r
31         \r
32         This modules handles the 'chapter 9' processing, specifically the\r
33         standard device requests in table 9-3 from the universal serial bus\r
34         specification revision 2.0\r
35         \r
36         Specific types of devices may specify additional requests (for example\r
37         HID devices add a GET_DESCRIPTOR request for interfaces), but they\r
38         will not be part of this module.\r
39 \r
40         @todo some requests have to return a request error if device not configured:\r
41         @todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME\r
42         @todo this applies to the following if endpoint != 0:\r
43         @todo SET_FEATURE, GET_FEATURE \r
44 */\r
45 \r
46 #include "usbdebug.h"\r
47 #include "usbstruct.h"\r
48 #include "usbapi.h"\r
49 \r
50 #define MAX_DESC_HANDLERS       4               /**< device, interface, endpoint, other */\r
51 \r
52 \r
53 /* general descriptor field offsets */\r
54 #define DESC_bLength                                    0       /**< length offset */\r
55 #define DESC_bDescriptorType                    1       /**< descriptor type offset */  \r
56 \r
57 /* config descriptor field offsets */\r
58 #define CONF_DESC_wTotalLength                  2       /**< total length offset */\r
59 #define CONF_DESC_bConfigurationValue   5       /**< configuration value offset */      \r
60 #define CONF_DESC_bmAttributes                  7       /**< configuration characteristics */\r
61 \r
62 /* interface descriptor field offsets */\r
63 #define INTF_DESC_bAlternateSetting             3       /**< alternate setting offset */\r
64 \r
65 /* endpoint descriptor field offsets */\r
66 #define ENDP_DESC_bEndpointAddress              2       /**< endpoint address offset */\r
67 #define ENDP_DESC_wMaxPacketSize                4       /**< maximum packet size offset */\r
68 \r
69 \r
70 /** Currently selected configuration */\r
71 static unsigned char                            bConfiguration = 0;\r
72 /** Installed custom request handler */\r
73 static TFnHandleRequest *pfnHandleCustomReq = NULL;\r
74 /** Pointer to registered descriptors */\r
75 static const unsigned char                      *pabDescrip = NULL;\r
76 \r
77 \r
78 /**\r
79         Registers a pointer to a descriptor block containing all descriptors\r
80         for the device.\r
81 \r
82         @param [in]     pabDescriptors  The descriptor byte array\r
83  */\r
84 void USBRegisterDescriptors(const unsigned char *pabDescriptors)\r
85 {\r
86         pabDescrip = pabDescriptors;\r
87 }\r
88 \r
89 \r
90 /**\r
91         Parses the list of installed USB descriptors and attempts to find\r
92         the specified USB descriptor.\r
93                 \r
94         @param [in]             wTypeIndex      Type and index of the descriptor\r
95         @param [in]             wLangID         Language ID of the descriptor (currently unused)\r
96         @param [out]    *piLen          Descriptor length\r
97         @param [out]    *ppbData        Descriptor data\r
98         \r
99         @return TRUE if the descriptor was found, FALSE otherwise\r
100  */\r
101 BOOL USBGetDescriptor(unsigned short wTypeIndex, unsigned short wLangID, int *piLen, unsigned char **ppbData)\r
102 {\r
103         unsigned char   bType, bIndex;\r
104         unsigned char   *pab;\r
105         int iCurIndex;\r
106         \r
107         ASSERT(pabDescrip != NULL);\r
108 \r
109         bType = GET_DESC_TYPE(wTypeIndex);\r
110         bIndex = GET_DESC_INDEX(wTypeIndex);\r
111         \r
112         pab = (unsigned char *)pabDescrip;\r
113         iCurIndex = 0;\r
114         \r
115         while (pab[DESC_bLength] != 0) {\r
116                 if (pab[DESC_bDescriptorType] == bType) {\r
117                         if (iCurIndex == bIndex) {\r
118                                 // set data pointer\r
119                                 *ppbData = pab;\r
120                                 // get length from structure\r
121                                 if (bType == DESC_CONFIGURATION) {\r
122                                         // configuration descriptor is an exception, length is at offset 2 and 3\r
123                                         *piLen =        (pab[CONF_DESC_wTotalLength]) |\r
124                                                                 (pab[CONF_DESC_wTotalLength + 1] << 8);\r
125                                 }\r
126                                 else {\r
127                                         // normally length is at offset 0\r
128                                         *piLen = pab[DESC_bLength];\r
129                                 }\r
130                                 return TRUE;\r
131                         }\r
132                         iCurIndex++;\r
133                 }\r
134                 // skip to next descriptor\r
135                 pab += pab[DESC_bLength];\r
136         }\r
137         // nothing found\r
138         DBG("Desc %x not found!\n", wTypeIndex);\r
139         return FALSE;\r
140 }\r
141 \r
142 \r
143 /**\r
144         Configures the device according to the specified configuration index and\r
145         alternate setting by parsing the installed USB descriptor list.\r
146         A configuration index of 0 unconfigures the device.\r
147                 \r
148         @param [in]             bConfigIndex    Configuration index\r
149         @param [in]             bAltSetting             Alternate setting number\r
150         \r
151         @todo function always returns TRUE, add stricter checking?\r
152         \r
153         @return TRUE if successfully configured, FALSE otherwise\r
154  */\r
155 static BOOL USBSetConfiguration(unsigned char bConfigIndex, unsigned char bAltSetting)\r
156 {\r
157         unsigned char   *pab;\r
158         unsigned char   bCurConfig, bCurAltSetting;\r
159         unsigned char   bEP;\r
160         unsigned short  wMaxPktSize;\r
161         \r
162         ASSERT(pabDescrip != NULL);\r
163 \r
164         if (bConfigIndex == 0) {\r
165                 // unconfigure device\r
166                 USBHwConfigDevice(FALSE);\r
167         }\r
168         else {\r
169                 // configure endpoints for this configuration/altsetting\r
170                 pab = (unsigned char *)pabDescrip;\r
171                 bCurConfig = 0xFF;\r
172                 bCurAltSetting = 0xFF;\r
173 \r
174                 while (pab[DESC_bLength] != 0) {\r
175 \r
176                         switch (pab[DESC_bDescriptorType]) {\r
177 \r
178                         case DESC_CONFIGURATION:\r
179                                 // remember current configuration index\r
180                                 bCurConfig = pab[CONF_DESC_bConfigurationValue];\r
181                                 break;\r
182 \r
183                         case DESC_INTERFACE:\r
184                                 // remember current alternate setting\r
185                                 bCurAltSetting = pab[INTF_DESC_bAlternateSetting];\r
186                                 break;\r
187 \r
188                         case DESC_ENDPOINT:\r
189                                 if ((bCurConfig == bConfigIndex) &&\r
190                                         (bCurAltSetting == bAltSetting)) {\r
191                                         // endpoint found for desired config and alternate setting\r
192                                         bEP = pab[ENDP_DESC_bEndpointAddress];\r
193                                         wMaxPktSize =   (pab[ENDP_DESC_wMaxPacketSize]) |\r
194                                                                         (pab[ENDP_DESC_wMaxPacketSize + 1] << 8);\r
195                                         // configure endpoint\r
196                                         USBHwEPConfig(bEP, wMaxPktSize);\r
197                                 }\r
198                                 break;\r
199 \r
200                         default:\r
201                                 break;\r
202                         }\r
203                         // skip to next descriptor\r
204                         pab += pab[DESC_bLength];\r
205                 }\r
206                 \r
207                 // configure device\r
208                 USBHwConfigDevice(TRUE);\r
209         }\r
210 \r
211         return TRUE;\r
212 }\r
213 \r
214 \r
215 /**\r
216         Local function to handle a standard device request\r
217                 \r
218         @param [in]             pSetup          The setup packet\r
219         @param [in,out] *piLen          Pointer to data length\r
220         @param [in,out] ppbData         Data buffer.\r
221 \r
222         @return TRUE if the request was handled successfully\r
223  */\r
224 static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)\r
225 {\r
226         unsigned char   *pbData = *ppbData;\r
227 \r
228         switch (pSetup->bRequest) {\r
229         \r
230         case REQ_GET_STATUS:\r
231                 // bit 0: self-powered\r
232                 // bit 1: remote wakeup = not supported\r
233                 pbData[0] = 0;\r
234                 pbData[1] = 0;\r
235                 *piLen = 2;\r
236                 break;\r
237                 \r
238         case REQ_SET_ADDRESS:\r
239                 USBHwSetAddress(pSetup->wValue);\r
240                 break;\r
241 \r
242         case REQ_GET_DESCRIPTOR:\r
243                 DBG("D%x", pSetup->wValue);\r
244                 return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);\r
245 \r
246         case REQ_GET_CONFIGURATION:\r
247                 // indicate if we are configured\r
248                 pbData[0] = bConfiguration;\r
249                 *piLen = 1;\r
250                 break;\r
251 \r
252         case REQ_SET_CONFIGURATION:\r
253                 if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {\r
254                         DBG("USBSetConfiguration failed!\n");\r
255                         return FALSE;\r
256                 }\r
257                 // configuration successful, update current configuration\r
258                 bConfiguration = pSetup->wValue & 0xFF; \r
259                 break;\r
260 \r
261         case REQ_CLEAR_FEATURE:\r
262         case REQ_SET_FEATURE:\r
263                 if (pSetup->wValue == FEA_REMOTE_WAKEUP) {\r
264                         // put DEVICE_REMOTE_WAKEUP code here\r
265                 }\r
266                 if (pSetup->wValue == FEA_TEST_MODE) {\r
267                         // put TEST_MODE code here\r
268                 }\r
269                 return FALSE;\r
270 \r
271         case REQ_SET_DESCRIPTOR:\r
272                 DBG("Device req %d not implemented\n", pSetup->bRequest);\r
273                 return FALSE;\r
274 \r
275         default:\r
276                 DBG("Illegal device req %d\n", pSetup->bRequest);\r
277                 return FALSE;\r
278         }\r
279         \r
280         return TRUE;\r
281 }\r
282 \r
283 \r
284 /**\r
285         Local function to handle a standard interface request\r
286                 \r
287         @param [in]             pSetup          The setup packet\r
288         @param [in,out] *piLen          Pointer to data length\r
289         @param [in]             ppbData         Data buffer.\r
290 \r
291         @return TRUE if the request was handled successfully\r
292  */\r
293 static BOOL HandleStdInterfaceReq(TSetupPacket  *pSetup, int *piLen, unsigned char **ppbData)\r
294 {\r
295         unsigned char   *pbData = *ppbData;\r
296 \r
297         switch (pSetup->bRequest) {\r
298 \r
299         case REQ_GET_STATUS:\r
300                 // no bits specified\r
301                 pbData[0] = 0;\r
302                 pbData[1] = 0;\r
303                 *piLen = 2;\r
304                 break;\r
305 \r
306         case REQ_CLEAR_FEATURE:\r
307         case REQ_SET_FEATURE:\r
308                 // not defined for interface\r
309                 return FALSE;\r
310         \r
311         case REQ_GET_INTERFACE: // TODO use bNumInterfaces\r
312         // there is only one interface, return n-1 (= 0)\r
313                 pbData[0] = 0;\r
314                 *piLen = 1;\r
315                 break;\r
316         \r
317         case REQ_SET_INTERFACE: // TODO use bNumInterfaces\r
318                 // there is only one interface (= 0)\r
319                 if (pSetup->wValue != 0) {\r
320                         return FALSE;\r
321                 }\r
322                 *piLen = 0;\r
323                 break;\r
324 \r
325         default:\r
326                 DBG("Illegal interface req %d\n", pSetup->bRequest);\r
327                 return FALSE;\r
328         }\r
329 \r
330         return TRUE;\r
331 }\r
332 \r
333 \r
334 /**\r
335         Local function to handle a standard endpoint request\r
336                 \r
337         @param [in]             pSetup          The setup packet\r
338         @param [in,out] *piLen          Pointer to data length\r
339         @param [in]             ppbData         Data buffer.\r
340 \r
341         @return TRUE if the request was handled successfully\r
342  */\r
343 static BOOL HandleStdEndPointReq(TSetupPacket   *pSetup, int *piLen, unsigned char **ppbData)\r
344 {\r
345         unsigned char   *pbData = *ppbData;\r
346 \r
347         switch (pSetup->bRequest) {\r
348         case REQ_GET_STATUS:\r
349                 // bit 0 = endpointed halted or not\r
350                 pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0;\r
351                 pbData[1] = 0;\r
352                 *piLen = 2;\r
353                 break;\r
354                 \r
355         case REQ_CLEAR_FEATURE:\r
356                 if (pSetup->wValue == FEA_ENDPOINT_HALT) {\r
357                         // clear HALT by unstalling\r
358                         USBHwEPStall(pSetup->wIndex, FALSE);\r
359                         break;\r
360                 }\r
361                 // only ENDPOINT_HALT defined for endpoints\r
362                 return FALSE;\r
363         \r
364         case REQ_SET_FEATURE:\r
365                 if (pSetup->wValue == FEA_ENDPOINT_HALT) {\r
366                         // set HALT by stalling\r
367                         USBHwEPStall(pSetup->wIndex, TRUE);\r
368                         break;\r
369                 }\r
370                 // only ENDPOINT_HALT defined for endpoints\r
371                 return FALSE;\r
372 \r
373         case REQ_SYNCH_FRAME:\r
374                 DBG("EP req %d not implemented\n", pSetup->bRequest);\r
375                 return FALSE;\r
376 \r
377         default:\r
378                 DBG("Illegal EP req %d\n", pSetup->bRequest);\r
379                 return FALSE;\r
380         }\r
381         \r
382         return TRUE;\r
383 }\r
384 \r
385 \r
386 /**\r
387         Default handler for standard ('chapter 9') requests\r
388         \r
389         If a custom request handler was installed, this handler is called first.\r
390                 \r
391         @param [in]             pSetup          The setup packet\r
392         @param [in,out] *piLen          Pointer to data length\r
393         @param [in]             ppbData         Data buffer.\r
394 \r
395         @return TRUE if the request was handled successfully\r
396  */\r
397 BOOL USBHandleStandardRequest(TSetupPacket      *pSetup, int *piLen, unsigned char **ppbData)\r
398 {\r
399         // try the custom request handler first\r
400         if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {\r
401                 return TRUE;\r
402         }\r
403         \r
404         switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {\r
405         case REQTYPE_RECIP_DEVICE:              return HandleStdDeviceReq(pSetup, piLen, ppbData);\r
406         case REQTYPE_RECIP_INTERFACE:   return HandleStdInterfaceReq(pSetup, piLen, ppbData);\r
407         case REQTYPE_RECIP_ENDPOINT:    return HandleStdEndPointReq(pSetup, piLen, ppbData);\r
408         default:                                                return FALSE;\r
409         }\r
410 }\r
411 \r
412 \r
413 /**\r
414         Registers a callback for custom device requests\r
415         \r
416         In USBHandleStandardRequest, the custom request handler gets a first\r
417         chance at handling the request before it is handed over to the 'chapter 9'\r
418         request handler.\r
419         \r
420         This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR\r
421         request is sent to an interface, which is not covered by the 'chapter 9'\r
422         specification.\r
423                 \r
424         @param [in]     pfnHandler      Callback function pointer\r
425  */\r
426 void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)\r
427 {\r
428         pfnHandleCustomReq = pfnHandler;\r
429 }\r
430 \r