Changes in uspace/lib/usbdev/src/devpoll.c [5a6cc679:33b8d024] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/devpoll.c
r5a6cc679 r33b8d024 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2017 Petr Manek4 3 * All rights reserved. 5 4 * … … 48 47 #include <errno.h> 49 48 #include <fibril.h> 50 #include <fibril_synch.h>51 49 #include <stdbool.h> 52 50 #include <stdlib.h> … … 55 53 #include <stdint.h> 56 54 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 } 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; 98 72 99 73 100 74 /** Polling fibril. 101 75 * 102 * @param arg Pointer to usb_polling_t.76 * @param arg Pointer to polling_data_t. 103 77 * @return Always EOK. 104 78 */ … … 106 80 { 107 81 assert(arg); 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) { 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) { 117 89 const usb_endpoint_mapping_t *mapping = 118 polling->ep_mapping;90 data->polling_mapping; 119 91 usb_log_debug("Poll (%p): started polling of `%s' - " \ 120 92 "interface %d (%s,%d,%d), %zuB/%zu.\n", 121 polling, usb_device_get_name(polling->device),93 data, usb_device_get_name(data->dev), 122 94 (int) mapping->interface->interface_number, 123 95 usb_str_class(mapping->interface->interface_class), 124 96 (int) mapping->interface->interface_subclass, 125 97 (int) mapping->interface->interface_protocol, 126 polling->request_size, pipe->desc.max_transfer_size);98 data->request_size, pipe->max_packet_size); 127 99 } 128 100 129 101 size_t failed_attempts = 0; 130 while (failed_attempts <= p olling->max_failures) {102 while (failed_attempts <= params->max_failures) { 131 103 size_t actual_size; 132 const errno_t rc = usb_pipe_read(pipe, polling->buffer,133 polling->request_size, &actual_size);104 const errno_t rc = usb_pipe_read(pipe, data->buffer, 105 data->request_size, &actual_size); 134 106 135 107 if (rc == EOK) { 136 if (p olling->debug > 1) {108 if (params->debug > 1) { 137 109 usb_log_debug( 138 110 "Poll%p: received: '%s' (%zuB).\n", 139 polling,140 usb_debug_str_buffer( polling->buffer,111 data, 112 usb_debug_str_buffer(data->buffer, 141 113 actual_size, 16), 142 114 actual_size); … … 145 117 usb_log_debug( 146 118 "Poll%p: polling failed: %s.\n", 147 polling, str_error(rc));119 data, str_error(rc)); 148 120 } 149 121 150 122 /* If the pipe stalled, we can try to reset the stall. */ 151 if ( rc == ESTALL && polling->auto_clear_halt) {123 if ((rc == ESTALL) && (params->auto_clear_halt)) { 152 124 /* 153 125 * We ignore error here as this is usually a futile 154 126 * attempt anyway. 155 127 */ 156 usb_pipe_clear_halt( 157 usb_device_get_default_pipe(polling->device), pipe); 128 usb_request_clear_endpoint_halt( 129 usb_device_get_default_pipe(data->dev), 130 pipe->endpoint_no); 158 131 } 159 132 160 133 if (rc != EOK) { 161 134 ++failed_attempts; 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; 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; 169 139 } 170 140 continue; … … 172 142 173 143 /* We have the data, execute the callback now. */ 174 assert(p olling->on_data);175 const bool carry_on = p olling->on_data(polling->device,176 polling->buffer, actual_size, polling->arg);144 assert(params->on_data); 145 const bool carry_on = params->on_data( 146 data->dev, data->buffer, actual_size, params->arg); 177 147 178 148 if (!carry_on) { … … 186 156 187 157 /* Take a rest before next request. */ 188 158 189 159 // FIXME TODO: This is broken, the time is in ms not us. 190 160 // but first we need to fix drivers to actually stop using this, 191 161 // since polling delay should be implemented in HC schedule 192 async_usleep(p olling->delay);162 async_usleep(params->delay); 193 163 } 194 164 195 165 const bool failed = failed_attempts > 0; 196 166 197 if (polling->on_polling_end) 198 polling->on_polling_end(polling->device, failed, polling->arg); 199 200 if (polling->debug > 0) { 167 if (params->on_polling_end != NULL) { 168 params->on_polling_end(data->dev, failed, params->arg); 169 } 170 171 if (params->debug > 0) { 201 172 if (failed) { 202 173 usb_log_error("Polling of device `%s' terminated: " 203 174 "recurring failures.\n", 204 usb_device_get_name( polling->device));175 usb_device_get_name(data->dev)); 205 176 } else { 206 177 usb_log_debug("Polling of device `%s' terminated: " 207 178 "driver request.\n", 208 usb_device_get_name(polling->device)); 209 } 210 } 211 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); 179 usb_device_get_name(data->dev)); 180 } 181 } 182 183 /* Free the allocated memory. */ 184 free(data->buffer); 185 free(data); 186 218 187 return EOK; 219 188 } … … 229 198 * first request would be executed prior to return from this function). 230 199 * 231 * @param polling Polling data structure. 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). 232 205 * @return Error code. 233 206 * @retval EOK New fibril polling the device was already started. 234 207 */ 235 errno_t usb_polling_start(usb_polling_t *polling) 236 { 237 if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data) 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)) { 238 213 return EBADMEM; 239 240 if (!polling->request_size) 214 } 215 216 if (request_size == 0) 241 217 return EINVAL; 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))218 219 if (!epm || (epm->pipe.transfer_type != USB_TRANSFER_INTERRUPT) || 220 (epm->pipe.direction != USB_DIRECTION_IN)) 245 221 return EINVAL; 222 223 224 polling_data_t *polling_data = malloc(sizeof(polling_data_t)); 225 if (polling_data == NULL) { 226 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; 246 241 247 242 /* 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) 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); 253 252 return ENOMEM; 254 255 fibril_add_ready( polling->fibril);253 } 254 fibril_add_ready(fibril); 256 255 257 256 /* Fibril launched. That fibril will free the allocated data. */ 257 258 258 return EOK; 259 259 } 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; 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); 299 352 } 300 353
Note:
See TracChangeset
for help on using the changeset viewer.