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