source: mainline/uspace/drv/usbhub/usbhub.c@ 4a5e2f1

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

merge with /usb/development (compilation fix)

  • Property mode set to 100644
File size: 14.3 KB
RevLine 
[e080332]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
[71ed4849]39#include <usb_iface.h>
[e080332]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"
[f40a1e2]48#include "usb/usb.h"
[e080332]49
[71ed4849]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
[e080332]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);
[5097bed4]78 dprintf(1,"[usb_hub] address of newly created hub = %d", addr);
[e080332]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");
[f40a1e2]95
96 opResult = usb_drv_req_get_descriptor(hc, addr,
97 USB_REQUEST_TYPE_CLASS,
98 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
[e080332]99 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
[f40a1e2]100
[e080332]101 if (opResult != EOK) {
102 dprintf(1,"[usb_hub] 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,"[usb_hub] 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,"[usb_hub] 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,"[usb_hub] 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 */
[71ed4849]143 dev->ops = &hub_device_ops;
[e080332]144
145 //create the hub structure
146 //get hc connection
[71ed4849]147 int hc = usb_drv_hc_connect_auto(dev, 0);
148 if (hc < 0) {
149 return hc;
150 }
[e080332]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,"[usb_hub] could not get device descriptor, %d",opResult);
167 return opResult;
168 }
169 dprintf(1,"[usb_hub] hub has %d configurations",std_descriptor.configuration_count);
170 if(std_descriptor.configuration_count<1){
171 dprintf(1,"[usb_hub] THERE ARE NO CONFIGURATIONS AVAILABLE");
[f40a1e2]172 //shouldn`t I return?
[e080332]173 }
[5097bed4]174 /// \TODO check other configurations
[e080332]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,"[usb_hub] could not get configuration descriptor, %d",opResult);
181 return opResult;
182 }
183 //set configuration
[f40a1e2]184 opResult = usb_drv_req_set_configuration(hc, target.address,
185 config_descriptor.configuration_number);
186
[e080332]187 if (opResult != EOK) {
188 dprintf(1,"[usb_hub]something went wrong when setting hub`s configuration, %d", opResult);
189 }
190
[f40a1e2]191 usb_device_request_setup_packet_t request;
[e080332]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,"[usb_hub] powering port %d",port);
196 if (opResult != EOK) {
197 dprintf(1,"[usb_hub]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
[5097bed4]205 futex_down(&usb_hub_list_lock);
[e080332]206 usb_lst_append(&usb_hub_list, hub_info);
[5097bed4]207 futex_up(&usb_hub_list_lock);
208
[e080332]209 dprintf(1,"[usb_hub] hub info added to list");
210 //(void)hub_info;
211 usb_hub_check_hub_changes();
212
213
214
215 dprintf(1,"[usb_hub] 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
[5097bed4]232/**
[f40a1e2]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).
[5097bed4]235 * @param hc
236 * @return
237 */
238inline static int usb_hub_release_default_address(int hc){
239 int opResult;
240 dprintf(1,"[usb_hub] releasing default address");
241 opResult = usb_drv_release_default_address(hc);
242 if (opResult != EOK) {
243 dprintf(1,"[usb_hub] failed to release default address");
244 }
245 return opResult;
246}
247
[e080332]248/**
[f40a1e2]249 * Reset the port with new device and reserve the default address.
[e080332]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,"[usb_hub] some connection changed");
258 //get default address
259 opResult = usb_drv_reserve_default_address(hc);
260 if (opResult != EOK) {
261 dprintf(1,"[usb_hub] 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,"[usb_hub] something went wrong when reseting a port");
[5097bed4]273 usb_hub_release_default_address(hc);
[e080332]274 }
275}
276
277/**
[f40a1e2]278 * Finalize adding new device after port reset
[e080332]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,"[usb_hub] 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,"[usb_hub] 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,"[usb_hub] failed to get free USB address");
300 opResult = new_device_address;
301 usb_hub_release_default_address(hc);
302 return;
303 }
304 dprintf(1,"[usb_hub] 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,"[usb_hub] 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,"[usb_hub] 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,"[usb_hub] could not assign address of device in hcd");
333 return;
334 }
335 dprintf(1,"[usb_hub] new device address %d, handle %zu",
336 new_device_address, child_handle);
337
338}
339
340/**
[f40a1e2]341 * Unregister device address in hc
[e080332]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;
[5097bed4]350
[f40a1e2]351 /** \TODO remove device from device manager - not yet implemented in
352 * devide manager
353 */
[e080332]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/**
[f40a1e2]374 * Process interrupts on given hub port
[e080332]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);
[f40a1e2]432 if (status>>16) {
433 dprintf(1,"[usb_hub]there was some unsupported change on port %d: %X",port,status);
434
[e080332]435 }
436 /// \TODO handle other changes
437 /// \TODO debug log for various situations
438
439}
440
[f40a1e2]441/**
442 * Check changes on all known hubs.
[e080332]443 */
444void usb_hub_check_hub_changes(void) {
445 /*
446 * Iterate through all hubs.
447 */
448 usb_general_list_t * lst_item;
[5097bed4]449 futex_down(&usb_hub_list_lock);
[e080332]450 for (lst_item = usb_hub_list.next;
451 lst_item != &usb_hub_list;
452 lst_item = lst_item->next) {
[5097bed4]453 futex_up(&usb_hub_list_lock);
[e080332]454 usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
455 /*
456 * Check status change pipe of this hub.
457 */
458
459 usb_target_t target;
460 target.address = hub_info->usb_device->address;
461 target.endpoint = 1;/// \TODO get from endpoint descriptor
[6986418]462 /*dprintf(1,"[usb_hub] checking changes for hub at addr %d",
463 target.address);*/
[e080332]464
465 size_t port_count = hub_info->port_count;
466
467 /*
468 * Connect to respective HC.
469 */
[71ed4849]470 int hc = usb_drv_hc_connect_auto(hub_info->device, 0);
[e080332]471 if (hc < 0) {
472 continue;
473 }
474
475 /// FIXME: count properly
476 size_t byte_length = ((port_count+1) / 8) + 1;
477
478 void *change_bitmap = malloc(byte_length);
479 size_t actual_size;
480 usb_handle_t handle;
481
482 /*
483 * Send the request.
484 */
485 int opResult = usb_drv_async_interrupt_in(hc, target,
486 change_bitmap, byte_length, &actual_size,
487 &handle);
488
489 usb_drv_async_wait_for(handle);
490
491 if (opResult != EOK) {
492 dprintf(1,"[usb_hub] something went wrong while getting status of hub");
493 continue;
494 }
495 unsigned int port;
496 for (port = 1; port < port_count+1; ++port) {
497 bool interrupt =
498 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
499 if (interrupt) {
500 usb_hub_process_interrupt(
501 hub_info, hc, port, hub_info->usb_device->address);
502 }
503 }
[5097bed4]504 free(change_bitmap);
[e080332]505
506 ipc_hangup(hc);
[5097bed4]507 futex_down(&usb_hub_list_lock);
[e080332]508 }
[5097bed4]509 futex_up(&usb_hub_list_lock);
[e080332]510}
511
512
513
514
515
516/**
517 * @}
[71ed4849]518 */
Note: See TracBrowser for help on using the repository browser.