Changeset 8b71f3e in mainline
- Timestamp:
- 2018-01-14T21:16:03Z (7 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)
- Location:
- uspace
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
redc51615 r8b71f3e 161 161 162 162 /* Start hub operation. */ 163 const usb_device_polling_config_t config = { 164 .debug = 1, 165 .auto_clear_halt = true, 166 .delay = -1, 167 .max_failures = 3, 168 .on_data = hub_port_changes_callback, 169 .on_polling_end = usb_hub_polling_terminated_callback, 170 .on_error = usb_hub_polling_error_callback, 171 .arg = hub_dev, 172 }; 173 174 usb_endpoint_mapping_t *epm = 175 usb_device_get_mapped_ep_desc(hub_dev->usb_device, 163 usb_polling_t *polling = &hub_dev->polling; 164 opResult = usb_polling_init(polling); 165 if (opResult != EOK) { 166 ddf_fun_unbind(hub_dev->hub_fun); 167 ddf_fun_destroy(hub_dev->hub_fun); 168 usb_log_error("Failed to initialize polling fibril: %s.\n", 169 str_error(opResult)); 170 return opResult; 171 } 172 173 polling->device = hub_dev->usb_device; 174 polling->ep_mapping = usb_device_get_mapped_ep_desc(hub_dev->usb_device, 176 175 &hub_status_change_endpoint_description); 177 opResult = usb_device_poll(hub_dev->usb_device, epm, &config, 178 ((hub_dev->port_count + 1 + 7) / 8), &hub_dev->polling); 179 176 polling->request_size = ((hub_dev->port_count + 1 + 7) / 8); 177 polling->buffer = malloc(polling->request_size); 178 polling->on_data = hub_port_changes_callback; 179 polling->on_polling_end = usb_hub_polling_terminated_callback; 180 polling->on_error = usb_hub_polling_error_callback; 181 polling->arg = hub_dev; 182 183 opResult = usb_polling_start(polling); 180 184 if (opResult != EOK) { 181 185 /* Function is already bound */ 186 free(polling->buffer); 182 187 ddf_fun_unbind(hub_dev->hub_fun); 183 188 ddf_fun_destroy(hub_dev->hub_fun); … … 186 191 return opResult; 187 192 } 193 188 194 hub_dev->running = true; 189 195 usb_log_info("Controlling hub '%s' (%p: %zu ports).\n", … … 197 203 { 198 204 assert(!hub->running); 205 206 free(hub->polling.buffer); 207 usb_polling_fini(&hub->polling); 199 208 200 209 for (size_t port = 0; port < hub->port_count; ++port) { … … 233 242 usb_log_info("(%p) USB hub removed, joining polling fibril.", hub); 234 243 235 /* Join polling fibril . */236 usb_ device_poll_join(hub->polling);244 /* Join polling fibril (ignoring error code). */ 245 usb_polling_join(&hub->polling); 237 246 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 238 247 … … 254 263 usb_log_info("(%p) USB hub gone, joining polling fibril.", hub); 255 264 256 /* Join polling fibril . */257 usb_ device_poll_join(hub->polling);265 /* Join polling fibril (ignoring error code). */ 266 usb_polling_join(&hub->polling); 258 267 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 259 268 -
uspace/drv/bus/usb/usbhub/usbhub.h
redc51615 r8b71f3e 60 60 usb_device_t *usb_device; 61 61 /** Data polling handle. */ 62 usb_ device_polling_t *polling;62 usb_polling_t polling; 63 63 /** Number of pending operations on the mutex to prevent shooting 64 64 * ourselves in the foot. -
uspace/drv/hid/usbhid/main.c
redc51615 r8b71f3e 89 89 * This will create a separate fibril that will query the device 90 90 * for the data continuously. */ 91 const usb_device_polling_config_t config = { 92 .debug = 1, 93 .auto_clear_halt = true, 94 .delay = -1, 95 .max_failures = 3, 96 .on_data = usb_hid_polling_callback, 97 .on_polling_end = usb_hid_polling_ended_callback, 98 .on_error = usb_hid_polling_error_callback, 99 .arg = hid_dev, 100 }; 101 102 rc = usb_device_poll(dev, hid_dev->poll_pipe_mapping, &config, 103 hid_dev->poll_pipe_mapping->pipe.desc.max_transfer_size, &hid_dev->polling); 91 rc = usb_polling_start(&hid_dev->polling); 104 92 105 93 if (rc != EOK) { … … 122 110 assert(hid_dev); 123 111 124 /* Join polling fibril . */125 usb_ device_poll_join(hid_dev->polling);112 /* Join polling fibril (ignoring error code). */ 113 usb_polling_join(&hid_dev->polling); 126 114 127 115 /* Clean up. */ -
uspace/drv/hid/usbhid/usbhid.c
redc51615 r8b71f3e 445 445 ".\n"); 446 446 } 447 448 usb_polling_t *polling = &hid_dev->polling; 449 if ((rc = usb_polling_init(polling))) { 450 // FIXME 451 } 452 453 polling->device = hid_dev->usb_dev; 454 polling->ep_mapping = hid_dev->poll_pipe_mapping; 455 polling->request_size = hid_dev->poll_pipe_mapping->pipe.desc.max_transfer_size; 456 polling->buffer = malloc(polling->request_size); 457 polling->on_data = usb_hid_polling_callback, 458 polling->on_polling_end = usb_hid_polling_ended_callback, 459 polling->on_error = usb_hid_polling_error_callback, 460 polling->arg = hid_dev; 447 461 } 448 462 … … 537 551 assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0); 538 552 553 free(hid_dev->polling.buffer); 554 usb_polling_fini(&hid_dev->polling); 555 539 556 usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 540 557 hid_dev->subdrivers, hid_dev->subdriver_count); -
uspace/drv/hid/usbhid/usbhid.h
redc51615 r8b71f3e 107 107 usb_endpoint_mapping_t *poll_pipe_mapping; 108 108 109 /** Device polling handle. */110 usb_ device_polling_t *polling;109 /** Device polling structure. */ 110 usb_polling_t polling; 111 111 112 112 /** Subdrivers. */ -
uspace/lib/usbdev/include/usb/dev/poll.h
redc51615 r8b71f3e 43 43 #include <stddef.h> 44 44 #include <stdint.h> 45 #include <fibril_synch.h> 45 46 46 /** Automated polling instance. */47 typedef struct usb_device_polling usb_device_polling_t;48 47 49 /** Parameters and callbacks for automated polling. */ 50 typedef struct usb_device_polling_config { 51 /** Level of debugging messages from auto polling. 52 * 0 - nothing 53 * 1 - inform about errors and polling start/end 54 * 2 - also dump every retrieved buffer 55 */ 56 int debug; 48 /** USB automated polling. */ 49 typedef struct usb_polling { 50 /** Mandatory parameters - user is expected to configure these. */ 57 51 58 /** Maximum number of consecutive errors before polling termination. */59 size_t max_failures;52 /** USB device to poll. */ 53 usb_device_t *device; 60 54 61 /** Delay between poll requests in milliseconds. 62 * Set to negative value to use value from endpoint descriptor. 63 */ 64 int delay; 55 /** Device enpoint mapping to use for polling. */ 56 usb_endpoint_mapping_t *ep_mapping; 65 57 66 /** Whether to automatically try to clear the HALT feature after 67 * the endpoint stalls. 68 */ 69 bool auto_clear_halt; 58 /** Size of the recieved data. */ 59 size_t request_size; 60 61 /** Data buffer of at least `request_size`. User is responsible for its allocation. */ 62 uint8_t *buffer; 70 63 71 64 /** Callback when data arrives. … … 79 72 bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size, 80 73 void *arg); 74 75 76 /** Optional parameters - user can customize them, but they are defaulted to 77 * some reasonable values. 78 */ 79 80 /** Level of debugging messages from auto polling. 81 * 0 - nothing (default) 82 * 1 - inform about errors and polling start/end 83 * 2 - also dump every retrieved buffer 84 */ 85 int debug; 86 87 /** Maximum number of consecutive errors before polling termination (default 3). */ 88 size_t max_failures; 89 90 /** Delay between poll requests in milliseconds. 91 * By default, value from endpoint descriptor used. 92 */ 93 int delay; 94 95 /** Whether to automatically try to clear the HALT feature after 96 * the endpoint stalls (true by default). 97 */ 98 bool auto_clear_halt; 99 100 /** Argument to pass to callbacks (default NULL). */ 101 void *arg; 81 102 82 103 /** Callback when polling is terminated. … … 98 119 bool (*on_error)(usb_device_t *dev, int err_code, void *arg); 99 120 100 /** Argument to pass to callbacks. */101 void *arg;102 } usb_device_polling_config_t;103 121 104 int usb_device_poll(usb_device_t *, usb_endpoint_mapping_t *, 105 const usb_device_polling_config_t *, size_t, usb_device_polling_t **); 122 /** Internal parameters - user is not expected to set them. Messing with them 123 * can result in unexpected behavior if you do not know what you are doing. 124 */ 106 125 107 int usb_device_poll_join(usb_device_polling_t *); 126 /** Fibril used for polling. */ 127 fid_t fibril; 128 129 /** True if polling is currently in operation. */ 130 volatile bool running; 131 132 /** True if polling should terminate as soon as possible. */ 133 volatile bool joining; 134 135 /** Synchronization primitives for joining polling end. */ 136 fibril_mutex_t guard; 137 fibril_condvar_t cv; 138 } usb_polling_t; 139 140 int usb_polling_init(usb_polling_t *); 141 void usb_polling_fini(usb_polling_t *); 142 143 int usb_polling_start(usb_polling_t *); 144 int usb_polling_join(usb_polling_t *); 108 145 109 146 #endif -
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.