]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c
Add Full build configuration to the Kinetis demo. Still a work in progress.
[freertos] / Demo / CORTEX_LPC1768_GCC_Rowley / 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         ( void ) wLangID;\r
108         ASSERT(pabDescrip != NULL);\r
109 \r
110         bType = GET_DESC_TYPE(wTypeIndex);\r
111         bIndex = GET_DESC_INDEX(wTypeIndex);\r
112 \r
113         pab = (unsigned char *)pabDescrip;\r
114         iCurIndex = 0;\r
115 \r
116         while (pab[DESC_bLength] != 0) {\r
117                 if (pab[DESC_bDescriptorType] == bType) {\r
118                         if (iCurIndex == bIndex) {\r
119                                 // set data pointer\r
120                                 *ppbData = pab;\r
121                                 // get length from structure\r
122                                 if (bType == DESC_CONFIGURATION) {\r
123                                         // configuration descriptor is an exception, length is at offset 2 and 3\r
124                                         *piLen =        (pab[CONF_DESC_wTotalLength]) |\r
125                                                                 (pab[CONF_DESC_wTotalLength + 1] << 8);\r
126                                 }\r
127                                 else {\r
128                                         // normally length is at offset 0\r
129                                         *piLen = pab[DESC_bLength];\r
130                                 }\r
131                                 return TRUE;\r
132                         }\r
133                         iCurIndex++;\r
134                 }\r
135                 // skip to next descriptor\r
136                 pab += pab[DESC_bLength];\r
137         }\r
138         // nothing found\r
139         DBG("Desc %x not found!\n", wTypeIndex);\r
140         return FALSE;\r
141 }\r
142 \r
143 \r
144 /**\r
145         Configures the device according to the specified configuration index and\r
146         alternate setting by parsing the installed USB descriptor list.\r
147         A configuration index of 0 unconfigures the device.\r
148 \r
149         @param [in]             bConfigIndex    Configuration index\r
150         @param [in]             bAltSetting             Alternate setting number\r
151 \r
152         @todo function always returns TRUE, add stricter checking?\r
153 \r
154         @return TRUE if successfully configured, FALSE otherwise\r
155  */\r
156 static BOOL USBSetConfiguration(unsigned char bConfigIndex, unsigned char bAltSetting)\r
157 {\r
158         unsigned char   *pab;\r
159         unsigned char   bCurConfig, bCurAltSetting;\r
160         unsigned char   bEP;\r
161         unsigned short  wMaxPktSize;\r
162 \r
163         ASSERT(pabDescrip != NULL);\r
164 \r
165         if (bConfigIndex == 0) {\r
166                 // unconfigure device\r
167                 USBHwConfigDevice(FALSE);\r
168         }\r
169         else {\r
170                 // configure endpoints for this configuration/altsetting\r
171                 pab = (unsigned char *)pabDescrip;\r
172                 bCurConfig = 0xFF;\r
173                 bCurAltSetting = 0xFF;\r
174 \r
175                 while (pab[DESC_bLength] != 0) {\r
176 \r
177                         switch (pab[DESC_bDescriptorType]) {\r
178 \r
179                         case DESC_CONFIGURATION:\r
180                                 // remember current configuration index\r
181                                 bCurConfig = pab[CONF_DESC_bConfigurationValue];\r
182                                 break;\r
183 \r
184                         case DESC_INTERFACE:\r
185                                 // remember current alternate setting\r
186                                 bCurAltSetting = pab[INTF_DESC_bAlternateSetting];\r
187                                 break;\r
188 \r
189                         case DESC_ENDPOINT:\r
190                                 if ((bCurConfig == bConfigIndex) &&\r
191                                         (bCurAltSetting == bAltSetting)) {\r
192                                         // endpoint found for desired config and alternate setting\r
193                                         bEP = pab[ENDP_DESC_bEndpointAddress];\r
194                                         wMaxPktSize =   (pab[ENDP_DESC_wMaxPacketSize]) |\r
195                                                                         (pab[ENDP_DESC_wMaxPacketSize + 1] << 8);\r
196                                         // configure endpoint\r
197                                         USBHwEPConfig(bEP, wMaxPktSize);\r
198                                 }\r
199                                 break;\r
200 \r
201                         default:\r
202                                 break;\r
203                         }\r
204                         // skip to next descriptor\r
205                         pab += pab[DESC_bLength];\r
206                 }\r
207 \r
208                 // configure device\r
209                 USBHwConfigDevice(TRUE);\r
210         }\r
211 \r
212         return TRUE;\r
213 }\r
214 \r
215 \r
216 /**\r
217         Local function to handle a standard device request\r
218 \r
219         @param [in]             pSetup          The setup packet\r
220         @param [in,out] *piLen          Pointer to data length\r
221         @param [in,out] ppbData         Data buffer.\r
222 \r
223         @return TRUE if the request was handled successfully\r
224  */\r
225 static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)\r
226 {\r
227         unsigned char   *pbData = *ppbData;\r
228 \r
229         switch (pSetup->bRequest) {\r
230 \r
231         case REQ_GET_STATUS:\r
232                 // bit 0: self-powered\r
233                 // bit 1: remote wakeup = not supported\r
234                 pbData[0] = 0;\r
235                 pbData[1] = 0;\r
236                 *piLen = 2;\r
237                 break;\r
238 \r
239         case REQ_SET_ADDRESS:\r
240                 USBHwSetAddress(pSetup->wValue);\r
241                 break;\r
242 \r
243         case REQ_GET_DESCRIPTOR:\r
244                 DBG("D%x", pSetup->wValue);\r
245                 return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);\r
246 \r
247         case REQ_GET_CONFIGURATION:\r
248                 // indicate if we are configured\r
249                 pbData[0] = bConfiguration;\r
250                 *piLen = 1;\r
251                 break;\r
252 \r
253         case REQ_SET_CONFIGURATION:\r
254                 if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {\r
255                         DBG("USBSetConfiguration failed!\n");\r
256                         return FALSE;\r
257                 }\r
258                 // configuration successful, update current configuration\r
259                 bConfiguration = pSetup->wValue & 0xFF;\r
260                 break;\r
261 \r
262         case REQ_CLEAR_FEATURE:\r
263         case REQ_SET_FEATURE:\r
264                 if (pSetup->wValue == FEA_REMOTE_WAKEUP) {\r
265                         // put DEVICE_REMOTE_WAKEUP code here\r
266                 }\r
267                 if (pSetup->wValue == FEA_TEST_MODE) {\r
268                         // put TEST_MODE code here\r
269                 }\r
270                 return FALSE;\r
271 \r
272         case REQ_SET_DESCRIPTOR:\r
273                 DBG("Device req %d not implemented\n", pSetup->bRequest);\r
274                 return FALSE;\r
275 \r
276         default:\r
277                 DBG("Illegal device req %d\n", pSetup->bRequest);\r
278                 return FALSE;\r
279         }\r
280 \r
281         return TRUE;\r
282 }\r
283 \r
284 \r
285 /**\r
286         Local function to handle a standard interface request\r
287 \r
288         @param [in]             pSetup          The setup packet\r
289         @param [in,out] *piLen          Pointer to data length\r
290         @param [in]             ppbData         Data buffer.\r
291 \r
292         @return TRUE if the request was handled successfully\r
293  */\r
294 static BOOL HandleStdInterfaceReq(TSetupPacket  *pSetup, int *piLen, unsigned char **ppbData)\r
295 {\r
296         unsigned char   *pbData = *ppbData;\r
297 \r
298         switch (pSetup->bRequest) {\r
299 \r
300         case REQ_GET_STATUS:\r
301                 // no bits specified\r
302                 pbData[0] = 0;\r
303                 pbData[1] = 0;\r
304                 *piLen = 2;\r
305                 break;\r
306 \r
307         case REQ_CLEAR_FEATURE:\r
308         case REQ_SET_FEATURE:\r
309                 // not defined for interface\r
310                 return FALSE;\r
311 \r
312         case REQ_GET_INTERFACE: // TODO use bNumInterfaces\r
313         // there is only one interface, return n-1 (= 0)\r
314                 pbData[0] = 0;\r
315                 *piLen = 1;\r
316                 break;\r
317 \r
318         case REQ_SET_INTERFACE: // TODO use bNumInterfaces\r
319                 // there is only one interface (= 0)\r
320                 if (pSetup->wValue != 0) {\r
321                         return FALSE;\r
322                 }\r
323                 *piLen = 0;\r
324                 break;\r
325 \r
326         default:\r
327                 DBG("Illegal interface req %d\n", pSetup->bRequest);\r
328                 return FALSE;\r
329         }\r
330 \r
331         return TRUE;\r
332 }\r
333 \r
334 \r
335 /**\r
336         Local function to handle a standard endpoint request\r
337 \r
338         @param [in]             pSetup          The setup packet\r
339         @param [in,out] *piLen          Pointer to data length\r
340         @param [in]             ppbData         Data buffer.\r
341 \r
342         @return TRUE if the request was handled successfully\r
343  */\r
344 static BOOL HandleStdEndPointReq(TSetupPacket   *pSetup, int *piLen, unsigned char **ppbData)\r
345 {\r
346         unsigned char   *pbData = *ppbData;\r
347 \r
348         switch (pSetup->bRequest) {\r
349         case REQ_GET_STATUS:\r
350                 // bit 0 = endpointed halted or not\r
351                 pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0;\r
352                 pbData[1] = 0;\r
353                 *piLen = 2;\r
354                 break;\r
355 \r
356         case REQ_CLEAR_FEATURE:\r
357                 if (pSetup->wValue == FEA_ENDPOINT_HALT) {\r
358                         // clear HALT by unstalling\r
359                         USBHwEPStall(pSetup->wIndex, FALSE);\r
360                         break;\r
361                 }\r
362                 // only ENDPOINT_HALT defined for endpoints\r
363                 return FALSE;\r
364 \r
365         case REQ_SET_FEATURE:\r
366                 if (pSetup->wValue == FEA_ENDPOINT_HALT) {\r
367                         // set HALT by stalling\r
368                         USBHwEPStall(pSetup->wIndex, TRUE);\r
369                         break;\r
370                 }\r
371                 // only ENDPOINT_HALT defined for endpoints\r
372                 return FALSE;\r
373 \r
374         case REQ_SYNCH_FRAME:\r
375                 DBG("EP req %d not implemented\n", pSetup->bRequest);\r
376                 return FALSE;\r
377 \r
378         default:\r
379                 DBG("Illegal EP req %d\n", pSetup->bRequest);\r
380                 return FALSE;\r
381         }\r
382 \r
383         return TRUE;\r
384 }\r
385 \r
386 \r
387 /**\r
388         Default handler for standard ('chapter 9') requests\r
389 \r
390         If a custom request handler was installed, this handler is called first.\r
391 \r
392         @param [in]             pSetup          The setup packet\r
393         @param [in,out] *piLen          Pointer to data length\r
394         @param [in]             ppbData         Data buffer.\r
395 \r
396         @return TRUE if the request was handled successfully\r
397  */\r
398 BOOL USBHandleStandardRequest(TSetupPacket      *pSetup, int *piLen, unsigned char **ppbData)\r
399 {\r
400         // try the custom request handler first\r
401         if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {\r
402                 return TRUE;\r
403         }\r
404 \r
405         switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {\r
406         case REQTYPE_RECIP_DEVICE:              return HandleStdDeviceReq(pSetup, piLen, ppbData);\r
407         case REQTYPE_RECIP_INTERFACE:   return HandleStdInterfaceReq(pSetup, piLen, ppbData);\r
408         case REQTYPE_RECIP_ENDPOINT:    return HandleStdEndPointReq(pSetup, piLen, ppbData);\r
409         default:                                                return FALSE;\r
410         }\r
411 }\r
412 \r
413 \r
414 /**\r
415         Registers a callback for custom device requests\r
416 \r
417         In USBHandleStandardRequest, the custom request handler gets a first\r
418         chance at handling the request before it is handed over to the 'chapter 9'\r
419         request handler.\r
420 \r
421         This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR\r
422         request is sent to an interface, which is not covered by the 'chapter 9'\r
423         specification.\r
424 \r
425         @param [in]     pfnHandler      Callback function pointer\r
426  */\r
427 void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)\r
428 {\r
429         pfnHandleCustomReq = pfnHandler;\r
430 }\r
431 \r