| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
RNDISClassHost.c
Go to the documentation of this file.
1 /*
2 * @brief Host mode driver for the library USB RNDIS Class driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * Copyright(C) Dean Camera, 2011, 2012
7 * All rights reserved.
8 *
9 * @par
10 * Software that is described herein is for illustrative purposes only
11 * which provides customers with programming information regarding the
12 * LPC products. This software is supplied "AS IS" without any warranties of
13 * any kind, and NXP Semiconductors and its licensor disclaim any and
14 * all warranties, express or implied, including all implied warranties of
15 * merchantability, fitness for a particular purpose and non-infringement of
16 * intellectual property rights. NXP Semiconductors assumes no responsibility
17 * or liability for the use of the software, conveys no license or rights under any
18 * patent, copyright, mask work right, or any other intellectual property rights in
19 * or to any products. NXP Semiconductors reserves the right to make changes
20 * in the software without notification. NXP Semiconductors also makes no
21 * representation or warranty that such application will be suitable for the
22 * specified use without further testing or modification.
23 *
24 * @par
25 * Permission to use, copy, modify, and distribute this software and its
26 * documentation is hereby granted, under NXP Semiconductors' and its
27 * licensor's relevant copyrights in the software, without fee, provided that it
28 * is used in conjunction with NXP Semiconductors microcontrollers. This
29 * copyright, permission, and disclaimer notice must appear in all copies of
30 * this code.
31 */
32
33
34 #define __INCLUDE_FROM_USB_DRIVER
35 #include "../../Core/USBMode.h"
36
37 #if defined(USB_CAN_BE_HOST)
38
39 #define __INCLUDE_FROM_RNDIS_DRIVER
40 #define __INCLUDE_FROM_RNDIS_HOST_C
41 #include "RNDISClassHost.h"
42
43 uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
44 uint16_t ConfigDescriptorSize,
45 void* ConfigDescriptorData)
46 {
47 USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
48 USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
49 USB_Descriptor_Endpoint_t* NotificationEndpoint = NULL;
50 USB_Descriptor_Interface_t* RNDISControlInterface = NULL;
51 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
52
53 memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
54
55 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
56 return RNDIS_ENUMERROR_InvalidConfigDescriptor;
57
58 RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
59
60 while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
61 {
62 if (!(RNDISControlInterface) ||
63 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
64 DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
65 {
66 if (NotificationEndpoint)
67 {
68 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
69 DCOMP_RNDIS_Host_NextRNDISDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
70 {
71 return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
72 }
73
74 DataINEndpoint = NULL;
75 DataOUTEndpoint = NULL;
76 }
77 else
78 {
79 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
80 DCOMP_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
81 {
82 return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
83 }
84
85 RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
86
87 NotificationEndpoint = NULL;
88 }
89
90 continue;
91 }
92
93 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
94
95 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
96 {
97 if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
98 NotificationEndpoint = EndpointData;
99 else
100 DataINEndpoint = EndpointData;
101 }
102 else
103 {
104 DataOUTEndpoint = EndpointData;
105 }
106 }
107
108 for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
109 {
110 uint16_t Size;
111 uint8_t Type;
112 uint8_t Token;
113 uint8_t EndpointAddress;
114 uint8_t InterruptPeriod;
115 bool DoubleBanked;
116
117 if (PipeNum == RNDISInterfaceInfo->Config.DataINPipeNumber)
118 {
119 Size = le16_to_cpu(DataINEndpoint->EndpointSize);
120 EndpointAddress = DataINEndpoint->EndpointAddress;
121 Token = PIPE_TOKEN_IN;
122 Type = EP_TYPE_BULK;
123 DoubleBanked = RNDISInterfaceInfo->Config.DataINPipeDoubleBank;
124 InterruptPeriod = 0;
125
126 RNDISInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
127 }
128 else if (PipeNum == RNDISInterfaceInfo->Config.DataOUTPipeNumber)
129 {
130 Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
131 EndpointAddress = DataOUTEndpoint->EndpointAddress;
132 Token = PIPE_TOKEN_OUT;
133 Type = EP_TYPE_BULK;
134 DoubleBanked = RNDISInterfaceInfo->Config.DataOUTPipeDoubleBank;
135 InterruptPeriod = 0;
136
137 RNDISInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
138 }
139 else if (PipeNum == RNDISInterfaceInfo->Config.NotificationPipeNumber)
140 {
141 Size = le16_to_cpu(NotificationEndpoint->EndpointSize);
142 EndpointAddress = NotificationEndpoint->EndpointAddress;
143 Token = PIPE_TOKEN_IN;
144 Type = EP_TYPE_INTERRUPT;
145 DoubleBanked = RNDISInterfaceInfo->Config.NotificationPipeDoubleBank;
146 InterruptPeriod = NotificationEndpoint->PollingIntervalMS;
147
148 RNDISInterfaceInfo->State.NotificationPipeSize = NotificationEndpoint->EndpointSize;
149 }
150 else
151 {
152 continue;
153 }
154
155 if (!(Pipe_ConfigurePipe(portnum,PipeNum, Type, Token, EndpointAddress, Size,
156 DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
157 {
158 return CDC_ENUMERROR_PipeConfigurationFailed;
159 }
160
161 if (InterruptPeriod)
162 Pipe_SetInterruptPeriod(InterruptPeriod);
163 }
164
165 RNDISInterfaceInfo->State.ControlInterfaceNumber = RNDISControlInterface->InterfaceNumber;
166 RNDISInterfaceInfo->State.IsActive = true;
167
168 return RNDIS_ENUMERROR_NoError;
169 }
170
171 static uint8_t DCOMP_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor)
172 {
173 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
174
175 if (Header->Type == DTYPE_Interface)
176 {
177 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
178
179 if ((Interface->Class == CDC_CSCP_CDCClass) &&
180 (Interface->SubClass == CDC_CSCP_ACMSubclass) &&
181 (Interface->Protocol == CDC_CSCP_VendorSpecificProtocol))
182 {
183 return DESCRIPTOR_SEARCH_Found;
184 }
185 }
186
187 return DESCRIPTOR_SEARCH_NotFound;
188 }
189
190 static uint8_t DCOMP_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor)
191 {
192 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
193
194 if (Header->Type == DTYPE_Interface)
195 {
196 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor,
197 USB_Descriptor_Interface_t);
198
199 if ((Interface->Class == CDC_CSCP_CDCDataClass) &&
200 (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
201 (Interface->Protocol == CDC_CSCP_NoDataProtocol))
202 {
203 return DESCRIPTOR_SEARCH_Found;
204 }
205 }
206
207 return DESCRIPTOR_SEARCH_NotFound;
208 }
209
210 static uint8_t DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor)
211 {
212 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
213
214 if (Header->Type == DTYPE_Endpoint)
215 {
216 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
217
218 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
219
220 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
221 !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
222 {
223 return DESCRIPTOR_SEARCH_Found;
224 }
225 }
226 else if (Header->Type == DTYPE_Interface)
227 {
228 return DESCRIPTOR_SEARCH_Fail;
229 }
230
231 return DESCRIPTOR_SEARCH_NotFound;
232 }
233
234 static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
235 void* Buffer,
236 const uint16_t Length)
237 {
238 USB_ControlRequest = (USB_Request_Header_t)
239 {
240 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
241 .bRequest = RNDIS_REQ_SendEncapsulatedCommand,
242 .wValue = 0,
243 .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
244 .wLength = Length,
245 };
246 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
247
248 Pipe_SelectPipe(portnum,PIPE_CONTROLPIPE);
249
250 return USB_Host_SendControlRequest(portnum,Buffer);
251 }
252
253 static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
254 void* Buffer,
255 const uint16_t Length)
256 {
257 USB_ControlRequest = (USB_Request_Header_t)
258 {
259 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
260 .bRequest = RNDIS_REQ_GetEncapsulatedResponse,
261 .wValue = 0,
262 .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
263 .wLength = Length,
264 };
265 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
266
267 Pipe_SelectPipe(portnum,PIPE_CONTROLPIPE);
268
269 return USB_Host_SendControlRequest(portnum,Buffer);
270 }
271
272 uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
273 {
274 uint8_t ErrorCode;
275
276 RNDIS_KeepAlive_Message_t KeepAliveMessage;
277 RNDIS_KeepAlive_Complete_t KeepAliveMessageResponse;
278
279 KeepAliveMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_MSG);
280 KeepAliveMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Message_t));
281 KeepAliveMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
282
283 if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &KeepAliveMessage,
284 sizeof(RNDIS_KeepAlive_Message_t))) != HOST_SENDCONTROL_Successful)
285 {
286 return ErrorCode;
287 }
288
289 if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &KeepAliveMessageResponse,
290 sizeof(RNDIS_KeepAlive_Complete_t))) != HOST_SENDCONTROL_Successful)
291 {
292 return ErrorCode;
293 }
294
295 return HOST_SENDCONTROL_Successful;
296 }
297
298 uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
299 {
300 uint8_t ErrorCode;
301
302 RNDIS_Initialize_Message_t InitMessage;
303 RNDIS_Initialize_Complete_t InitMessageResponse;
304
305 InitMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_MSG);
306 InitMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Initialize_Message_t));
307 InitMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
308
309 InitMessage.MajorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR);
310 InitMessage.MinorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR);
311 InitMessage.MaxTransferSize = cpu_to_le32(RNDISInterfaceInfo->Config.HostMaxPacketSize);
312
313 if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &InitMessage,
314 sizeof(RNDIS_Initialize_Message_t))) != HOST_SENDCONTROL_Successful)
315 {
316 return ErrorCode;
317 }
318
319 if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &InitMessageResponse,
320 sizeof(RNDIS_Initialize_Complete_t))) != HOST_SENDCONTROL_Successful)
321 {
322 return ErrorCode;
323 }
324
325 if (InitMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
326 return RNDIS_ERROR_LOGICAL_CMD_FAILED;
327
328 RNDISInterfaceInfo->State.DeviceMaxPacketSize = le32_to_cpu(InitMessageResponse.MaxTransferSize);
329
330 return HOST_SENDCONTROL_Successful;
331 }
332
333 uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
334 const uint32_t Oid,
335 void* Buffer,
336 const uint16_t Length)
337 {
338 uint8_t ErrorCode;
339
340 struct
341 {
342 RNDIS_Set_Message_t SetMessage;
343
344 /* Temporary fix VLA issue on IAR compiler */
345 #define ContiguousBufferLength 1024
346
347 uint8_t ContiguousBuffer[ContiguousBufferLength];
348 } SetMessageData;
349
350 RNDIS_Set_Complete_t SetMessageResponse;
351
352 SetMessageData.SetMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_SET_MSG);
353 SetMessageData.SetMessage.MessageLength = cpu_to_le32(sizeof(RNDIS_Set_Message_t) + Length);
354 SetMessageData.SetMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
355
356 SetMessageData.SetMessage.Oid = cpu_to_le32(Oid);
357 SetMessageData.SetMessage.InformationBufferLength = cpu_to_le32(Length);
358 SetMessageData.SetMessage.InformationBufferOffset = CPU_TO_LE32(sizeof(RNDIS_Set_Message_t) - sizeof(RNDIS_Message_Header_t));
359 SetMessageData.SetMessage.DeviceVcHandle = CPU_TO_LE32(0);
360
361 memcpy(&SetMessageData.ContiguousBuffer, Buffer, Length);
362
363 if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &SetMessageData,
364 SetMessageData.SetMessage.MessageLength)) != HOST_SENDCONTROL_Successful)
365 {
366 return ErrorCode;
367 }
368
369 if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &SetMessageResponse,
370 sizeof(RNDIS_Set_Complete_t))) != HOST_SENDCONTROL_Successful)
371 {
372 return ErrorCode;
373 }
374
375 if (SetMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
376 return RNDIS_ERROR_LOGICAL_CMD_FAILED;
377
378 return HOST_SENDCONTROL_Successful;
379 }
380
381 uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
382 const uint32_t Oid,
383 void* Buffer,
384 const uint16_t MaxLength)
385 {
386 uint8_t ErrorCode;
387
388 RNDIS_Query_Message_t QueryMessage;
389
390 struct
391 {
392 RNDIS_Query_Complete_t QueryMessageResponse;
393
394 /* Temporary fix VLA issue on IAR compiler */
395 #define ContiguousBufferLength 1024
396
397 uint8_t ContiguousBuffer[ContiguousBufferLength];
398 } QueryMessageResponseData;
399
400 QueryMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_QUERY_MSG);
401 QueryMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Query_Message_t));
402 QueryMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
403
404 QueryMessage.Oid = cpu_to_le32(Oid);
405 QueryMessage.InformationBufferLength = CPU_TO_LE32(0);
406 QueryMessage.InformationBufferOffset = CPU_TO_LE32(0);
407 QueryMessage.DeviceVcHandle = CPU_TO_LE32(0);
408
409 if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &QueryMessage,
410 sizeof(RNDIS_Query_Message_t))) != HOST_SENDCONTROL_Successful)
411 {
412 return ErrorCode;
413 }
414
415 if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &QueryMessageResponseData,
416 sizeof(QueryMessageResponseData))) != HOST_SENDCONTROL_Successful)
417 {
418 return ErrorCode;
419 }
420
421 if (QueryMessageResponseData.QueryMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
422 return RNDIS_ERROR_LOGICAL_CMD_FAILED;
423
424 memcpy(Buffer, &QueryMessageResponseData.ContiguousBuffer, MaxLength);
425
426 return HOST_SENDCONTROL_Successful;
427 }
428
429 bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
430 {
431 bool PacketWaiting;
432 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
433
434 if ((USB_HostState[portnum] != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
435 return false;
436
437 Pipe_SelectPipe(portnum,RNDISInterfaceInfo->Config.DataINPipeNumber);
438
439 Pipe_Unfreeze();
440 PacketWaiting = Pipe_IsINReceived(portnum);
441 Pipe_Freeze();
442
443 return PacketWaiting;
444 }
445
446 uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
447 void* Buffer,
448 uint16_t* const PacketLength)
449 {
450 uint8_t ErrorCode;
451 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
452
453 if ((USB_HostState[portnum] != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
454 return PIPE_READYWAIT_DeviceDisconnected;
455
456 Pipe_SelectPipe(portnum,RNDISInterfaceInfo->Config.DataINPipeNumber);
457 Pipe_Unfreeze();
458
459 if (!(Pipe_IsReadWriteAllowed(portnum)))
460 {
461 if (Pipe_IsINReceived(portnum))
462 Pipe_ClearIN(portnum);
463
464 *PacketLength = 0;
465 Pipe_Freeze();
466 return PIPE_RWSTREAM_NoError;
467 }
468
469 RNDIS_Packet_Message_t DeviceMessage;
470
471 if ((ErrorCode = Pipe_Read_Stream_LE(portnum,&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
472 NULL)) != PIPE_RWSTREAM_NoError)
473 {
474 return ErrorCode;
475 }
476
477 *PacketLength = (uint16_t)le32_to_cpu(DeviceMessage.DataLength);
478
479 Pipe_Discard_Stream(portnum,DeviceMessage.DataOffset -
480 (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)),
481 NULL);
482
483 Pipe_Read_Stream_LE(portnum,Buffer, *PacketLength, NULL);
484
485 if (!(Pipe_BytesInPipe(portnum)))
486 Pipe_ClearIN(portnum);
487
488 Pipe_Freeze();
489
490 return PIPE_RWSTREAM_NoError;
491 }
492
493 uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
494 void* Buffer,
495 const uint16_t PacketLength)
496 {
497 uint8_t ErrorCode;
498 uint8_t portnum = RNDISInterfaceInfo->Config.PortNumber;
499
500 if ((USB_HostState[portnum] != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
501 return PIPE_READYWAIT_DeviceDisconnected;
502
503 RNDIS_Packet_Message_t DeviceMessage;
504
505 memset(&DeviceMessage, 0, sizeof(RNDIS_Packet_Message_t));
506 DeviceMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG);
507 DeviceMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) + PacketLength);
508 DeviceMessage.DataOffset = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
509 DeviceMessage.DataLength = cpu_to_le32(PacketLength);
510
511 Pipe_SelectPipe(portnum,RNDISInterfaceInfo->Config.DataOUTPipeNumber);
512 Pipe_Unfreeze();
513
514 if ((ErrorCode = Pipe_Write_Stream_LE(portnum,&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
515 NULL)) != PIPE_RWSTREAM_NoError)
516 {
517 return ErrorCode;
518 }
519
520 Pipe_Write_Stream_LE(portnum,Buffer, PacketLength, NULL);
521 Pipe_ClearOUT(portnum);
522
523 Pipe_Freeze();
524
525 return PIPE_RWSTREAM_NoError;
526 }
527
528 #endif
529