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