1/*
2 * Copyright (c) 2007-2013 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <barrelfish/barrelfish.h>
12
13#include <usb/usb.h>
14
15#include <usb_controller.h>
16#include <usb_xfer.h>
17#include <usb_device.h>
18#include <usb_endpoint.h>
19#include <usb_pipe.h>
20
21/**
22 * \brief goes through the endpoints of a device and returns the one that
23 *        matches the criteria
24 *
25 * \param device the device we want to consider for the lookup
26 * \param iface  the interface in which we want to look for
27 * \param filter filter defining which endpoint we want
28 *
29 * \return pointer to the endpoint on success
30 *         NULL if no endpoint is fould
31 *
32 * NOTE: Filter may contain a specific direction, endpoint number or type.
33 *       Each filter criteria may also be "ANY"
34 */
35struct usb_endpoint *usb_endpoint_lookup(struct usb_device *device,
36        uint8_t iface, const struct usb_xfer_config *filter)
37{
38
39    uint8_t ep_index = 0;
40
41    struct usb_endpoint *ep = device->endpoints;
42
43    usb_endpoint_address_t *epaddr;
44    usb_endpoint_attributes_t *epattr;
45
46    uint8_t any = 1;
47
48    /* loop over all endpoints */
49    for (uint8_t ep_current = 0; ep_current < device->ep_max; ep_current++) {
50        if (ep == NULL) {
51            /* no endpoint allocated, continue with next */
52            continue;
53        }
54
55        if ((ep->descriptor == NULL) || (ep->iface_index != iface)) {
56            /* there is no descriptor or the wrong interface */
57            continue;
58        }
59
60        /* we have a valid endpoint sofar, so check filter criteria */
61        epaddr = &(ep->descriptor->bEndpointAddress);
62        epattr = &(ep->descriptor->bmAttributes);
63
64        /* check for direction */
65        if (filter->direction != USB_ENDPOINT_DIRECTION_ANY) {
66            any = 0;
67            if (epaddr->direction != filter->direction) {
68                /* wrong direction, check next next */
69                continue;
70            }
71        }
72
73        /* checking matching endpoint address */
74        if (filter->endpoint != USB_ENDPOINT_ADDRESS_ANY) {
75            any = 0;
76            if (epaddr->ep_number != filter->endpoint) {
77                /* wrong endpoint address */
78                continue;
79            }
80        }
81
82        /* checking the matching type */
83        if (filter->type != USB_ENDPOINT_TYPE_ANY) {
84            any = 0;
85            if (epattr->xfer_type != filter->type) {
86                /* wrong xfer type */
87                continue;
88            }
89        }
90
91        if (!(ep_index--) && !any) {
92            USB_DEBUG_XFER("Endpoint found: iface=0x%x, ep=0x%x\n",
93                    iface, ep->endpoint_address);
94            return (ep);
95        }
96
97        ep++;
98    }
99
100    /* the default control endpoint is not located in the endpoints array */
101    if (device->ctrl_ep.descriptor && any && !ep_index) {
102        USB_DEBUG_XFER("usb_endpoint_lookup(): found default ctrl ep\n");
103        return (&device->ctrl_ep);
104    }
105
106    /* no matching endpoint found */
107    return (NULL);
108}
109
110/**
111 * \brief initializes the endpoint with the correct data
112 *
113 * \param device the usb device this endpoint belongs to
114 * \param iface_index the interface index this endpoint belongs to
115 * \param desc the endpoint descriptor of this endpoint
116 * \param ep the endpoint to initialize
117 */
118void usb_endpoint_init(struct usb_device *device, uint8_t iface_index,
119        struct usb_endpoint_descriptor *desc, struct usb_endpoint *ep)
120{
121    USB_DEBUG_TR_ENTER;
122
123    /*
124     * call the endpoint init function of the host controller in a save way
125     * This sets the pipe function pointers to the correspinding transfer type
126     */
127    struct usb_hcdi_bus_fn *bus_fn = device->controller->hcdi_bus_fn;
128
129    if (bus_fn && bus_fn->endpoint_init) {
130        (bus_fn->endpoint_init)(device, desc, ep);
131    }
132
133    /* set the values of this endpoint */
134    ep->descriptor = desc;
135    ep->iface_index = iface_index;
136    ep->endpoint_address = desc->bEndpointAddress.ep_number;
137    ep->max_packet_size = desc->wMaxPacketSize;
138
139    /* initialze the endpoint queue */
140    ep->transfers.head.first = NULL;
141    ep->transfers.head.last_next = &(ep->transfers.head.first);
142    ep->transfers.command = &usb_pipe_start;
143
144    if (ep->pipe_fn == NULL) {
145        return;
146    }
147
148    /* some devices may need a clear stall on new endpoints */
149    if (bus_fn->clear_stall != NULL) {
150        (bus_fn->clear_stall)(device, ep);
151    }
152}
153