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