1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** USBX Component                                                        */
17 /**                                                                       */
18 /**   ASIX Class                                                          */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_host_class_asix.h"
30 #include "ux_host_stack.h"
31 
32 
33 #if !defined(UX_HOST_STANDALONE)
34 
35 static inline UINT _ux_host_class_asix_link_up_controls(UX_HOST_CLASS_ASIX  *asix);
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _ux_host_class_asix_thread                          PORTABLE C      */
42 /*                                                           6.2.0        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Chaoqiong Xiao, Microsoft Corporation                               */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This is the Asix thread that monitors the link change flag.         */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    asix                                   Asix instance                */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_host_stack_transfer_request        Transfer request             */
62 /*    _ux_host_semaphore_get                 Get semaphore                */
63 /*    _ux_host_semaphore_put                 Put semaphore                */
64 /*    _ux_utility_memory_allocate            Allocate memory              */
65 /*    _ux_utility_memory_free                Free memory                  */
66 /*    _ux_utility_memory_set                 Set memory                   */
67 /*    _ux_network_driver_activate            Activate NetX USB interface  */
68 /*    _ux_network_driver_link_down           Set state to link down       */
69 /*    _ux_network_driver_link_up             Set state to link up         */
70 /*    nx_packet_allocate                     Allocate NetX packet         */
71 /*    nx_packet_transmit_release             Release NetX packet          */
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    Asix class initialization                                           */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
82 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            verified memset and memcpy  */
84 /*                                            cases,                      */
85 /*                                            resulting in version 6.1    */
86 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
87 /*                                            refined macros names,       */
88 /*                                            resulting in version 6.1.10 */
89 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
90 /*                                            internal clean up,          */
91 /*                                            fixed standalone compile,   */
92 /*                                            resulting in version 6.1.11 */
93 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
94 /*                                            removed internal NX pool,   */
95 /*                                            moved NX driver activate,   */
96 /*                                            refined control REQ flow,   */
97 /*                                            refined reception flow,     */
98 /*                                            refined interrupt flow,     */
99 /*                                            resulting in version 6.2.0  */
100 /*                                                                        */
101 /**************************************************************************/
_ux_host_class_asix_thread(ULONG parameter)102 VOID  _ux_host_class_asix_thread(ULONG parameter)
103 {
104 
105 UX_HOST_CLASS_ASIX          *asix;
106 UX_TRANSFER                 *transfer_request;
107 NX_PACKET                   *packet;
108 NX_PACKET                   *current_packet;
109 NX_PACKET                   *next_packet;
110 UCHAR                       *buffer;
111 ULONG                       buffer_count;
112 ULONG                       asix_length;
113 ULONG                       asix_count;
114 ULONG                       asix_remain;
115 ULONG                       packet_discard;
116 ULONG                       buffer_remain;
117 ULONG                       copy_length;
118 UINT                        status;
119 UX_DEVICE                   *device;
120 ULONG                       available0, available1;
121 USB_NETWORK_DEVICE_TYPE     *ux_nx_device;
122 
123 
124     /* Cast the parameter passed in the thread into the asix pointer.  */
125     UX_THREAD_EXTENSION_PTR_GET(asix, UX_HOST_CLASS_ASIX, parameter)
126 
127     /* Loop forever waiting for changes signaled through the semaphore. */
128     while (1)
129     {
130 
131         /* Wait for the semaphore to be put by the asix interrupt event.  */
132         status = _ux_host_semaphore_get(&asix -> ux_host_class_asix_interrupt_notification_semaphore, UX_WAIT_FOREVER);
133 
134         /* Check for successful completion.  */
135         if (status != UX_SUCCESS)
136             return;
137 
138         /* Protect Thread reentry to this instance.  */
139         status =  _ux_host_semaphore_get(&asix -> ux_host_class_asix_semaphore, UX_WAIT_FOREVER);
140 
141         /* Check for successful completion.  */
142         if (status != UX_SUCCESS)
143             return;
144 
145         /* Check the link state. It is either pending up or down.  */
146         if (asix -> ux_host_class_asix_link_state == UX_HOST_CLASS_ASIX_LINK_STATE_PENDING_UP)
147         {
148 
149             /* Issue a list of control requests to setup link up.  */
150             status = _ux_host_class_asix_link_up_controls(asix);
151             if (status != UX_SUCCESS)
152             {
153 
154                 /* Unprotect thread reentry to this instance.  */
155                 _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore);
156                 continue;
157             }
158 
159             /* Now the link is up.  */
160             asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_UP;
161 
162             /* Communicate the state with the network driver.  */
163             _ux_network_driver_link_up(asix -> ux_host_class_asix_network_handle);
164 
165             /* Reactivate interrupt notification polling.  */
166             _ux_host_stack_transfer_request(&asix -> ux_host_class_asix_interrupt_endpoint -> ux_endpoint_transfer_request);
167 
168             /* Unprotect thread reentry to this instance.  */
169             _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore);
170 
171             /* Re-check packet pool on link up.  */
172             asix -> ux_host_class_asix_packet_pool = UX_NULL;
173 
174             /* Keep polling if device is connected and link is up.  */
175 
176             /* Initialize variables.  */
177             device = asix -> ux_host_class_asix_device;
178             packet = UX_NULL;
179             buffer = UX_NULL;
180             asix_length = 0;
181             asix_count = 0;
182             buffer_count = 0;
183             packet_discard = UX_FALSE;
184             asix -> ux_host_class_asix_packet_available_min = 0xFFFFFFFF;
185 
186             /* Polling loop.  */
187             while(device -> ux_device_state == UX_DEVICE_CONFIGURED &&
188                 asix -> ux_host_class_asix_link_state == UX_HOST_CLASS_ASIX_LINK_STATE_UP)
189             {
190 
191                 /* Check if packet pool is ready.  */
192                 if (asix -> ux_host_class_asix_packet_pool == UX_NULL)
193                 {
194 
195                     /* Get the network device handle.  */
196                     ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)(asix -> ux_host_class_asix_network_handle);
197 
198                     /* Get packet pool from IP instance (if available).  */
199                     if (ux_nx_device -> ux_network_device_ip_instance != UX_NULL)
200                     {
201                         asix -> ux_host_class_asix_packet_pool = ux_nx_device -> ux_network_device_ip_instance -> nx_ip_default_packet_pool;
202                     }
203                     else
204                     {
205 
206                         /* Error trap.  */
207                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_POOL_ERROR);
208 
209                         _ux_utility_delay_ms(UX_HOST_CLASS_ASIX_PACKET_POOL_WAIT);
210                         continue;
211                     }
212                 }
213 
214                 /* Get transfer request for bulk in reception. */
215                 transfer_request =  &asix -> ux_host_class_asix_bulk_in_endpoint -> ux_endpoint_transfer_request;
216 
217                 /* If there is no buffer ready, read it.  */
218                 if (buffer == UX_NULL)
219                 {
220 
221                     /* Set the data pointer.  */
222                     transfer_request -> ux_transfer_request_data_pointer = asix -> ux_host_class_asix_receive_buffer;
223 
224                     /* And length.  */
225                     transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE;
226                     transfer_request -> ux_transfer_request_actual_length =     0;
227 
228                     /* Schedule a reception.  */
229                     status = _ux_host_stack_transfer_request(transfer_request);
230 
231                     /* Check if it's started successfully.  */
232                     if (status != UX_SUCCESS)
233                     {
234 
235                         /* If a packet (chain) is on-going, release it.  */
236                         if (packet != UX_NULL)
237                         {
238                             nx_packet_release(packet);
239                             packet = UX_NULL;
240                         }
241                         continue;
242                     }
243 
244                     /* Wait for transfer completion.  */
245                     _ux_host_semaphore_get_norc(&transfer_request -> ux_transfer_request_semaphore, UX_WAIT_FOREVER);
246 
247                     /* Check completion code.  */
248                     if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
249                     {
250 
251                         /* Abort transfer.  */
252                         _ux_host_stack_transfer_request_abort(transfer_request);
253 
254                         /* If a packet (chain) is on-going, release it.  */
255                         if (packet != UX_NULL)
256                         {
257                             nx_packet_release(packet);
258                             packet = UX_NULL;
259                         }
260                         continue;
261                     }
262 
263                     /* If it's ZLP, reset buffer and ASIX packet and transfer again.  */
264                     if (transfer_request -> ux_transfer_request_actual_length == 0)
265                     {
266 
267                         /* Packet should have been processed!  */
268                         if (packet != UX_NULL)
269                         {
270 
271                             /* ASIX header corrupt?  */
272                             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
273                             nx_packet_release(packet);
274                             packet = UX_NULL;
275                         }
276 
277                         buffer = UX_NULL;
278                         buffer_count = 0;
279                         asix_length = 0;
280                         continue;
281                     }
282 
283                     /* Buffer is ready.  */
284                     buffer = asix -> ux_host_class_asix_receive_buffer;
285                 }
286 
287                 /* There is data in buffer, extract the data to packets.  */
288 
289                 /* If there is no packet, allocate it.  */
290                 if (packet == UX_NULL)
291                 {
292 
293                     /* Get a free NX Packet.  */
294                     available0 = asix -> ux_host_class_asix_packet_pool -> nx_packet_pool_available;
295                     status = nx_packet_allocate(asix -> ux_host_class_asix_packet_pool,
296                                 &packet, NX_RECEIVE_PACKET,
297                                 UX_MS_TO_TICK(UX_HOST_CLASS_ASIX_PACKET_ALLOCATE_WAIT));
298                     available1 = asix -> ux_host_class_asix_packet_pool -> nx_packet_pool_available;
299                     if (asix -> ux_host_class_asix_packet_available_min > available1)
300                         asix -> ux_host_class_asix_packet_available_min = available1;
301                     if (asix -> ux_host_class_asix_packet_available_min > available0)
302                         asix -> ux_host_class_asix_packet_available_min = available0;
303                     if (status != NX_SUCCESS)
304                     {
305 
306                         /* Error trap.  */
307                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR);
308                         continue;
309                     }
310 
311                     /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header.  */
312                     packet -> nx_packet_prepend_ptr += sizeof(USHORT);
313                     packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr;
314 
315                     /* Log the packet.  */
316 
317                 }
318 
319                 /* Get remaining in buffer.  */
320                 buffer_remain = transfer_request -> ux_transfer_request_actual_length -
321                                 buffer_count;
322 
323                 /* For new packet, get packet length from ASIX header.  */
324                 if (asix_length == 0)
325                 {
326 
327                     /* If remaining less than 2 bytes in buffer, read buffer again.  */
328                     if (buffer_remain < 2)
329                     {
330                         buffer = UX_NULL;
331                         buffer_count = 0;
332                         continue;
333                     }
334 
335                     /* Get ASIX packet length.  */
336                     asix_length = _ux_utility_short_get(buffer + buffer_count);
337                     asix_length &= UX_HOST_CLASS_ASIX_RX_PACKET_LENGTH_MASK;
338                     asix_count = 0;
339 
340                     /* If remaining 2-3 bytes, skip 2 of next buffer.  */
341                     if (buffer_remain < 4)
342                     {
343                         buffer = UX_NULL;
344                         buffer_count = 2;
345                         continue;
346                     }
347 
348                     /* Skip header in buffer, it's not copied to NX packet.  */
349                     buffer_count += 4;
350                     buffer_remain -= 4;
351                 }
352 
353                 /* Get remaining in ASIX packet.  */
354                 asix_remain = asix_length - asix_count;
355 
356                 /* Get actual length to process.  */
357                 if (asix_remain <= buffer_remain)
358                     copy_length = asix_remain;
359                 else
360                     copy_length = buffer_remain;
361 
362                 /* Check if the data is discarded.  */
363                 if (packet_discard == UX_FALSE && copy_length)
364                 {
365 
366                     /* Append data to packet.  */
367                     status = nx_packet_data_append(packet,
368                                         buffer + buffer_count, copy_length,
369                                         asix -> ux_host_class_asix_packet_pool,
370                                         UX_MS_TO_TICK(UX_HOST_CLASS_ASIX_PACKET_ALLOCATE_WAIT));
371                     if (status != NX_SUCCESS)
372                     {
373 
374                         /* There is error, this ASIX packet is discarded.  */
375                         packet_discard = UX_TRUE;
376                     }
377                 }
378 
379                 /* Update counts.  */
380                 buffer_count += copy_length;
381                 asix_count += copy_length;
382 
383                 /* If packet size is odd, padding one byte is ignored.  */
384                 if (asix_length & 0x1u)
385                     buffer_count ++;
386 
387                 /* Check if buffer ends.  */
388                 if (buffer_count >= transfer_request -> ux_transfer_request_actual_length)
389                 {
390                     buffer = UX_NULL;
391                     buffer_count = 0;
392                 }
393 
394                 /* Check if ASIX packet ends.
395                  * - ASIX count achieve its length.
396                  * - Buffer achieve its end and it's a short packet.
397                  */
398                 if (asix_count >= asix_length ||
399                     (buffer == UX_NULL &&
400                      transfer_request -> ux_transfer_request_actual_length <
401                      transfer_request -> ux_transfer_request_requested_length))
402                 {
403 
404                     /* Check if packet is discarded.  */
405                     if (packet_discard)
406                     {
407 
408                         packet_discard = UX_FALSE;
409 
410                         /* Re-allocate packet.  */
411                         nx_packet_release(packet);
412                         packet = UX_NULL;
413                         continue;
414                     }
415 
416                     /* Send that packet to the NetX USB broker.  */
417                     _ux_network_driver_packet_received(asix -> ux_host_class_asix_network_handle, packet);
418                     packet = UX_NULL;
419 
420                     /* Reset ASIX packet.  */
421                     asix_length = 0;
422 
423                     continue;
424                 }
425 
426                 /* Buffer ends but packet continues.  */
427                 /* Buffer already reset to start reception again.  */
428             }
429 
430             /* Release packet not sent to NX.  */
431             if (packet)
432                 nx_packet_release(packet);
433         }
434         else
435         {
436 
437             /* Abort pending transfers.  */
438             _ux_host_stack_endpoint_transfer_abort(asix -> ux_host_class_asix_bulk_out_endpoint);
439 
440             /* We need to free the packets that will not be sent.  */
441             current_packet =  asix -> ux_host_class_asix_xmit_queue;
442 
443             /* Get the next packet associated with the first packet.  */
444             next_packet = current_packet -> nx_packet_queue_next;
445 
446             /* Parse all these packets that were scheduled.  */
447             while (current_packet != UX_NULL)
448             {
449 
450                 /* Free the packet that was just sent.  First do some housekeeping.  */
451                 current_packet -> nx_packet_prepend_ptr =  current_packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_ASIX_ETHERNET_SIZE;
452                 current_packet -> nx_packet_length =  current_packet -> nx_packet_length - UX_HOST_CLASS_ASIX_ETHERNET_SIZE;
453 
454                 /* And ask Netx to release it.  */
455                 nx_packet_transmit_release(current_packet);
456 
457                 /* Next packet becomes the current one.  */
458                 current_packet = next_packet;
459 
460                 /* Next packet now.  */
461                 if (current_packet != UX_NULL)
462 
463                     /* Get the next packet associated with the first packet.  */
464                     next_packet = current_packet -> nx_packet_queue_next;
465 
466             }
467 
468             /* Communicate the state with the network driver.  */
469             _ux_network_driver_link_down(asix -> ux_host_class_asix_network_handle);
470 
471             /* Now the link is down.  */
472             asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_DOWN;
473 
474             /* Reactivate interrupt notification polling.  */
475             _ux_host_stack_transfer_request(&asix -> ux_host_class_asix_interrupt_endpoint -> ux_endpoint_transfer_request);
476 
477             /* Unprotect thread reentry to this instance.  */
478             _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore);
479         }
480     }
481 }
482 
_ux_host_class_asix_link_up_controls(UX_HOST_CLASS_ASIX * asix)483 static inline UINT _ux_host_class_asix_link_up_controls(UX_HOST_CLASS_ASIX  *asix)
484 {
485 
486 UCHAR                       *setup_buffer;
487 UX_ENDPOINT                 *control_endpoint;
488 UX_TRANSFER                 *transfer_request;
489 UINT                        status;
490 
491 
492     /* We need to get the default control endpoint transfer request pointer.  */
493     control_endpoint =  &asix -> ux_host_class_asix_device -> ux_device_control_endpoint;
494     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
495 
496     /* Need to allocate memory for the buffer.  */
497     setup_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_SETUP_BUFFER_SIZE);
498     if (setup_buffer == UX_NULL)
499         return(UX_MEMORY_INSUFFICIENT);
500 
501     /* Request ownership of Serial Management Interface.  */
502     transfer_request -> ux_transfer_request_data_pointer        =  UX_NULL;
503     transfer_request -> ux_transfer_request_requested_length    =  0;
504     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_OWN_SMI ;
505     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
506     transfer_request -> ux_transfer_request_value               =  0;
507     transfer_request -> ux_transfer_request_index               =  0;
508 
509     /* Send request to HCD layer.  */
510     status =  _ux_host_stack_transfer_request(transfer_request);
511 
512     /* Check status, if error, do not proceed.  */
513     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
514     {
515 
516         /* Free all used resources.  */
517         _ux_utility_memory_free(setup_buffer);
518         return(UX_TRANSFER_ERROR);
519     }
520 
521     /* Get the value of the PHYIDR1 in the PHY register.  */
522     transfer_request -> ux_transfer_request_data_pointer        =  setup_buffer;
523     transfer_request -> ux_transfer_request_requested_length    =  2;
524     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_READ_PHY_REG;
525     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
526     transfer_request -> ux_transfer_request_value               =  asix -> ux_host_class_asix_primary_phy_id;
527     transfer_request -> ux_transfer_request_index               =  UX_HOST_CLASS_ASIX_PHY_REG_ANLPAR;
528 
529     /* Send request to HCD layer.  */
530     status =  _ux_host_stack_transfer_request(transfer_request);
531 
532     /* Check status, if error, do not proceed.  */
533     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS ||
534         transfer_request -> ux_transfer_request_actual_length != 2)
535     {
536 
537         /* Free all used resources.  */
538         _ux_utility_memory_free(setup_buffer);
539         return(UX_TRANSFER_ERROR);
540     }
541 
542     /* Release SMI ownership. */
543     transfer_request -> ux_transfer_request_data_pointer        =  UX_NULL;
544     transfer_request -> ux_transfer_request_requested_length    =  0;
545     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_RELEASE_SMI;
546     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
547     transfer_request -> ux_transfer_request_value               =  0;
548     transfer_request -> ux_transfer_request_index               =  0;
549 
550     /* Send request to HCD layer.  */
551     status =  _ux_host_stack_transfer_request(transfer_request);
552 
553     /* Check status, if error, do not proceed.  */
554     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
555     {
556 
557         /* Free all used resources.  */
558         _ux_utility_memory_free(setup_buffer);
559         return(UX_TRANSFER_ERROR);
560     }
561 
562     /* Check speed.  */
563     if (asix -> ux_host_class_asix_speed_selected == UX_HOST_CLASS_ASIX_SPEED_SELECTED_100MPBS)
564 
565         /* Set speed at 100MBPS.  */
566         transfer_request -> ux_transfer_request_value =  UX_HOST_CLASS_ASIX_MEDIUM_PS;
567 
568     /* Write the value of the Medium Mode. */
569     transfer_request -> ux_transfer_request_data_pointer        =  UX_NULL;
570     transfer_request -> ux_transfer_request_requested_length    =  0;
571     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_WRITE_MEDIUM_MODE;
572     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
573     transfer_request -> ux_transfer_request_value               |=  (UX_HOST_CLASS_ASIX_MEDIUM_FD | UX_HOST_CLASS_ASIX_MEDIUM_BIT2 | UX_HOST_CLASS_ASIX_MEDIUM_RFC_ENABLED |
574                                                                     UX_HOST_CLASS_ASIX_MEDIUM_TFC_ENABLED | UX_HOST_CLASS_ASIX_MEDIUM_RE_ENABLED);
575     transfer_request -> ux_transfer_request_index               =  0;
576 
577     /* Send request to HCD layer.  */
578     status =  _ux_host_stack_transfer_request(transfer_request);
579 
580     /* Check status, if error, do not proceed.  */
581     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
582     {
583 
584         /* Free all used resources.  */
585         _ux_utility_memory_free(setup_buffer);
586         return(UX_TRANSFER_ERROR);
587     }
588 
589     /* Set the Rx Control register value.  */
590     transfer_request -> ux_transfer_request_data_pointer        =  UX_NULL;
591     transfer_request -> ux_transfer_request_requested_length    =  0;
592     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_WRITE_RX_CTL;
593     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
594     transfer_request -> ux_transfer_request_value               =  (UX_HOST_CLASS_ASIX_RXCR_AM | UX_HOST_CLASS_ASIX_RXCR_AB |
595                                                                     UX_HOST_CLASS_ASIX_RXCR_SO | UX_HOST_CLASS_ASIX_RXCR_MFB_2048);
596     transfer_request -> ux_transfer_request_index               =  0;
597 
598     /* Send request to HCD layer.  */
599     status =  _ux_host_stack_transfer_request(transfer_request);
600 
601     /* Check status, if error, do not proceed.  */
602     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
603     {
604 
605         /* Free all used resources.  */
606         _ux_utility_memory_free(setup_buffer);
607         return(UX_TRANSFER_ERROR);
608     }
609 
610     /* Set the multicast value.  */
611     transfer_request -> ux_transfer_request_data_pointer        =  setup_buffer;
612     transfer_request -> ux_transfer_request_requested_length    =  8;
613     transfer_request -> ux_transfer_request_function            =  UX_HOST_CLASS_ASIX_REQ_WRITE_MULTICAST_FILTER;
614     transfer_request -> ux_transfer_request_type                =  UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE;
615     transfer_request -> ux_transfer_request_value               =  0;
616     transfer_request -> ux_transfer_request_index               =  0;
617 
618     /* Fill in the multicast filter.  */
619     _ux_utility_memory_set(setup_buffer, 0, 8); /* Use case of memset is verified. */
620     *(setup_buffer +1) = 0x40;
621 
622     /* Send request to HCD layer.  */
623     status =  _ux_host_stack_transfer_request(transfer_request);
624 
625     /* Check status, if error, do not proceed.  */
626     if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS ||
627         transfer_request -> ux_transfer_request_actual_length != 8)
628     {
629 
630         /* Free all used resources.  */
631         _ux_utility_memory_free(setup_buffer);
632         return(UX_TRANSFER_ERROR);
633     }
634 
635     /* Free all used resources.  */
636     _ux_utility_memory_free(setup_buffer);
637     return(UX_SUCCESS);
638 }
639 #endif
640