iface.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky, Jan Vesely
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 };

Generated on Thu Jun 2 07:45:44 2011 for HelenOS/USB by  doxygen 1.4.7