Changeset 8b71f3e in mainline for uspace/lib/usbdev/src/devpoll.c
- Timestamp:
- 2018-01-14T21:16:03Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 17c1d9db
- Parents:
- edc51615
- git-author:
- Petr Manek <petr.manek@…> (2018-01-14 21:16:00)
- git-committer:
- Petr Manek <petr.manek@…> (2018-01-14 21:16:03)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/devpoll.c
redc51615 r8b71f3e 54 54 #include <stdint.h> 55 55 56 /** Private automated polling instance data. */ 57 struct usb_device_polling { 58 /** Parameters for automated polling. */ 59 usb_device_polling_config_t config; 60 61 /** USB device to poll. */ 62 usb_device_t *dev; 63 64 /** Device enpoint mapping to use for polling. */ 65 usb_endpoint_mapping_t *ep_mapping; 66 67 /** Size of the recieved data. */ 68 size_t request_size; 69 70 /** Data buffer. */ 71 uint8_t *buffer; 72 73 /** True if polling is currently in operation. */ 74 volatile bool running; 75 76 /** True if polling should terminate as soon as possible. */ 77 volatile bool joining; 78 79 /** Synchronization primitives for joining polling end. */ 80 fibril_mutex_t guard; 81 fibril_condvar_t cv; 82 }; 83 84 85 static void polling_fini(usb_device_polling_t *polling) 86 { 87 /* Free the allocated memory. */ 88 free(polling->buffer); 89 free(polling); 56 57 /** Initialize the polling data structure, its internals and configuration 58 * with default values. 59 * 60 * @param polling Valid polling data structure. 61 * @return Error code. 62 * @retval EOK Polling data structure is ready to be used. 63 */ 64 int usb_polling_init(usb_polling_t *polling) 65 { 66 if (!polling) 67 return EBADMEM; 68 69 /* Zero out everything */ 70 memset(polling, 0, sizeof(usb_polling_t)); 71 72 /* Internal initializers. */ 73 fibril_mutex_initialize(&polling->guard); 74 fibril_condvar_initialize(&polling->cv); 75 76 /* Default configuration. */ 77 polling->auto_clear_halt = true; 78 polling->delay = -1; 79 polling->max_failures = 3; 80 81 return EOK; 82 } 83 84 85 /** Destroy the polling data structure. 86 * This function does nothing but a safety check whether the polling 87 * was joined successfully. 88 * 89 * @param polling Polling data structure. 90 */ 91 void usb_polling_fini(usb_polling_t *polling) 92 { 93 /* Nothing done at the moment. */ 94 assert(polling); 95 assert(!polling->running); 90 96 } 91 97 … … 93 99 /** Polling fibril. 94 100 * 95 * @param arg Pointer to usb_ device_polling_t.101 * @param arg Pointer to usb_polling_t. 96 102 * @return Always EOK. 97 103 */ … … 99 105 { 100 106 assert(arg); 101 usb_device_polling_t *data = arg; 102 data->running = true; 103 104 /* Helper to reduce typing. */ 105 const usb_device_polling_config_t *params = &data->config; 106 107 usb_pipe_t *pipe = &data->ep_mapping->pipe; 108 109 if (params->debug > 0) { 107 usb_polling_t *polling = arg; 108 polling->running = true; 109 110 usb_pipe_t *pipe = &polling->ep_mapping->pipe; 111 112 if (polling->debug > 0) { 110 113 const usb_endpoint_mapping_t *mapping = 111 data->ep_mapping;114 polling->ep_mapping; 112 115 usb_log_debug("Poll (%p): started polling of `%s' - " \ 113 116 "interface %d (%s,%d,%d), %zuB/%zu.\n", 114 data, usb_device_get_name(data->dev),117 polling, usb_device_get_name(polling->device), 115 118 (int) mapping->interface->interface_number, 116 119 usb_str_class(mapping->interface->interface_class), 117 120 (int) mapping->interface->interface_subclass, 118 121 (int) mapping->interface->interface_protocol, 119 data->request_size, pipe->desc.max_transfer_size);122 polling->request_size, pipe->desc.max_transfer_size); 120 123 } 121 124 122 125 size_t failed_attempts = 0; 123 while (failed_attempts <= p arams->max_failures) {126 while (failed_attempts <= polling->max_failures) { 124 127 size_t actual_size; 125 const int rc = usb_pipe_read(pipe, data->buffer,126 data->request_size, &actual_size);128 const int rc = usb_pipe_read(pipe, polling->buffer, 129 polling->request_size, &actual_size); 127 130 128 131 if (rc == EOK) { 129 if (p arams->debug > 1) {132 if (polling->debug > 1) { 130 133 usb_log_debug( 131 134 "Poll%p: received: '%s' (%zuB).\n", 132 data,133 usb_debug_str_buffer( data->buffer,135 polling, 136 usb_debug_str_buffer(polling->buffer, 134 137 actual_size, 16), 135 138 actual_size); … … 138 141 usb_log_debug( 139 142 "Poll%p: polling failed: %s.\n", 140 data, str_error(rc));143 polling, str_error(rc)); 141 144 } 142 145 143 146 /* If the pipe stalled, we can try to reset the stall. */ 144 if ( (rc == ESTALL) && (params->auto_clear_halt)) {147 if (rc == ESTALL && polling->auto_clear_halt) { 145 148 /* 146 149 * We ignore error here as this is usually a futile … … 148 151 */ 149 152 usb_request_clear_endpoint_halt( 150 usb_device_get_default_pipe( data->dev),153 usb_device_get_default_pipe(polling->device), 151 154 pipe->desc.endpoint_no); 152 155 } … … 154 157 if (rc != EOK) { 155 158 ++failed_attempts; 156 const bool cont = (params->on_error == NULL) ? true : 157 params->on_error(data->dev, rc, params->arg); 158 if (!cont || data->joining) { 159 const bool carry_on = !polling->on_error ? true : 160 polling->on_error(polling->device, rc, polling->arg); 161 162 if (!carry_on || polling->joining) { 159 163 /* This is user requested abort, erases failures. */ 160 164 failed_attempts = 0; … … 165 169 166 170 /* We have the data, execute the callback now. */ 167 assert(p arams->on_data);168 const bool carry_on = p arams->on_data(169 data->dev, data->buffer, actual_size, params->arg);171 assert(polling->on_data); 172 const bool carry_on = polling->on_data(polling->device, 173 polling->buffer, actual_size, polling->arg); 170 174 171 175 if (!carry_on) { … … 183 187 // but first we need to fix drivers to actually stop using this, 184 188 // since polling delay should be implemented in HC schedule 185 async_usleep(p arams->delay);189 async_usleep(polling->delay); 186 190 } 187 191 188 192 const bool failed = failed_attempts > 0; 189 193 190 if (params->on_polling_end != NULL) { 191 params->on_polling_end(data->dev, failed, params->arg); 192 } 193 194 if (params->debug > 0) { 194 if (polling->on_polling_end) 195 polling->on_polling_end(polling->device, failed, polling->arg); 196 197 if (polling->debug > 0) { 195 198 if (failed) { 196 199 usb_log_error("Polling of device `%s' terminated: " 197 200 "recurring failures.\n", 198 usb_device_get_name( data->dev));201 usb_device_get_name(polling->device)); 199 202 } else { 200 203 usb_log_debug("Polling of device `%s' terminated: " 201 204 "driver request.\n", 202 usb_device_get_name( data->dev));205 usb_device_get_name(polling->device)); 203 206 } 204 207 } 205 208 206 data->running = false;209 polling->running = false; 207 210 208 211 /* Notify joiners, if any. */ 209 fibril_condvar_broadcast(&data->cv); 210 211 /* Free allocated memory. */ 212 if (!data->joining) { 213 polling_fini(data); 214 } 215 212 fibril_condvar_broadcast(&polling->cv); 216 213 return EOK; 217 214 } … … 227 224 * first request would be executed prior to return from this function). 228 225 * 229 * @param dev Device to be periodically polled. 230 * @param epm Endpoint mapping to use. 231 * @param config Polling settings. 232 * @param req_size How many bytes to ask for in each request. 226 * @param polling Polling data structure. 233 227 * @return Error code. 234 228 * @retval EOK New fibril polling the device was already started. 235 229 */ 236 int usb_device_poll(usb_device_t *dev, usb_endpoint_mapping_t *epm, 237 const usb_device_polling_config_t *config, size_t req_size, 238 usb_device_polling_t **handle) 239 { 240 int rc; 241 if (!dev || !config || !config->on_data) 230 int usb_polling_start(usb_polling_t *polling) 231 { 232 if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data) 242 233 return EBADMEM; 243 234 244 if (! req_size)235 if (!polling->request_size) 245 236 return EINVAL; 246 237 247 if (! epm || (epm->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) ||248 (epm->pipe.desc.direction != USB_DIRECTION_IN))238 if (!polling->ep_mapping || (polling->ep_mapping->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) 239 || (polling->ep_mapping->pipe.desc.direction != USB_DIRECTION_IN)) 249 240 return EINVAL; 250 241 251 usb_device_polling_t *instance = malloc(sizeof(usb_device_polling_t)); 252 if (!instance) 242 /* Negative value means use descriptor provided value. */ 243 if (polling->delay < 0) 244 polling->delay = polling->ep_mapping->descriptor->poll_interval; 245 246 polling->fibril = fibril_create(polling_fibril, polling); 247 if (!polling->fibril) 253 248 return ENOMEM; 254 249 255 /* Fill-in the data. */ 256 instance->buffer = malloc(req_size); 257 if (!instance->buffer) { 258 rc = ENOMEM; 259 goto err_instance; 260 } 261 instance->request_size = req_size; 262 instance->dev = dev; 263 instance->ep_mapping = epm; 264 instance->joining = false; 265 fibril_mutex_initialize(&instance->guard); 266 fibril_condvar_initialize(&instance->cv); 267 268 /* Copy provided settings. */ 269 instance->config = *config; 270 271 /* Negative value means use descriptor provided value. */ 272 if (config->delay < 0) { 273 instance->config.delay = epm->descriptor->poll_interval; 274 } 275 276 fid_t fibril = fibril_create(polling_fibril, instance); 277 if (!fibril) { 278 rc = ENOMEM; 279 goto err_buffer; 280 } 281 fibril_add_ready(fibril); 282 283 if (handle) 284 *handle = instance; 250 fibril_add_ready(polling->fibril); 285 251 286 252 /* Fibril launched. That fibril will free the allocated data. */ 287 253 return EOK; 288 289 err_buffer: 290 free(instance->buffer); 291 err_instance: 292 free(instance); 293 return rc; 294 } 295 296 int usb_device_poll_join(usb_device_polling_t *polling) 254 } 255 256 /** Close the polling pipe permanently and synchronously wait 257 * until the automatic polling fibril terminates. 258 * 259 * It is safe to deallocate the polling data structure (and its 260 * data buffer) only after a successful call to this function. 261 * 262 * @warning Call to this function will trigger execution of the 263 * on_error() callback with EINTR error code. 264 * 265 * @parram polling Polling data structure. 266 * @return Error code. 267 * @retval EOK Polling fibril has been successfully terminated. 268 */ 269 int usb_polling_join(usb_polling_t *polling) 297 270 { 298 271 int rc; … … 300 273 return EBADMEM; 301 274 275 /* Check if the fibril already terminated. */ 276 if (!polling->running) 277 return EOK; 278 302 279 /* Set the flag */ 303 280 polling->joining = true; 304 281 305 282 /* Unregister the pipe. */ 306 if ((rc = usb_device_unmap_ep(polling->ep_mapping))) {283 if ((rc = usb_device_unmap_ep(polling->ep_mapping))) 307 284 return rc; 308 }309 285 310 286 /* Wait for the fibril to terminate. */ … … 314 290 fibril_mutex_unlock(&polling->guard); 315 291 316 /* Free the instance. */317 polling_fini(polling);318 319 292 return EOK; 320 293 }
Note:
See TracChangeset
for help on using the changeset viewer.