Changeset c83a55c in mainline for uspace/lib
- Timestamp:
- 2011-10-31T06:52:54Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c25e39b
- Parents:
- e8ab32f (diff), 3ce78580 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- uspace/lib
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/include/usb/dev/driver.h
re8ab32f rc83a55c 161 161 } usb_driver_t; 162 162 163 int usb_driver_main( usb_driver_t *);163 int usb_driver_main(const usb_driver_t *); 164 164 165 165 int usb_device_select_interface(usb_device_t *, uint8_t, … … 171 171 usb_endpoint_mapping_t **, size_t *); 172 172 int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t); 173 int usb_device_ create(ddf_dev_t *, const usb_endpoint_description_t **,174 usb_device_t **, const char **);173 int usb_device_init(usb_device_t *, ddf_dev_t *, 174 const usb_endpoint_description_t **, const char **); 175 175 void usb_device_deinit(usb_device_t *); 176 176 177 void * usb_device_data_alloc(usb_device_t *, size_t); 177 178 … … 179 180 int usb_alternate_interfaces_create(const uint8_t *, size_t, int, 180 181 usb_alternate_interfaces_t **); 181 182 void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *); 182 183 #endif 183 184 /** -
uspace/lib/usbdev/src/altiface.c
re8ab32f rc83a55c 98 98 assert(config_descr_size > 0); 99 99 100 *alternates_ptr = NULL; 100 101 if (interface_number < 0) { 101 alternates_ptr = NULL;102 102 return EOK; 103 103 } … … 105 105 usb_alternate_interfaces_t *alternates 106 106 = malloc(sizeof(usb_alternate_interfaces_t)); 107 108 107 if (alternates == NULL) { 109 108 return ENOMEM; … … 119 118 } 120 119 121 alternates->alternatives = malloc(alternates->alternative_count122 *sizeof(usb_alternate_interface_descriptors_t));120 alternates->alternatives = calloc(alternates->alternative_count, 121 sizeof(usb_alternate_interface_descriptors_t)); 123 122 if (alternates->alternatives == NULL) { 124 123 free(alternates); … … 176 175 } 177 176 178 177 void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *alternate) 178 { 179 if (!alternate) 180 return; 181 free(alternate->alternatives); 182 free(alternate); 183 } 179 184 /** 180 185 * @} -
uspace/lib/usbdev/src/devdrv.c
re8ab32f rc83a55c 64 64 * @return Task exit status. 65 65 */ 66 int usb_driver_main( usb_driver_t *drv)66 int usb_driver_main(const usb_driver_t *drv) 67 67 { 68 68 assert(drv != NULL); … … 140 140 assert(driver->ops->device_add); 141 141 142 int rc; 143 144 usb_device_t *dev = NULL; 142 usb_device_t *dev = ddf_dev_data_alloc(gen_dev, sizeof(usb_device_t)); 143 if (dev == NULL) { 144 usb_log_error("USB device `%s' structure allocation failed.\n", 145 gen_dev->name); 146 return ENOMEM; 147 } 145 148 const char *err_msg = NULL; 146 rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);147 if (rc != EOK) { 148 usb_log_error("USB device `%s' creationfailed (%s): %s.\n",149 int rc = usb_device_init(dev, gen_dev, driver->endpoints, &err_msg); 150 if (rc != EOK) { 151 usb_log_error("USB device `%s' init failed (%s): %s.\n", 149 152 gen_dev->name, err_msg, str_error(rc)); 150 153 return rc; 151 154 } 152 gen_dev->driver_data = dev;153 155 154 156 rc = driver->ops->device_add(dev); … … 516 518 517 519 518 /** Create new instance of USB device. 519 * 520 /** Initialize new instance of USB device. 521 * 522 * @param[in] usb_dev Pointer to the new device. 520 523 * @param[in] ddf_dev Generic DDF device backing the USB one. 521 524 * @param[in] endpoints NULL terminated array of endpoints (NULL for none). 522 * @param[out] dev_ptr Where to store pointer to the new device.523 525 * @param[out] errstr_ptr Where to store description of context 524 526 * (in case error occurs). 525 527 * @return Error code. 526 528 */ 527 int usb_device_create(ddf_dev_t *ddf_dev, 528 const usb_endpoint_description_t **endpoints, 529 usb_device_t **dev_ptr, const char **errstr_ptr) 530 { 531 assert(dev_ptr != NULL); 529 int usb_device_init(usb_device_t *usb_dev, ddf_dev_t *ddf_dev, 530 const usb_endpoint_description_t **endpoints, const char **errstr_ptr) 531 { 532 assert(usb_dev != NULL); 532 533 assert(ddf_dev != NULL); 533 534 534 int rc; 535 536 usb_device_t *dev = malloc(sizeof(usb_device_t)); 537 if (dev == NULL) { 538 *errstr_ptr = "structure allocation"; 539 return ENOMEM; 540 } 541 542 // FIXME: proper deallocation in case of errors 543 544 dev->ddf_dev = ddf_dev; 545 dev->driver_data = NULL; 546 dev->descriptors.configuration = NULL; 547 dev->alternate_interfaces = NULL; 548 549 dev->pipes_count = 0; 550 dev->pipes = NULL; 535 usb_dev->ddf_dev = ddf_dev; 536 usb_dev->driver_data = NULL; 537 usb_dev->descriptors.configuration = NULL; 538 usb_dev->alternate_interfaces = NULL; 539 usb_dev->pipes_count = 0; 540 usb_dev->pipes = NULL; 551 541 552 542 /* Initialize backing wire and control pipe. */ 553 rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);543 int rc = init_wire_and_ctrl_pipe(usb_dev, errstr_ptr); 554 544 if (rc != EOK) { 555 545 return rc; … … 557 547 558 548 /* Get our interface. */ 559 dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);549 usb_dev->interface_no = usb_device_get_assigned_interface(ddf_dev); 560 550 561 551 /* Retrieve standard descriptors. */ 562 rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe, 563 &dev->descriptors); 564 if (rc != EOK) { 552 rc = usb_device_retrieve_descriptors(&usb_dev->ctrl_pipe, 553 &usb_dev->descriptors); 554 if (rc != EOK) { 555 /* Nothing allocated, nothing to free. */ 565 556 *errstr_ptr = "descriptor retrieval"; 566 557 return rc; 567 558 } 568 559 569 /* Create alternate interfaces. */ 570 rc = usb_alternate_interfaces_create(dev->descriptors.configuration, 571 dev->descriptors.configuration_size, dev->interface_no, 572 &dev->alternate_interfaces); 573 if (rc != EOK) { 574 /* We will try to silently ignore this. */ 575 dev->alternate_interfaces = NULL; 576 } 577 578 rc = initialize_other_pipes(endpoints, dev, 0); 579 if (rc != EOK) { 560 /* Create alternate interfaces. We will silently ignore failure. */ 561 //TODO Why ignore? 562 usb_alternate_interfaces_create(usb_dev->descriptors.configuration, 563 usb_dev->descriptors.configuration_size, usb_dev->interface_no, 564 &usb_dev->alternate_interfaces); 565 566 rc = initialize_other_pipes(endpoints, usb_dev, 0); 567 if (rc != EOK) { 568 /* Full configuration descriptor is allocated. */ 569 free(usb_dev->descriptors.configuration); 570 /* Alternate interfaces may be allocated */ 571 usb_alternate_interfaces_destroy(usb_dev->alternate_interfaces); 580 572 *errstr_ptr = "pipes initialization"; 581 573 return rc; … … 583 575 584 576 *errstr_ptr = NULL; 585 *dev_ptr = dev;586 577 587 578 return EOK; 588 579 } 589 580 590 /** Destroyinstance of a USB device.581 /** Clean instance of a USB device. 591 582 * 592 583 * @param dev Device to be de-initialized. … … 596 587 void usb_device_deinit(usb_device_t *dev) 597 588 { 598 if (dev == NULL) { 599 return; 600 } 601 602 /* Ignore errors and hope for the best. */ 603 destroy_current_pipes(dev); 604 605 if (dev->alternate_interfaces != NULL) { 606 free(dev->alternate_interfaces->alternatives); 607 } 608 free(dev->alternate_interfaces); 609 free(dev->descriptors.configuration); 610 free(dev->driver_data); 589 if (dev) { 590 /* Ignore errors and hope for the best. */ 591 destroy_current_pipes(dev); 592 593 usb_alternate_interfaces_destroy(dev->alternate_interfaces); 594 free(dev->descriptors.configuration); 595 free(dev->driver_data); 596 } 611 597 } 612 598 -
uspace/lib/usbhost/include/usb/host/endpoint.h
re8ab32f rc83a55c 36 36 #define LIBUSBHOST_HOST_ENDPOINT_H 37 37 38 #include <assert.h>39 38 #include <bool.h> 40 39 #include <adt/list.h> 41 40 #include <fibril_synch.h> 42 43 41 #include <usb/usb.h> 44 42 43 /** Host controller side endpoint structure. */ 45 44 typedef struct endpoint { 45 /** Part of linked list. */ 46 link_t link; 47 /** USB address. */ 46 48 usb_address_t address; 49 /** USB endpoint number. */ 47 50 usb_endpoint_t endpoint; 51 /** Communication direction. */ 48 52 usb_direction_t direction; 53 /** USB transfer type. */ 49 54 usb_transfer_type_t transfer_type; 55 /** Communication speed. */ 50 56 usb_speed_t speed; 57 /** Maximum size of data packets. */ 51 58 size_t max_packet_size; 59 /** Necessary bandwidth. */ 60 size_t bandwidth; 61 /** Value of the toggle bit. */ 52 62 unsigned toggle:1; 63 /** True if there is a batch using this scheduled for this endpoint. */ 64 volatile bool active; 65 /** Protects resources and active status changes. */ 53 66 fibril_mutex_t guard; 67 /** Signals change of active status. */ 54 68 fibril_condvar_t avail; 55 volatile bool active; 56 void (*destroy_hook)(struct endpoint *); 69 /** Optional device specific data. */ 57 70 struct { 71 /** Device specific data. */ 58 72 void *data; 73 /** Callback to get the value of toggle bit. */ 59 74 int (*toggle_get)(void *); 75 /** Callback to set the value of toggle bit. */ 60 76 void (*toggle_set)(void *, int); 61 77 } hc_data; 62 78 } endpoint_t; 63 79 64 endpoint_t * endpoint_ get(usb_address_t address, usb_endpoint_t endpoint,80 endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint, 65 81 usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed, 66 size_t max_packet_size); 67 82 size_t max_packet_size, size_t bw); 68 83 void endpoint_destroy(endpoint_t *instance); 69 84 70 85 void endpoint_set_hc_data(endpoint_t *instance, 71 void *data, void (*destroy_hook)(endpoint_t *), 72 int (*toggle_get)(void *), void (*toggle_set)(void *, int)); 73 86 void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int)); 74 87 void endpoint_clear_hc_data(endpoint_t *instance); 75 88 76 89 void endpoint_use(endpoint_t *instance); 77 78 90 void endpoint_release(endpoint_t *instance); 79 91 80 92 int endpoint_toggle_get(endpoint_t *instance); 81 82 93 void endpoint_toggle_set(endpoint_t *instance, int toggle); 83 94 84 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target); 95 /** list_get_instance wrapper. 96 * @param item Pointer to link member. 97 * @return Pointer to enpoint_t structure. 98 */ 99 static inline endpoint_t * endpoint_get_instance(link_t *item) 100 { 101 return list_get_instance(item, endpoint_t, link); 102 } 85 103 #endif 86 104 /** -
uspace/lib/usbhost/include/usb/host/hcd.h
re8ab32f rc83a55c 37 37 38 38 #include <assert.h> 39 #include <usbhc_iface.h> 40 39 41 #include <usb/host/usb_device_manager.h> 40 42 #include <usb/host/usb_endpoint_manager.h> 41 43 #include <usb/host/usb_transfer_batch.h> 42 #include <usbhc_iface.h>43 44 44 45 typedef struct hcd hcd_t; 45 46 47 /** Generic host controller driver structure. */ 46 48 struct hcd { 49 /** Device manager storing handles and addresses. */ 47 50 usb_device_manager_t dev_manager; 51 /** Endpoint manager. */ 48 52 usb_endpoint_manager_t ep_manager; 53 54 /** Device specific driver data. */ 49 55 void *private_data; 50 56 /** Transfer scheduling, implement in device driver. */ 51 57 int (*schedule)(hcd_t *, usb_transfer_batch_t *); 58 /** Hook called upon registering new endpoint. */ 52 59 int (*ep_add_hook)(hcd_t *, endpoint_t *); 60 /** Hook called upon removing of an endpoint. */ 61 void (*ep_remove_hook)(hcd_t *, endpoint_t *); 53 62 }; 54 63 /*----------------------------------------------------------------------------*/ 55 static inline int hcd_init(hcd_t *hcd, size_t bandwidth, 64 /** Initialize hcd_t structure. 65 * Initializes device and endpoint managers. Sets data nd hook pointer to NULL. 66 * @param hcd hcd_t structure to initialize, non-null. 67 * @param bandwidth Available bandwidth, passed to endpoint manager. 68 * @param bw_count Bandwidth compute function, passed to endpoint manager. 69 */ 70 static inline void hcd_init(hcd_t *hcd, size_t bandwidth, 56 71 size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t)) 57 72 { 58 73 assert(hcd); 59 74 usb_device_manager_init(&hcd->dev_manager); 60 return usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count); 75 usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count); 76 hcd->private_data = NULL; 77 hcd->schedule = NULL; 78 hcd->ep_add_hook = NULL; 79 hcd->ep_remove_hook = NULL; 61 80 } 62 81 /*----------------------------------------------------------------------------*/ 63 static inline void hcd_destroy(hcd_t *hcd) 64 { 65 usb_endpoint_manager_destroy(&hcd->ep_manager); 66 } 67 /*----------------------------------------------------------------------------*/68 static inline void reset_ep_if_need( 69 hcd_t *hcd, usb_target_t target, const char* setup_data)82 /** Check registered endpoints and reset toggle bit if necessary. 83 * @param hcd hcd_t structure, non-null. 84 * @param target Control communication target. 85 * @param setup_data Setup packet of the control communication. 86 */ 87 static inline void reset_ep_if_need(hcd_t *hcd, usb_target_t target, 88 const char setup_data[8]) 70 89 { 71 90 assert(hcd); 72 usb_endpoint_manager_reset_ if_need(91 usb_endpoint_manager_reset_eps_if_need( 73 92 &hcd->ep_manager, target, (const uint8_t *)setup_data); 74 93 } 75 94 /*----------------------------------------------------------------------------*/ 76 static inline hcd_t * fun_to_hcd(ddf_fun_t *fun) 95 /** Data retrieve wrapper. 96 * @param fun ddf function, non-null. 97 * @return pointer cast to hcd_t*. 98 */ 99 static inline hcd_t * fun_to_hcd(const ddf_fun_t *fun) 77 100 { 78 101 assert(fun); -
uspace/lib/usbhost/include/usb/host/usb_device_manager.h
re8ab32f rc83a55c 49 49 #define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1) 50 50 51 /** Information about attached USB device. */52 struct usb_device_info {53 usb_speed_t speed;54 bool occupied;55 devman_handle_t handle;56 };57 58 51 /** Host controller device manager. 59 * You shall not access members directly but only using functions below.52 * You shall not access members directly. 60 53 */ 61 54 typedef struct { 62 struct usb_device_info devices[USB_ADDRESS_COUNT]; 55 /** Information about attached USB devices. */ 56 struct { 57 usb_speed_t speed; /**< Device speed */ 58 bool occupied; /**< The address is in use. */ 59 devman_handle_t handle; /**< Devman handle of the device. */ 60 } devices[USB_ADDRESS_COUNT]; 63 61 fibril_mutex_t guard; 62 /** The last reserved address */ 64 63 usb_address_t last_address; 65 64 } usb_device_manager_t; … … 70 69 usb_device_manager_t *instance, usb_speed_t speed); 71 70 72 voidusb_device_manager_bind(usb_device_manager_t *instance,71 int usb_device_manager_bind(usb_device_manager_t *instance, 73 72 usb_address_t address, devman_handle_t handle); 74 73 75 voidusb_device_manager_release(usb_device_manager_t *instance,74 int usb_device_manager_release(usb_device_manager_t *instance, 76 75 usb_address_t address); 77 76 78 usb_address_t usb_device_manager_find (usb_device_manager_t *instance,77 usb_address_t usb_device_manager_find_address(usb_device_manager_t *instance, 79 78 devman_handle_t handle); 80 79 81 bool usb_device_manager_find_by_address(usb_device_manager_t *instance, 82 usb_address_t address, devman_handle_t *handle); 83 84 usb_speed_t usb_device_manager_get_speed(usb_device_manager_t *instance, 85 usb_address_t address); 80 int usb_device_manager_get_info_by_address(usb_device_manager_t *instance, 81 usb_address_t address, devman_handle_t *handle, usb_speed_t *speed); 86 82 #endif 87 83 /** -
uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
re8ab32f rc83a55c 40 40 #define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H 41 41 42 #include <stdlib.h> 43 #include <adt/hash_table.h> 42 #include <adt/list.h> 44 43 #include <fibril_synch.h> 45 44 #include <usb/usb.h> 45 46 46 #include <usb/host/endpoint.h> 47 47 48 #define BANDWIDTH_TOTAL_USB11 12000000 48 /** Bytes per second in FULL SPEED */ 49 #define BANDWIDTH_TOTAL_USB11 (12000000 / 8) 50 /** 90% of total bandwidth is available for periodic transfers */ 49 51 #define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9) 52 /** 16 addresses per list */ 53 #define ENDPOINT_LIST_COUNT 8 50 54 55 /** Endpoint management structure */ 51 56 typedef struct usb_endpoint_manager { 52 hash_table_t ep_table; 57 /** Store endpoint_t instances */ 58 list_t endpoint_lists[ENDPOINT_LIST_COUNT]; 59 /** Prevents races accessing lists */ 53 60 fibril_mutex_t guard; 61 /** Size of the bandwidth pool */ 54 62 size_t free_bw; 63 /** Use this function to count bw required by EP */ 55 64 size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t); 56 65 } usb_endpoint_manager_t; … … 63 72 size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t)); 64 73 65 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance); 74 void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance, 75 usb_target_t target, const uint8_t data[8]); 66 76 67 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance, 68 endpoint_t *ep, size_t data_size); 69 70 int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance, 77 int usb_endpoint_manager_register_ep( 78 usb_endpoint_manager_t *instance, endpoint_t *ep, size_t data_size); 79 int usb_endpoint_manager_unregister_ep( 80 usb_endpoint_manager_t *instance, endpoint_t *ep); 81 endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance, 71 82 usb_address_t address, usb_endpoint_t ep, usb_direction_t direction); 72 83 73 endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance, 74 usb_address_t address, usb_endpoint_t ep, usb_direction_t direction, 75 size_t *bw); 76 77 void usb_endpoint_manager_reset_if_need( 78 usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data); 79 80 /** Wrapper combining allocation and insertion */ 81 static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance, 84 int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance, 82 85 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, 83 86 usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size, 84 size_t data_size) 85 { 86 endpoint_t *ep = endpoint_get( 87 address, endpoint, direction, type, speed, max_packet_size); 88 if (!ep) 89 return ENOMEM; 87 size_t data_size, int (*callback)(endpoint_t *, void *), void *arg); 90 88 91 const int ret = 92 usb_endpoint_manager_register_ep(instance, ep, data_size); 93 if (ret != EOK) { 94 endpoint_destroy(ep); 95 } 96 return ret; 97 } 89 int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance, 90 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, 91 void (*callback)(endpoint_t *, void *), void *arg); 98 92 #endif 99 93 /** 100 94 * @} 101 95 */ 102 -
uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
re8ab32f rc83a55c 43 43 #define USB_SETUP_PACKET_SIZE 8 44 44 45 typedef struct usb_transfer_batch usb_transfer_batch_t;46 45 /** Structure stores additional data needed for communication with EP */ 47 struct usb_transfer_batch {46 typedef struct usb_transfer_batch { 48 47 /** Endpoint used for communication */ 49 48 endpoint_t *ep; … … 77 76 /** Callback to properly remove driver data during destruction */ 78 77 void (*private_data_dtor)(void *p_data); 79 } ;78 } usb_transfer_batch_t; 80 79 81 80 /** Printf formatting string for dumping usb_transfer_batch_t. */ … … 93 92 94 93 95 usb_transfer_batch_t * usb_transfer_batch_ get(94 usb_transfer_batch_t * usb_transfer_batch_create( 96 95 endpoint_t *ep, 97 96 char *buffer, … … 105 104 void (*private_data_dtor)(void *p_data) 106 105 ); 106 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance); 107 107 108 void usb_transfer_batch_finish( usb_transfer_batch_t *instance,108 void usb_transfer_batch_finish(const usb_transfer_batch_t *instance, 109 109 const void* data, size_t size); 110 void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);111 void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);112 void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);113 114 /** Helper function, calls callback and correctly destroys batch structure.115 *116 * @param[in] instance Batch structure to use.117 */118 static inline void usb_transfer_batch_call_in_and_dispose(119 usb_transfer_batch_t *instance)120 {121 assert(instance);122 usb_transfer_batch_call_in(instance);123 usb_transfer_batch_dispose(instance);124 }125 110 /*----------------------------------------------------------------------------*/ 126 /** Helper function calls callback and correctly destroys batch structure. 127 * 128 * @param[in] instance Batch structure to use. 129 */ 130 static inline void usb_transfer_batch_call_out_and_dispose( 131 usb_transfer_batch_t *instance) 132 { 133 assert(instance); 134 usb_transfer_batch_call_out(instance); 135 usb_transfer_batch_dispose(instance); 136 } 137 /*----------------------------------------------------------------------------*/ 138 /** Helper function, sets error value and finishes transfer. 111 /** Override error value and finishes transfer. 139 112 * 140 113 * @param[in] instance Batch structure to use. … … 151 124 } 152 125 /*----------------------------------------------------------------------------*/ 153 /** Helper function, determines batch direction absed on the present callbacks154 * @param[in] instance Batch structure to use .126 /** Determine batch direction based on the callbacks present 127 * @param[in] instance Batch structure to use, non-null. 155 128 * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT. 156 129 */ -
uspace/lib/usbhost/src/endpoint.c
re8ab32f rc83a55c 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup drvusbuhcihc 28 /** @addtogroup libusbhost 30 29 * @{ 31 30 */ … … 39 38 #include <usb/host/endpoint.h> 40 39 41 endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint, 40 /** Allocate ad initialize endpoint_t structure. 41 * @param address USB address. 42 * @param endpoint USB endpoint number. 43 * @param direction Communication direction. 44 * @param type USB transfer type. 45 * @param speed Communication speed. 46 * @param max_packet_size Maximum size of data packets. 47 * @param bw Required bandwidth. 48 * @return Pointer to initialized endpoint_t structure, NULL on failure. 49 */ 50 endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint, 42 51 usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed, 43 size_t max_packet_size )52 size_t max_packet_size, size_t bw) 44 53 { 45 54 endpoint_t *instance = malloc(sizeof(endpoint_t)); … … 51 60 instance->speed = speed; 52 61 instance->max_packet_size = max_packet_size; 62 instance->bandwidth = bw; 53 63 instance->toggle = 0; 54 64 instance->active = false; 55 instance->destroy_hook = NULL;56 65 instance->hc_data.data = NULL; 57 66 instance->hc_data.toggle_get = NULL; 58 67 instance->hc_data.toggle_set = NULL; 68 link_initialize(&instance->link); 59 69 fibril_mutex_initialize(&instance->guard); 60 70 fibril_condvar_initialize(&instance->avail); 61 endpoint_clear_hc_data(instance);62 71 } 63 72 return instance; 64 73 } 65 74 /*----------------------------------------------------------------------------*/ 75 /** Properly dispose of endpoint_t structure. 76 * @param instance endpoint_t structure. 77 */ 66 78 void endpoint_destroy(endpoint_t *instance) 67 79 { 68 80 assert(instance); 81 //TODO: Do something about waiting fibrils. 69 82 assert(!instance->active); 70 if (instance->hc_data.data) { 71 assert(instance->destroy_hook); 72 instance->destroy_hook(instance); 73 } 83 assert(instance->hc_data.data == NULL); 74 84 free(instance); 75 85 } 76 86 /*----------------------------------------------------------------------------*/ 87 /** Set device specific data and hooks. 88 * @param instance endpoint_t structure. 89 * @param data device specific data. 90 * @param toggle_get Hook to call when retrieving value of toggle bit. 91 * @param toggle_set Hook to call when setting the value of toggle bit. 92 */ 77 93 void endpoint_set_hc_data(endpoint_t *instance, 78 void *data, void (*destroy_hook)(endpoint_t *), 79 int (*toggle_get)(void *), void (*toggle_set)(void *, int)) 94 void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int)) 80 95 { 81 96 assert(instance); 82 instance->destroy_hook = destroy_hook;97 fibril_mutex_lock(&instance->guard); 83 98 instance->hc_data.data = data; 84 99 instance->hc_data.toggle_get = toggle_get; 85 100 instance->hc_data.toggle_set = toggle_set; 101 fibril_mutex_unlock(&instance->guard); 86 102 } 87 103 /*----------------------------------------------------------------------------*/ 104 /** Clear device specific data and hooks. 105 * @param instance endpoint_t structure. 106 * @note This function does not free memory pointed to by data pointer. 107 */ 88 108 void endpoint_clear_hc_data(endpoint_t *instance) 89 109 { 90 110 assert(instance); 91 instance->destroy_hook = NULL;111 fibril_mutex_lock(&instance->guard); 92 112 instance->hc_data.data = NULL; 93 113 instance->hc_data.toggle_get = NULL; 94 114 instance->hc_data.toggle_set = NULL; 115 fibril_mutex_unlock(&instance->guard); 95 116 } 96 117 /*----------------------------------------------------------------------------*/ 118 /** Mark the endpoint as active and block access for further fibrils. 119 * @param instance endpoint_t structure. 120 */ 97 121 void endpoint_use(endpoint_t *instance) 98 122 { … … 105 129 } 106 130 /*----------------------------------------------------------------------------*/ 131 /** Mark the endpoint as inactive and allow access for further fibrils. 132 * @param instance endpoint_t structure. 133 */ 107 134 void endpoint_release(endpoint_t *instance) 108 135 { … … 114 141 } 115 142 /*----------------------------------------------------------------------------*/ 143 /** Get the value of toggle bit. 144 * @param instance endpoint_t structure. 145 * @note Will use provided hook. 146 */ 116 147 int endpoint_toggle_get(endpoint_t *instance) 117 148 { 118 149 assert(instance); 150 fibril_mutex_lock(&instance->guard); 119 151 if (instance->hc_data.toggle_get) 120 152 instance->toggle = 121 153 instance->hc_data.toggle_get(instance->hc_data.data); 122 return (int)instance->toggle; 154 const int ret = instance->toggle; 155 fibril_mutex_unlock(&instance->guard); 156 return ret; 123 157 } 124 158 /*----------------------------------------------------------------------------*/ 159 /** Set the value of toggle bit. 160 * @param instance endpoint_t structure. 161 * @note Will use provided hook. 162 */ 125 163 void endpoint_toggle_set(endpoint_t *instance, int toggle) 126 164 { 127 165 assert(instance); 128 166 assert(toggle == 0 || toggle == 1); 167 fibril_mutex_lock(&instance->guard); 168 instance->toggle = toggle; 129 169 if (instance->hc_data.toggle_set) 130 170 instance->hc_data.toggle_set(instance->hc_data.data, toggle); 131 instance->toggle = toggle; 132 } 133 /*----------------------------------------------------------------------------*/ 134 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target) 135 { 136 assert(instance); 137 if (instance->address == target.address && 138 (instance->endpoint == target.endpoint || target.endpoint == 0)) 139 endpoint_toggle_set(instance, 0); 171 fibril_mutex_unlock(&instance->guard); 140 172 } 141 173 /** -
uspace/lib/usbhost/src/iface.c
re8ab32f rc83a55c 49 49 assert(hcd); 50 50 51 int ret; 52 53 size_t res_bw; 54 endpoint_t *ep = usb_endpoint_manager_get_ep(&hcd->ep_manager, 55 target.address, target.endpoint, direction, &res_bw); 51 endpoint_t *ep = usb_endpoint_manager_find_ep(&hcd->ep_manager, 52 target.address, target.endpoint, direction); 56 53 if (ep == NULL) { 57 54 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", … … 65 62 const size_t bw = bandwidth_count_usb11( 66 63 ep->speed, ep->transfer_type, size, ep->max_packet_size); 67 if (res_bw < bw) { 64 /* Check if we have enough bandwidth reserved */ 65 if (ep->bandwidth < bw) { 68 66 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 69 67 "but only %zu is reserved.\n", 70 target.address, target.endpoint, name, bw, res_bw);68 ep->address, ep->endpoint, name, bw, ep->bandwidth); 71 69 return ENOSPC; 72 70 } … … 78 76 /* No private data and no private data dtor */ 79 77 usb_transfer_batch_t *batch = 80 usb_transfer_batch_ get(ep, data, size, setup_data,78 usb_transfer_batch_create(ep, data, size, setup_data, 81 79 in, out, arg, fun, NULL, NULL); 82 80 if (!batch) { … … 84 82 } 85 83 86 ret = hcd->schedule(hcd, batch);84 const int ret = hcd->schedule(hcd, batch); 87 85 if (ret != EOK) 88 usb_transfer_batch_d ispose(batch);86 usb_transfer_batch_destroy(batch); 89 87 90 88 return ret; … … 130 128 131 129 usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle); 132 usb_device_manager_bind(&hcd->dev_manager, address, handle); 133 return EOK; 130 return usb_device_manager_bind(&hcd->dev_manager, address, handle); 134 131 } 135 132 /*----------------------------------------------------------------------------*/ … … 147 144 hcd_t *hcd = fun_to_hcd(fun); 148 145 assert(hcd); 149 const bool found = 150 usb_device_manager_find_by_address(&hcd->dev_manager, address, handle); 151 return found ? EOK : ENOENT; 146 return usb_device_manager_get_info_by_address( 147 &hcd->dev_manager, address, handle, NULL); 152 148 } 153 149 /*----------------------------------------------------------------------------*/ … … 166 162 usb_device_manager_release(&hcd->dev_manager, address); 167 163 return EOK; 164 } 165 /*----------------------------------------------------------------------------*/ 166 static int register_helper(endpoint_t *ep, void *arg) 167 { 168 hcd_t *hcd = arg; 169 assert(ep); 170 assert(hcd); 171 if (hcd->ep_add_hook) 172 return hcd->ep_add_hook(hcd, ep); 173 return EOK; 174 } 175 /*----------------------------------------------------------------------------*/ 176 static void unregister_helper(endpoint_t *ep, void *arg) 177 { 178 hcd_t *hcd = arg; 179 assert(ep); 180 assert(hcd); 181 if (hcd->ep_remove_hook) 182 hcd->ep_remove_hook(hcd, ep); 168 183 } 169 184 /*----------------------------------------------------------------------------*/ … … 180 195 /* Default address is not bound or registered, 181 196 * thus it does not provide speed info. */ 182 const usb_speed_t speed = (address == 0) ? ep_speed : 183 usb_device_manager_get_speed(&hcd->dev_manager, address); 197 usb_speed_t speed = ep_speed; 198 /* NOTE The function will return EINVAL and won't 199 * touch speed variable for default address */ 200 usb_device_manager_get_info_by_address( 201 &hcd->dev_manager, address, NULL, &speed); 184 202 185 203 usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n", … … 188 206 max_packet_size, interval); 189 207 190 endpoint_t *ep = endpoint_get( 191 address, endpoint, direction, transfer_type, speed, max_packet_size); 192 if (!ep) 193 return ENOMEM; 194 int ret = EOK; 195 196 if (hcd->ep_add_hook) { 197 ret = hcd->ep_add_hook(hcd, ep); 198 } 199 if (ret != EOK) { 200 endpoint_destroy(ep); 201 return ret; 202 } 203 204 ret = usb_endpoint_manager_register_ep(&hcd->ep_manager, ep, size); 205 if (ret != EOK) { 206 endpoint_destroy(ep); 207 } 208 return ret; 208 return usb_endpoint_manager_add_ep(&hcd->ep_manager, address, endpoint, 209 direction, transfer_type, speed, max_packet_size, size, 210 register_helper, hcd); 209 211 } 210 212 /*----------------------------------------------------------------------------*/ … … 218 220 usb_log_debug("Unregister endpoint %d:%d %s.\n", 219 221 address, endpoint, usb_str_direction(direction)); 220 return usb_endpoint_manager_ unregister_ep(&hcd->ep_manager, address,221 endpoint, direction );222 return usb_endpoint_manager_remove_ep(&hcd->ep_manager, address, 223 endpoint, direction, unregister_helper, hcd); 222 224 } 223 225 /*----------------------------------------------------------------------------*/ -
uspace/lib/usbhost/src/usb_device_manager.c
re8ab32f rc83a55c 38 38 #include <usb/host/usb_device_manager.h> 39 39 40 /*----------------------------------------------------------------------------*/41 40 /** Initialize device manager structure. 42 41 * … … 48 47 { 49 48 assert(instance); 50 unsigned i = 0; 51 for (; i < USB_ADDRESS_COUNT; ++i) { 49 for (unsigned i = 0; i < USB_ADDRESS_COUNT; ++i) { 52 50 instance->devices[i].occupied = false; 53 51 instance->devices[i].handle = 0; … … 77 75 ++new_address; 78 76 if (new_address > USB11_ADDRESS_MAX) 79 new_address = 1; 77 new_address = 1; // NOTE it should be safe to put 0 here 78 // TODO Use mod 80 79 if (new_address == instance->last_address) { 81 80 fibril_mutex_unlock(&instance->guard); … … 86 85 assert(new_address != USB_ADDRESS_DEFAULT); 87 86 assert(instance->devices[new_address].occupied == false); 87 assert(instance->devices[new_address].handle == 0); 88 88 89 89 instance->devices[new_address].occupied = true; … … 100 100 * @param[in] address Device address 101 101 * @param[in] handle Devman handle of the device. 102 */ 103 void usb_device_manager_bind(usb_device_manager_t *instance, 102 * @return Error code. 103 */ 104 int usb_device_manager_bind(usb_device_manager_t *instance, 104 105 usb_address_t address, devman_handle_t handle) 105 106 { 106 assert(instance); 107 fibril_mutex_lock(&instance->guard); 108 109 assert(address > 0); 110 assert(address <= USB11_ADDRESS_MAX); 111 assert(instance->devices[address].occupied); 112 107 if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) { 108 return EINVAL; 109 } 110 assert(instance); 111 112 fibril_mutex_lock(&instance->guard); 113 /* Not reserved */ 114 if (!instance->devices[address].occupied) { 115 fibril_mutex_unlock(&instance->guard); 116 return ENOENT; 117 } 118 /* Already bound */ 119 if (instance->devices[address].handle != 0) { 120 fibril_mutex_unlock(&instance->guard); 121 return EEXISTS; 122 } 113 123 instance->devices[address].handle = handle; 114 124 fibril_mutex_unlock(&instance->guard); 125 return EOK; 115 126 } 116 127 /*----------------------------------------------------------------------------*/ … … 119 130 * @param[in] instance Device manager structure to use. 120 131 * @param[in] address Device address 121 */ 122 void usb_device_manager_release( 132 * @return Error code. 133 */ 134 int usb_device_manager_release( 123 135 usb_device_manager_t *instance, usb_address_t address) 124 136 { 125 assert(instance); 126 assert(address > 0); 127 assert(address <= USB11_ADDRESS_MAX); 128 129 fibril_mutex_lock(&instance->guard); 130 assert(instance->devices[address].occupied); 137 if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) { 138 return EINVAL; 139 } 140 assert(instance); 141 142 fibril_mutex_lock(&instance->guard); 143 if (!instance->devices[address].occupied) { 144 fibril_mutex_unlock(&instance->guard); 145 return ENOENT; 146 } 131 147 132 148 instance->devices[address].occupied = false; 133 fibril_mutex_unlock(&instance->guard); 149 instance->devices[address].handle = 0; 150 fibril_mutex_unlock(&instance->guard); 151 return EOK; 134 152 } 135 153 /*----------------------------------------------------------------------------*/ … … 140 158 * @return USB Address, or error code. 141 159 */ 142 usb_address_t usb_device_manager_find (160 usb_address_t usb_device_manager_find_address( 143 161 usb_device_manager_t *instance, devman_handle_t handle) 144 162 { 145 163 assert(instance); 146 164 fibril_mutex_lock(&instance->guard); 147 usb_address_t address = 1;148 while (address <= USB11_ADDRESS_MAX){165 for (usb_address_t address = 1; address <= USB11_ADDRESS_MAX; ++address) 166 { 149 167 if (instance->devices[address].handle == handle) { 150 168 assert(instance->devices[address].occupied); … … 152 170 return address; 153 171 } 154 ++address;155 172 } 156 173 fibril_mutex_unlock(&instance->guard); 157 174 return ENOENT; 158 175 } 159 160 /** Find devman handle a ssigned to USB address.161 * Intentionally refuse to find handle ofdefault address.176 /*----------------------------------------------------------------------------*/ 177 /** Find devman handle and speed assigned to USB address. 178 * Intentionally refuse to work on default address. 162 179 * 163 180 * @param[in] instance Device manager structure to use. 164 181 * @param[in] address Address the caller wants to find. 165 182 * @param[out] handle Where to store found handle. 166 * @ return Whether such address is currently occupied.167 * /168 bool usb_device_manager_find_by_address(usb_device_manager_t *instance, 169 usb_address_t address, devman_handle_t *handle) 170 { 171 assert(instance); 172 fibril_mutex_lock(&instance->guard);183 * @param[out] speed Assigned speed. 184 * @return Error code. 185 */ 186 int usb_device_manager_get_info_by_address(usb_device_manager_t *instance, 187 usb_address_t address, devman_handle_t *handle, usb_speed_t *speed) 188 { 189 assert(instance); 173 190 if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) { 174 fibril_mutex_unlock(&instance->guard); 175 return false; 176 } 191 return EINVAL; 192 } 193 194 fibril_mutex_lock(&instance->guard); 177 195 if (!instance->devices[address].occupied) { 178 196 fibril_mutex_unlock(&instance->guard); 179 return false;197 return ENOENT; 180 198 } 181 199 … … 183 201 *handle = instance->devices[address].handle; 184 202 } 185 186 fibril_mutex_unlock(&instance->guard); 187 return true; 188 } 189 190 /*----------------------------------------------------------------------------*/ 191 /** Get speed associated with the address 192 * 193 * @param[in] instance Device manager structure to use. 194 * @param[in] address Address of the device. 195 * @return USB speed. 196 */ 197 usb_speed_t usb_device_manager_get_speed( 198 usb_device_manager_t *instance, usb_address_t address) 199 { 200 assert(instance); 201 assert(address >= 0); 202 assert(address <= USB11_ADDRESS_MAX); 203 204 return instance->devices[address].speed; 203 if (speed != NULL) { 204 *speed = instance->devices[address].speed; 205 } 206 207 fibril_mutex_unlock(&instance->guard); 208 return EOK; 205 209 } 206 210 /** -
uspace/lib/usbhost/src/usb_endpoint_manager.c
re8ab32f rc83a55c 34 34 #include <usb/host/usb_endpoint_manager.h> 35 35 36 #define BUCKET_COUNT 7 37 38 #define MAX_KEYS (3) 39 typedef struct { 40 link_t link; 41 size_t bw; 42 endpoint_t *ep; 43 } node_t; 44 /*----------------------------------------------------------------------------*/ 45 static hash_index_t node_hash(unsigned long key[]) 46 { 47 /* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1]) 48 * produces unique value for every address.endpoint pair */ 49 return ((key[0] << 4) | key[1]) % BUCKET_COUNT; 50 } 51 /*----------------------------------------------------------------------------*/ 52 static int node_compare(unsigned long key[], hash_count_t keys, link_t *item) 53 { 54 assert(item); 55 node_t *node = hash_table_get_instance(item, node_t, link); 56 assert(node); 57 assert(node->ep); 58 bool match = true; 59 switch (keys) { 60 case 3: 61 match = match && 62 ((key[2] == node->ep->direction) 63 || (node->ep->direction == USB_DIRECTION_BOTH)); 64 case 2: 65 match = match && (key[1] == (unsigned long)node->ep->endpoint); 66 case 1: 67 match = match && (key[0] == (unsigned long)node->ep->address); 68 break; 69 default: 70 match = false; 71 } 72 return match; 73 } 74 /*----------------------------------------------------------------------------*/ 75 static void node_remove(link_t *item) 76 { 77 assert(item); 78 node_t *node = hash_table_get_instance(item, node_t, link); 79 endpoint_destroy(node->ep); 80 free(node); 81 } 82 /*----------------------------------------------------------------------------*/ 83 static void node_toggle_reset_filtered(link_t *item, void *arg) 84 { 85 assert(item); 86 node_t *node = hash_table_get_instance(item, node_t, link); 87 usb_target_t *target = arg; 88 endpoint_toggle_reset_filtered(node->ep, *target); 89 } 90 /*----------------------------------------------------------------------------*/ 91 static hash_table_operations_t op = { 92 .hash = node_hash, 93 .compare = node_compare, 94 .remove_callback = node_remove, 95 }; 96 /*----------------------------------------------------------------------------*/ 36 /** Endpoint compare helper function. 37 * 38 * USB_DIRECTION_BOTH matches both IN and OUT. 39 * @param ep Endpoint to compare, non-null. 40 * @param address Tested address. 41 * @param endpoint Tested endpoint number. 42 * @param direction Tested direction. 43 * @return True if ep can be used to communicate with given device, 44 * false otherwise. 45 */ 46 static inline bool ep_match(const endpoint_t *ep, 47 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 48 { 49 assert(ep); 50 return 51 ((direction == ep->direction) 52 || (ep->direction == USB_DIRECTION_BOTH) 53 || (direction == USB_DIRECTION_BOTH)) 54 && (endpoint == ep->endpoint) 55 && (address == ep->address); 56 } 57 /*----------------------------------------------------------------------------*/ 58 /** Get list that holds endpints for given address. 59 * @param instance usb_endpoint_manager structure, non-null. 60 * @param addr USB address, must be >= 0. 61 * @return Pointer to the appropriate list. 62 */ 63 static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr) 64 { 65 assert(instance); 66 assert(addr >= 0); 67 return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT]; 68 } 69 /*----------------------------------------------------------------------------*/ 70 /** Internal search function, works on locked structure. 71 * @param instance usb_endpoint_manager structure, non-null. 72 * @param address USB address, must be valid. 73 * @param endpoint USB endpoint number. 74 * @param direction Communication direction. 75 * @return Pointer to endpoint_t structure representing given communication 76 * target, NULL if there is no such endpoint registered. 77 */ 78 static endpoint_t * find_locked(usb_endpoint_manager_t *instance, 79 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 80 { 81 assert(instance); 82 assert(fibril_mutex_is_locked(&instance->guard)); 83 if (address < 0) 84 return NULL; 85 list_foreach(*get_list(instance, address), iterator) { 86 endpoint_t *ep = endpoint_get_instance(iterator); 87 if (ep_match(ep, address, endpoint, direction)) 88 return ep; 89 } 90 return NULL; 91 } 92 /*----------------------------------------------------------------------------*/ 93 /** Calculate bandwidth that needs to be reserved for communication with EP. 94 * Calculation follows USB 1.1 specification. 95 * @param speed Device's speed. 96 * @param type Type of the transfer. 97 * @param size Number of byte to transfer. 98 * @param max_packet_size Maximum bytes in one packet. 99 */ 97 100 size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type, 98 101 size_t size, size_t max_packet_size) … … 106 109 const unsigned packet_count = 107 110 (size + max_packet_size - 1) / max_packet_size; 108 /* TODO: It may be that ISO and INT transfers use only one data packet 109 * per transaction, but I did not find text in UB spec that confirms 110 * this */ 111 /* TODO: It may be that ISO and INT transfers use only one packet per 112 * transaction, but I did not find text in USB spec to confirm this */ 111 113 /* NOTE: All data packets will be considered to be max_packet_size */ 112 114 switch (speed) … … 137 139 } 138 140 /*----------------------------------------------------------------------------*/ 141 /** Initialize to default state. 142 * You need to provide valid bw_count function if you plan to use 143 * add_endpoint/remove_endpoint pair. 144 * 145 * @param instance usb_endpoint_manager structure, non-null. 146 * @param available_bandwidth Size of the bandwidth pool. 147 * @param bw_count function to use to calculate endpoint bw requirements. 148 * @return Error code. 149 */ 139 150 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance, 140 151 size_t available_bandwidth, … … 145 156 instance->free_bw = available_bandwidth; 146 157 instance->bw_count = bw_count; 147 const bool ht = 148 hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op); 149 return ht ? EOK : ENOMEM; 150 } 151 /*----------------------------------------------------------------------------*/ 152 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance) 153 { 154 hash_table_destroy(&instance->ep_table); 155 } 156 /*----------------------------------------------------------------------------*/ 157 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance, 158 endpoint_t *ep, size_t data_size) 159 { 160 assert(instance); 161 assert(instance->bw_count); 162 assert(ep); 163 const size_t bw = instance->bw_count(ep->speed, ep->transfer_type, 164 data_size, ep->max_packet_size); 165 166 fibril_mutex_lock(&instance->guard); 167 168 if (bw > instance->free_bw) { 169 fibril_mutex_unlock(&instance->guard); 170 return ENOSPC; 171 } 172 173 unsigned long key[MAX_KEYS] = 174 {ep->address, ep->endpoint, ep->direction}; 175 176 const link_t *item = 177 hash_table_find(&instance->ep_table, key); 178 if (item != NULL) { 179 fibril_mutex_unlock(&instance->guard); 180 return EEXISTS; 181 } 182 183 node_t *node = malloc(sizeof(node_t)); 184 if (node == NULL) { 185 fibril_mutex_unlock(&instance->guard); 186 return ENOMEM; 187 } 188 189 node->bw = bw; 190 node->ep = ep; 191 link_initialize(&node->link); 192 193 hash_table_insert(&instance->ep_table, key, &node->link); 194 instance->free_bw -= bw; 195 fibril_mutex_unlock(&instance->guard); 196 return EOK; 197 } 198 /*----------------------------------------------------------------------------*/ 199 int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance, 200 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 201 { 202 assert(instance); 203 unsigned long key[MAX_KEYS] = {address, endpoint, direction}; 204 205 fibril_mutex_lock(&instance->guard); 206 link_t *item = hash_table_find(&instance->ep_table, key); 207 if (item == NULL) { 208 fibril_mutex_unlock(&instance->guard); 209 return EINVAL; 210 } 211 212 node_t *node = hash_table_get_instance(item, node_t, link); 213 if (node->ep->active) { 214 fibril_mutex_unlock(&instance->guard); 215 return EBUSY; 216 } 217 218 instance->free_bw += node->bw; 219 hash_table_remove(&instance->ep_table, key, MAX_KEYS); 220 221 fibril_mutex_unlock(&instance->guard); 222 return EOK; 223 } 224 /*----------------------------------------------------------------------------*/ 225 endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance, 226 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, 227 size_t *bw) 228 { 229 assert(instance); 230 unsigned long key[MAX_KEYS] = {address, endpoint, direction}; 231 232 fibril_mutex_lock(&instance->guard); 233 const link_t *item = hash_table_find(&instance->ep_table, key); 234 if (item == NULL) { 235 fibril_mutex_unlock(&instance->guard); 236 return NULL; 237 } 238 const node_t *node = hash_table_get_instance(item, node_t, link); 239 if (bw) 240 *bw = node->bw; 241 242 fibril_mutex_unlock(&instance->guard); 243 return node->ep; 158 for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) { 159 list_initialize(&instance->endpoint_lists[i]); 160 } 161 return EOK; 244 162 } 245 163 /*----------------------------------------------------------------------------*/ 246 164 /** Check setup packet data for signs of toggle reset. 247 165 * 248 * @param[in] instance Device keeper structure to use.166 * @param[in] instance usb_endpoint_manager structure, non-null. 249 167 * @param[in] target Device to receive setup packet. 250 168 * @param[in] data Setup packet data. 251 169 * 252 * Really ugly one. 253 */ 254 void usb_endpoint_manager_reset_ if_need(255 usb_ endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)170 * Really ugly one. Resets toggle bit on all endpoints that need it. 171 */ 172 void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance, 173 usb_target_t target, const uint8_t data[8]) 256 174 { 257 175 assert(instance); … … 267 185 /* Recipient is endpoint, value is zero (ENDPOINT_STALL) */ 268 186 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) { 187 fibril_mutex_lock(&instance->guard); 269 188 /* endpoint number is < 16, thus first byte is enough */ 270 usb_target_t reset_target = 271 { .address = target.address, data[4] }; 272 fibril_mutex_lock(&instance->guard); 273 hash_table_apply(&instance->ep_table, 274 node_toggle_reset_filtered, &reset_target); 189 list_foreach(*get_list(instance, target.address), it) { 190 endpoint_t *ep = endpoint_get_instance(it); 191 if ((ep->address == target.address) 192 && (ep->endpoint = data[4])) { 193 endpoint_toggle_set(ep,0); 194 } 195 } 275 196 fibril_mutex_unlock(&instance->guard); 276 197 } … … 279 200 case 0x9: /* Set Configuration */ 280 201 case 0x11: /* Set Interface */ 281 /* Recipient must be device */ 202 /* Recipient must be device, this resets all endpoints, 203 * In fact there should be no endpoints but EP 0 registered 204 * as different interfaces use different endpoints. */ 282 205 if ((data[0] & 0xf) == 0) { 283 usb_target_t reset_target =284 { .address = target.address, 0 };285 206 fibril_mutex_lock(&instance->guard); 286 hash_table_apply(&instance->ep_table, 287 node_toggle_reset_filtered, &reset_target); 207 list_foreach(*get_list(instance, target.address), it) { 208 endpoint_t *ep = endpoint_get_instance(it); 209 if (ep->address == target.address) { 210 endpoint_toggle_set(ep,0); 211 } 212 } 288 213 fibril_mutex_unlock(&instance->guard); 289 214 } … … 291 216 } 292 217 } 218 /*----------------------------------------------------------------------------*/ 219 /** Register endpoint structure. 220 * Checks for duplicates. 221 * @param instance usb_endpoint_manager, non-null. 222 * @param ep endpoint_t to register. 223 * @param data_size Size of data to transfer. 224 * @return Error code. 225 */ 226 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance, 227 endpoint_t *ep, size_t data_size) 228 { 229 assert(instance); 230 if (ep == NULL || ep->address < 0) 231 return EINVAL; 232 233 fibril_mutex_lock(&instance->guard); 234 /* Check for available bandwidth */ 235 if (ep->bandwidth > instance->free_bw) { 236 fibril_mutex_unlock(&instance->guard); 237 return ENOSPC; 238 } 239 240 /* Check for existence */ 241 const endpoint_t *endpoint = 242 find_locked(instance, ep->address, ep->endpoint, ep->direction); 243 if (endpoint != NULL) { 244 fibril_mutex_unlock(&instance->guard); 245 return EEXISTS; 246 } 247 list_append(&ep->link, get_list(instance, ep->address)); 248 249 instance->free_bw -= ep->bandwidth; 250 fibril_mutex_unlock(&instance->guard); 251 return EOK; 252 } 253 /*----------------------------------------------------------------------------*/ 254 /** Unregister endpoint structure. 255 * Checks for duplicates. 256 * @param instance usb_endpoint_manager, non-null. 257 * @param ep endpoint_t to unregister. 258 * @return Error code. 259 */ 260 int usb_endpoint_manager_unregister_ep( 261 usb_endpoint_manager_t *instance, endpoint_t *ep) 262 { 263 assert(instance); 264 if (ep == NULL || ep->address < 0) 265 return EINVAL; 266 267 fibril_mutex_lock(&instance->guard); 268 if (!list_member(&ep->link, get_list(instance, ep->address))) { 269 fibril_mutex_unlock(&instance->guard); 270 return ENOENT; 271 } 272 list_remove(&ep->link); 273 instance->free_bw += ep->bandwidth; 274 fibril_mutex_unlock(&instance->guard); 275 return EOK; 276 } 277 /*----------------------------------------------------------------------------*/ 278 /** Find endpoint_t representing the given communication route. 279 * @param instance usb_endpoint_manager, non-null. 280 * @param address 281 */ 282 endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance, 283 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 284 { 285 assert(instance); 286 287 fibril_mutex_lock(&instance->guard); 288 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 289 fibril_mutex_unlock(&instance->guard); 290 return ep; 291 } 292 /*----------------------------------------------------------------------------*/ 293 /** Create and register new endpoint_t structure. 294 * @param instance usb_endpoint_manager structure, non-null. 295 * @param address USB address. 296 * @param endpoint USB endpoint number. 297 * @param direction Communication direction. 298 * @param type USB transfer type. 299 * @param speed USB Communication speed. 300 * @param max_packet_size Maximum size of data packets. 301 * @param data_size Expected communication size. 302 * @param callback function to call just after registering. 303 * @param arg Argument to pass to the callback function. 304 * @return Error code. 305 */ 306 int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance, 307 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, 308 usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size, 309 size_t data_size, int (*callback)(endpoint_t *, void *), void *arg) 310 { 311 assert(instance); 312 if (instance->bw_count == NULL) 313 return ENOTSUP; 314 if (address < 0) 315 return EINVAL; 316 317 const size_t bw = 318 instance->bw_count(speed, type, data_size, max_packet_size); 319 320 fibril_mutex_lock(&instance->guard); 321 /* Check for available bandwidth */ 322 if (bw > instance->free_bw) { 323 fibril_mutex_unlock(&instance->guard); 324 return ENOSPC; 325 } 326 327 /* Check for existence */ 328 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 329 if (ep != NULL) { 330 fibril_mutex_unlock(&instance->guard); 331 return EEXISTS; 332 } 333 334 ep = endpoint_create( 335 address, endpoint, direction, type, speed, max_packet_size, bw); 336 if (!ep) { 337 fibril_mutex_unlock(&instance->guard); 338 return ENOMEM; 339 } 340 341 if (callback) { 342 const int ret = callback(ep, arg); 343 if (ret != EOK) { 344 fibril_mutex_unlock(&instance->guard); 345 endpoint_destroy(ep); 346 return ret; 347 } 348 } 349 list_append(&ep->link, get_list(instance, ep->address)); 350 351 instance->free_bw -= ep->bandwidth; 352 fibril_mutex_unlock(&instance->guard); 353 return EOK; 354 } 355 /*----------------------------------------------------------------------------*/ 356 /** Unregister and destroy endpoint_t structure representing given route. 357 * @param instance usb_endpoint_manager structure, non-null. 358 * @param address USB address. 359 * @param endpoint USB endpoint number. 360 * @param direction Communication direction. 361 * @param callback Function to call after unregister, before destruction. 362 * @arg Argument to pass to the callback function. 363 * @return Error code. 364 */ 365 int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance, 366 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, 367 void (*callback)(endpoint_t *, void *), void *arg) 368 { 369 assert(instance); 370 fibril_mutex_lock(&instance->guard); 371 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 372 if (ep != NULL) { 373 list_remove(&ep->link); 374 instance->free_bw += ep->bandwidth; 375 } 376 fibril_mutex_unlock(&instance->guard); 377 if (ep == NULL) 378 return ENOENT; 379 380 if (callback) { 381 callback(ep, arg); 382 } 383 endpoint_destroy(ep); 384 return EOK; 385 } -
uspace/lib/usbhost/src/usb_transfer_batch.c
re8ab32f rc83a55c 37 37 #include <usb/usb.h> 38 38 #include <usb/debug.h> 39 39 40 #include <usb/host/usb_transfer_batch.h> 40 41 #include <usb/host/hcd.h> 41 42 42 usb_transfer_batch_t * usb_transfer_batch_get( 43 /** Allocate and initialize usb_transfer_batch structure. 44 * @param ep endpoint used by the transfer batch. 45 * @param buffer data to send/recieve. 46 * @param buffer_size Size of data buffer. 47 * @param setup_buffer Data to send in SETUP stage of control transfer. 48 * @param func_in callback on IN transfer completion. 49 * @param func_out callback on OUT transfer completion. 50 * @param arg Argument to pass to the callback function. 51 * @param private_data driver specific per batch data. 52 * @param private_data_dtor Function to properly destroy private_data. 53 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure. 54 */ 55 usb_transfer_batch_t * usb_transfer_batch_create( 43 56 endpoint_t *ep, 44 57 char *buffer, … … 53 66 ) 54 67 { 68 if (func_in == NULL && func_out == NULL) 69 return NULL; 70 if (func_in != NULL && func_out != NULL) 71 return NULL; 72 55 73 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 56 74 if (instance) { … … 78 96 } 79 97 /*----------------------------------------------------------------------------*/ 80 /** Mark batch as finished and run callback.81 *82 * @param[in] instance Batch structure to use.83 * @param[in] data Data to copy to the output buffer.84 * @param[in] size Size of @p data.85 */86 void usb_transfer_batch_finish(87 usb_transfer_batch_t *instance, const void *data, size_t size)88 {89 assert(instance);90 assert(instance->ep);91 /* we care about the data and there are some to copy */92 if (instance->ep->direction != USB_DIRECTION_OUT93 && data) {94 const size_t min_size =95 size < instance->buffer_size ? size : instance->buffer_size;96 memcpy(instance->buffer, data, min_size);97 }98 if (instance->callback_out)99 usb_transfer_batch_call_out(instance);100 if (instance->callback_in)101 usb_transfer_batch_call_in(instance);102 103 }104 /*----------------------------------------------------------------------------*/105 /** Prepare data, get error status and call callback in.106 *107 * @param[in] instance Batch structure to use.108 * Copies data from transport buffer, and calls callback with appropriate109 * parameters.110 */111 void usb_transfer_batch_call_in(usb_transfer_batch_t *instance)112 {113 assert(instance);114 assert(instance->callback_in);115 116 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed (%zuB): %s.\n",117 instance, USB_TRANSFER_BATCH_ARGS(*instance),118 instance->transfered_size, str_error(instance->error));119 120 instance->callback_in(instance->fun, instance->error,121 instance->transfered_size, instance->arg);122 }123 /*----------------------------------------------------------------------------*/124 /** Get error status and call callback out.125 *126 * @param[in] instance Batch structure to use.127 */128 void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)129 {130 assert(instance);131 assert(instance->callback_out);132 133 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed: %s.\n",134 instance, USB_TRANSFER_BATCH_ARGS(*instance),135 str_error(instance->error));136 137 if (instance->ep->transfer_type == USB_TRANSFER_CONTROL138 && instance->error == EOK) {139 const usb_target_t target =140 {{ instance->ep->address, instance->ep->endpoint }};141 reset_ep_if_need(142 fun_to_hcd(instance->fun), target, instance->setup_buffer);143 }144 145 instance->callback_out(instance->fun,146 instance->error, instance->arg);147 }148 /*----------------------------------------------------------------------------*/149 98 /** Correctly dispose all used data structures. 150 99 * 151 100 * @param[in] instance Batch structure to use. 152 101 */ 153 void usb_transfer_batch_d ispose(usb_transfer_batch_t *instance)102 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance) 154 103 { 155 104 if (!instance) … … 166 115 free(instance); 167 116 } 117 /*----------------------------------------------------------------------------*/ 118 /** Prepare data and call the right callback. 119 * 120 * @param[in] instance Batch structure to use. 121 * @param[in] data Data to copy to the output buffer. 122 * @param[in] size Size of @p data. 123 */ 124 void usb_transfer_batch_finish( 125 const usb_transfer_batch_t *instance, const void *data, size_t size) 126 { 127 assert(instance); 128 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 129 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 130 131 /* NOTE: Only one of these pointers should be set. */ 132 if (instance->callback_out) { 133 /* Check for commands that reset toggle bit */ 134 if (instance->ep->transfer_type == USB_TRANSFER_CONTROL 135 && instance->error == EOK) { 136 const usb_target_t target = 137 {{ instance->ep->address, instance->ep->endpoint }}; 138 reset_ep_if_need(fun_to_hcd(instance->fun), target, 139 instance->setup_buffer); 140 } 141 instance->callback_out(instance->fun, 142 instance->error, instance->arg); 143 } 144 145 if (instance->callback_in) { 146 /* We care about the data and there are some to copy */ 147 if (data) { 148 const size_t min_size = size < instance->buffer_size 149 ? size : instance->buffer_size; 150 memcpy(instance->buffer, data, min_size); 151 } 152 instance->callback_in(instance->fun, instance->error, 153 instance->transfered_size, instance->arg); 154 } 155 } 168 156 /** 169 157 * @}
Note:
See TracChangeset
for help on using the changeset viewer.