Changeset 7265558 in mainline for uspace/lib/usbhost/src/usb_endpoint_manager.c
- Timestamp:
- 2011-10-28T20:53:41Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 48ae3ef
- Parents:
- 83c3123
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/usb_endpoint_manager.c
r83c3123 r7265558 34 34 #include <usb/host/usb_endpoint_manager.h> 35 35 36 #define BUCKET_COUNT 7 37 #define MAX_KEYS (3) 38 39 static hash_index_t usb_hash(unsigned long key[]) 40 { 41 /* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1]) 42 * produces unique value for every address.endpoint pair */ 43 return ((key[0] << 4) | key[1]) % BUCKET_COUNT; 44 } 45 /*----------------------------------------------------------------------------*/ 46 static int ep_compare(unsigned long key[], hash_count_t keys, link_t *item) 47 { 48 assert(item); 49 endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link); 36 static inline bool ep_match(const endpoint_t *ep, 37 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 38 { 50 39 assert(ep); 51 bool match = true; 52 switch (keys) { 53 case 3: 54 match = match && 55 ((key[2] == ep->direction) 56 || (ep->direction == USB_DIRECTION_BOTH) 57 || (key[2] == USB_DIRECTION_BOTH)); 58 case 2: 59 match = match && (key[1] == (unsigned long)ep->endpoint); 60 case 1: 61 match = match && (key[0] == (unsigned long)ep->address); 62 break; 63 default: 64 match = false; 65 } 66 return match; 67 } 68 /*----------------------------------------------------------------------------*/ 69 static void ep_remove(link_t *item) 70 { 71 assert(item); 72 endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link); 73 endpoint_destroy(ep); 74 } 75 /*----------------------------------------------------------------------------*/ 76 static void toggle_reset_filtered(link_t *item, void *arg) 77 { 78 assert(item); 79 endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link); 80 const usb_target_t *target = arg; 81 endpoint_toggle_reset_filtered(ep, *target); 82 } 83 /*----------------------------------------------------------------------------*/ 84 static hash_table_operations_t op = { 85 .hash = usb_hash, 86 .compare = ep_compare, 87 .remove_callback = ep_remove, 88 }; 40 return 41 ((direction == ep->direction) 42 || (ep->direction == USB_DIRECTION_BOTH) 43 || (direction == USB_DIRECTION_BOTH)) 44 && (endpoint == ep->endpoint) 45 && (address == ep->address); 46 } 47 /*----------------------------------------------------------------------------*/ 48 static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr) 49 { 50 assert(instance); 51 return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT]; 52 } 53 /*----------------------------------------------------------------------------*/ 54 static endpoint_t * find_locked(usb_endpoint_manager_t *instance, 55 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 56 { 57 assert(instance); 58 assert(fibril_mutex_is_locked(&instance->guard)); 59 list_foreach(*get_list(instance, address), iterator) { 60 endpoint_t *ep = endpoint_get_instance(iterator); 61 if (ep_match(ep, address, endpoint, direction)) 62 return ep; 63 } 64 return NULL; 65 } 89 66 /*----------------------------------------------------------------------------*/ 90 67 size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type, … … 99 76 const unsigned packet_count = 100 77 (size + max_packet_size - 1) / max_packet_size; 101 /* TODO: It may be that ISO and INT transfers use only one data packet 102 * per transaction, but I did not find text in UB spec that confirms 103 * this */ 78 /* TODO: It may be that ISO and INT transfers use only one packet per 79 * transaction, but I did not find text in USB spec to confirm this */ 104 80 /* NOTE: All data packets will be considered to be max_packet_size */ 105 81 switch (speed) … … 138 114 instance->free_bw = available_bandwidth; 139 115 instance->bw_count = bw_count; 140 const bool ht = 141 hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op); 142 return ht ? EOK : ENOMEM; 143 } 144 /*----------------------------------------------------------------------------*/ 145 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance) 146 { 147 hash_table_destroy(&instance->ep_table); 116 for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) { 117 list_initialize(&instance->endpoint_lists[i]); 118 } 119 return EOK; 148 120 } 149 121 /*----------------------------------------------------------------------------*/ … … 164 136 } 165 137 166 unsigned long key[MAX_KEYS] = 167 {ep->address, ep->endpoint, ep->direction}; 168 169 const link_t *item = 170 hash_table_find(&instance->ep_table, key); 171 if (item != NULL) { 138 /* Check for existence */ 139 const endpoint_t *endpoint = 140 find_locked(instance, ep->address, ep->endpoint, ep->direction); 141 if (endpoint != NULL) { 172 142 fibril_mutex_unlock(&instance->guard); 173 143 return EEXISTS; 174 144 } 175 176 hash_table_insert(&instance->ep_table, key, &ep->link); 145 list_t *list = get_list(instance, ep->address); 146 list_append(&ep->link, list); 147 177 148 instance->free_bw -= ep->bandwidth; 178 149 fibril_mutex_unlock(&instance->guard); … … 184 155 { 185 156 assert(instance); 186 unsigned long key[MAX_KEYS] = {address, endpoint, direction};187 157 188 158 fibril_mutex_lock(&instance->guard); 189 link_t *item = hash_table_find(&instance->ep_table, key); 190 if (item == NULL) { 191 fibril_mutex_unlock(&instance->guard); 192 return EINVAL; 193 } 194 195 endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link); 196 if (ep->active) { 197 fibril_mutex_unlock(&instance->guard); 198 return EBUSY; 199 } 200 201 instance->free_bw += ep->bandwidth; 202 hash_table_remove(&instance->ep_table, key, MAX_KEYS); 159 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 160 if (ep != NULL) { 161 list_remove(&ep->link); 162 instance->free_bw += ep->bandwidth; 163 } 203 164 204 165 fibril_mutex_unlock(&instance->guard); 205 return EOK; 166 endpoint_destroy(ep); 167 return (ep != NULL) ? EOK : EINVAL; 206 168 } 207 169 /*----------------------------------------------------------------------------*/ … … 210 172 { 211 173 assert(instance); 212 unsigned long key[MAX_KEYS] = {address, endpoint, direction};213 174 214 175 fibril_mutex_lock(&instance->guard); 215 const link_t *item = hash_table_find(&instance->ep_table, key); 216 if (item == NULL) { 217 fibril_mutex_unlock(&instance->guard); 218 return NULL; 219 } 220 endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link); 221 176 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 222 177 fibril_mutex_unlock(&instance->guard); 178 223 179 return ep; 224 180 } … … 247 203 /* Recipient is endpoint, value is zero (ENDPOINT_STALL) */ 248 204 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) { 205 fibril_mutex_lock(&instance->guard); 249 206 /* endpoint number is < 16, thus first byte is enough */ 250 usb_target_t reset_target = 251 { .address = target.address, data[4] }; 252 fibril_mutex_lock(&instance->guard); 253 hash_table_apply(&instance->ep_table, 254 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 && (ep->endpoint = data[4])) { 211 endpoint_toggle_set(ep,0); 212 } 213 } 255 214 fibril_mutex_unlock(&instance->guard); 256 215 } … … 259 218 case 0x9: /* Set Configuration */ 260 219 case 0x11: /* Set Interface */ 261 /* Recipient must be device */ 220 /* Recipient must be device, this resets all endpoints, 221 * In fact there should be no endpoints but EP 0 registered 222 * as different interfaces use different endpoints. */ 262 223 if ((data[0] & 0xf) == 0) { 263 usb_target_t reset_target =264 { .address = target.address, 0 };265 224 fibril_mutex_lock(&instance->guard); 266 hash_table_apply(&instance->ep_table, 267 toggle_reset_filtered, &reset_target); 225 list_foreach(*get_list(instance, target.address), it) { 226 endpoint_t *ep = endpoint_get_instance(it); 227 if (ep->address == target.address) { 228 endpoint_toggle_set(ep,0); 229 } 230 } 268 231 fibril_mutex_unlock(&instance->guard); 269 232 }
Note:
See TracChangeset
for help on using the changeset viewer.