Changes in uspace/lib/usbhost/src/hcd.c [f527f58:a5b3de6] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/hcd.c
rf527f58 ra5b3de6 41 41 #include <errno.h> 42 42 #include <usb_iface.h> 43 #include <str_error.h> 43 44 44 45 #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 }85 46 86 47 … … 93 54 * @param bw_count Bandwidth compute function, passed to endpoint manager. 94 55 */ 95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth, 96 bw_count_func_t bw_count) 97 { 56 void hcd_init(hcd_t *hcd) { 98 57 assert(hcd); 99 usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed);100 58 101 hcd_set_implementation(hcd, NULL, NULL );59 hcd_set_implementation(hcd, NULL, NULL, NULL); 102 60 } 103 61 … … 106 64 assert(hcd); 107 65 usb_address_t address = 0; 108 const int ret = usb_bus_request_address( 109 &hcd->bus, &address, false, speed); 66 const int ret = bus_request_address(hcd->bus, &address, false, speed); 110 67 if (ret != EOK) 111 68 return ret; … … 113 70 } 114 71 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 168 72 /** Prepare generic usb_transfer_batch and schedule it. 169 73 * @param hcd Host controller driver. 170 * @param fun DDF fun171 74 * @param target address and endpoint number. 172 75 * @param setup_data Data to use in setup stage (Control communication type) … … 177 80 * @return Error code. 178 81 */ 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) 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) 184 85 { 185 86 assert(hcd); 87 assert(device->address == target.address); 186 88 187 endpoint_t *ep = usb_bus_find_ep(&hcd->bus,188 target.address, target.endpoint, direction);189 if (ep == NULL) {190 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",191 target.address, target.endpoint, name);192 return ENOENT;193 }194 195 usb_log_debug2("%s %d:%d %zu(%zu).\n",196 name, target.address, target.endpoint, size, ep->max_packet_size);197 198 const size_t bw = bandwidth_count_usb11(199 ep->speed, ep->transfer_type, size, ep->max_packet_size);200 /* Check if we have enough bandwidth reserved */201 if (ep->bandwidth < bw) {202 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "203 "but only %zu is reserved.\n",204 ep->address, ep->endpoint, name, bw, ep->bandwidth);205 return ENOSPC;206 }207 89 if (!hcd->ops.schedule) { 208 90 usb_log_error("HCD does not implement scheduler.\n"); … … 210 92 } 211 93 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 } 94 endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction); 95 if (ep == NULL) { 96 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 97 device->address, target.endpoint, name); 98 return ENOENT; 230 99 } 231 100 232 usb_transfer_batch_t *batch = usb_transfer_batch_create( 233 ep, data, size, setup_data, in, out, arg); 101 // TODO cut here aka provide helper to call with instance of endpoint_t in hand 102 103 usb_log_debug2("%s %d:%d %zu(%zu).\n", 104 name, target.address, target.endpoint, size, ep->max_packet_size); 105 106 const size_t bw = bus_count_bw(ep, size); 107 /* Check if we have enough bandwidth reserved */ 108 if (ep->bandwidth < bw) { 109 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 110 "but only %zu is reserved.\n", 111 device->address, ep->endpoint, name, bw, ep->bandwidth); 112 return ENOSPC; 113 } 114 115 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 234 116 if (!batch) { 235 117 usb_log_error("Failed to create transfer batch.\n"); … … 237 119 } 238 120 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_mode 132 = usb_request_get_toggle_reset_mode(&batch->setup.packet); 133 239 134 const int ret = hcd->ops.schedule(hcd, batch); 240 if (ret != EOK) 135 if (ret != EOK) { 136 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 241 137 usb_transfer_batch_destroy(batch); 138 } 242 139 243 140 /* Drop our own reference to ep. */ … … 248 145 249 146 typedef struct { 250 volatile unsigned done; 251 int ret; 252 size_t size; 147 fibril_mutex_t done_mtx; 148 fibril_condvar_t done_cv; 149 unsigned done; 150 151 size_t transfered_size; 152 int error; 253 153 } sync_data_t; 254 154 255 static void transfer_in_cb(int ret, size_t size, void* data)155 static int sync_transfer_complete(usb_transfer_batch_t *batch) 256 156 { 257 sync_data_t *d = data;157 sync_data_t *d = batch->on_complete_data; 258 158 assert(d); 259 d->ret = ret; 159 d->transfered_size = batch->transfered_size; 160 d->error = batch->error; 161 fibril_mutex_lock(&d->done_mtx); 260 162 d->done = 1; 261 d->size = size; 163 fibril_condvar_broadcast(&d->done_cv); 164 fibril_mutex_unlock(&d->done_mtx); 165 return EOK; 262 166 } 263 167 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) 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) 276 171 { 277 172 assert(hcd); 278 sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size }; 173 sync_data_t sd = { .done = 0 }; 174 fibril_mutex_initialize(&sd.done_mtx); 175 fibril_condvar_initialize(&sd.done_cv); 279 176 280 const int ret = hcd_send_batch(hcd, target, dir, data, size, setup_data,281 d ir == USB_DIRECTION_IN ? transfer_in_cb : NULL,282 dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name);177 const int ret = hcd_send_batch(hcd, device, target, direction, 178 data, size, setup_data, 179 sync_transfer_complete, &sd, name); 283 180 if (ret != EOK) 284 181 return ret; 285 182 286 while (!sd.done) { 287 async_usleep(1000); 288 } 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); 289 187 290 if (sd.ret== EOK)291 return sd.size;292 return sd.ret;188 return (sd.error == EOK) 189 ? (ssize_t) sd.transfered_size 190 : (ssize_t) sd.error; 293 191 } 294 192
Note:
See TracChangeset
for help on using the changeset viewer.