source: mainline/uspace/drv/bus/usb/xhci/endpoint.c@ 05770666

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 05770666 was 1af4c00, checked in by Salmelu <salmelu@…>, 8 years ago

xhci: fixed transition to and from streams

Added remove streams function to transition the endpoint back to single ring no streams mode.
Requesting streams now stops the endpoint, clears the ring and executes update endpoint command.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2017 Petr Manek
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbxhci
30 * @{
31 */
32/** @file
33 * @brief The host controller endpoint management.
34 */
35
36#include <usb/host/endpoint.h>
37#include <usb/descriptor.h>
38
39#include <errno.h>
40#include <macros.h>
41
42#include "hc.h"
43#include "bus.h"
44#include "commands.h"
45#include "endpoint.h"
46#include "streams.h"
47
48static int alloc_transfer_ds(xhci_endpoint_t *);
49
50/**
51 * Initialize new XHCI endpoint.
52 * @param[in] xhci_ep Allocated XHCI endpoint to initialize.
53 * @param[in] dev Device, to which the endpoint belongs.
54 * @param[in] desc USB endpoint descriptor carrying configuration data.
55 *
56 * @return Error code.
57 */
58int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, device_t *dev, const usb_endpoint_descriptors_t *desc)
59{
60 int rc;
61 assert(xhci_ep);
62
63 endpoint_t *ep = &xhci_ep->base;
64
65 endpoint_init(ep, dev, desc);
66
67 xhci_ep->max_burst = desc->companion.max_burst + 1;
68
69 if (ep->transfer_type == USB_TRANSFER_BULK)
70 xhci_ep->max_streams = 1 << (USB_SSC_MAX_STREAMS(desc->companion));
71 else
72 xhci_ep->max_streams = 1;
73
74 if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)
75 xhci_ep->mult = USB_SSC_MULT(desc->companion) + 1;
76 else
77 xhci_ep->mult = 1;
78
79 /* In USB 3, the semantics of wMaxPacketSize changed. Now the number of
80 * packets per service interval is determined from max_burst and mult.
81 */
82 if (dev->speed >= USB_SPEED_SUPER) {
83 ep->packets_per_uframe = xhci_ep->max_burst * xhci_ep->mult;
84 ep->max_transfer_size = ep->max_packet_size * ep->packets_per_uframe;
85 }
86
87 xhci_ep->interval = desc->endpoint.poll_interval;
88
89 /*
90 * Only Low/Full speed interrupt endpoints have interval as a linear field,
91 * others have 2-based log of it.
92 */
93 if (dev->speed >= USB_SPEED_HIGH || ep->transfer_type != USB_TRANSFER_INTERRUPT) {
94 xhci_ep->interval = 1 << (xhci_ep->interval - 1);
95 }
96
97 /* Full speed devices have interval in frames */
98 if (dev->speed <= USB_SPEED_FULL) {
99 xhci_ep->interval *= 8;
100 }
101
102 if (xhci_ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS)
103 isoch_init(xhci_ep, desc);
104
105 if ((rc = alloc_transfer_ds(xhci_ep)))
106 goto err;
107
108 return EOK;
109
110err:
111 return rc;
112}
113
114/**
115 * Finalize XHCI endpoint.
116 * @param[in] xhci_ep XHCI endpoint to finalize.
117 */
118void xhci_endpoint_fini(xhci_endpoint_t *xhci_ep)
119{
120 assert(xhci_ep);
121
122 xhci_endpoint_free_transfer_ds(xhci_ep);
123
124 // TODO: Something missed?
125}
126
127/**
128 * Determine the type of a XHCI endpoint.
129 * @param[in] ep XHCI endpoint to query.
130 *
131 * @return EP_TYPE_[CONTROL|ISOCH|BULK|INTERRUPT]_[IN|OUT]
132 */
133int xhci_endpoint_type(xhci_endpoint_t *ep)
134{
135 const bool in = ep->base.direction == USB_DIRECTION_IN;
136
137 switch (ep->base.transfer_type) {
138 case USB_TRANSFER_CONTROL:
139 return EP_TYPE_CONTROL;
140
141 case USB_TRANSFER_ISOCHRONOUS:
142 return in ? EP_TYPE_ISOCH_IN
143 : EP_TYPE_ISOCH_OUT;
144
145 case USB_TRANSFER_BULK:
146 return in ? EP_TYPE_BULK_IN
147 : EP_TYPE_BULK_OUT;
148
149 case USB_TRANSFER_INTERRUPT:
150 return in ? EP_TYPE_INTERRUPT_IN
151 : EP_TYPE_INTERRUPT_OUT;
152 }
153
154 return EP_TYPE_INVALID;
155}
156
157/** Allocate transfer data structures for XHCI endpoint not using streams.
158 * @param[in] xhci_ep XHCI endpoint to allocate data structures for.
159 *
160 * @return Error code.
161 */
162static int alloc_transfer_ds(xhci_endpoint_t *xhci_ep)
163{
164 /* Can't use XHCI_EP_FMT because the endpoint may not have device. */
165 usb_log_debug2("Allocating main transfer ring for endpoint " XHCI_EP_FMT, XHCI_EP_ARGS(*xhci_ep));
166
167 xhci_ep->primary_stream_data_array = NULL;
168 xhci_ep->primary_stream_data_size = 0;
169
170 int err;
171 if ((err = xhci_trb_ring_init(&xhci_ep->ring))) {
172 return err;
173 }
174
175 if (xhci_ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
176 if ((err = isoch_alloc_transfers(xhci_ep))) {
177 xhci_trb_ring_fini(&xhci_ep->ring);
178 return err;
179 }
180 }
181
182 return EOK;
183}
184
185/** Free transfer data structures for XHCI endpoint.
186 * @param[in] xhci_ep XHCI endpoint to free data structures for.
187 */
188void xhci_endpoint_free_transfer_ds(xhci_endpoint_t *xhci_ep)
189{
190 if (xhci_ep->primary_stream_data_size) {
191 xhci_stream_free_ds(xhci_ep);
192 } else {
193 usb_log_debug2("Freeing main transfer ring of endpoint " XHCI_EP_FMT, XHCI_EP_ARGS(*xhci_ep));
194 xhci_trb_ring_fini(&xhci_ep->ring);
195 }
196
197 if (xhci_ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS)
198 isoch_fini(xhci_ep);
199}
200
201/** See section 4.5.1 of the xHCI spec.
202 */
203uint8_t xhci_endpoint_dci(xhci_endpoint_t *ep)
204{
205 return (2 * ep->base.endpoint) +
206 (ep->base.transfer_type == USB_TRANSFER_CONTROL
207 || ep->base.direction == USB_DIRECTION_IN);
208}
209
210/** Return an index to the endpoint array. The indices are assigned as follows:
211 * 0 EP0 BOTH
212 * 1 EP1 OUT
213 * 2 EP1 IN
214 *
215 * For control endpoints >0, the IN endpoint index is used.
216 *
217 * The index returned must be usually offset by a number of contexts preceding
218 * the endpoint contexts themselves.
219 */
220uint8_t xhci_endpoint_index(xhci_endpoint_t *ep)
221{
222 return xhci_endpoint_dci(ep) - 1;
223}
224
225/** Configure endpoint context of a control endpoint.
226 * @param[in] ep XHCI control endpoint.
227 * @param[in] ctx Endpoint context to configure.
228 */
229static void setup_control_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx)
230{
231 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
232 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
233 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ep->max_burst - 1);
234 XHCI_EP_MULT_SET(*ctx, ep->mult - 1);
235 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
236 XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
237 XHCI_EP_DCS_SET(*ctx, 1);
238}
239
240/** Configure endpoint context of a bulk endpoint.
241 * @param[in] ep XHCI bulk endpoint.
242 * @param[in] ctx Endpoint context to configure.
243 */
244static void setup_bulk_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx)
245{
246 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
247 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
248 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ep->max_burst - 1);
249 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
250
251 XHCI_EP_MAX_P_STREAMS_SET(*ctx, 0);
252 XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
253 XHCI_EP_DCS_SET(*ctx, 1);
254}
255
256/** Configure endpoint context of a isochronous endpoint.
257 * @param[in] ep XHCI isochronous endpoint.
258 * @param[in] ctx Endpoint context to configure.
259 */
260static void setup_isoch_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx)
261{
262 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
263 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
264 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ep->max_burst - 1);
265 XHCI_EP_MULT_SET(*ctx, ep->mult - 1);
266 XHCI_EP_ERROR_COUNT_SET(*ctx, 0);
267 XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
268 XHCI_EP_DCS_SET(*ctx, 1);
269 XHCI_EP_INTERVAL_SET(*ctx, fnzb32(ep->interval) % 32);
270
271 XHCI_EP_MAX_ESIT_PAYLOAD_LO_SET(*ctx, ep->isoch->max_size & 0xFFFF);
272 XHCI_EP_MAX_ESIT_PAYLOAD_HI_SET(*ctx, (ep->isoch->max_size >> 16) & 0xFF);
273}
274
275/** Configure endpoint context of a interrupt endpoint.
276 * @param[in] ep XHCI interrupt endpoint.
277 * @param[in] ctx Endpoint context to configure.
278 */
279static void setup_interrupt_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx)
280{
281 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
282 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
283 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ep->max_burst - 1);
284 XHCI_EP_MULT_SET(*ctx, 0);
285 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
286 XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
287 XHCI_EP_DCS_SET(*ctx, 1);
288 XHCI_EP_INTERVAL_SET(*ctx, fnzb32(ep->interval) % 32);
289 // TODO: max ESIT payload
290}
291
292/** Type of endpoint context configuration function. */
293typedef void (*setup_ep_ctx_helper)(xhci_endpoint_t *, xhci_ep_ctx_t *);
294
295/** Static array, which maps USB endpoint types to their respective endpoint context configuration functions. */
296static const setup_ep_ctx_helper setup_ep_ctx_helpers[] = {
297 [USB_TRANSFER_CONTROL] = setup_control_ep_ctx,
298 [USB_TRANSFER_ISOCHRONOUS] = setup_isoch_ep_ctx,
299 [USB_TRANSFER_BULK] = setup_bulk_ep_ctx,
300 [USB_TRANSFER_INTERRUPT] = setup_interrupt_ep_ctx,
301};
302
303/** Configure endpoint context of XHCI endpoint.
304 * @param[in] ep Associated XHCI endpoint.
305 * @param[in] ep_ctx Endpoint context to configure.
306 */
307void xhci_setup_endpoint_context(xhci_endpoint_t *ep, xhci_ep_ctx_t *ep_ctx)
308{
309 assert(ep);
310 assert(ep_ctx);
311
312 usb_transfer_type_t tt = ep->base.transfer_type;
313
314 memset(ep_ctx, 0, sizeof(*ep_ctx));
315 setup_ep_ctx_helpers[tt](ep, ep_ctx);
316}
317
318/**
319 * @}
320 */
Note: See TracBrowser for help on using the repository browser.