source: mainline/uspace/drv/usbhub/usbhub.c@ e080332

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e080332 was e080332, checked in by Matus Dekanek <smekideki@…>, 15 years ago

usb hub code refactoring

  • Property mode set to 100644
File size: 14.3 KB
Line 
1/*
2 * Copyright (c) 2010 Matus Dekanek
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup usb hub driver
29 * @{
30 */
31/** @file
32 * @brief usb hub main functionality
33 */
34
35#include <driver.h>
36#include <bool.h>
37#include <errno.h>
38
39#include <usbhc_iface.h>
40#include <usb/usbdrv.h>
41#include <usb/descriptor.h>
42#include <usb/devreq.h>
43#include <usb/classes/hub.h>
44
45#include "usbhub.h"
46#include "usbhub_private.h"
47#include "port_status.h"
48
49//*********************************************
50//
51// hub driver code, initialization
52//
53//*********************************************
54
55usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
56 usb_hub_info_t* result = usb_new(usb_hub_info_t);
57 //result->device = device;
58 result->port_count = -1;
59 /// \TODO is this correct? is the device stored?
60 result->device = device;
61
62
63 //printf("[usb_hub] phone to hc = %d\n", hc);
64 if (hc < 0) {
65 return result;
66 }
67 //get some hub info
68 usb_address_t addr = usb_drv_get_my_address(hc, device);
69 dprintf(1,"[usb_hub] addres of newly created hub = %d", addr);
70 /*if(addr<0){
71 //return result;
72
73 }*/
74
75 result->usb_device = usb_new(usb_hcd_attached_device_info_t);
76 result->usb_device->address = addr;
77
78 // get hub descriptor
79 usb_target_t target;
80 target.address = addr;
81 target.endpoint = 0;
82 usb_device_request_setup_packet_t request;
83 //printf("[usb_hub] creating descriptor request\n");
84 usb_hub_set_descriptor_request(&request);
85
86 //printf("[usb_hub] creating serialized descriptor\n");
87 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
88 usb_hub_descriptor_t * descriptor;
89 size_t received_size;
90 int opResult;
91 //printf("[usb_hub] starting control transaction\n");
92 opResult = usb_drv_sync_control_read(
93 hc, target, &request, serialized_descriptor,
94 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
95 if (opResult != EOK) {
96 dprintf(1,"[usb_hub] failed when receiving hub descriptor, badcode = %d",opResult);
97 free(serialized_descriptor);
98 return result;
99 }
100 //printf("[usb_hub] deserializing descriptor\n");
101 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
102 if(descriptor==NULL){
103 dprintf(1,"[usb_hub] could not deserialize descriptor ");
104 result->port_count = 1;///\TODO this code is only for debug!!!
105 return result;
106 }
107 //printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
108 result->port_count = descriptor->ports_count;
109 result->attached_devs = (usb_hub_attached_device_t*)
110 malloc((result->port_count+1) * sizeof(usb_hub_attached_device_t));
111 int i;
112 for(i=0;i<result->port_count+1;++i){
113 result->attached_devs[i].devman_handle=0;
114 result->attached_devs[i].address=0;
115 }
116 //printf("[usb_hub] freeing data\n");
117 free(serialized_descriptor);
118 free(descriptor->devices_removable);
119 free(descriptor);
120
121 //finish
122
123 dprintf(1,"[usb_hub] hub info created");
124
125 return result;
126}
127
128int usb_add_hub_device(device_t *dev) {
129 dprintf(1, "add_hub_device(handle=%d)", (int) dev->handle);
130 dprintf(1,"[usb_hub] hub device");
131
132 /*
133 * We are some (probably deeply nested) hub.
134 * Thus, assign our own operations and explore already
135 * connected devices.
136 */
137
138 //create the hub structure
139 //get hc connection
140 int hc = usb_drv_hc_connect(dev, 0);
141
142 usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
143 int port;
144 int opResult;
145 usb_device_request_setup_packet_t request;
146 usb_target_t target;
147 target.address = hub_info->usb_device->address;
148 target.endpoint = 0;
149
150 //get configuration descriptor
151 // this is not fully correct - there are more configurations
152 // and all should be checked
153 usb_standard_device_descriptor_t std_descriptor;
154 opResult = usb_drv_req_get_device_descriptor(hc, target.address,
155 &std_descriptor);
156 if(opResult!=EOK){
157 dprintf(1,"[usb_hub] could not get device descriptor, %d",opResult);
158 return opResult;
159 }
160 dprintf(1,"[usb_hub] hub has %d configurations",std_descriptor.configuration_count);
161 if(std_descriptor.configuration_count<1){
162 dprintf(1,"[usb_hub] THERE ARE NO CONFIGURATIONS AVAILABLE");
163 }
164 usb_standard_configuration_descriptor_t config_descriptor;
165 opResult = usb_drv_req_get_bare_configuration_descriptor(hc,
166 target.address, 0,
167 &config_descriptor);
168 if(opResult!=EOK){
169 dprintf(1,"[usb_hub] could not get configuration descriptor, %d",opResult);
170 return opResult;
171 }
172 //set configuration
173 request.request_type = 0;
174 request.request = USB_DEVREQ_SET_CONFIGURATION;
175 request.index=0;
176 request.length=0;
177 request.value_high=0;
178 request.value_low = config_descriptor.configuration_number;
179 opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
180 if (opResult != EOK) {
181 dprintf(1,"[usb_hub]something went wrong when setting hub`s configuration, %d", opResult);
182 }
183
184
185 for (port = 1; port < hub_info->port_count+1; ++port) {
186 usb_hub_set_power_port_request(&request, port);
187 opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
188 dprintf(1,"[usb_hub] powering port %d",port);
189 if (opResult != EOK) {
190 dprintf(1,"[usb_hub]something went wrong when setting hub`s %dth port", port);
191 }
192 }
193 //ports powered, hub seems to be enabled
194
195
196 ipc_hangup(hc);
197
198 //add the hub to list
199 usb_lst_append(&usb_hub_list, hub_info);
200 dprintf(1,"[usb_hub] hub info added to list");
201 //(void)hub_info;
202 usb_hub_check_hub_changes();
203
204
205
206 dprintf(1,"[usb_hub] hub dev added");
207 dprintf(1,"\taddress %d, has %d ports ",
208 hub_info->usb_device->address,
209 hub_info->port_count);
210 dprintf(1,"\tused configuration %d",config_descriptor.configuration_number);
211
212 return EOK;
213 //return ENOTSUP;
214}
215
216
217
218//*********************************************
219//
220// hub driver code, main loop
221//
222//*********************************************
223
224/**
225 * reset the port with new device and reserve the default address
226 * @param hc
227 * @param port
228 * @param target
229 */
230static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
231 usb_device_request_setup_packet_t request;
232 int opResult;
233 dprintf(1,"[usb_hub] some connection changed");
234 //get default address
235 opResult = usb_drv_reserve_default_address(hc);
236 if (opResult != EOK) {
237 dprintf(1,"[usb_hub] cannot assign default address, it is probably used");
238 return;
239 }
240 //reset port
241 usb_hub_set_reset_port_request(&request, port);
242 opResult = usb_drv_sync_control_write(
243 hc, target,
244 &request,
245 NULL, 0
246 );
247 if (opResult != EOK) {
248 dprintf(1,"[usb_hub] something went wrong when reseting a port");
249 }
250}
251
252/**
253 * convenience function for releasing default address and writing debug info
254 * (these few lines are used too often to be written again and again)
255 * @param hc
256 * @return
257 */
258inline static int usb_hub_release_default_address(int hc){
259 int opResult;
260 dprintf(1,"[usb_hub] releasing default address");
261 opResult = usb_drv_release_default_address(hc);
262 if (opResult != EOK) {
263 dprintf(1,"[usb_hub] failed to release default address");
264 }
265 return opResult;
266}
267
268
269/**
270 * finalize adding new device after port reset
271 * @param hc
272 * @param port
273 * @param target
274 */
275static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
276 int hc, uint16_t port, usb_target_t target) {
277
278 int opResult;
279 dprintf(1,"[usb_hub] finalizing add device");
280 opResult = usb_hub_clear_port_feature(hc, target.address,
281 port, USB_HUB_FEATURE_C_PORT_RESET);
282 if (opResult != EOK) {
283 dprintf(1,"[usb_hub] failed to clear port reset feature");
284 usb_hub_release_default_address(hc);
285 return;
286 }
287
288 /* Request address at from host controller. */
289 usb_address_t new_device_address = usb_drv_request_address(hc);
290 if (new_device_address < 0) {
291 dprintf(1,"[usb_hub] failed to get free USB address");
292 opResult = new_device_address;
293 usb_hub_release_default_address(hc);
294 return;
295 }
296 dprintf(1,"[usb_hub] setting new address");
297 opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
298 new_device_address);
299
300 if (opResult != EOK) {
301 dprintf(1,"[usb_hub] could not set address for new device");
302 usb_hub_release_default_address(hc);
303 return;
304 }
305
306
307 opResult = usb_hub_release_default_address(hc);
308 if(opResult!=EOK){
309 return;
310 }
311
312 devman_handle_t child_handle;
313 opResult = usb_drv_register_child_in_devman(hc, hub->device,
314 new_device_address, &child_handle);
315 if (opResult != EOK) {
316 dprintf(1,"[usb_hub] could not start driver for new device");
317 return;
318 }
319 hub->attached_devs[port].devman_handle = child_handle;
320 hub->attached_devs[port].address = new_device_address;
321
322 opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
323 if (opResult != EOK) {
324 dprintf(1,"[usb_hub] could not assign address of device in hcd");
325 return;
326 }
327 dprintf(1,"[usb_hub] new device address %d, handle %zu",
328 new_device_address, child_handle);
329
330}
331
332/**
333 * unregister device address in hc, close the port
334 * @param hc
335 * @param port
336 * @param target
337 */
338static void usb_hub_removed_device(
339 usb_hub_info_t * hub, int hc, uint16_t port, usb_target_t target) {
340 //usb_device_request_setup_packet_t request;
341 int opResult;
342 //disable port
343 /*usb_hub_set_disable_port_request(&request, port);
344 opResult = usb_drv_sync_control_write(
345 hc, target,
346 &request,
347 NULL, 0
348 );
349 if (opResult != EOK) {
350 //continue;
351 printf("[usb_hub] something went wrong when disabling a port\n");
352 }*/
353 /// \TODO remove device
354
355 hub->attached_devs[port].devman_handle=0;
356 //close address
357 if(hub->attached_devs[port].address!=0){
358 opResult = usb_drv_release_address(hc,hub->attached_devs[port].address);
359 if(opResult != EOK) {
360 dprintf(1,
361 "[usb_hub] could not release address of removed device: %d"
362 ,opResult);
363 }
364 hub->attached_devs[port].address = 0;
365 }else{
366 dprintf(1,
367 "[usb_hub] this is strange, disconnected device had no address");
368 //device was disconnected before it`s port was reset - return default address
369 usb_drv_release_default_address(hc);
370 }
371}
372
373/**
374 * process interrupts on given hub port
375 * @param hc
376 * @param port
377 * @param target
378 */
379static void usb_hub_process_interrupt(usb_hub_info_t * hub, int hc,
380 uint16_t port, usb_address_t address) {
381 dprintf(1,"[usb_hub] interrupt at port %d", port);
382 //determine type of change
383 usb_target_t target;
384 target.address=address;
385 target.endpoint=0;
386 usb_port_status_t status;
387 size_t rcvd_size;
388 usb_device_request_setup_packet_t request;
389 int opResult;
390 usb_hub_set_port_status_request(&request, port);
391 //endpoint 0
392
393 opResult = usb_drv_sync_control_read(
394 hc, target,
395 &request,
396 &status, 4, &rcvd_size
397 );
398 if (opResult != EOK) {
399 dprintf(1,"[usb_hub] ERROR: could not get port status");
400 return;
401 }
402 if (rcvd_size != sizeof (usb_port_status_t)) {
403 dprintf(1,"[usb_hub] ERROR: received status has incorrect size");
404 return;
405 }
406 //something connected/disconnected
407 if (usb_port_connect_change(&status)) {
408 opResult = usb_hub_clear_port_feature(hc, target.address,
409 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
410 // TODO: check opResult
411 if (usb_port_dev_connected(&status)) {
412 dprintf(1,"[usb_hub] some connection changed");
413 usb_hub_init_add_device(hc, port, target);
414 } else {
415 usb_hub_removed_device(hub, hc, port, target);
416 }
417 }
418 //port reset
419 if (usb_port_reset_completed(&status)) {
420 dprintf(1,"[usb_hub] port reset complete");
421 if (usb_port_enabled(&status)) {
422 usb_hub_finalize_add_device(hub, hc, port, target);
423 } else {
424 dprintf(1,"[usb_hub] ERROR: port reset, but port still not enabled");
425 }
426 }
427
428 usb_port_set_connect_change(&status, false);
429 usb_port_set_reset(&status, false);
430 usb_port_set_reset_completed(&status, false);
431 usb_port_set_dev_connected(&status, false);
432 if (status) {
433 dprintf(1,"[usb_hub]there was some unsupported change on port %d",port);
434 }
435 /// \TODO handle other changes
436 /// \TODO debug log for various situations
437
438}
439
440/* Check changes on all known hubs.
441 */
442void usb_hub_check_hub_changes(void) {
443 /*
444 * Iterate through all hubs.
445 */
446 usb_general_list_t * lst_item;
447 for (lst_item = usb_hub_list.next;
448 lst_item != &usb_hub_list;
449 lst_item = lst_item->next) {
450 usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
451 /*
452 * Check status change pipe of this hub.
453 */
454
455 usb_target_t target;
456 target.address = hub_info->usb_device->address;
457 target.endpoint = 1;/// \TODO get from endpoint descriptor
458 dprintf(1,"[usb_hub] checking changes for hub at addr %d",
459 target.address);
460
461 size_t port_count = hub_info->port_count;
462
463 /*
464 * Connect to respective HC.
465 */
466 int hc = usb_drv_hc_connect(hub_info->device, 0);
467 if (hc < 0) {
468 continue;
469 }
470
471 /// FIXME: count properly
472 size_t byte_length = ((port_count+1) / 8) + 1;
473
474 void *change_bitmap = malloc(byte_length);
475 size_t actual_size;
476 usb_handle_t handle;
477
478 /*
479 * Send the request.
480 */
481 int opResult = usb_drv_async_interrupt_in(hc, target,
482 change_bitmap, byte_length, &actual_size,
483 &handle);
484
485 usb_drv_async_wait_for(handle);
486
487 if (opResult != EOK) {
488 dprintf(1,"[usb_hub] something went wrong while getting status of hub");
489 continue;
490 }
491 unsigned int port;
492 for (port = 1; port < port_count+1; ++port) {
493 bool interrupt =
494 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
495 if (interrupt) {
496 usb_hub_process_interrupt(
497 hub_info, hc, port, hub_info->usb_device->address);
498 }
499 }
500
501 ipc_hangup(hc);
502 }
503}
504
505
506
507
508
509/**
510 * @}
511 */
Note: See TracBrowser for help on using the repository browser.