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

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

using correct usb address api at hub driver

  • 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 printf("[usb_hub] addres of newly created hub = %d\n", addr);
313 /*if(addr<0){
314 //return result;
315
316 }*/
317
318 result->device = usb_new(usb_hcd_attached_device_info_t);
319 result->device->address = addr;
320
321 // get hub descriptor
322 usb_target_t target;
323 target.address = addr;
324 target.endpoint = 0;
325 usb_device_request_setup_packet_t request;
326 //printf("[usb_hub] creating descriptor request\n");
327 usb_hub_set_descriptor_request(&request);
328
329 //printf("[usb_hub] creating serialized descriptor\n");
330 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
331 usb_hub_descriptor_t * descriptor;
332 size_t received_size;
333 int opResult;
334 //printf("[usb_hub] starting control transaction\n");
335 opResult = usb_drv_sync_control_read(
336 hc, target, &request, serialized_descriptor,
337 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
338 if (opResult != EOK) {
339 printf("[usb_hub] failed when receiving hub descriptor, badcode = %d\n",opResult);
340 ///\TODO memory leak will occur here!
341 return result;
342 }
343 //printf("[usb_hub] deserializing descriptor\n");
344 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
345 if(descriptor==NULL){
346 printf("[usb_hub] could not deserialize descriptor \n");
347 result->port_count = 1;///\TODO this code is only for debug!!!
348 return result;
349 }
350 //printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
351 result->port_count = descriptor->ports_count;
352 //printf("[usb_hub] freeing data\n");
353 free(serialized_descriptor);
354 free(descriptor->devices_removable);
355 free(descriptor);
356
357 //finish
358
359 printf("[usb_hub] hub info created\n");
360
361 return result;
362}
363
364/** Callback when new hub device is detected.
365 *
366 * @param dev New device.
367 * @return Error code.
368 */
369int usb_add_hub_device(device_t *dev) {
370 printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
371 printf("[usb_hub] hub device\n");
372
373 /*
374 * We are some (probably deeply nested) hub.
375 * Thus, assign our own operations and explore already
376 * connected devices.
377 */
378
379 //create the hub structure
380 //get hc connection
381 /// \TODO correct params
382 int hc = usb_drv_hc_connect(dev, 0);
383
384 usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
385 int port;
386 int opResult;
387 usb_device_request_setup_packet_t request;
388 usb_target_t target;
389 target.address = hub_info->device->address;
390 target.endpoint = 0;
391 for (port = 0; port < hub_info->port_count; ++port) {
392 usb_hub_set_power_port_request(&request, port);
393 opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
394 if (opResult != EOK) {
395 printf("[usb_hub]something went wrong when setting hub`s %dth port\n", port);
396 }
397 }
398 //ports powered, hub seems to be enabled
399
400 ipc_hangup(hc);
401
402 //add the hub to list
403 usb_lst_append(&usb_hub_list, hub_info);
404 printf("[usb_hub] hub info added to list\n");
405 //(void)hub_info;
406 check_hub_changes();
407
408 /// \TODO start the check loop, if not already started...
409
410 //this is just a test for port status bitmap type
411 usb_hub_test_port_status();
412
413 printf("[usb_hub] hub dev added\n");
414
415 return EOK;
416 //return ENOTSUP;
417}
418
419//*********************************************
420//
421// hub driver code, main loop
422//
423//*********************************************
424
425/**
426 * reset the port with new device and reserve the default address
427 * @param hc
428 * @param port
429 * @param target
430 */
431
432static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
433 usb_device_request_setup_packet_t request;
434 int opResult;
435 printf("[usb_hub] some connection changed\n");
436
437 opResult = usb_drv_reserve_default_address(hc);
438 if (opResult != EOK) {
439 printf("[usb_hub] cannot assign default address, it is probably used\n");
440 return;
441 }
442 //reset port
443 usb_hub_set_reset_port_request(&request, port);
444 opResult = usb_drv_sync_control_write(
445 hc, target,
446 &request,
447 NULL, 0
448 );
449 if (opResult != EOK) {
450 //continue;
451 printf("[usb_hub] something went wrong when reseting a port\n");
452 }
453}
454
455/**
456 * finalize adding new device after port reset
457 * @param hc
458 * @param port
459 * @param target
460 */
461static void usb_hub_finalize_add_device(
462 int hc, uint16_t port, usb_target_t target) {
463
464 usb_device_request_setup_packet_t request;
465 int opResult;
466 printf("[usb_hub] finalizing add device\n");
467 usb_address_t new_device_address =
468 usb_drv_request_address(hc);
469 usb_hub_set_set_address_request
470 (&request, new_device_address);
471 opResult = usb_drv_sync_control_write(
472 hc, target,
473 &request,
474 NULL, 0
475 );
476 if (opResult != EOK) {
477 printf("[usb_hub] could not set address for new device\n");
478 //will retry later...
479 return;
480 }
481 usb_drv_release_default_address(hc);
482
483
484 /// \TODO driver work
485 //add_child_device.....
486}
487
488/**
489 * unregister device address in hc, close the port
490 * @param hc
491 * @param port
492 * @param target
493 */
494static void usb_hub_removed_device(int hc, uint16_t port, usb_target_t target) {
495 usb_device_request_setup_packet_t request;
496 int opResult;
497 //disable port
498 usb_hub_set_disable_port_request(&request, port);
499 opResult = usb_drv_sync_control_write(
500 hc, target,
501 &request,
502 NULL, 0
503 );
504 if (opResult != EOK) {
505 //continue;
506 printf("[usb_hub] something went wrong when disabling a port\n");
507 }
508 //remove device
509 //close address
510 //
511
512 ///\TODO this code is not complete
513}
514
515/**
516 * process interrupts on given hub port
517 * @param hc
518 * @param port
519 * @param target
520 */
521static void usb_hub_process_interrupt(int hc, uint16_t port, usb_target_t target) {
522 printf("[usb_hub] interrupt at port %d\n", port);
523 //determine type of change
524 usb_port_status_t status;
525 size_t rcvd_size;
526 usb_device_request_setup_packet_t request;
527 int opResult;
528 usb_hub_set_port_status_request(&request, port);
529
530 opResult = usb_drv_sync_control_read(
531 hc, target,
532 &request,
533 &status, 4, &rcvd_size
534 );
535 if (opResult != EOK) {
536 printf("[usb_hub] ERROR: could not get port status\n");
537 return;
538 }
539 if (rcvd_size != sizeof (usb_port_status_t)) {
540 printf("[usb_hub] ERROR: received status has incorrect size\n");
541 return;
542 }
543 //something connected/disconnected
544 if (usb_port_connect_change(&status)) {
545 if (usb_port_dev_connected(&status)) {
546 printf("[usb_hub] some connection changed\n");
547 usb_hub_init_add_device(hc, port, target);
548 } else {
549 usb_hub_removed_device(hc, port, target);
550 }
551 }
552 //port reset
553 if (usb_port_reset_completed(&status)) {
554 printf("[usb_hub] finalizing add device\n");
555 if (usb_port_enabled(&status)) {
556 usb_hub_finalize_add_device(hc, port, target);
557 } else {
558 printf("[usb_hub] ERROR: port reset, but port still not enabled\n");
559 }
560 }
561
562 usb_port_set_connect_change(&status, false);
563 usb_port_set_reset(&status, false);
564 usb_port_set_reset_completed(&status, false);
565 usb_port_set_dev_connected(&status, false);
566 if (status) {
567 printf("[usb_hub]there was some unsupported change on port\n");
568 }
569 /// \TODO handle other changes
570 /// \TODO debug log for various situations
571
572
573
574 /*
575 //configure device
576 usb_drv_reserve_default_address(hc);
577
578 usb_address_t new_device_address = usb_drv_request_address(hc);
579
580
581 usb_drv_release_default_address(hc);
582 * */
583}
584
585/** Check changes on all known hubs.
586 */
587static void check_hub_changes(void) {
588 /*
589 * Iterate through all hubs.
590 */
591 usb_general_list_t * lst_item;
592 for (lst_item = usb_hub_list.next;
593 lst_item != &usb_hub_list;
594 lst_item = lst_item->next) {
595 printf("[usb_hub] checking hub changes\n");
596 /*
597 * Check status change pipe of this hub.
598 */
599
600 usb_target_t target = {
601 .address = 5,
602 .endpoint = 1
603 };
604 /// \TODO uncomment once it works correctly
605 //target.address = usb_create_hub_info(lst_item)->device->address;
606
607 size_t port_count = 7;
608
609 /*
610 * Connect to respective HC.
611 */
612 /// \FIXME this is incorrect code: here
613 /// must be used particular device instead of NULL
614 //which one?
615 int hc = usb_drv_hc_connect(NULL, 0);
616 if (hc < 0) {
617 continue;
618 }
619
620 // FIXME: count properly
621 size_t byte_length = (port_count / 8) + 1;
622
623 void *change_bitmap = malloc(byte_length);
624 size_t actual_size;
625 usb_handle_t handle;
626
627 /*
628 * Send the request.
629 */
630 int opResult = usb_drv_async_interrupt_in(hc, target,
631 change_bitmap, byte_length, &actual_size,
632 &handle);
633
634 usb_drv_async_wait_for(handle);
635
636 if (opResult != EOK) {
637 printf("[usb_hub] something went wrong while getting status of hub\n");
638 continue;
639 }
640 unsigned int port;
641 for (port = 0; port < port_count; ++port) {
642 bool interrupt = (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
643 if (interrupt) {
644 usb_hub_process_interrupt(hc, port, target);
645 }
646 }
647
648
649 /*
650 * TODO: handle the changes.
651 */
652
653 /*
654 * WARNING: sample code, will not work out of the box.
655 * And does not contain code for checking for errors.
656 */
657#if 0
658 /*
659 * Before opening the port, we must acquire the default
660 * address.
661 */
662 usb_drv_reserve_default_address(hc);
663
664 usb_address_t new_device_address = usb_drv_request_address(hc);
665
666 // TODO: open the port
667
668 // TODO: send request for setting address to new_device_address
669
670 /*
671 * Once new address is set, we can release the default
672 * address.
673 */
674 usb_drv_release_default_address(hc);
675
676 /*
677 * Obtain descriptors and create match ids for devman.
678 */
679
680 // TODO: get device descriptors
681
682 // TODO: create match ids
683
684 // TODO: add child device
685
686 // child_device_register sets the device handle
687 // TODO: store it here
688 devman_handle_t new_device_handle = 0;
689
690 /*
691 * Inform the HC that the new device has devman handle
692 * assigned.
693 */
694 usb_drv_bind_address(hc, new_device_address, new_device_handle);
695
696 /*
697 * That's all.
698 */
699#endif
700
701
702 /*
703 * Hang-up the HC-connected phone.
704 */
705 ipc_hangup(hc);
706 }
707}
708
709/**
710 * @}
711 */
Note: See TracBrowser for help on using the repository browser.