Changes in uspace/lib/usbdev/src/devpoll.c [33b8d024:5a6cc679] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/devpoll.c
r33b8d024 r5a6cc679 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2017 Petr Manek 3 4 * All rights reserved. 4 5 * … … 47 48 #include <errno.h> 48 49 #include <fibril.h> 50 #include <fibril_synch.h> 49 51 #include <stdbool.h> 50 52 #include <stdlib.h> … … 53 55 #include <stdint.h> 54 56 55 /** Maximum number of failed consecutive requests before announcing failure. */ 56 #define MAX_FAILED_ATTEMPTS 3 57 58 /** Data needed for polling. */ 59 typedef struct { 60 /** Parameters for automated polling. */ 61 usb_device_auto_polling_t auto_polling; 62 63 /** USB device to poll. */ 64 usb_device_t *dev; 65 /** Device enpoint mapping to use for polling. */ 66 usb_endpoint_mapping_t *polling_mapping; 67 /** Size of the recieved data. */ 68 size_t request_size; 69 /** Data buffer. */ 70 uint8_t *buffer; 71 } polling_data_t; 57 58 /** Initialize the polling data structure, its internals and configuration 59 * with default values. 60 * 61 * @param polling Valid polling data structure. 62 * @return Error code. 63 * @retval EOK Polling data structure is ready to be used. 64 */ 65 int usb_polling_init(usb_polling_t *polling) 66 { 67 if (!polling) 68 return EBADMEM; 69 70 /* Zero out everything */ 71 memset(polling, 0, sizeof(usb_polling_t)); 72 73 /* Internal initializers. */ 74 fibril_mutex_initialize(&polling->guard); 75 fibril_condvar_initialize(&polling->cv); 76 77 /* Default configuration. */ 78 polling->auto_clear_halt = true; 79 polling->delay = -1; 80 polling->max_failures = 3; 81 82 return EOK; 83 } 84 85 86 /** Destroy the polling data structure. 87 * This function does nothing but a safety check whether the polling 88 * was joined successfully. 89 * 90 * @param polling Polling data structure. 91 */ 92 void usb_polling_fini(usb_polling_t *polling) 93 { 94 /* Nothing done at the moment. */ 95 assert(polling); 96 assert(!polling->running); 97 } 72 98 73 99 74 100 /** Polling fibril. 75 101 * 76 * @param arg Pointer to polling_data_t.102 * @param arg Pointer to usb_polling_t. 77 103 * @return Always EOK. 78 104 */ … … 80 106 { 81 107 assert(arg); 82 polling_data_t *data = arg; 83 /* Helper to reduce typing. */ 84 const usb_device_auto_polling_t *params = &data->auto_polling; 85 86 usb_pipe_t *pipe = &data->polling_mapping->pipe; 87 88 if (params->debug > 0) { 108 usb_polling_t *polling = arg; 109 110 fibril_mutex_lock(&polling->guard); 111 polling->running = true; 112 fibril_mutex_unlock(&polling->guard); 113 114 usb_pipe_t *pipe = &polling->ep_mapping->pipe; 115 116 if (polling->debug > 0) { 89 117 const usb_endpoint_mapping_t *mapping = 90 data->polling_mapping;118 polling->ep_mapping; 91 119 usb_log_debug("Poll (%p): started polling of `%s' - " \ 92 120 "interface %d (%s,%d,%d), %zuB/%zu.\n", 93 data, usb_device_get_name(data->dev),121 polling, usb_device_get_name(polling->device), 94 122 (int) mapping->interface->interface_number, 95 123 usb_str_class(mapping->interface->interface_class), 96 124 (int) mapping->interface->interface_subclass, 97 125 (int) mapping->interface->interface_protocol, 98 data->request_size, pipe->max_packet_size);126 polling->request_size, pipe->desc.max_transfer_size); 99 127 } 100 128 101 129 size_t failed_attempts = 0; 102 while (failed_attempts <= p arams->max_failures) {130 while (failed_attempts <= polling->max_failures) { 103 131 size_t actual_size; 104 const errno_t rc = usb_pipe_read(pipe, data->buffer,105 data->request_size, &actual_size);132 const errno_t rc = usb_pipe_read(pipe, polling->buffer, 133 polling->request_size, &actual_size); 106 134 107 135 if (rc == EOK) { 108 if (p arams->debug > 1) {136 if (polling->debug > 1) { 109 137 usb_log_debug( 110 138 "Poll%p: received: '%s' (%zuB).\n", 111 data,112 usb_debug_str_buffer( data->buffer,139 polling, 140 usb_debug_str_buffer(polling->buffer, 113 141 actual_size, 16), 114 142 actual_size); … … 117 145 usb_log_debug( 118 146 "Poll%p: polling failed: %s.\n", 119 data, str_error(rc));147 polling, str_error(rc)); 120 148 } 121 149 122 150 /* If the pipe stalled, we can try to reset the stall. */ 123 if ( (rc == ESTALL) && (params->auto_clear_halt)) {151 if (rc == ESTALL && polling->auto_clear_halt) { 124 152 /* 125 153 * We ignore error here as this is usually a futile 126 154 * attempt anyway. 127 155 */ 128 usb_request_clear_endpoint_halt( 129 usb_device_get_default_pipe(data->dev), 130 pipe->endpoint_no); 156 usb_pipe_clear_halt( 157 usb_device_get_default_pipe(polling->device), pipe); 131 158 } 132 159 133 160 if (rc != EOK) { 134 161 ++failed_attempts; 135 const bool cont = (params->on_error == NULL) ? true : 136 params->on_error(data->dev, rc, params->arg); 137 if (!cont) { 138 failed_attempts = params->max_failures; 162 const bool carry_on = !polling->on_error ? true : 163 polling->on_error(polling->device, rc, polling->arg); 164 165 if (!carry_on || polling->joining) { 166 /* This is user requested abort, erases failures. */ 167 failed_attempts = 0; 168 break; 139 169 } 140 170 continue; … … 142 172 143 173 /* We have the data, execute the callback now. */ 144 assert(p arams->on_data);145 const bool carry_on = p arams->on_data(146 data->dev, data->buffer, actual_size, params->arg);174 assert(polling->on_data); 175 const bool carry_on = polling->on_data(polling->device, 176 polling->buffer, actual_size, polling->arg); 147 177 148 178 if (!carry_on) { … … 156 186 157 187 /* Take a rest before next request. */ 158 188 159 189 // FIXME TODO: This is broken, the time is in ms not us. 160 190 // but first we need to fix drivers to actually stop using this, 161 191 // since polling delay should be implemented in HC schedule 162 async_usleep(p arams->delay);192 async_usleep(polling->delay); 163 193 } 164 194 165 195 const bool failed = failed_attempts > 0; 166 196 167 if (params->on_polling_end != NULL) { 168 params->on_polling_end(data->dev, failed, params->arg); 169 } 170 171 if (params->debug > 0) { 197 if (polling->on_polling_end) 198 polling->on_polling_end(polling->device, failed, polling->arg); 199 200 if (polling->debug > 0) { 172 201 if (failed) { 173 202 usb_log_error("Polling of device `%s' terminated: " 174 203 "recurring failures.\n", 175 usb_device_get_name( data->dev));204 usb_device_get_name(polling->device)); 176 205 } else { 177 206 usb_log_debug("Polling of device `%s' terminated: " 178 207 "driver request.\n", 179 usb_device_get_name( data->dev));208 usb_device_get_name(polling->device)); 180 209 } 181 210 } 182 211 183 /* Free the allocated memory. */ 184 free(data->buffer); 185 free(data); 186 212 fibril_mutex_lock(&polling->guard); 213 polling->running = false; 214 fibril_mutex_unlock(&polling->guard); 215 216 /* Notify joiners, if any. */ 217 fibril_condvar_broadcast(&polling->cv); 187 218 return EOK; 188 219 } … … 198 229 * first request would be executed prior to return from this function). 199 230 * 200 * @param dev Device to be periodically polled. 201 * @param epm Endpoint mapping to use. 202 * @param polling Polling settings. 203 * @param request_size How many bytes to ask for in each request. 204 * @param arg Custom argument (passed as is to the callbacks). 231 * @param polling Polling data structure. 205 232 * @return Error code. 206 233 * @retval EOK New fibril polling the device was already started. 207 234 */ 208 static errno_t usb_device_auto_polling_internal(usb_device_t *dev, 209 usb_endpoint_mapping_t *epm, const usb_device_auto_polling_t *polling, 210 size_t request_size) 211 { 212 if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) { 235 errno_t usb_polling_start(usb_polling_t *polling) 236 { 237 if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data) 213 238 return EBADMEM; 214 } 215 216 if (request_size == 0) 239 240 if (!polling->request_size) 217 241 return EINVAL; 218 219 if (! epm || (epm->pipe.transfer_type != USB_TRANSFER_INTERRUPT) ||220 (epm->pipe.direction != USB_DIRECTION_IN))242 243 if (!polling->ep_mapping || (polling->ep_mapping->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) 244 || (polling->ep_mapping->pipe.desc.direction != USB_DIRECTION_IN)) 221 245 return EINVAL; 222 223 224 polling_data_t *polling_data = malloc(sizeof(polling_data_t)); 225 if (polling_data == NULL) { 246 247 /* Negative value means use descriptor provided value. */ 248 if (polling->delay < 0) 249 polling->delay = polling->ep_mapping->descriptor->poll_interval; 250 251 polling->fibril = fibril_create(polling_fibril, polling); 252 if (!polling->fibril) 226 253 return ENOMEM; 227 } 228 229 /* Fill-in the data. */ 230 polling_data->buffer = malloc(sizeof(request_size)); 231 if (polling_data->buffer == NULL) { 232 free(polling_data); 233 return ENOMEM; 234 } 235 polling_data->request_size = request_size; 236 polling_data->dev = dev; 237 polling_data->polling_mapping = epm; 238 239 /* Copy provided settings. */ 240 polling_data->auto_polling = *polling; 241 242 /* Negative value means use descriptor provided value. */ 243 if (polling->delay < 0) { 244 polling_data->auto_polling.delay = 245 epm->descriptor->poll_interval; 246 } 247 248 fid_t fibril = fibril_create(polling_fibril, polling_data); 249 if (fibril == 0) { 250 free(polling_data->buffer); 251 free(polling_data); 252 return ENOMEM; 253 } 254 fibril_add_ready(fibril); 254 255 fibril_add_ready(polling->fibril); 255 256 256 257 /* Fibril launched. That fibril will free the allocated data. */ 257 258 258 return EOK; 259 259 } 260 /** Start automatic device polling over interrupt in pipe. 261 * 262 * The polling settings is copied thus it is okay to destroy the structure 263 * after this function returns. 264 * 265 * @warning There is no guarantee when the request to the device 266 * will be sent for the first time (it is possible that this 267 * first request would be executed prior to return from this function). 268 * 269 * @param dev Device to be periodically polled. 270 * @param pipe_index Index of the endpoint pipe used for polling. 271 * @param polling Polling settings. 272 * @param req_size How many bytes to ask for in each request. 273 * @param arg Custom argument (passed as is to the callbacks). 274 * @return Error code. 275 * @retval EOK New fibril polling the device was already started. 276 */ 277 errno_t usb_device_auto_polling(usb_device_t *usb_dev, usb_endpoint_t ep, 278 const usb_device_auto_polling_t *polling, size_t req_size) 279 { 280 usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(usb_dev, ep); 281 return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size); 282 } 283 284 /** Start automatic device polling over interrupt in pipe. 285 * 286 * @warning It is up to the callback to produce delays between individual 287 * requests. 288 * 289 * @warning There is no guarantee when the request to the device 290 * will be sent for the first time (it is possible that this 291 * first request would be executed prior to return from this function). 292 * 293 * @param dev Device to be periodically polled. 294 * @param ep Endpoint used for polling. 295 * @param callback Callback when data are available. 296 * @param request_size How many bytes to ask for in each request. 297 * @param delay NUmber of ms to wait between queries, -1 to use descriptor val. 298 * @param terminated_callback Callback when polling is terminated. 299 * @param arg Custom argument (passed as is to the callbacks). 300 * @return Error code. 301 * @retval EOK New fibril polling the device was already started. 302 */ 303 errno_t usb_device_auto_poll(usb_device_t *dev, usb_endpoint_t ep, 304 usb_polling_callback_t callback, size_t request_size, int delay, 305 usb_polling_terminted_callback_t terminated_callback, void *arg) 306 { 307 const usb_device_auto_polling_t auto_polling = { 308 .debug = 1, 309 .auto_clear_halt = true, 310 .delay = delay, 311 .max_failures = MAX_FAILED_ATTEMPTS, 312 .on_data = callback, 313 .on_polling_end = terminated_callback, 314 .on_error = NULL, 315 .arg = arg, 316 }; 317 318 usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(dev, ep); 319 return usb_device_auto_polling_internal( 320 dev, epm, &auto_polling, request_size); 321 } 322 323 errno_t usb_device_auto_polling_desc(usb_device_t *usb_dev, 324 const usb_endpoint_description_t *desc, 325 const usb_device_auto_polling_t *polling, size_t req_size) 326 { 327 usb_endpoint_mapping_t *epm = 328 usb_device_get_mapped_ep_desc(usb_dev, desc); 329 return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size); 330 } 331 332 errno_t usb_device_auto_poll_desc(usb_device_t * usb_dev, 333 const usb_endpoint_description_t *desc, usb_polling_callback_t callback, 334 size_t req_size, int delay, 335 usb_polling_terminted_callback_t terminated_callback, void *arg) 336 { 337 const usb_device_auto_polling_t auto_polling = { 338 .debug = 1, 339 .auto_clear_halt = true, 340 .delay = delay, 341 .max_failures = MAX_FAILED_ATTEMPTS, 342 .on_data = callback, 343 .on_polling_end = terminated_callback, 344 .on_error = NULL, 345 .arg = arg, 346 }; 347 348 usb_endpoint_mapping_t *epm = 349 usb_device_get_mapped_ep_desc(usb_dev, desc); 350 return usb_device_auto_polling_internal( 351 usb_dev, epm, &auto_polling, req_size); 260 261 /** Close the polling pipe permanently and synchronously wait 262 * until the automatic polling fibril terminates. 263 * 264 * It is safe to deallocate the polling data structure (and its 265 * data buffer) only after a successful call to this function. 266 * 267 * @warning Call to this function will trigger execution of the 268 * on_error() callback with EINTR error code. 269 * 270 * @parram polling Polling data structure. 271 * @return Error code. 272 * @retval EOK Polling fibril has been successfully terminated. 273 */ 274 errno_t usb_polling_join(usb_polling_t *polling) 275 { 276 errno_t rc; 277 if (!polling) 278 return EBADMEM; 279 280 /* Check if the fibril already terminated. */ 281 if (!polling->running) 282 return EOK; 283 284 /* Set the flag */ 285 polling->joining = true; 286 287 /* Unregister the pipe. */ 288 rc = usb_device_unmap_ep(polling->ep_mapping); 289 if (rc != EOK && rc != ENOENT && rc != EHANGUP) 290 return rc; 291 292 /* Wait for the fibril to terminate. */ 293 fibril_mutex_lock(&polling->guard); 294 while (polling->running) 295 fibril_condvar_wait(&polling->cv, &polling->guard); 296 fibril_mutex_unlock(&polling->guard); 297 298 return EOK; 352 299 } 353 300
Note:
See TracChangeset
for help on using the changeset viewer.