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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2c091a6 was 2c091a6, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

xhci ep: fixed error path

  • Property mode set to 100644
File size: 8.9 KB
RevLine 
[c0ec9e7]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
[b7db009]36#include <usb/host/utils/malloc32.h>
[41924f30]37#include <usb/host/endpoint.h>
[9b2f69e]38#include <usb/descriptor.h>
[41924f30]39
[c0ec9e7]40#include <errno.h>
41
[41924f30]42#include "bus.h"
[d7869d7e]43#include "commands.h"
[c0ec9e7]44#include "endpoint.h"
45
[41924f30]46int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, xhci_bus_t *xhci_bus)
[c0ec9e7]47{
[41924f30]48 assert(xhci_ep);
49 assert(xhci_bus);
[176a70a]50
[41924f30]51 bus_t *bus = &xhci_bus->base;
52 endpoint_t *ep = &xhci_ep->base;
[176a70a]53
[41924f30]54 endpoint_init(ep, bus);
55
[2b61945]56 return xhci_trb_ring_init(&xhci_ep->ring);
[c0ec9e7]57}
58
[41924f30]59void xhci_endpoint_fini(xhci_endpoint_t *xhci_ep)
[c0ec9e7]60{
[41924f30]61 assert(xhci_ep);
62
[176a70a]63 /* FIXME: Tear down TR's? */
[2b61945]64 xhci_trb_ring_fini(&xhci_ep->ring);
[c0ec9e7]65}
66
[2b61945]67/** See section 4.5.1 of the xHCI spec.
68 */
69uint8_t xhci_endpoint_dci(xhci_endpoint_t *ep)
[c10daa8]70{
[2b61945]71 return (2 * ep->base.target.endpoint) +
72 (ep->base.transfer_type == USB_TRANSFER_CONTROL
73 || ep->base.direction == USB_DIRECTION_IN);
[9b2f69e]74}
75
[dbf32b1]76/** Return an index to the endpoint array. The indices are assigned as follows:
77 * 0 EP0 BOTH
78 * 1 EP1 OUT
79 * 2 EP1 IN
80 *
81 * For control endpoints >0, the IN endpoint index is used.
[913007f]82 *
[dbf32b1]83 * The index returned must be usually offset by a number of contexts preceding
84 * the endpoint contexts themselves.
85 */
86uint8_t xhci_endpoint_index(xhci_endpoint_t *ep)
[9b2f69e]87{
[2b61945]88 return xhci_endpoint_dci(ep) - 1;
[9b2f69e]89}
90
91static int xhci_endpoint_type(xhci_endpoint_t *ep)
92{
93 const bool in = ep->base.direction == USB_DIRECTION_IN;
94
95 switch (ep->base.transfer_type) {
96 case USB_TRANSFER_CONTROL:
97 return EP_TYPE_CONTROL;
98
99 case USB_TRANSFER_ISOCHRONOUS:
100 return in ? EP_TYPE_ISOCH_IN
101 : EP_TYPE_ISOCH_OUT;
102
103 case USB_TRANSFER_BULK:
104 return in ? EP_TYPE_BULK_IN
105 : EP_TYPE_BULK_OUT;
106
107 case USB_TRANSFER_INTERRUPT:
108 return in ? EP_TYPE_INTERRUPT_IN
109 : EP_TYPE_INTERRUPT_OUT;
110 }
111
112 return EP_TYPE_INVALID;
113}
114
115static void setup_control_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
116 xhci_trb_ring_t *ring)
117{
118 // EP0 is configured elsewhere.
119 assert(ep->base.target.endpoint > 0);
120
121 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
122 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
123 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
124 XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
125 XHCI_EP_DCS_SET(*ctx, 1);
126}
127
128static void setup_bulk_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
129 xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
130{
131 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
132 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
[2b61945]133 XHCI_EP_MAX_BURST_SIZE_SET(*ctx,
134 xhci_device_get(ep->base.device)->usb3 ? ss_desc->max_burst : 0);
[9b2f69e]135 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
136
137 // FIXME: Get maxStreams and other things from ss_desc
138 const uint8_t maxStreams = 0;
139 if (maxStreams > 0) {
140 // TODO: allocate and clear primary stream array
141 // TODO: XHCI_EP_MAX_P_STREAMS_SET(ctx, psa_size);
142 // TODO: XHCI_EP_TR_DPTR_SET(ctx, psa_start_phys_addr);
143 // TODO: set HID
144 // TODO: set LSA
145 } else {
146 XHCI_EP_MAX_P_STREAMS_SET(*ctx, 0);
147 XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
148 XHCI_EP_DCS_SET(*ctx, 1);
149 }
150}
151
152static void setup_isoch_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
153 xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
154{
155 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
156 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
157 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ss_desc->max_burst);
158 // FIXME: get Mult field from SS companion descriptor somehow
159 XHCI_EP_MULT_SET(*ctx, 0);
160 XHCI_EP_ERROR_COUNT_SET(*ctx, 0);
161 XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
162 XHCI_EP_DCS_SET(*ctx, 1);
163 // TODO: max ESIT payload
164}
165
166static void setup_interrupt_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
167 xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
168{
169 XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
170 XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
171 XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ss_desc->max_burst);
172 XHCI_EP_MULT_SET(*ctx, 0);
173 XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
174 XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
175 XHCI_EP_DCS_SET(*ctx, 1);
176 // TODO: max ESIT payload
[c10daa8]177}
178
179int xhci_device_add_endpoint(xhci_device_t *dev, xhci_endpoint_t *ep)
180{
[2b61945]181 assert(dev);
182 assert(ep);
183
184 int err = ENOMEM;
[2e5aea1]185 const usb_endpoint_t ep_num = ep->base.target.endpoint;
[9b2f69e]186
[2b61945]187 assert(&dev->base == ep->base.device);
188 assert(dev->base.address == ep->base.target.address);
189 assert(!dev->endpoints[ep_num]);
190
191 dev->endpoints[ep_num] = ep;
[c10daa8]192 ++dev->active_endpoint_count;
[9b2f69e]193
[2b61945]194 if (ep_num == 0)
195 /* EP 0 is initialized while setting up the device,
196 * so we must not issue the command now. */
197 return EOK;
198
199 // FIXME: Retrieve this from somewhere, if applicable.
200 usb_superspeed_endpoint_companion_descriptor_t ss_desc;
201 memset(&ss_desc, 0, sizeof(ss_desc));
202
203 // Prepare input context.
204 xhci_input_ctx_t *ictx = malloc32(sizeof(xhci_input_ctx_t));
205 if (!ictx)
206 goto err;
207
208 memset(ictx, 0, sizeof(xhci_input_ctx_t));
209
210 // Quoting sec. 4.6.6: A1, D0, D1 are down, A0 is up.
211 XHCI_INPUT_CTRL_CTX_ADD_CLEAR(ictx->ctrl_ctx, 1);
212 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 0);
213 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 1);
214 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
[2c091a6]215
216 const unsigned ep_idx = xhci_endpoint_index(ep);
[2b61945]217 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, ep_idx + 1); /* Preceded by slot ctx */
218
219 xhci_trb_ring_t *ep_ring = &ep->ring;
220 xhci_ep_ctx_t *ep_ctx = &ictx->endpoint_ctx[ep_idx];
221
222 // TODO: Convert to table
223 switch (ep->base.transfer_type) {
224 case USB_TRANSFER_CONTROL:
225 setup_control_ep_ctx(ep, ep_ctx, ep_ring);
226 break;
227
228 case USB_TRANSFER_BULK:
229 setup_bulk_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
230 break;
231
232 case USB_TRANSFER_ISOCHRONOUS:
233 setup_isoch_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
234 break;
235
236 case USB_TRANSFER_INTERRUPT:
237 setup_interrupt_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
238 break;
[9b2f69e]239 }
[2b61945]240
241 // Issue configure endpoint command (sec 4.3.5).
242 xhci_cmd_t cmd;
243 xhci_cmd_init(&cmd);
244
245 cmd.slot_id = dev->slot_id;
246 xhci_send_configure_endpoint_command(dev->hc, &cmd, ictx);
247 if ((err = xhci_cmd_wait(&cmd, XHCI_DEFAULT_TIMEOUT)) != EOK)
248 goto err_ictx;
249
250 xhci_cmd_fini(&cmd);
251
252 free32(ictx);
253 return EOK;
254
[9b2f69e]255err_ictx:
[2b61945]256 free32(ictx);
257err:
[2c091a6]258 dev->endpoints[ep_num] = NULL;
[2b61945]259 dev->active_endpoint_count--;
[9b2f69e]260 return err;
[c10daa8]261}
262
263int xhci_device_remove_endpoint(xhci_device_t *dev, xhci_endpoint_t *ep)
264{
[2b61945]265 assert(&dev->base == ep->base.device);
266 assert(dev->base.address == ep->base.target.address);
[c10daa8]267 assert(dev->endpoints[ep->base.target.endpoint]);
268
[9b2f69e]269 // TODO: Issue configure endpoint command to drop this endpoint.
270
[c10daa8]271 dev->endpoints[ep->base.target.endpoint] = NULL;
272 --dev->active_endpoint_count;
273 return EOK;
274}
275
276xhci_endpoint_t * xhci_device_get_endpoint(xhci_device_t *dev, usb_endpoint_t ep)
277{
278 return dev->endpoints[ep];
279}
280
[d7869d7e]281int xhci_device_configure(xhci_device_t *dev, xhci_hc_t *hc)
282{
283 int err;
284
285 // Prepare input context.
286 xhci_input_ctx_t *ictx = malloc(sizeof(xhci_input_ctx_t));
287 if (!ictx) {
288 return ENOMEM;
289 }
290
291 memset(ictx, 0, sizeof(xhci_input_ctx_t));
292
293 // Quoting sec. 4.6.6: A1, D0, D1 are down, A0 is up.
294 XHCI_INPUT_CTRL_CTX_ADD_CLEAR(ictx->ctrl_ctx, 1);
295 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 0);
296 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 1);
297 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
298
299 // TODO: Set slot context and other flags. (probably forgot a lot of 'em)
300
301 // Issue configure endpoint command (sec 4.3.5).
302 xhci_cmd_t cmd;
303 xhci_cmd_init(&cmd);
304
305 cmd.slot_id = dev->slot_id;
306 xhci_send_configure_endpoint_command(hc, &cmd, ictx);
[913007f]307 if ((err = xhci_cmd_wait(&cmd, XHCI_DEFAULT_TIMEOUT)) != EOK)
[d7869d7e]308 goto err_cmd;
309
310 xhci_cmd_fini(&cmd);
311 return EOK;
312
313err_cmd:
314 free(ictx);
315 return err;
316}
317
[c0ec9e7]318/**
319 * @}
320 */
Note: See TracBrowser for help on using the repository browser.