1 #include <stdio.h>
2 #include "tx_api.h"
3 #include "ux_api.h"
4 #include "ux_system.h"
5 #include "ux_utility.h"
6 #include "ux_device_stack.h"
7 #include "ux_test.h"
8 #include "ux_host_class_hub.h"
9 #include "ux_device_class_dummy_hub.h"
10 
11 #define PORT_START 1
12 #define PORT_STATUS_PORT_POWER_BIT 8
13 
14 UCHAR _ux_device_class_hub_name[] = "_ux_device_class_hub_name";
15 
_ux_device_class_hub_thread_entry(ULONG param)16 static VOID _ux_device_class_hub_thread_entry(ULONG param)
17 {
18 UX_DEVICE_CLASS_HUB *hub;
19 UX_SLAVE_CLASS      *hub_class;
20 UX_SLAVE_ENDPOINT   *endpoint;
21 UX_SLAVE_TRANSFER   *transfer;
22 UINT                status;
23     UX_THREAD_EXTENSION_PTR_GET(hub_class ,UX_SLAVE_CLASS, param);
24     hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance;
25     while(1)
26     {
27         endpoint = hub->interrupt_endpoint;
28         if (endpoint)
29         {
30             transfer = &endpoint->ux_slave_endpoint_transfer_request;
31             status = _ux_device_stack_transfer_request(transfer,
32                         transfer -> ux_slave_transfer_request_requested_length,
33                         transfer -> ux_slave_transfer_request_requested_length);
34             _ux_utility_memory_set(transfer->ux_slave_transfer_request_data_pointer, 0, transfer->ux_slave_transfer_request_transfer_length);
35         }
36         _ux_device_thread_suspend(&hub->hub_thread);
37     }
38 }
39 
_ux_device_class_hub_initialize(UX_SLAVE_CLASS_COMMAND * command)40 static VOID _ux_device_class_hub_initialize(UX_SLAVE_CLASS_COMMAND *command)
41 {
42 
43 UX_SLAVE_CLASS              *hub_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr;
44 UX_DEVICE_CLASS_HUB_PARAMS  *hub_params = (UX_DEVICE_CLASS_HUB_PARAMS *)command->ux_slave_class_command_parameter;
45 UX_DEVICE_CLASS_HUB         *hub;
46 
47     hub = (UX_DEVICE_CLASS_HUB *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DEVICE_CLASS_HUB));
48     UX_TEST_ASSERT(hub != UX_NULL);
49 
50     hub_class->ux_slave_class_instance = hub;
51     hub->hub_class = hub_class;
52 
53     hub->hub_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
54     UX_TEST_ASSERT(hub->hub_thread_stack != UX_NULL);
55     UX_TEST_CHECK_SUCCESS(_ux_device_thread_create(
56             &hub->hub_thread, "hub_thread",
57             _ux_device_class_hub_thread_entry, (ULONG)(ALIGN_TYPE)hub_class,
58             hub->hub_thread_stack, UX_THREAD_STACK_SIZE,
59             30, 30, 0, UX_DONT_START));
60     UX_THREAD_EXTENSION_PTR_SET(&hub->hub_thread, hub_class);
61 
62     /* Save parameters.  */
63     _ux_utility_memory_copy(&hub->params, hub_params, sizeof(*hub_params));
64 }
65 
_ux_device_class_hub_uninitialize(UX_SLAVE_CLASS_COMMAND * command)66 static VOID _ux_device_class_hub_uninitialize(UX_SLAVE_CLASS_COMMAND *command)
67 {
68 }
_ux_device_class_hub_notify_changes(UX_DEVICE_CLASS_HUB * hub,UCHAR * changes,UINT rpt_size)69 VOID _ux_device_class_hub_notify_changes(UX_DEVICE_CLASS_HUB *hub, UCHAR *changes, UINT rpt_size)
70 {
71 UX_SLAVE_ENDPOINT   *endpoint;
72 UX_SLAVE_TRANSFER   *transfer;
73 UCHAR               *buff;
74     endpoint = hub->interrupt_endpoint;
75     if (endpoint == UX_NULL || rpt_size == 0)
76         return;
77     transfer = &endpoint->ux_slave_endpoint_transfer_request;
78     buff = transfer->ux_slave_transfer_request_data_pointer;
79     if (rpt_size > transfer->ux_slave_transfer_request_transfer_length)
80         rpt_size = transfer->ux_slave_transfer_request_transfer_length;
81     transfer -> ux_slave_transfer_request_requested_length = rpt_size;
82     _ux_utility_memory_copy(buff, changes, rpt_size);
83     tx_thread_resume(&hub->hub_thread);
84 }
_ux_device_class_hub_notify_change(UX_DEVICE_CLASS_HUB * hub,UINT change_pos,UINT rpt_size)85 VOID _ux_device_class_hub_notify_change(UX_DEVICE_CLASS_HUB *hub, UINT change_pos, UINT rpt_size)
86 {
87 UX_SLAVE_ENDPOINT   *endpoint;
88 UX_SLAVE_TRANSFER   *transfer;
89 UCHAR               *buff;
90 UINT                byte_pos, bit_pos;
91     endpoint = hub->interrupt_endpoint;
92     if (endpoint == UX_NULL || rpt_size == 0)
93         return;
94     transfer = &endpoint->ux_slave_endpoint_transfer_request;
95     buff = transfer->ux_slave_transfer_request_data_pointer;
96     byte_pos = change_pos >> 3;
97     bit_pos = change_pos & 0x7u;
98     if (rpt_size >= transfer->ux_slave_transfer_request_transfer_length)
99         rpt_size = transfer->ux_slave_transfer_request_transfer_length;
100     if (byte_pos >= rpt_size)
101         return;
102     buff[byte_pos] |= 1u << bit_pos;
103     transfer -> ux_slave_transfer_request_requested_length = rpt_size;
104     tx_thread_resume(&hub->hub_thread);
105 }
106 
_ux_device_class_hub_activate(UX_SLAVE_CLASS_COMMAND * command)107 static UINT _ux_device_class_hub_activate(UX_SLAVE_CLASS_COMMAND *command)
108 {
109 
110 UX_SLAVE_CLASS              *hub_class = command->ux_slave_class_command_class_ptr;
111 UX_SLAVE_INTERFACE          *interface = (UX_SLAVE_INTERFACE *)command->ux_slave_class_command_interface;
112 UX_SLAVE_ENDPOINT           *endpoint;
113 UX_SLAVE_TRANSFER           *transfer;
114 UX_DEVICE_CLASS_HUB         *hub;
115 UINT                        i;
116 
117     hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance;
118 
119     /* Our dummy hub has one port. When the host sends the SetPortFeature request,
120        wIndex contains the port number, which is 1-based. USBX uses wIndex to
121        pick which class/interface to send the command to. The problem is that
122        in this case, wIndex is not an interface number! So we have to manually
123        link the port number (1 in this case) to this class. We just set every
124        entry since we don't expect there to be any other classes registered.
125        If we do start expecting that, then we'll handle it then (as opposed to now). */
126     for (i = 0; i < UX_MAX_SLAVE_INTERFACES; i++)
127     {
128         _ux_system_slave->ux_system_slave_interface_class_array[i] = hub_class;
129     }
130 
131     /* We need to get the interrupt in endpoint. */
132     endpoint = interface->ux_slave_interface_first_endpoint;
133     while (endpoint)
134     {
135         /* Is this interrupt in? */
136         if (endpoint->ux_slave_endpoint_descriptor.bmAttributes == 0x03 &&
137             (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) == 0x80)
138         {
139             /* Found it. */
140             break;
141         }
142 
143         endpoint = endpoint->ux_slave_endpoint_next_endpoint;
144     }
145     /* Note that we don't always expect there to be an endpoint since some tests
146        depend on no endpoint. */
147     if (endpoint)
148     {
149         hub->interrupt_endpoint = endpoint;
150 
151         /* If there is interrupt endpoint, create notify thread for notification support.  */
152         if (endpoint != UX_NULL)
153         {
154             transfer = &endpoint->ux_slave_endpoint_transfer_request;
155             transfer->ux_slave_transfer_request_data_pointer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, transfer->ux_slave_transfer_request_transfer_length);
156             if(transfer->ux_slave_transfer_request_data_pointer == UX_NULL)
157                 return(UX_MEMORY_INSUFFICIENT);
158         }
159     }
160 
161     if (hub->params.instance_activate)
162     {
163         hub->params.instance_activate(hub);
164     }
165     return(UX_SUCCESS);
166 }
167 
_ux_device_class_hub_deactivate(UX_SLAVE_CLASS_COMMAND * command)168 static VOID _ux_device_class_hub_deactivate(UX_SLAVE_CLASS_COMMAND *command)
169 {
170 
171 UX_SLAVE_CLASS              *hub_class = command->ux_slave_class_command_class_ptr;
172 UX_DEVICE_CLASS_HUB         *hub;
173 
174     hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance;
175     if (hub->interrupt_endpoint)
176     {
177         _ux_device_stack_transfer_abort(&hub->interrupt_endpoint->ux_slave_endpoint_transfer_request, UX_TRANSFER_BUS_RESET);
178         _ux_utility_memory_free(hub->interrupt_endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
179     }
180 
181     if (hub->params.instance_deactivate)
182     {
183         hub->params.instance_deactivate(hub);
184     }
185 }
186 
_ux_device_class_hub_change(UX_SLAVE_CLASS_COMMAND * command)187 static VOID _ux_device_class_hub_change(UX_SLAVE_CLASS_COMMAND *command)
188 {
189     UX_TEST_ASSERT(0);
190 }
191 
_ux_device_class_hub_control_request(UX_SLAVE_CLASS_COMMAND * command)192 static VOID _ux_device_class_hub_control_request(UX_SLAVE_CLASS_COMMAND *command)
193 {
194 
195 UCHAR                       *setup_data;
196 UCHAR                       bmRequestType;
197 UCHAR                       bRequest;
198 USHORT                      wValue;
199 USHORT                      wIndex;
200 USHORT                      wLength;
201 UCHAR                       port_index;
202 UCHAR                       descriptor_type;
203 UCHAR                       *data_ptr;
204 UX_SLAVE_DEVICE             *device;
205 UX_SLAVE_TRANSFER           *transfer_request;
206 UX_SLAVE_CLASS              *hub_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr;
207 UX_DEVICE_CLASS_HUB         *dummy_hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance;
208 
209     /* Get the pointer to the device.  */
210     device =  &_ux_system_slave->ux_system_slave_device;
211 
212     /* Get the pointer to the transfer request associated with the control endpoint.  */
213     transfer_request =  &device->ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
214 
215     setup_data = transfer_request->ux_slave_transfer_request_setup;
216     bmRequestType = setup_data[0];
217     bRequest = setup_data[1];
218     wValue = (USHORT)_ux_utility_short_get(&setup_data[2]);
219     wIndex = (USHORT)_ux_utility_short_get(&setup_data[4]);
220     wLength = (USHORT)_ux_utility_short_get(&setup_data[6]);
221 
222     data_ptr = transfer_request->ux_slave_transfer_request_data_pointer;
223 
224     switch (bRequest)
225     {
226 
227         case UX_SET_FEATURE:
228 
229             /* Get the port. */
230             port_index = (UCHAR) (wValue & 0x00ff);
231 
232             /* What feature? */
233             switch (wValue)
234             {
235 
236                 case UX_HOST_CLASS_HUB_PORT_RESET:
237 
238                     if (!dummy_hub->dont_reset_port_when_commanded_to)
239                     {
240 
241                         /* Tell the host we reset. */
242                         dummy_hub->port_change |= UX_HOST_CLASS_HUB_PORT_CHANGE_RESET;
243                         _ux_device_class_hub_notify_change(dummy_hub, 1, 1);
244                     }
245 
246                     /* Note that the speed is in port_status, and should've been
247                        set by the application. */
248 
249                     break;
250 
251                 case UX_HOST_CLASS_HUB_PORT_POWER:
252 
253                     /* Do nothing. */
254                     break;
255 
256                 default:
257 
258                     UX_TEST_ASSERT(0);
259                     break;
260             }
261 
262             break;
263 
264         case UX_CLEAR_FEATURE:
265 
266             /* What feature? */
267             switch (wValue)
268             {
269 
270                 case UX_HOST_CLASS_HUB_C_PORT_RESET:
271 
272                     /* Clear it. */
273                     dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_RESET);
274 
275                     break;
276 
277                 case UX_HOST_CLASS_HUB_C_PORT_ENABLE:
278 
279                     /* Clear it. */
280                     dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_ENABLE);
281 
282                     break;
283 
284                 case UX_HOST_CLASS_HUB_C_PORT_SUSPEND:
285 
286                     /* Clear it. */
287                     dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_SUSPEND);
288 
289                     break;
290 
291                 case UX_HOST_CLASS_HUB_C_PORT_OVER_CURRENT:
292 
293                     /* Clear it. */
294                     dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_OVER_CURRENT);
295 
296                     break;
297 
298                 case UX_HOST_CLASS_HUB_C_PORT_CONNECTION:
299 
300                     /* Clear it.  */
301                     dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION);
302                     break;
303 
304                 case UX_HOST_CLASS_HUB_PORT_ENABLE:
305 
306                     /* Do nothing. */
307                     break;
308 
309                 default:
310 
311                     UX_TEST_ASSERT(0);
312                     break;
313             }
314 
315             break;
316 
317         case UX_HOST_CLASS_HUB_GET_STATUS:
318 
319             /* Setup the data. */
320             *((USHORT *)&data_ptr[0]) = dummy_hub->port_status;
321             *((USHORT *)&data_ptr[2]) = dummy_hub->port_change;
322 
323             UX_TEST_CHECK_SUCCESS(_ux_device_stack_transfer_request(transfer_request, UX_HUB_DESCRIPTOR_LENGTH, UX_HUB_DESCRIPTOR_LENGTH));
324 
325             break;
326 
327         case UX_GET_DESCRIPTOR:
328 
329             /* Ensure this is for the hub descriptor and send it. */
330 
331             descriptor_type = (wValue & 0xff00) >> 8;
332             UX_TEST_ASSERT(descriptor_type == UX_HUB_DESCRIPTOR_ITEM);
333             UX_TEST_ASSERT(wLength == UX_HUB_DESCRIPTOR_LENGTH);
334 
335             _ux_utility_memory_copy(transfer_request->ux_slave_transfer_request_data_pointer, dummy_hub->params.descriptor, dummy_hub->params.descriptor_length);
336 
337             UX_TEST_CHECK_SUCCESS(_ux_device_stack_transfer_request(transfer_request, UX_HUB_DESCRIPTOR_LENGTH, UX_HUB_DESCRIPTOR_LENGTH));
338 
339             break;
340 
341         default:
342 
343             UX_TEST_ASSERT(0);
344             break;
345     }
346 }
347 
_ux_device_class_hub_entry(UX_SLAVE_CLASS_COMMAND * command)348 UINT _ux_device_class_hub_entry(UX_SLAVE_CLASS_COMMAND *command)
349 {
350 
351     switch(command -> ux_slave_class_command_request)
352     {
353 
354     case UX_SLAVE_CLASS_COMMAND_INITIALIZE:
355         _ux_device_class_hub_initialize(command);
356         break;
357 
358     case UX_SLAVE_CLASS_COMMAND_UNINITIALIZE:
359         _ux_device_class_hub_uninitialize(command);
360         break;
361 
362     case UX_SLAVE_CLASS_COMMAND_QUERY:
363         /* For now, always return success. */
364         break;
365 
366     case UX_SLAVE_CLASS_COMMAND_ACTIVATE:
367         return _ux_device_class_hub_activate(command);
368 
369     case UX_SLAVE_CLASS_COMMAND_CHANGE:
370         UX_TEST_ASSERT(0);
371         break;
372 
373     case UX_SLAVE_CLASS_COMMAND_DEACTIVATE:
374         _ux_device_class_hub_deactivate(command);
375         break;
376 
377     case UX_SLAVE_CLASS_COMMAND_REQUEST:
378         _ux_device_class_hub_control_request(command);
379         break;
380 
381     default:
382         UX_TEST_ASSERT(0);
383         break;
384 
385     }
386     return(UX_SUCCESS);
387 }
388