source: mainline/uspace/drv/usbhub/utils.c@ 98d06b8

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

hub driver:
connect a new device
init a hub

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