Changeset 5fd9c30 in mainline for uspace/lib/usbhost
- Timestamp:
- 2017-10-21T20:52:56Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 766043c
- Parents:
- 74b852b
- Location:
- uspace/lib/usbhost
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/include/usb/host/bus.h
r74b852b r5fd9c30 33 33 * 34 34 * The purpose of this structure is to keep information about connected devices 35 * and en points, manage available bandwidth and the toggle bit flipping.35 * and endpoints, manage available bandwidth and the toggle bit flipping. 36 36 * 37 37 * The generic implementation is provided for USB 1 and 2 in usb2_bus.c. Some … … 53 53 typedef struct bus bus_t; 54 54 typedef struct ddf_fun ddf_fun_t; 55 typedef struct usb_transfer_batch usb_transfer_batch_t; 55 56 56 57 typedef struct device { … … 85 86 int (*release_endpoint)(bus_t *, endpoint_t *); 86 87 endpoint_t *(*find_endpoint)(bus_t *, usb_target_t, usb_direction_t); 88 void (*destroy_endpoint)(endpoint_t *); /**< Optional */ 89 bool (*endpoint_get_toggle)(endpoint_t *); /**< Optional */ 90 void (*endpoint_set_toggle)(endpoint_t *, bool); /**< Optional */ 87 91 88 92 int (*request_address)(bus_t *, usb_address_t*, bool, usb_speed_t); … … 93 97 size_t (*count_bw) (endpoint_t *, size_t); 94 98 95 /* Endpoint ops, optional (have generic fallback) */ 96 void (*destroy_endpoint)(endpoint_t *); 97 bool (*endpoint_get_toggle)(endpoint_t *); 98 void (*endpoint_set_toggle)(endpoint_t *, bool); 99 usb_transfer_batch_t *(*create_batch)(bus_t *, endpoint_t *); /**< Optional */ 100 void (*destroy_batch)(usb_transfer_batch_t *); /**< Optional */ 99 101 } bus_ops_t; 100 102 … … 135 137 int bus_release_address(bus_t *, usb_address_t); 136 138 139 137 140 static inline int bus_reserve_default_address(bus_t *bus, usb_speed_t speed) { 138 141 usb_address_t addr = USB_ADDRESS_DEFAULT; -
uspace/lib/usbhost/include/usb/host/endpoint.h
r74b852b r5fd9c30 48 48 typedef struct bus bus_t; 49 49 typedef struct device device_t; 50 typedef struct usb_transfer_batch usb_transfer_batch_t; 50 51 51 52 /** Host controller side endpoint structure. */ -
uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
r74b852b r5fd9c30 37 37 #define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H 38 38 39 #include <usb/host/endpoint.h>40 39 #include <usb/usb.h> 40 #include <usb/request.h> 41 41 42 #include <assert.h>43 42 #include <stddef.h> 44 43 #include <stdint.h> … … 47 46 #define USB_SETUP_PACKET_SIZE 8 48 47 48 typedef struct endpoint endpoint_t; 49 typedef struct bus bus_t; 50 typedef struct usb_transfer_batch usb_transfer_batch_t; 51 52 /** Callback to be called on transfer. */ 53 typedef int (*usb_transfer_batch_callback_t)(usb_transfer_batch_t *); 54 49 55 /** Structure stores additional data needed for communication with EP */ 50 56 typedef struct usb_transfer_batch { 51 57 /** Endpoint used for communication */ 52 58 endpoint_t *ep; 53 /** Function called on completion (IN version) */ 54 usbhc_iface_transfer_in_callback_t callback_in; 55 /** Function called on completion (OUT version) */ 56 usbhc_iface_transfer_out_callback_t callback_out; 57 /** Argument to pass to the completion function */ 58 void *arg; 59 /** Size reported to be sent */ 60 size_t expected_size; 61 62 /** Direction of the transfer */ 63 usb_direction_t dir; 64 65 /** Function called on completion */ 66 usb_transfer_batch_callback_t on_complete; 67 /** Arbitrary data for the handler */ 68 void *on_complete_data; 69 70 /** Place to store SETUP data needed by control transfers */ 71 union { 72 char buffer [USB_SETUP_PACKET_SIZE]; 73 usb_device_request_setup_packet_t packet; 74 uint64_t packed; 75 } setup; 76 77 /** Resetting the Toggle */ 78 toggle_reset_mode_t toggle_reset_mode; 79 59 80 /** Place for data to send/receive */ 60 81 char *buffer; 61 82 /** Size of memory pointed to by buffer member */ 62 83 size_t buffer_size; 63 /** Place to store SETUP data needed by control transfers */64 char setup_buffer[USB_SETUP_PACKET_SIZE];65 /** Used portion of setup_buffer member66 *67 * SETUP buffer must be 8 bytes for control transfers and is left68 * unused for all other transfers. Thus, this field is either 0 or 8.69 */70 size_t setup_size;71 84 72 /** Actually used portion of the buffer 73 * This member is never accessed by functions provided in this header, 74 * with the exception of usb_transfer_batch_finish. For external use. 75 */ 85 /** Actually used portion of the buffer */ 76 86 size_t transfered_size; 77 /** Indicates success/failure of the communication 78 * This member is never accessed by functions provided in this header, 79 * with the exception of usb_transfer_batch_finish. For external use. 80 */ 87 /** Indicates success/failure of the communication */ 81 88 int error; 82 89 } usb_transfer_batch_t; … … 95 102 (batch).buffer_size, (batch).ep->max_packet_size 96 103 104 void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *); 105 void usb_transfer_batch_finish(usb_transfer_batch_t *); 97 106 98 usb_transfer_batch_t * usb_transfer_batch_create( 99 endpoint_t *ep, 100 char *buffer, 101 size_t buffer_size, 102 uint64_t setup_buffer, 103 usbhc_iface_transfer_in_callback_t func_in, 104 usbhc_iface_transfer_out_callback_t func_out, 105 void *arg 106 ); 107 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance); 107 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *); 108 void usb_transfer_batch_destroy(usb_transfer_batch_t *); 108 109 109 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 110 const void* data, size_t size, int error); 111 112 /** Finish batch using stored error value and transferred size. 113 * 114 * @param[in] instance Batch structure to use. 115 * @param[in] data Data to copy to the output buffer. 110 /** Provided to ease the transition. Wraps old-style handlers into a new one. 116 111 */ 117 static inline void usb_transfer_batch_finish( 118 const usb_transfer_batch_t *instance, const void* data) 119 { 120 assert(instance); 121 usb_transfer_batch_finish_error( 122 instance, data, instance->transfered_size, instance->error); 123 } 124 125 /** Determine batch direction based on the callbacks present 126 * @param[in] instance Batch structure to use, non-null. 127 * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT. 128 */ 129 static inline usb_direction_t usb_transfer_batch_direction( 130 const usb_transfer_batch_t *instance) 131 { 132 assert(instance); 133 if (instance->callback_in) { 134 assert(instance->callback_out == NULL); 135 assert(instance->ep == NULL 136 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 137 || instance->ep->direction == USB_DIRECTION_IN); 138 return USB_DIRECTION_IN; 139 } 140 if (instance->callback_out) { 141 assert(instance->callback_in == NULL); 142 assert(instance->ep == NULL 143 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 144 || instance->ep->direction == USB_DIRECTION_OUT); 145 return USB_DIRECTION_OUT; 146 } 147 assert(false); 148 } 112 extern void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *, 113 usbhc_iface_transfer_in_callback_t, 114 usbhc_iface_transfer_out_callback_t, void *); 149 115 150 116 #endif -
uspace/lib/usbhost/src/hcd.c
r74b852b r5fd9c30 69 69 } 70 70 71 typedef struct {72 void *original_data;73 usbhc_iface_transfer_out_callback_t original_callback;74 usb_target_t target;75 hcd_t *hcd;76 } toggle_t;77 78 static void toggle_reset_callback(int retval, void *arg)79 {80 assert(arg);81 toggle_t *toggle = arg;82 if (retval == EOK) {83 usb_log_debug2("Reseting toggle on %d:%d.\n",84 toggle->target.address, toggle->target.endpoint);85 bus_reset_toggle(toggle->hcd->bus,86 toggle->target, toggle->target.endpoint == 0);87 }88 89 toggle->original_callback(retval, toggle->original_data);90 }91 92 71 /** Prepare generic usb_transfer_batch and schedule it. 93 72 * @param hcd Host controller driver. 94 * @param fun DDF fun95 73 * @param target address and endpoint number. 96 74 * @param setup_data Data to use in setup stage (Control communication type) … … 101 79 * @return Error code. 102 80 */ 103 int hcd_send_batch( 104 hcd_t *hcd, usb_target_t target, usb_direction_t direction, 105 void *data, size_t size, uint64_t setup_data, 106 usbhc_iface_transfer_in_callback_t in, 107 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) 81 int hcd_send_batch(hcd_t *hcd, usb_target_t target, usb_direction_t direction, 82 void *data, size_t size, uint64_t setup_data, 83 usbhc_iface_transfer_in_callback_t in, usbhc_iface_transfer_out_callback_t out, 84 void *arg, const char *name) 108 85 { 109 86 assert(hcd); … … 132 109 } 133 110 134 /* Check for commands that reset toggle bit */ 135 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 136 const int reset_toggle = usb_request_needs_toggle_reset( 137 (usb_device_request_setup_packet_t *) &setup_data); 138 if (reset_toggle >= 0) { 139 assert(out); 140 toggle_t *toggle = malloc(sizeof(toggle_t)); 141 if (!toggle) 142 return ENOMEM; 143 toggle->target.address = target.address; 144 toggle->target.endpoint = reset_toggle; 145 toggle->original_callback = out; 146 toggle->original_data = arg; 147 toggle->hcd = hcd; 148 149 arg = toggle; 150 out = toggle_reset_callback; 151 } 152 } 153 154 usb_transfer_batch_t *batch = usb_transfer_batch_create( 155 ep, data, size, setup_data, in, out, arg); 111 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 156 112 if (!batch) { 157 113 usb_log_error("Failed to create transfer batch.\n"); 158 114 return ENOMEM; 159 115 } 116 117 batch->buffer = data; 118 batch->buffer_size = size; 119 batch->setup.packed = setup_data; 120 batch->dir = direction; 121 122 /* Check for commands that reset toggle bit */ 123 if (ep->transfer_type == USB_TRANSFER_CONTROL) 124 batch->toggle_reset_mode 125 = usb_request_get_toggle_reset_mode(&batch->setup.packet); 126 127 usb_transfer_batch_set_old_handlers(batch, in, out, arg); 160 128 161 129 const int ret = hcd->ops.schedule(hcd, batch); -
uspace/lib/usbhost/src/usb_transfer_batch.c
r74b852b r5fd9c30 34 34 35 35 #include <usb/host/usb_transfer_batch.h> 36 #include <usb/host/endpoint.h> 37 #include <usb/host/bus.h> 36 38 #include <usb/debug.h> 37 39 38 40 #include <assert.h> 39 41 #include <errno.h> 40 #include <macros.h>41 #include <mem.h>42 #include <stdlib.h>43 #include <usbhc_iface.h>44 42 45 /** Allocate and initialize usb_transfer_batch structure. 46 * @param ep endpoint used by the transfer batch. 47 * @param buffer data to send/recieve. 48 * @param buffer_size Size of data buffer. 49 * @param setup_buffer Data to send in SETUP stage of control transfer. 50 * @param func_in callback on IN transfer completion. 51 * @param func_out callback on OUT transfer completion. 52 * @param fun DDF function (passed to callback function). 53 * @param arg Argument to pass to the callback function. 54 * @param private_data driver specific per batch data. 55 * @param private_data_dtor Function to properly destroy private_data. 56 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure. 43 44 /** Create a batch on given endpoint. 57 45 */ 58 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer, 59 size_t buffer_size, 60 uint64_t setup_buffer, 61 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, 63 void *arg) 46 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep) 64 47 { 65 if (func_in == NULL && func_out == NULL) 66 return NULL; 67 if (func_in != NULL && func_out != NULL) 68 return NULL; 48 assert(ep); 49 assert(ep->bus); 69 50 70 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 71 if (instance) { 72 instance->ep = ep; 73 instance->callback_in = func_in; 74 instance->callback_out = func_out; 75 instance->arg = arg; 76 instance->buffer = buffer; 77 instance->buffer_size = buffer_size; 78 instance->setup_size = 0; 79 instance->transfered_size = 0; 80 instance->error = EOK; 81 if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) { 82 memcpy(instance->setup_buffer, &setup_buffer, 83 USB_SETUP_PACKET_SIZE); 84 instance->setup_size = USB_SETUP_PACKET_SIZE; 85 } 86 if (instance->ep) 87 endpoint_use(instance->ep); 88 } 89 return instance; 51 usb_transfer_batch_t *batch; 52 if (ep->bus->ops.create_batch) 53 batch = ep->bus->ops.create_batch(ep->bus, ep); 54 else 55 batch = malloc(sizeof(usb_transfer_batch_t)); 56 57 return batch; 90 58 } 91 59 92 /** Correctly dispose all used data structures. 93 * 94 * @param[in] instance Batch structure to use. 60 /** Initialize given batch structure. 95 61 */ 96 void usb_transfer_batch_ destroy(const usb_transfer_batch_t *instance)62 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep) 97 63 { 98 if (!instance) 99 return; 100 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 101 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 102 if (instance->ep) { 103 endpoint_release(instance->ep); 104 } 105 free(instance); 64 memset(batch, 0, sizeof(*batch)); 65 66 batch->ep = ep; 67 68 endpoint_use(ep); 106 69 } 107 70 108 /** Prepare data and call the right callback.71 /** Call the handler of the batch. 109 72 * 110 * @param[in] instance Batch structure to use. 111 * @param[in] data Data to copy to the output buffer. 112 * @param[in] size Size of @p data. 113 * @param[in] error Error value to use. 73 * @param[in] batch Batch structure to use. 114 74 */ 115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 116 const void *data, size_t size, int error) 75 static int batch_complete(usb_transfer_batch_t *batch) 117 76 { 118 assert(instance); 119 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 120 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 77 assert(batch); 121 78 122 /* NOTE: Only one of these pointers should be set. */ 123 if (instance->callback_out) { 124 instance->callback_out(error, instance->arg); 79 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed.\n", 80 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 81 82 if (batch->error == EOK && batch->toggle_reset_mode != RESET_NONE) { 83 usb_log_debug2("Reseting %s due to transaction of %d:%d.\n", 84 batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle", 85 batch->ep->target.address, batch->ep->target.endpoint); 86 bus_reset_toggle(batch->ep->bus, 87 batch->ep->target, batch->toggle_reset_mode == RESET_ALL); 125 88 } 126 89 127 if (instance->callback_in) { 128 /* We care about the data and there are some to copy */ 129 const size_t safe_size = min(size, instance->buffer_size); 130 if (data) { 131 memcpy(instance->buffer, data, safe_size); 132 } 133 instance->callback_in(error, safe_size, instance->arg); 134 } 90 return batch->on_complete 91 ? batch->on_complete(batch) 92 : EOK; 93 } 94 95 /** Destroy the batch. 96 * 97 * @param[in] batch Batch structure to use. 98 */ 99 void usb_transfer_batch_destroy(usb_transfer_batch_t *batch) 100 { 101 assert(batch); 102 assert(batch->ep); 103 assert(batch->ep->bus); 104 105 usb_log_debug2("batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 106 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 107 108 bus_t *bus = batch->ep->bus; 109 if (bus->ops.destroy_batch) 110 bus->ops.destroy_batch(batch); 111 else 112 free(batch); 113 114 endpoint_release(batch->ep); 115 } 116 117 /** Finish a transfer batch: call handler, destroy batch, release endpoint. 118 * 119 * Call only after the batch have been scheduled && completed! 120 * 121 * @param[in] batch Batch structure to use. 122 */ 123 void usb_transfer_batch_finish(usb_transfer_batch_t *batch) 124 { 125 if (!batch_complete(batch)) 126 usb_log_warning("failed to complete batch %p!", batch); 127 128 usb_transfer_batch_destroy(batch); 129 } 130 131 132 struct old_handler_wrapper_data { 133 usbhc_iface_transfer_in_callback_t in_callback; 134 usbhc_iface_transfer_out_callback_t out_callback; 135 void *arg; 136 }; 137 138 static int old_handler_wrapper(usb_transfer_batch_t *batch) 139 { 140 struct old_handler_wrapper_data *data = batch->on_complete_data; 141 142 assert(data); 143 144 if (data->out_callback) 145 data->out_callback(batch->error, data->arg); 146 147 if (data->in_callback) 148 data->in_callback(batch->error, batch->transfered_size, data->arg); 149 150 free(data); 151 return EOK; 152 } 153 154 void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *batch, 155 usbhc_iface_transfer_in_callback_t in_callback, 156 usbhc_iface_transfer_out_callback_t out_callback, 157 void *arg) 158 { 159 struct old_handler_wrapper_data *data = malloc(sizeof(*data)); 160 161 data->in_callback = in_callback; 162 data->out_callback = out_callback; 163 data->arg = arg; 164 165 batch->on_complete = old_handler_wrapper; 166 batch->on_complete_data = data; 135 167 } 136 168 /**
Note:
See TracChangeset
for help on using the changeset viewer.