Changeset 5400606 in mainline
- Timestamp:
- 2011-10-29T13:35:40Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4dfc905
- Parents:
- 2fd1f0c6
- Location:
- uspace/lib/usbhost
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
r2fd1f0c6 r5400606 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 */ 50 53 #define ENDPOINT_LIST_COUNT 8 51 54 55 /** Endpoint management structure */ 52 56 typedef struct usb_endpoint_manager { 57 /** Store endpoint_t instances */ 53 58 list_t endpoint_lists[ENDPOINT_LIST_COUNT]; 59 /** Prevents races accessing lists */ 54 60 fibril_mutex_t guard; 61 /** Size of the bandwidth pool */ 55 62 size_t free_bw; 63 /** Use this function to count bw required by EP */ 56 64 size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t); 57 65 } usb_endpoint_manager_t; … … 64 72 size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t)); 65 73 66 void usb_endpoint_manager_reset_eps_if_need( 67 usb_ endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);74 void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance, 75 usb_target_t target, const uint8_t data[8]); 68 76 69 77 int usb_endpoint_manager_register_ep( -
uspace/lib/usbhost/src/usb_endpoint_manager.c
r2fd1f0c6 r5400606 34 34 #include <usb/host/usb_endpoint_manager.h> 35 35 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 */ 36 46 static inline bool ep_match(const endpoint_t *ep, 37 47 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) … … 46 56 } 47 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 */ 48 63 static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr) 49 64 { 50 65 assert(instance); 66 assert(addr >= 0); 51 67 return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT]; 52 68 } 53 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 */ 54 78 static endpoint_t * find_locked(usb_endpoint_manager_t *instance, 55 79 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) … … 57 81 assert(instance); 58 82 assert(fibril_mutex_is_locked(&instance->guard)); 83 if (address < 0) 84 return NULL; 59 85 list_foreach(*get_list(instance, address), iterator) { 60 86 endpoint_t *ep = endpoint_get_instance(iterator); … … 65 91 } 66 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 */ 67 100 size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type, 68 101 size_t size, size_t max_packet_size) … … 106 139 } 107 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 */ 108 150 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance, 109 151 size_t available_bandwidth, … … 122 164 /** Check setup packet data for signs of toggle reset. 123 165 * 124 * @param[in] instance Device keeper structure to use.166 * @param[in] instance usb_endpoint_manager structure, non-null. 125 167 * @param[in] target Device to receive setup packet. 126 168 * @param[in] data Setup packet data. 127 169 * 128 * Really ugly one. 129 */ 130 void usb_endpoint_manager_reset_eps_if_need( 131 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]) 132 174 { 133 175 assert(instance); … … 175 217 } 176 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 */ 177 226 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance, 178 227 endpoint_t *ep, size_t data_size) 179 228 { 180 229 assert(instance); 181 assert(instance->bw_count); 182 assert(ep); 183 fibril_mutex_lock(&instance->guard); 184 230 if (ep == NULL || ep->address < 0) 231 return EINVAL; 232 233 fibril_mutex_lock(&instance->guard); 234 /* Check for available bandwidth */ 185 235 if (ep->bandwidth > instance->free_bw) { 186 236 fibril_mutex_unlock(&instance->guard); … … 195 245 return EEXISTS; 196 246 } 197 list_t *list = get_list(instance, ep->address); 198 list_append(&ep->link, list); 247 list_append(&ep->link, get_list(instance, ep->address)); 199 248 200 249 instance->free_bw -= ep->bandwidth; … … 203 252 } 204 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 */ 205 260 int usb_endpoint_manager_unregister_ep( 206 261 usb_endpoint_manager_t *instance, endpoint_t *ep) 207 262 { 208 263 assert(instance); 209 if (ep == NULL) 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); 210 270 return ENOENT; 211 fibril_mutex_lock(&instance->guard);271 } 212 272 list_remove(&ep->link); 213 fibril_mutex_unlock(&instance->guard); 214 return EOK; 215 } 216 /*----------------------------------------------------------------------------*/ 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 */ 217 282 endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance, 218 283 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) … … 223 288 endpoint_t *ep = find_locked(instance, address, endpoint, direction); 224 289 fibril_mutex_unlock(&instance->guard); 225 226 290 return ep; 227 291 } 228 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 */ 229 306 int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance, 230 307 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction, … … 233 310 { 234 311 assert(instance); 312 if (instance->bw_count == NULL) 313 return ENOTSUP; 314 if (address < 0) 315 return EINVAL; 316 235 317 const size_t bw = 236 318 instance->bw_count(speed, type, data_size, max_packet_size); 237 319 238 endpoint_t *ep = endpoint_create( 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( 239 335 address, endpoint, direction, type, speed, max_packet_size, bw); 240 if (!ep) 336 if (!ep) { 337 fibril_mutex_unlock(&instance->guard); 241 338 return ENOMEM; 339 } 242 340 243 341 if (callback) { 244 342 const int ret = callback(ep, arg); 245 343 if (ret != EOK) { 344 fibril_mutex_unlock(&instance->guard); 246 345 endpoint_destroy(ep); 247 346 return ret; 248 347 } 249 348 } 250 251 const int ret = 252 usb_endpoint_manager_register_ep(instance, ep, data_size); 253 if (ret != EOK) { 254 endpoint_destroy(ep); 255 } 256 return ret; 257 } 258 /*----------------------------------------------------------------------------*/ 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 */ 259 365 int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance, 260 366 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
Note:
See TracChangeset
for help on using the changeset viewer.