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