source: mainline/uspace/drv/usbhub/utils.c@ 10096231

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

hub is successfully initialized

  • Property mode set to 100644
File size: 17.9 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
29/** @addtogroup libusb usb
30 * @{
31 */
32/** @file
33 * @brief Hub driver.
34 */
35#include <driver.h>
36#include <usb/devreq.h>
37#include <usbhc_iface.h>
38#include <usb/usbdrv.h>
39#include <usb/descriptor.h>
40#include <driver.h>
41#include <bool.h>
42#include <errno.h>
43#include <usb/classes/hub.h>
44#include "usbhub.h"
45#include "usbhub_private.h"
46#include "port_status.h"
47#include <usb/devreq.h>
48
49static void check_hub_changes(void);
50
51size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
52
53//*********************************************
54//
55// various utils
56//
57//*********************************************
58
59//hub descriptor utils
60
61void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
62 //base size
63 size_t size = 7;
64 //variable size according to port count
65 size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
66 size += 2 * var_size;
67 uint8_t * result = (uint8_t*) malloc(size);
68 //size
69 result[0] = size;
70 //descriptor type
71 result[1] = USB_DESCTYPE_HUB;
72 result[2] = descriptor->ports_count;
73 /// @fixme handling of endianness??
74 result[3] = descriptor->hub_characteristics / 256;
75 result[4] = descriptor->hub_characteristics % 256;
76 result[5] = descriptor->pwr_on_2_good_time;
77 result[6] = descriptor->current_requirement;
78
79 size_t i;
80 for (i = 0; i < var_size; ++i) {
81 result[7 + i] = descriptor->devices_removable[i];
82 }
83 for (i = 0; i < var_size; ++i) {
84 result[7 + var_size + i] = 255;
85 }
86 return result;
87}
88
89usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
90 uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
91
92 if (sdescriptor[1] != USB_DESCTYPE_HUB) {
93 printf("[usb_hub] wrong descriptor %x\n",sdescriptor[1]);
94 return NULL;
95 }
96
97 usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t);
98
99
100 result->ports_count = sdescriptor[2];
101 /// @fixme handling of endianness??
102 result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
103 result->pwr_on_2_good_time = sdescriptor[5];
104 result->current_requirement = sdescriptor[6];
105 size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
106 result->devices_removable = (uint8_t*) malloc(var_size);
107 //printf("[usb_hub] getting removable devices data \n");
108 size_t i;
109 for (i = 0; i < var_size; ++i) {
110 result->devices_removable[i] = sdescriptor[7 + i];
111 }
112 return result;
113}
114
115//control transactions
116
117int usb_drv_sync_control_read(
118 int phone, usb_target_t target,
119 usb_device_request_setup_packet_t * request,
120 void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
121 ) {
122 usb_handle_t handle;
123 int opResult;
124 //setup
125 opResult = usb_drv_async_control_read_setup(phone, target,
126 request, sizeof (usb_device_request_setup_packet_t),
127 &handle);
128 if (opResult != EOK) {
129 return opResult;
130 }
131 opResult = usb_drv_async_wait_for(handle);
132 if (opResult != EOK) {
133 return opResult;
134 }
135 //read
136 opResult = usb_drv_async_control_read_data(phone, target,
137 rcvd_buffer, rcvd_size, actual_size,
138 &handle);
139 if (opResult != EOK) {
140 return opResult;
141 }
142 opResult = usb_drv_async_wait_for(handle);
143 if (opResult != EOK) {
144 return opResult;
145 }
146 //finalize
147 opResult = usb_drv_async_control_read_status(phone, target,
148 &handle);
149 if (opResult != EOK) {
150 return opResult;
151 }
152 opResult = usb_drv_async_wait_for(handle);
153 if (opResult != EOK) {
154 return opResult;
155 }
156 return EOK;
157}
158
159int usb_drv_sync_control_write(
160 int phone, usb_target_t target,
161 usb_device_request_setup_packet_t * request,
162 void * sent_buffer, size_t sent_size
163 ) {
164 usb_handle_t handle;
165 int opResult;
166 //setup
167 opResult = usb_drv_async_control_write_setup(phone, target,
168 request, sizeof (usb_device_request_setup_packet_t),
169 &handle);
170 if (opResult != EOK) {
171 return opResult;
172 }
173 opResult = usb_drv_async_wait_for(handle);
174 if (opResult != EOK) {
175 return opResult;
176 }
177 //write
178 opResult = usb_drv_async_control_write_data(phone, target,
179 sent_buffer, sent_size,
180 &handle);
181 if (opResult != EOK) {
182 return opResult;
183 }
184 opResult = usb_drv_async_wait_for(handle);
185 if (opResult != EOK) {
186 return opResult;
187 }
188 //finalize
189 opResult = usb_drv_async_control_write_status(phone, target,
190 &handle);
191 if (opResult != EOK) {
192 return opResult;
193 }
194 opResult = usb_drv_async_wait_for(handle);
195 if (opResult != EOK) {
196 return opResult;
197 }
198 return EOK;
199}
200
201//list implementation
202
203usb_general_list_t * usb_lst_create(void) {
204 usb_general_list_t* result = usb_new(usb_general_list_t);
205 usb_lst_init(result);
206 return result;
207}
208
209void usb_lst_init(usb_general_list_t * lst) {
210 lst->prev = lst;
211 lst->next = lst;
212 lst->data = NULL;
213}
214
215void usb_lst_prepend(usb_general_list_t* item, void* data) {
216 usb_general_list_t* appended = usb_new(usb_general_list_t);
217 appended->data = data;
218 appended->next = item;
219 appended->prev = item->prev;
220 item->prev->next = appended;
221 item->prev = appended;
222}
223
224void usb_lst_append(usb_general_list_t* item, void* data) {
225 usb_general_list_t* appended = usb_new(usb_general_list_t);
226 appended->data = data;
227 appended->next = item->next;
228 appended->prev = item;
229 item->next->prev = appended;
230 item->next = appended;
231}
232
233void usb_lst_remove(usb_general_list_t* item) {
234 item->next->prev = item->prev;
235 item->prev->next = item->next;
236}
237
238static void usb_hub_test_port_status(void) {
239 printf("[usb_hub] -------------port status test---------\n");
240 usb_port_status_t status = 0;
241
242 //printf("original status %d (should be 0)\n",(uint32_t)status);
243 usb_port_set_bit(&status, 1, 1);
244 //printf("%d =?= 2\n",(uint32_t)status);
245 if (status != 2) {
246 printf("[usb_port_status] test failed: wrong set of bit 1\n");
247 return;
248 }
249 usb_port_set_bit(&status, 3, 1);
250 if (status != 10) {
251 printf("[usb_port_status] test failed: wrong set of bit 3\n");
252 return;
253 }
254
255 usb_port_set_bit(&status, 15, 1);
256 if (status != 10 + (1 << 15)) {
257 printf("[usb_port_status] test failed: wrong set of bit 15\n");
258 return;
259 }
260 usb_port_set_bit(&status, 1, 0);
261 if (status != 8 + (1 << 15)) {
262 printf("[usb_port_status] test failed: wrong unset of bit 1\n");
263 return;
264 }
265 int i;
266 for (i = 0; i < 32; ++i) {
267 if (i == 3 || i == 15) {
268 if (!usb_port_get_bit(&status, i)) {
269 printf("[usb_port_status] test failed: wrong bit at %d\n", i);
270 }
271 } else {
272 if (usb_port_get_bit(&status, i)) {
273 printf("[usb_port_status] test failed: wrong bit at %d\n", i);
274 }
275 }
276 }
277
278 printf("test ok\n");
279
280
281 //printf("%d =?= 10\n",(uint32_t)status);
282
283 //printf("this should be 0: %d \n",usb_port_get_bit(&status,0));
284 //printf("this should be 1: %d \n",usb_port_get_bit(&status,1));
285 //printf("this should be 0: %d \n",usb_port_get_bit(&status,2));
286 //printf("this should be 1: %d \n",usb_port_get_bit(&status,3));
287 //printf("this should be 0: %d \n",usb_port_get_bit(&status,4));
288
289
290
291
292}
293
294//*********************************************
295//
296// hub driver code, initialization
297//
298//*********************************************
299
300usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
301 usb_hub_info_t* result = usb_new(usb_hub_info_t);
302 //result->device = device;
303 result->port_count = -1;
304
305
306 //printf("[usb_hub] phone to hc = %d\n", hc);
307 if (hc < 0) {
308 return result;
309 }
310 //get some hub info
311 usb_address_t addr = usb_drv_get_my_address(hc, device);
312 addr = 7;
313 printf("[usb_hub] addres of newly created hub = %d\n", addr);
314 /*if(addr<0){
315 //return result;
316
317 }*/
318
319 result->device = usb_new(usb_hcd_attached_device_info_t);
320 result->device->address = addr;
321
322 // get hub descriptor
323 usb_target_t target;
324 target.address = addr;
325 target.endpoint = 0;
326 usb_device_request_setup_packet_t request;
327 //printf("[usb_hub] creating descriptor request\n");
328 usb_hub_set_descriptor_request(&request);
329
330 //printf("[usb_hub] creating serialized descriptor\n");
331 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
332 usb_hub_descriptor_t * descriptor;
333 size_t received_size;
334 int opResult;
335 //printf("[usb_hub] starting control transaction\n");
336 opResult = usb_drv_sync_control_read(
337 hc, target, &request, serialized_descriptor,
338 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
339 if (opResult != EOK) {
340 printf("[usb_hub] failed when receiving hub descriptor, badcode = %d\n",opResult);
341 ///\TODO memory leak will occur here!
342 return result;
343 }
344 //printf("[usb_hub] deserializing descriptor\n");
345 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
346 if(descriptor==NULL){
347 printf("[usb_hub] could not deserialize descriptor \n");
348 result->port_count = 1;///\TODO this code is only for debug!!!
349 return result;
350 }
351 //printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
352 result->port_count = descriptor->ports_count;
353 //printf("[usb_hub] freeing data\n");
354 free(serialized_descriptor);
355 free(descriptor->devices_removable);
356 free(descriptor);
357
358 //finish
359
360 printf("[usb_hub] hub info created\n");
361
362 return result;
363}
364
365/** Callback when new hub device is detected.
366 *
367 * @param dev New device.
368 * @return Error code.
369 */
370int usb_add_hub_device(device_t *dev) {
371 printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
372 printf("[usb_hub] hub device\n");
373
374 /*
375 * We are some (probably deeply nested) hub.
376 * Thus, assign our own operations and explore already
377 * connected devices.
378 */
379
380 //create the hub structure
381 //get hc connection
382 /// \TODO correct params
383 int hc = usb_drv_hc_connect(dev, 0);
384
385 usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
386 int port;
387 int opResult;
388 usb_device_request_setup_packet_t request;
389 usb_target_t target;
390 target.address = hub_info->device->address;
391 target.endpoint = 0;
392 for (port = 0; port < hub_info->port_count; ++port) {
393 usb_hub_set_power_port_request(&request, port);
394 opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
395 if (opResult != EOK) {
396 printf("[usb_hub]something went wrong when setting hub`s %dth port\n", port);
397 }
398 }
399 //ports powered, hub seems to be enabled
400
401 ipc_hangup(hc);
402
403 //add the hub to list
404 usb_lst_append(&usb_hub_list, hub_info);
405 printf("[usb_hub] hub info added to list\n");
406 //(void)hub_info;
407 check_hub_changes();
408
409 /// \TODO start the check loop, if not already started...
410
411 //this is just a test for port status bitmap type
412 usb_hub_test_port_status();
413
414 printf("[usb_hub] hub dev added\n");
415
416 return EOK;
417 //return ENOTSUP;
418}
419
420//*********************************************
421//
422// hub driver code, main loop
423//
424//*********************************************
425
426/**
427 * reset the port with new device and reserve the default address
428 * @param hc
429 * @param port
430 * @param target
431 */
432
433static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
434 usb_device_request_setup_packet_t request;
435 int opResult;
436 printf("[usb_hub] some connection changed\n");
437
438 opResult = usb_drv_reserve_default_address(hc);
439 if (opResult != EOK) {
440 printf("[usb_hub] cannot assign default address, it is probably used\n");
441 return;
442 }
443 //reset port
444 usb_hub_set_reset_port_request(&request, port);
445 opResult = usb_drv_sync_control_write(
446 hc, target,
447 &request,
448 NULL, 0
449 );
450 if (opResult != EOK) {
451 //continue;
452 printf("[usb_hub] something went wrong when reseting a port\n");
453 }
454}
455
456/**
457 * finalize adding new device after port reset
458 * @param hc
459 * @param port
460 * @param target
461 */
462static void usb_hub_finalize_add_device(
463 int hc, uint16_t port, usb_target_t target) {
464
465 usb_device_request_setup_packet_t request;
466 int opResult;
467 printf("[usb_hub] finalizing add device\n");
468 usb_address_t new_device_address =
469 usb_drv_request_address(hc);
470 usb_hub_set_set_address_request
471 (&request, new_device_address);
472 opResult = usb_drv_sync_control_write(
473 hc, target,
474 &request,
475 NULL, 0
476 );
477 if (opResult != EOK) {
478 printf("[usb_hub] could not set address for new device\n");
479 //will retry later...
480 return;
481 }
482 usb_drv_release_default_address(hc);
483
484
485 /// \TODO driver work
486 //add_child_device.....
487}
488
489/**
490 * unregister device address in hc, close the port
491 * @param hc
492 * @param port
493 * @param target
494 */
495static void usb_hub_removed_device(int hc, uint16_t port, usb_target_t target) {
496 usb_device_request_setup_packet_t request;
497 int opResult;
498 //disable port
499 usb_hub_set_disable_port_request(&request, port);
500 opResult = usb_drv_sync_control_write(
501 hc, target,
502 &request,
503 NULL, 0
504 );
505 if (opResult != EOK) {
506 //continue;
507 printf("[usb_hub] something went wrong when disabling a port\n");
508 }
509 //remove device
510 //close address
511 //
512
513 ///\TODO this code is not complete
514}
515
516/**
517 * process interrupts on given hub port
518 * @param hc
519 * @param port
520 * @param target
521 */
522static void usb_hub_process_interrupt(int hc, uint16_t port, usb_target_t target) {
523 printf("[usb_hub] interrupt at port %d\n", port);
524 //determine type of change
525 usb_port_status_t status;
526 size_t rcvd_size;
527 usb_device_request_setup_packet_t request;
528 int opResult;
529 usb_hub_set_port_status_request(&request, port);
530
531 opResult = usb_drv_sync_control_read(
532 hc, target,
533 &request,
534 &status, 4, &rcvd_size
535 );
536 if (opResult != EOK) {
537 printf("[usb_hub] ERROR: could not get port status\n");
538 return;
539 }
540 if (rcvd_size != sizeof (usb_port_status_t)) {
541 printf("[usb_hub] ERROR: received status has incorrect size\n");
542 return;
543 }
544 //something connected/disconnected
545 if (usb_port_connect_change(&status)) {
546 if (usb_port_dev_connected(&status)) {
547 printf("[usb_hub] some connection changed\n");
548 usb_hub_init_add_device(hc, port, target);
549 } else {
550 usb_hub_removed_device(hc, port, target);
551 }
552 }
553 //port reset
554 if (usb_port_reset_completed(&status)) {
555 printf("[usb_hub] finalizing add device\n");
556 if (usb_port_enabled(&status)) {
557 usb_hub_finalize_add_device(hc, port, target);
558 } else {
559 printf("[usb_hub] ERROR: port reset, but port still not enabled\n");
560 }
561 }
562
563 usb_port_set_connect_change(&status, false);
564 usb_port_set_reset(&status, false);
565 usb_port_set_reset_completed(&status, false);
566 usb_port_set_dev_connected(&status, false);
567 if (status) {
568 printf("[usb_hub]there was some unsupported change on port\n");
569 }
570 /// \TODO handle other changes
571 /// \TODO debug log for various situations
572
573
574
575 /*
576 //configure device
577 usb_drv_reserve_default_address(hc);
578
579 usb_address_t new_device_address = usb_drv_request_address(hc);
580
581
582 usb_drv_release_default_address(hc);
583 * */
584}
585
586/** Check changes on all known hubs.
587 */
588static void check_hub_changes(void) {
589 /*
590 * Iterate through all hubs.
591 */
592 usb_general_list_t * lst_item;
593 for (lst_item = usb_hub_list.next;
594 lst_item != &usb_hub_list;
595 lst_item = lst_item->next) {
596 printf("[usb_hub] checking hub changes\n");
597 /*
598 * Check status change pipe of this hub.
599 */
600
601 usb_target_t target = {
602 .address = 5,
603 .endpoint = 1
604 };
605 /// \TODO uncomment once it works correctly
606 //target.address = usb_create_hub_info(lst_item)->device->address;
607
608 size_t port_count = 7;
609
610 /*
611 * Connect to respective HC.
612 */
613 /// \FIXME this is incorrect code: here
614 /// must be used particular device instead of NULL
615 //which one?
616 int hc = usb_drv_hc_connect(NULL, 0);
617 if (hc < 0) {
618 continue;
619 }
620
621 // FIXME: count properly
622 size_t byte_length = (port_count / 8) + 1;
623
624 void *change_bitmap = malloc(byte_length);
625 size_t actual_size;
626 usb_handle_t handle;
627
628 /*
629 * Send the request.
630 */
631 int opResult = usb_drv_async_interrupt_in(hc, target,
632 change_bitmap, byte_length, &actual_size,
633 &handle);
634
635 usb_drv_async_wait_for(handle);
636
637 if (opResult != EOK) {
638 printf("[usb_hub] something went wrong while getting status of hub\n");
639 continue;
640 }
641 unsigned int port;
642 for (port = 0; port < port_count; ++port) {
643 bool interrupt = (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
644 if (interrupt) {
645 usb_hub_process_interrupt(hc, port, target);
646 }
647 }
648
649
650 /*
651 * TODO: handle the changes.
652 */
653
654 /*
655 * WARNING: sample code, will not work out of the box.
656 * And does not contain code for checking for errors.
657 */
658#if 0
659 /*
660 * Before opening the port, we must acquire the default
661 * address.
662 */
663 usb_drv_reserve_default_address(hc);
664
665 usb_address_t new_device_address = usb_drv_request_address(hc);
666
667 // TODO: open the port
668
669 // TODO: send request for setting address to new_device_address
670
671 /*
672 * Once new address is set, we can release the default
673 * address.
674 */
675 usb_drv_release_default_address(hc);
676
677 /*
678 * Obtain descriptors and create match ids for devman.
679 */
680
681 // TODO: get device descriptors
682
683 // TODO: create match ids
684
685 // TODO: add child device
686
687 // child_device_register sets the device handle
688 // TODO: store it here
689 devman_handle_t new_device_handle = 0;
690
691 /*
692 * Inform the HC that the new device has devman handle
693 * assigned.
694 */
695 usb_drv_bind_address(hc, new_device_address, new_device_handle);
696
697 /*
698 * That's all.
699 */
700#endif
701
702
703 /*
704 * Hang-up the HC-connected phone.
705 */
706 ipc_hangup(hc);
707 }
708}
709
710/**
711 * @}
712 */
Note: See TracBrowser for help on using the repository browser.