00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00034 #include <ddf/driver.h>
00035 #include <errno.h>
00036
00037 #include <usb/debug.h>
00038 #include <usb/host/endpoint.h>
00039
00040 #include "iface.h"
00041 #include "hc.h"
00042
00043 static inline int setup_batch(
00044 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
00045 void *data, size_t size, void * setup_data, size_t setup_size,
00046 usbhc_iface_transfer_in_callback_t in,
00047 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
00048 hc_t **hc, usb_transfer_batch_t **batch)
00049 {
00050 assert(hc);
00051 assert(batch);
00052 assert(fun);
00053 *hc = fun_to_hc(fun);
00054 assert(*hc);
00055
00056 size_t res_bw;
00057 endpoint_t *ep = hc_get_endpoint(*hc,
00058 target.address, target.endpoint, direction, &res_bw);
00059 if (ep == NULL) {
00060 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
00061 target.address, target.endpoint, name);
00062 return ENOENT;
00063 }
00064
00065 usb_log_debug("%s %d:%d %zu(%zu).\n",
00066 name, target.address, target.endpoint, size, ep->max_packet_size);
00067
00068 const size_t bw = bandwidth_count_usb11(
00069 ep->speed, ep->transfer_type, size, ep->max_packet_size);
00070 if (res_bw < bw) {
00071 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
00072 "but only %zu is reserved.\n",
00073 target.address, target.endpoint, name, bw, res_bw);
00074 return ENOSPC;
00075 }
00076
00077 *batch = batch_get(
00078 fun, ep, data, size, setup_data, setup_size, in, out, arg);
00079 if (!*batch)
00080 return ENOMEM;
00081 return EOK;
00082 }
00083
00091 static int request_address(
00092 ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
00093 {
00094 assert(fun);
00095 hc_t *hc = fun_to_hc(fun);
00096 assert(hc);
00097 assert(address);
00098
00099 usb_log_debug("Address request with speed %d.\n", speed);
00100 *address = device_keeper_get_free_address(&hc->manager, speed);
00101 usb_log_debug("Address request with result: %d.\n", *address);
00102 if (*address <= 0)
00103 return *address;
00104 return EOK;
00105 }
00106
00114 static int bind_address(
00115 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
00116 {
00117 assert(fun);
00118 hc_t *hc = fun_to_hc(fun);
00119 assert(hc);
00120 usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
00121 usb_device_keeper_bind(&hc->manager, address, handle);
00122 return EOK;
00123 }
00124
00125
00133 static int find_by_address(ddf_fun_t *fun, usb_address_t address,
00134 devman_handle_t *handle)
00135 {
00136 assert(fun);
00137 hc_t *hc = fun_to_hc(fun);
00138 assert(hc);
00139 bool found =
00140 usb_device_keeper_find_by_address(&hc->manager, address, handle);
00141 return found ? EOK : ENOENT;
00142 }
00143
00144
00151 static int release_address(ddf_fun_t *fun, usb_address_t address)
00152 {
00153 assert(fun);
00154 hc_t *hc = fun_to_hc(fun);
00155 assert(hc);
00156 usb_log_debug("Address release %d.\n", address);
00157 usb_device_keeper_release(&hc->manager, address);
00158 return EOK;
00159 }
00160
00173 static int register_endpoint(ddf_fun_t *fun,
00174 usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint,
00175 usb_transfer_type_t transfer_type, usb_direction_t direction,
00176 size_t max_packet_size, unsigned int interval)
00177 {
00178 hc_t *hc = fun_to_hc(fun);
00179 assert(hc);
00180
00181 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
00182 if (speed >= USB_SPEED_MAX) {
00183 speed = ep_speed;
00184 }
00185 const size_t size = max_packet_size;
00186
00187 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
00188 address, endpoint, usb_str_transfer_type(transfer_type),
00189 usb_str_speed(speed), direction, size, max_packet_size, interval);
00190
00191 return hc_add_endpoint(hc, address, endpoint, speed, transfer_type,
00192 direction, max_packet_size, size, interval);
00193 }
00194
00195 static int unregister_endpoint(
00196 ddf_fun_t *fun, usb_address_t address,
00197 usb_endpoint_t endpoint, usb_direction_t direction)
00198 {
00199 hc_t *hc = fun_to_hc(fun);
00200 assert(hc);
00201 usb_log_debug("Unregister endpoint %d:%d %d.\n",
00202 address, endpoint, direction);
00203 return hc_remove_endpoint(hc, address, endpoint, direction);
00204 }
00205
00222 static int interrupt_out(
00223 ddf_fun_t *fun, usb_target_t target, void *data,
00224 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
00225 {
00226 usb_transfer_batch_t *batch = NULL;
00227 hc_t *hc = NULL;
00228 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
00229 NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
00230 if (ret != EOK)
00231 return ret;
00232 batch_interrupt_out(batch);
00233 ret = hc_schedule(hc, batch);
00234 if (ret != EOK) {
00235 usb_transfer_batch_dispose(batch);
00236 }
00237 return ret;
00238 }
00239
00256 static int interrupt_in(
00257 ddf_fun_t *fun, usb_target_t target, void *data,
00258 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
00259 {
00260 usb_transfer_batch_t *batch = NULL;
00261 hc_t *hc = NULL;
00262 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
00263 NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
00264 if (ret != EOK)
00265 return ret;
00266 batch_interrupt_in(batch);
00267 ret = hc_schedule(hc, batch);
00268 if (ret != EOK) {
00269 usb_transfer_batch_dispose(batch);
00270 }
00271 return ret;
00272 }
00273
00290 static int bulk_out(
00291 ddf_fun_t *fun, usb_target_t target, void *data,
00292 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
00293 {
00294 usb_transfer_batch_t *batch = NULL;
00295 hc_t *hc = NULL;
00296 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
00297 NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
00298 if (ret != EOK)
00299 return ret;
00300 batch_bulk_out(batch);
00301 ret = hc_schedule(hc, batch);
00302 if (ret != EOK) {
00303 usb_transfer_batch_dispose(batch);
00304 }
00305 return ret;
00306 }
00307
00324 static int bulk_in(
00325 ddf_fun_t *fun, usb_target_t target, void *data,
00326 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
00327 {
00328 usb_transfer_batch_t *batch = NULL;
00329 hc_t *hc = NULL;
00330 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
00331 NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
00332 if (ret != EOK)
00333 return ret;
00334 batch_bulk_in(batch);
00335 ret = hc_schedule(hc, batch);
00336 if (ret != EOK) {
00337 usb_transfer_batch_dispose(batch);
00338 }
00339 return ret;
00340 }
00341
00361 static int control_write(
00362 ddf_fun_t *fun, usb_target_t target,
00363 void *setup_data, size_t setup_size, void *data, size_t size,
00364 usbhc_iface_transfer_out_callback_t callback, void *arg)
00365 {
00366 usb_transfer_batch_t *batch = NULL;
00367 hc_t *hc = NULL;
00368 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
00369 setup_data, setup_size, NULL, callback, arg, "Control WRITE",
00370 &hc, &batch);
00371 if (ret != EOK)
00372 return ret;
00373 usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
00374 batch_control_write(batch);
00375 ret = hc_schedule(hc, batch);
00376 if (ret != EOK) {
00377 usb_transfer_batch_dispose(batch);
00378 }
00379 return ret;
00380 }
00381
00401 static int control_read(
00402 ddf_fun_t *fun, usb_target_t target,
00403 void *setup_data, size_t setup_size, void *data, size_t size,
00404 usbhc_iface_transfer_in_callback_t callback, void *arg)
00405 {
00406 usb_transfer_batch_t *batch = NULL;
00407 hc_t *hc = NULL;
00408 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
00409 setup_data, setup_size, callback, NULL, arg, "Control READ",
00410 &hc, &batch);
00411 if (ret != EOK)
00412 return ret;
00413 batch_control_read(batch);
00414 ret = hc_schedule(hc, batch);
00415 if (ret != EOK) {
00416 usb_transfer_batch_dispose(batch);
00417 }
00418 return ret;
00419 }
00420
00421 usbhc_iface_t hc_iface = {
00422 .request_address = request_address,
00423 .bind_address = bind_address,
00424 .find_by_address = find_by_address,
00425 .release_address = release_address,
00426
00427 .register_endpoint = register_endpoint,
00428 .unregister_endpoint = unregister_endpoint,
00429
00430 .interrupt_out = interrupt_out,
00431 .interrupt_in = interrupt_in,
00432
00433 .bulk_out = bulk_out,
00434 .bulk_in = bulk_in,
00435
00436 .control_write = control_write,
00437 .control_read = control_read,
00438 };