/* * Copyright (c) 2011 Jan Vesely * Copyright (c) 2018 Ondrej Hlavaty * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup libusbhost * @{ */ /** @file * * Endpoint structure is tightly coupled to the bus. The bus controls the * life-cycle of endpoint. In order to keep endpoints lightweight, operations * on endpoints are part of the bus structure. * */ #ifndef LIBUSBHOST_HOST_ENDPOINT_H #define LIBUSBHOST_HOST_ENDPOINT_H #include <adt/list.h> #include <fibril_synch.h> #include <refcount.h> #include <stdbool.h> #include <time.h> #include <usb/usb.h> #include <usb/host/bus.h> #include <usbhc_iface.h> typedef struct bus bus_t; typedef struct device device_t; typedef struct transfer_request transfer_request_t; typedef struct usb_transfer_batch usb_transfer_batch_t; /** * Host controller side endpoint structure. * * This structure, though reference-counted, is very fragile. It is responsible * for synchronizing transfer batch scheduling and completion. * * To avoid situations, in which two locks must be obtained to schedule/finish * a transfer, the endpoint inherits a lock from the outside. Because the * concrete instance of mutex can be unknown at the time of initialization, * the HC shall pass the right lock at the time of onlining the endpoint. * * The fields used for scheduling (online, active_batch) are to be used only * under that guard and by functions designed for this purpose. The driver can * also completely avoid using this mechanism, in which case it is on its own in * question of transfer aborting. * * Relevant information can be found in the documentation of HelenOS xHCI * project. */ typedef struct endpoint { /** USB device */ device_t *device; /** Reference count. */ atomic_refcount_t refcnt; /** An inherited guard */ fibril_mutex_t *guard; /** Whether it's allowed to schedule on this endpoint */ bool online; /** The currently active transfer batch. */ usb_transfer_batch_t *active_batch; /** Signals change of active status. */ fibril_condvar_t avail; /** Endpoint number */ usb_endpoint_t endpoint; /** Communication direction. */ usb_direction_t direction; /** USB transfer type. */ usb_transfer_type_t transfer_type; /** Maximum size of one packet */ size_t max_packet_size; /** Maximum size of one transfer */ size_t max_transfer_size; /* Policies for transfer buffers */ /** A hint for optimal performance. */ dma_policy_t transfer_buffer_policy; /** Enforced by the library. */ dma_policy_t required_transfer_buffer_policy; /** * Number of packets that can be sent in one service interval * (not necessarily uframe, despite its name) */ unsigned packets_per_uframe; /* This structure is meant to be extended by overriding. */ } endpoint_t; extern void endpoint_init(endpoint_t *, device_t *, const usb_endpoint_descriptors_t *); extern void endpoint_add_ref(endpoint_t *); extern void endpoint_del_ref(endpoint_t *); extern void endpoint_set_online(endpoint_t *, fibril_mutex_t *); extern void endpoint_set_offline_locked(endpoint_t *); extern void endpoint_wait_timeout_locked(endpoint_t *ep, usec_t); extern int endpoint_activate_locked(endpoint_t *, usb_transfer_batch_t *); extern void endpoint_deactivate_locked(endpoint_t *); int endpoint_send_batch(endpoint_t *, const transfer_request_t *); static inline bus_t *endpoint_get_bus(endpoint_t *ep) { device_t *const device = ep->device; return device ? device->bus : NULL; } #endif /** * @} */