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 "batch.h"
00042 #include "hc.h"
00043
00044 static inline int setup_batch(
00045 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
00046 void *data, size_t size, void * setup_data, size_t setup_size,
00047 usbhc_iface_transfer_in_callback_t in,
00048 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
00049 hc_t **hc, usb_transfer_batch_t **batch)
00050 {
00051 assert(hc);
00052 assert(batch);
00053 assert(fun);
00054 *hc = fun_to_hc(fun);
00055 assert(*hc);
00056
00057 size_t res_bw;
00058 endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
00059 target.address, target.endpoint, direction, &res_bw);
00060 if (ep == NULL) {
00061 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
00062 target.address, target.endpoint, name);
00063 return ENOENT;
00064 }
00065
00066 usb_log_debug("%s %d:%d %zu(%zu).\n",
00067 name, target.address, target.endpoint, size, ep->max_packet_size);
00068
00069 const size_t bw = bandwidth_count_usb11(
00070 ep->speed, ep->transfer_type, size, ep->max_packet_size);
00071 if (res_bw < bw) {
00072 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
00073 "but only %zu is reserved.\n",
00074 target.address, target.endpoint, name, bw, res_bw);
00075 return ENOSPC;
00076 }
00077
00078 *batch = batch_get(
00079 fun, ep, data, size, setup_data, setup_size, in, out, arg);
00080 if (!*batch)
00081 return ENOMEM;
00082 return EOK;
00083 }
00084
00092 static int request_address(
00093 ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
00094 {
00095 assert(fun);
00096 hc_t *hc = fun_to_hc(fun);
00097 assert(hc);
00098 assert(address);
00099
00100 usb_log_debug("Address request with speed %d.\n", speed);
00101 *address = device_keeper_get_free_address(&hc->manager, speed);
00102 usb_log_debug("Address request with result: %d.\n", *address);
00103 if (*address <= 0)
00104 return *address;
00105 return EOK;
00106 }
00107
00115 static int bind_address(
00116 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
00117 {
00118 assert(fun);
00119 hc_t *hc = fun_to_hc(fun);
00120 assert(hc);
00121 usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
00122 usb_device_keeper_bind(&hc->manager, address, handle);
00123 return EOK;
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 const bool found =
00140 usb_device_keeper_find_by_address(&hc->manager, address, handle);
00141 return found ? EOK : ENOENT;
00142 }
00143
00150 static int release_address(ddf_fun_t *fun, usb_address_t address)
00151 {
00152 assert(fun);
00153 hc_t *hc = fun_to_hc(fun);
00154 assert(hc);
00155 usb_log_debug("Address release %d.\n", address);
00156 usb_device_keeper_release(&hc->manager, address);
00157 return EOK;
00158 }
00159
00160 static int register_endpoint(
00161 ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
00162 usb_endpoint_t endpoint,
00163 usb_transfer_type_t transfer_type, usb_direction_t direction,
00164 size_t max_packet_size, unsigned int interval)
00165 {
00166 assert(fun);
00167 hc_t *hc = fun_to_hc(fun);
00168 assert(hc);
00169 const size_t size = max_packet_size;
00170 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
00171 if (speed >= USB_SPEED_MAX) {
00172 speed = ep_speed;
00173 }
00174 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
00175 address, endpoint, usb_str_transfer_type(transfer_type),
00176 usb_str_speed(speed), direction, size, max_packet_size, interval);
00177
00178 return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint,
00179 direction, transfer_type, speed, max_packet_size, size);
00180 }
00181
00182 static int unregister_endpoint(
00183 ddf_fun_t *fun, usb_address_t address,
00184 usb_endpoint_t endpoint, usb_direction_t direction)
00185 {
00186 assert(fun);
00187 hc_t *hc = fun_to_hc(fun);
00188 assert(hc);
00189 usb_log_debug("Unregister endpoint %d:%d %d.\n",
00190 address, endpoint, direction);
00191 return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
00192 endpoint, direction);
00193 }
00194
00205 static int interrupt_out(
00206 ddf_fun_t *fun, usb_target_t target, void *data,
00207 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
00208 {
00209 usb_transfer_batch_t *batch = NULL;
00210 hc_t *hc = NULL;
00211 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
00212 NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
00213 if (ret != EOK)
00214 return ret;
00215 assert(batch);
00216 assert(hc);
00217 batch_interrupt_out(batch);
00218 ret = hc_schedule(hc, batch);
00219 if (ret != EOK) {
00220 usb_transfer_batch_dispose(batch);
00221 }
00222 return ret;
00223 }
00224
00235 static int interrupt_in(
00236 ddf_fun_t *fun, usb_target_t target, void *data,
00237 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
00238 {
00239 usb_transfer_batch_t *batch = NULL;
00240 hc_t *hc = NULL;
00241 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
00242 NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
00243 if (ret != EOK)
00244 return ret;
00245 assert(batch);
00246 assert(hc);
00247 batch_interrupt_in(batch);
00248 ret = hc_schedule(hc, batch);
00249 if (ret != EOK) {
00250 usb_transfer_batch_dispose(batch);
00251 }
00252 return ret;
00253 }
00254
00265 static int bulk_out(
00266 ddf_fun_t *fun, usb_target_t target, void *data,
00267 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
00268 {
00269 usb_transfer_batch_t *batch = NULL;
00270 hc_t *hc = NULL;
00271 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
00272 NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
00273 if (ret != EOK)
00274 return ret;
00275 assert(batch);
00276 assert(hc);
00277 batch_bulk_out(batch);
00278 ret = hc_schedule(hc, batch);
00279 if (ret != EOK) {
00280 usb_transfer_batch_dispose(batch);
00281 }
00282 return ret;
00283 }
00284
00295 static int bulk_in(
00296 ddf_fun_t *fun, usb_target_t target, void *data,
00297 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
00298 {
00299 usb_transfer_batch_t *batch = NULL;
00300 hc_t *hc = NULL;
00301 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
00302 NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
00303 if (ret != EOK)
00304 return ret;
00305 assert(batch);
00306 assert(hc);
00307 batch_bulk_in(batch);
00308 ret = hc_schedule(hc, batch);
00309 if (ret != EOK) {
00310 usb_transfer_batch_dispose(batch);
00311 }
00312 return ret;
00313 }
00314
00327 static int control_write(
00328 ddf_fun_t *fun, usb_target_t target,
00329 void *setup_data, size_t setup_size, void *data, size_t size,
00330 usbhc_iface_transfer_out_callback_t callback, void *arg)
00331 {
00332 usb_transfer_batch_t *batch = NULL;
00333 hc_t *hc = NULL;
00334 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
00335 setup_data, setup_size, NULL, callback, arg, "Control WRITE",
00336 &hc, &batch);
00337 if (ret != EOK)
00338 return ret;
00339 assert(batch);
00340 assert(hc);
00341 usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
00342 batch_control_write(batch);
00343 ret = hc_schedule(hc, batch);
00344 if (ret != EOK) {
00345 usb_transfer_batch_dispose(batch);
00346 }
00347 return ret;
00348 }
00349
00362 static int control_read(
00363 ddf_fun_t *fun, usb_target_t target,
00364 void *setup_data, size_t setup_size, void *data, size_t size,
00365 usbhc_iface_transfer_in_callback_t callback, void *arg)
00366 {
00367 usb_transfer_batch_t *batch = NULL;
00368 hc_t *hc = NULL;
00369 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
00370 setup_data, setup_size, callback, NULL, arg, "Control READ",
00371 &hc, &batch);
00372 if (ret != EOK)
00373 return ret;
00374 assert(batch);
00375 assert(hc);
00376 batch_control_read(batch);
00377 ret = hc_schedule(hc, batch);
00378 if (ret != EOK) {
00379 usb_transfer_batch_dispose(batch);
00380 }
00381 return ret;
00382 }
00383
00384 usbhc_iface_t hc_iface = {
00385 .request_address = request_address,
00386 .bind_address = bind_address,
00387 .find_by_address = find_by_address,
00388 .release_address = release_address,
00389
00390 .register_endpoint = register_endpoint,
00391 .unregister_endpoint = unregister_endpoint,
00392
00393 .interrupt_out = interrupt_out,
00394 .interrupt_in = interrupt_in,
00395
00396 .bulk_out = bulk_out,
00397 .bulk_in = bulk_in,
00398
00399 .control_write = control_write,
00400 .control_read = control_read,
00401 };