Changes in uspace/lib/usbhost/src/hcd.c [a5b3de6:f527f58] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/hcd.c
ra5b3de6 rf527f58 41 41 #include <errno.h> 42 42 #include <usb_iface.h> 43 #include <str_error.h>44 43 45 44 #include "hcd.h" 45 46 /** Calls ep_add_hook upon endpoint registration. 47 * @param ep Endpoint to be registered. 48 * @param arg hcd_t in disguise. 49 * @return Error code. 50 */ 51 static int register_helper(endpoint_t *ep, void *arg) 52 { 53 hcd_t *hcd = arg; 54 assert(ep); 55 assert(hcd); 56 if (hcd->ops.ep_add_hook) 57 return hcd->ops.ep_add_hook(hcd, ep); 58 return EOK; 59 } 60 61 /** Calls ep_remove_hook upon endpoint removal. 62 * @param ep Endpoint to be unregistered. 63 * @param arg hcd_t in disguise. 64 */ 65 static void unregister_helper(endpoint_t *ep, void *arg) 66 { 67 hcd_t *hcd = arg; 68 assert(ep); 69 assert(hcd); 70 if (hcd->ops.ep_remove_hook) 71 hcd->ops.ep_remove_hook(hcd, ep); 72 } 73 74 /** Calls ep_remove_hook upon endpoint removal. Prints warning. 75 * * @param ep Endpoint to be unregistered. 76 * * @param arg hcd_t in disguise. 77 * */ 78 static void unregister_helper_warn(endpoint_t *ep, void *arg) 79 { 80 assert(ep); 81 usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n", 82 ep->address, ep->endpoint, usb_str_direction(ep->direction)); 83 unregister_helper(ep, arg); 84 } 46 85 47 86 … … 54 93 * @param bw_count Bandwidth compute function, passed to endpoint manager. 55 94 */ 56 void hcd_init(hcd_t *hcd) { 57 assert(hcd); 58 59 hcd_set_implementation(hcd, NULL, NULL, NULL); 95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth, 96 bw_count_func_t bw_count) 97 { 98 assert(hcd); 99 usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed); 100 101 hcd_set_implementation(hcd, NULL, NULL); 60 102 } 61 103 … … 64 106 assert(hcd); 65 107 usb_address_t address = 0; 66 const int ret = bus_request_address(hcd->bus, &address, false, speed); 108 const int ret = usb_bus_request_address( 109 &hcd->bus, &address, false, speed); 67 110 if (ret != EOK) 68 111 return ret; … … 70 113 } 71 114 115 int hcd_release_address(hcd_t *hcd, usb_address_t address) 116 { 117 assert(hcd); 118 return usb_bus_remove_address(&hcd->bus, address, 119 unregister_helper_warn, hcd); 120 } 121 122 int hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed) 123 { 124 assert(hcd); 125 usb_address_t address = 0; 126 return usb_bus_request_address(&hcd->bus, &address, true, speed); 127 } 128 129 int hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir, 130 usb_transfer_type_t type, size_t max_packet_size, unsigned packets, 131 size_t size, usb_address_t tt_address, unsigned tt_port) 132 { 133 assert(hcd); 134 return usb_bus_add_ep(&hcd->bus, target.address, 135 target.endpoint, dir, type, max_packet_size, packets, size, 136 register_helper, hcd, tt_address, tt_port); 137 } 138 139 int hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir) 140 { 141 assert(hcd); 142 return usb_bus_remove_ep(&hcd->bus, target.address, 143 target.endpoint, dir, unregister_helper, hcd); 144 } 145 146 147 typedef struct { 148 void *original_data; 149 usbhc_iface_transfer_out_callback_t original_callback; 150 usb_target_t target; 151 hcd_t *hcd; 152 } toggle_t; 153 154 static void toggle_reset_callback(int retval, void *arg) 155 { 156 assert(arg); 157 toggle_t *toggle = arg; 158 if (retval == EOK) { 159 usb_log_debug2("Reseting toggle on %d:%d.\n", 160 toggle->target.address, toggle->target.endpoint); 161 usb_bus_reset_toggle(&toggle->hcd->bus, 162 toggle->target, toggle->target.endpoint == 0); 163 } 164 165 toggle->original_callback(retval, toggle->original_data); 166 } 167 72 168 /** Prepare generic usb_transfer_batch and schedule it. 73 169 * @param hcd Host controller driver. 170 * @param fun DDF fun 74 171 * @param target address and endpoint number. 75 172 * @param setup_data Data to use in setup stage (Control communication type) … … 80 177 * @return Error code. 81 178 */ 82 int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target, 83 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 84 usb_transfer_batch_callback_t on_complete, void *arg, const char *name) 85 { 86 assert(hcd); 87 assert(device->address == target.address); 88 89 if (!hcd->ops.schedule) { 90 usb_log_error("HCD does not implement scheduler.\n"); 91 return ENOTSUP; 92 } 93 94 endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction); 179 int hcd_send_batch( 180 hcd_t *hcd, usb_target_t target, usb_direction_t direction, 181 void *data, size_t size, uint64_t setup_data, 182 usbhc_iface_transfer_in_callback_t in, 183 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) 184 { 185 assert(hcd); 186 187 endpoint_t *ep = usb_bus_find_ep(&hcd->bus, 188 target.address, target.endpoint, direction); 95 189 if (ep == NULL) { 96 190 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 97 device->address, target.endpoint, name);191 target.address, target.endpoint, name); 98 192 return ENOENT; 99 193 } 100 101 // TODO cut here aka provide helper to call with instance of endpoint_t in hand102 194 103 195 usb_log_debug2("%s %d:%d %zu(%zu).\n", 104 196 name, target.address, target.endpoint, size, ep->max_packet_size); 105 197 106 const size_t bw = bus_count_bw(ep, size); 198 const size_t bw = bandwidth_count_usb11( 199 ep->speed, ep->transfer_type, size, ep->max_packet_size); 107 200 /* Check if we have enough bandwidth reserved */ 108 201 if (ep->bandwidth < bw) { 109 202 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 110 203 "but only %zu is reserved.\n", 111 device->address, ep->endpoint, name, bw, ep->bandwidth);204 ep->address, ep->endpoint, name, bw, ep->bandwidth); 112 205 return ENOSPC; 113 206 } 114 115 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 207 if (!hcd->ops.schedule) { 208 usb_log_error("HCD does not implement scheduler.\n"); 209 return ENOTSUP; 210 } 211 212 /* Check for commands that reset toggle bit */ 213 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 214 const int reset_toggle = usb_request_needs_toggle_reset( 215 (usb_device_request_setup_packet_t *) &setup_data); 216 if (reset_toggle >= 0) { 217 assert(out); 218 toggle_t *toggle = malloc(sizeof(toggle_t)); 219 if (!toggle) 220 return ENOMEM; 221 toggle->target.address = target.address; 222 toggle->target.endpoint = reset_toggle; 223 toggle->original_callback = out; 224 toggle->original_data = arg; 225 toggle->hcd = hcd; 226 227 arg = toggle; 228 out = toggle_reset_callback; 229 } 230 } 231 232 usb_transfer_batch_t *batch = usb_transfer_batch_create( 233 ep, data, size, setup_data, in, out, arg); 116 234 if (!batch) { 117 235 usb_log_error("Failed to create transfer batch.\n"); … … 119 237 } 120 238 121 batch->target = target;122 batch->buffer = data;123 batch->buffer_size = size;124 batch->setup.packed = setup_data;125 batch->dir = direction;126 batch->on_complete = on_complete;127 batch->on_complete_data = arg;128 129 /* Check for commands that reset toggle bit */130 if (ep->transfer_type == USB_TRANSFER_CONTROL)131 batch->toggle_reset_mode132 = usb_request_get_toggle_reset_mode(&batch->setup.packet);133 134 239 const int ret = hcd->ops.schedule(hcd, batch); 135 if (ret != EOK) { 136 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 240 if (ret != EOK) 137 241 usb_transfer_batch_destroy(batch); 138 }139 242 140 243 /* Drop our own reference to ep. */ … … 145 248 146 249 typedef struct { 147 fibril_mutex_t done_mtx; 148 fibril_condvar_t done_cv; 149 unsigned done; 150 151 size_t transfered_size; 152 int error; 250 volatile unsigned done; 251 int ret; 252 size_t size; 153 253 } sync_data_t; 154 254 155 static int sync_transfer_complete(usb_transfer_batch_t *batch)156 { 157 sync_data_t *d = batch->on_complete_data;255 static void transfer_in_cb(int ret, size_t size, void* data) 256 { 257 sync_data_t *d = data; 158 258 assert(d); 159 d->transfered_size = batch->transfered_size; 160 d->error = batch->error; 161 fibril_mutex_lock(&d->done_mtx); 259 d->ret = ret; 162 260 d->done = 1; 163 fibril_condvar_broadcast(&d->done_cv); 164 fibril_mutex_unlock(&d->done_mtx); 165 return EOK; 166 } 167 168 ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target, 169 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 170 const char *name) 171 { 172 assert(hcd); 173 sync_data_t sd = { .done = 0 }; 174 fibril_mutex_initialize(&sd.done_mtx); 175 fibril_condvar_initialize(&sd.done_cv); 176 177 const int ret = hcd_send_batch(hcd, device, target, direction, 178 data, size, setup_data, 179 sync_transfer_complete, &sd, name); 261 d->size = size; 262 } 263 264 static void transfer_out_cb(int ret, void* data) 265 { 266 sync_data_t *d = data; 267 assert(data); 268 d->ret = ret; 269 d->done = 1; 270 } 271 272 /** this is really ugly version of sync usb communication */ 273 ssize_t hcd_send_batch_sync( 274 hcd_t *hcd, usb_target_t target, usb_direction_t dir, 275 void *data, size_t size, uint64_t setup_data, const char* name) 276 { 277 assert(hcd); 278 sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size }; 279 280 const int ret = hcd_send_batch(hcd, target, dir, data, size, setup_data, 281 dir == USB_DIRECTION_IN ? transfer_in_cb : NULL, 282 dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name); 180 283 if (ret != EOK) 181 284 return ret; 182 285 183 fibril_mutex_lock(&sd.done_mtx); 184 while (!sd.done) 185 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx); 186 fibril_mutex_unlock(&sd.done_mtx); 187 188 return (sd.error == EOK) 189 ? (ssize_t) sd.transfered_size 190 : (ssize_t) sd.error; 286 while (!sd.done) { 287 async_usleep(1000); 288 } 289 290 if (sd.ret == EOK) 291 return sd.size; 292 return sd.ret; 191 293 } 192 294
Note:
See TracChangeset
for help on using the changeset viewer.