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