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