source: mainline/uspace/drv/usbhub/usbhub.c@ 0cfc68f0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0cfc68f0 was 0cfc68f0, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Hub driver: debugging messages clean-up

Removed duplicit prefix of the message.

Corrected some indentation issues.

  • Property mode set to 100644
File size: 14.0 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 <usb_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#include "usb/usb.h"
49
50static usb_iface_t hub_usb_iface = {
51 .get_hc_handle = usb_drv_find_hc
52};
53
54static device_ops_t hub_device_ops = {
55 .interfaces[USB_DEV_IFACE] = &hub_usb_iface
56};
57
58//*********************************************
59//
60// hub driver code, initialization
61//
62//*********************************************
63
64usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
65 usb_hub_info_t* result = usb_new(usb_hub_info_t);
66 //result->device = device;
67 result->port_count = -1;
68 /// \TODO is this correct? is the device stored?
69 result->device = device;
70
71
72 //printf("[usb_hub] phone to hc = %d\n", hc);
73 if (hc < 0) {
74 return result;
75 }
76 //get some hub info
77 usb_address_t addr = usb_drv_get_my_address(hc, device);
78 dprintf(1, "address of newly created hub = %d", addr);
79 /*if(addr<0){
80 //return result;
81
82 }*/
83
84 result->usb_device = usb_new(usb_hcd_attached_device_info_t);
85 result->usb_device->address = addr;
86
87 // get hub descriptor
88
89 //printf("[usb_hub] creating serialized descriptor\n");
90 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
91 usb_hub_descriptor_t * descriptor;
92 size_t received_size;
93 int opResult;
94 //printf("[usb_hub] starting control transaction\n");
95
96 opResult = usb_drv_req_get_descriptor(hc, addr,
97 USB_REQUEST_TYPE_CLASS,
98 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
99 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
100
101 if (opResult != EOK) {
102 dprintf(1, "failed when receiving hub descriptor, badcode = %d",opResult);
103 free(serialized_descriptor);
104 return result;
105 }
106 //printf("[usb_hub] deserializing descriptor\n");
107 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
108 if(descriptor==NULL){
109 dprintf(1, "could not deserialize descriptor ");
110 result->port_count = 1;///\TODO this code is only for debug!!!
111 return result;
112 }
113 //printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
114 result->port_count = descriptor->ports_count;
115 result->attached_devs = (usb_hub_attached_device_t*)
116 malloc((result->port_count+1) * sizeof(usb_hub_attached_device_t));
117 int i;
118 for(i=0;i<result->port_count+1;++i){
119 result->attached_devs[i].devman_handle=0;
120 result->attached_devs[i].address=0;
121 }
122 //printf("[usb_hub] freeing data\n");
123 free(serialized_descriptor);
124 free(descriptor->devices_removable);
125 free(descriptor);
126
127 //finish
128
129 dprintf(1, "hub info created");
130
131 return result;
132}
133
134int usb_add_hub_device(device_t *dev) {
135 dprintf(1, "add_hub_device(handle=%d)", (int) dev->handle);
136 dprintf(1, "hub device");
137
138 /*
139 * We are some (probably deeply nested) hub.
140 * Thus, assign our own operations and explore already
141 * connected devices.
142 */
143 dev->ops = &hub_device_ops;
144
145 //create the hub structure
146 //get hc connection
147 int hc = usb_drv_hc_connect_auto(dev, 0);
148 if (hc < 0) {
149 return hc;
150 }
151
152 usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
153 int port;
154 int opResult;
155 usb_target_t target;
156 target.address = hub_info->usb_device->address;
157 target.endpoint = 0;
158
159 //get configuration descriptor
160 // this is not fully correct - there are more configurations
161 // and all should be checked
162 usb_standard_device_descriptor_t std_descriptor;
163 opResult = usb_drv_req_get_device_descriptor(hc, target.address,
164 &std_descriptor);
165 if(opResult!=EOK){
166 dprintf(1, "could not get device descriptor, %d",opResult);
167 return opResult;
168 }
169 dprintf(1, "hub has %d configurations",std_descriptor.configuration_count);
170 if(std_descriptor.configuration_count<1){
171 dprintf(1, "THERE ARE NO CONFIGURATIONS AVAILABLE");
172 //shouldn`t I return?
173 }
174 /// \TODO check other configurations
175 usb_standard_configuration_descriptor_t config_descriptor;
176 opResult = usb_drv_req_get_bare_configuration_descriptor(hc,
177 target.address, 0,
178 &config_descriptor);
179 if(opResult!=EOK){
180 dprintf(1, "could not get configuration descriptor, %d",opResult);
181 return opResult;
182 }
183 //set configuration
184 opResult = usb_drv_req_set_configuration(hc, target.address,
185 config_descriptor.configuration_number);
186
187 if (opResult != EOK) {
188 dprintf(1, "something went wrong when setting hub`s configuration, %d", opResult);
189 }
190
191 usb_device_request_setup_packet_t request;
192 for (port = 1; port < hub_info->port_count+1; ++port) {
193 usb_hub_set_power_port_request(&request, port);
194 opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
195 dprintf(1, "powering port %d",port);
196 if (opResult != EOK) {
197 dprintf(1, "something went wrong when setting hub`s %dth port", port);
198 }
199 }
200 //ports powered, hub seems to be enabled
201
202 ipc_hangup(hc);
203
204 //add the hub to list
205 futex_down(&usb_hub_list_lock);
206 usb_lst_append(&usb_hub_list, hub_info);
207 futex_up(&usb_hub_list_lock);
208
209 dprintf(1, "hub info added to list");
210 //(void)hub_info;
211 usb_hub_check_hub_changes();
212
213
214
215 dprintf(1, "hub dev added");
216 dprintf(1, "\taddress %d, has %d ports ",
217 hub_info->usb_device->address,
218 hub_info->port_count);
219 dprintf(1, "\tused configuration %d",config_descriptor.configuration_number);
220
221 return EOK;
222 //return ENOTSUP;
223}
224
225
226//*********************************************
227//
228// hub driver code, main loop
229//
230//*********************************************
231
232/**
233 * Convenience function for releasing default address and writing debug info
234 * (these few lines are used too often to be written again and again).
235 * @param hc
236 * @return
237 */
238inline static int usb_hub_release_default_address(int hc){
239 int opResult;
240 dprintf(1, "releasing default address");
241 opResult = usb_drv_release_default_address(hc);
242 if (opResult != EOK) {
243 dprintf(1, "failed to release default address");
244 }
245 return opResult;
246}
247
248/**
249 * Reset the port with new device and reserve the default address.
250 * @param hc
251 * @param port
252 * @param target
253 */
254static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
255 usb_device_request_setup_packet_t request;
256 int opResult;
257 dprintf(1, "some connection changed");
258 //get default address
259 opResult = usb_drv_reserve_default_address(hc);
260 if (opResult != EOK) {
261 dprintf(1, "cannot assign default address, it is probably used");
262 return;
263 }
264 //reset port
265 usb_hub_set_reset_port_request(&request, port);
266 opResult = usb_drv_sync_control_write(
267 hc, target,
268 &request,
269 NULL, 0
270 );
271 if (opResult != EOK) {
272 dprintf(1, "something went wrong when reseting a port");
273 usb_hub_release_default_address(hc);
274 }
275}
276
277/**
278 * Finalize adding new device after port reset
279 * @param hc
280 * @param port
281 * @param target
282 */
283static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
284 int hc, uint16_t port, usb_target_t target) {
285
286 int opResult;
287 dprintf(1, "finalizing add device");
288 opResult = usb_hub_clear_port_feature(hc, target.address,
289 port, USB_HUB_FEATURE_C_PORT_RESET);
290 if (opResult != EOK) {
291 dprintf(1, "failed to clear port reset feature");
292 usb_hub_release_default_address(hc);
293 return;
294 }
295
296 /* Request address at from host controller. */
297 usb_address_t new_device_address = usb_drv_request_address(hc);
298 if (new_device_address < 0) {
299 dprintf(1, "failed to get free USB address");
300 opResult = new_device_address;
301 usb_hub_release_default_address(hc);
302 return;
303 }
304 dprintf(1, "setting new address");
305 opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
306 new_device_address);
307
308 if (opResult != EOK) {
309 dprintf(1, "could not set address for new device");
310 usb_hub_release_default_address(hc);
311 return;
312 }
313
314
315 opResult = usb_hub_release_default_address(hc);
316 if(opResult!=EOK){
317 return;
318 }
319
320 devman_handle_t child_handle;
321 opResult = usb_drv_register_child_in_devman(hc, hub->device,
322 new_device_address, &child_handle);
323 if (opResult != EOK) {
324 dprintf(1, "could not start driver for new device");
325 return;
326 }
327 hub->attached_devs[port].devman_handle = child_handle;
328 hub->attached_devs[port].address = new_device_address;
329
330 opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
331 if (opResult != EOK) {
332 dprintf(1, "could not assign address of device in hcd");
333 return;
334 }
335 dprintf(1, "new device address %d, handle %zu",
336 new_device_address, child_handle);
337
338}
339
340/**
341 * Unregister device address in hc
342 * @param hc
343 * @param port
344 * @param target
345 */
346static void usb_hub_removed_device(
347 usb_hub_info_t * hub, int hc, uint16_t port, usb_target_t target) {
348 //usb_device_request_setup_packet_t request;
349 int opResult;
350
351 /** \TODO remove device from device manager - not yet implemented in
352 * devide manager
353 */
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, "could not release address of " \
361 "removed device: %d", opResult);
362 }
363 hub->attached_devs[port].address = 0;
364 }else{
365 dprintf(1, "this is strange, disconnected device had no address");
366 //device was disconnected before it`s port was reset - return default address
367 usb_drv_release_default_address(hc);
368 }
369}
370
371/**
372 * Process interrupts on given hub port
373 * @param hc
374 * @param port
375 * @param target
376 */
377static void usb_hub_process_interrupt(usb_hub_info_t * hub, int hc,
378 uint16_t port, usb_address_t address) {
379 dprintf(1, "interrupt at port %d", port);
380 //determine type of change
381 usb_target_t target;
382 target.address=address;
383 target.endpoint=0;
384 usb_port_status_t status;
385 size_t rcvd_size;
386 usb_device_request_setup_packet_t request;
387 int opResult;
388 usb_hub_set_port_status_request(&request, port);
389 //endpoint 0
390
391 opResult = usb_drv_sync_control_read(
392 hc, target,
393 &request,
394 &status, 4, &rcvd_size
395 );
396 if (opResult != EOK) {
397 dprintf(1, "ERROR: could not get port status");
398 return;
399 }
400 if (rcvd_size != sizeof (usb_port_status_t)) {
401 dprintf(1, "ERROR: received status has incorrect size");
402 return;
403 }
404 //something connected/disconnected
405 if (usb_port_connect_change(&status)) {
406 opResult = usb_hub_clear_port_feature(hc, target.address,
407 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
408 // TODO: check opResult
409 if (usb_port_dev_connected(&status)) {
410 dprintf(1, "some connection changed");
411 usb_hub_init_add_device(hc, port, target);
412 } else {
413 usb_hub_removed_device(hub, hc, port, target);
414 }
415 }
416 //port reset
417 if (usb_port_reset_completed(&status)) {
418 dprintf(1, "port reset complete");
419 if (usb_port_enabled(&status)) {
420 usb_hub_finalize_add_device(hub, hc, port, target);
421 } else {
422 dprintf(1, "ERROR: port reset, but port still not enabled");
423 }
424 }
425
426 usb_port_set_connect_change(&status, false);
427 usb_port_set_reset(&status, false);
428 usb_port_set_reset_completed(&status, false);
429 usb_port_set_dev_connected(&status, false);
430 if (status>>16) {
431 dprintf(1, "there was some unsupported change on port %d: %X",port,status);
432
433 }
434 /// \TODO handle other changes
435 /// \TODO debug log for various situations
436
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 futex_down(&usb_hub_list_lock);
448 for (lst_item = usb_hub_list.next;
449 lst_item != &usb_hub_list;
450 lst_item = lst_item->next) {
451 futex_up(&usb_hub_list_lock);
452 usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
453 /*
454 * Check status change pipe of this hub.
455 */
456
457 usb_target_t target;
458 target.address = hub_info->usb_device->address;
459 target.endpoint = 1;/// \TODO get from endpoint descriptor
460 dprintf(1, "checking changes for hub at addr %d",
461 target.address);
462
463 size_t port_count = hub_info->port_count;
464
465 /*
466 * Connect to respective HC.
467 */
468 int hc = usb_drv_hc_connect_auto(hub_info->device, 0);
469 if (hc < 0) {
470 continue;
471 }
472
473 /// FIXME: count properly
474 size_t byte_length = ((port_count+1) / 8) + 1;
475
476 void *change_bitmap = malloc(byte_length);
477 size_t actual_size;
478 usb_handle_t handle;
479
480 /*
481 * Send the request.
482 */
483 int opResult = usb_drv_async_interrupt_in(hc, target,
484 change_bitmap, byte_length, &actual_size,
485 &handle);
486
487 usb_drv_async_wait_for(handle);
488
489 if (opResult != EOK) {
490 dprintf(1, "something went wrong while getting status of hub");
491 continue;
492 }
493 unsigned int port;
494 for (port = 1; port < port_count+1; ++port) {
495 bool interrupt =
496 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
497 if (interrupt) {
498 usb_hub_process_interrupt(
499 hub_info, hc, port, hub_info->usb_device->address);
500 }
501 }
502 free(change_bitmap);
503
504 ipc_hangup(hc);
505 futex_down(&usb_hub_list_lock);
506 }
507 futex_up(&usb_hub_list_lock);
508}
509
510
511
512
513
514/**
515 * @}
516 */
Note: See TracBrowser for help on using the repository browser.