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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2e5aea1 was 2e5aea1, checked in by Petr Manek <petr.manek@…>, 8 years ago

Moved around a declaration. The OS builds again.

  • Property mode set to 100644
File size: 8.9 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/utils/malloc32.h>
37#include <usb/host/endpoint.h>
38#include <usb/descriptor.h>
39
40#include <errno.h>
41
42#include "bus.h"
43#include "commands.h"
44#include "endpoint.h"
45
46int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, xhci_bus_t *xhci_bus)
47{
48 assert(xhci_ep);
49 assert(xhci_bus);
50
51 bus_t *bus = &xhci_bus->base;
52 endpoint_t *ep = &xhci_ep->base;
53
54 endpoint_init(ep, bus);
55
56 return xhci_trb_ring_init(&xhci_ep->ring);
57}
58
59void xhci_endpoint_fini(xhci_endpoint_t *xhci_ep)
60{
61 assert(xhci_ep);
62
63 /* FIXME: Tear down TR's? */
64 xhci_trb_ring_fini(&xhci_ep->ring);
65}
66
67/** See section 4.5.1 of the xHCI spec.
68 */
69uint8_t xhci_endpoint_dci(xhci_endpoint_t *ep)
70{
71 return (2 * ep->base.target.endpoint) +
72 (ep->base.transfer_type == USB_TRANSFER_CONTROL
73 || ep->base.direction == USB_DIRECTION_IN);
74}
75
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.
82 *
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)
87{
88 return xhci_endpoint_dci(ep) - 1;
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);
133 XHCI_EP_MAX_BURST_SIZE_SET(*ctx,
134 xhci_device_get(ep->base.device)->usb3 ? ss_desc->max_burst : 0);
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
177}
178
179int xhci_device_add_endpoint(xhci_device_t *dev, xhci_endpoint_t *ep)
180{
181 assert(dev);
182 assert(ep);
183
184 int err = ENOMEM;
185 const usb_endpoint_t ep_num = ep->base.target.endpoint;
186
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;
192 ++dev->active_endpoint_count;
193
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 const unsigned ep_idx = xhci_endpoint_index(ep);
206 if (!ictx)
207 goto err;
208
209 memset(ictx, 0, sizeof(xhci_input_ctx_t));
210
211 // Quoting sec. 4.6.6: A1, D0, D1 are down, A0 is up.
212 XHCI_INPUT_CTRL_CTX_ADD_CLEAR(ictx->ctrl_ctx, 1);
213 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 0);
214 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 1);
215 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
216 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, ep_idx + 1); /* Preceded by slot ctx */
217
218 xhci_trb_ring_t *ep_ring = &ep->ring;
219 xhci_ep_ctx_t *ep_ctx = &ictx->endpoint_ctx[ep_idx];
220
221 // TODO: Convert to table
222 switch (ep->base.transfer_type) {
223 case USB_TRANSFER_CONTROL:
224 setup_control_ep_ctx(ep, ep_ctx, ep_ring);
225 break;
226
227 case USB_TRANSFER_BULK:
228 setup_bulk_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
229 break;
230
231 case USB_TRANSFER_ISOCHRONOUS:
232 setup_isoch_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
233 break;
234
235 case USB_TRANSFER_INTERRUPT:
236 setup_interrupt_ep_ctx(ep, ep_ctx, ep_ring, &ss_desc);
237 break;
238 }
239
240 // Issue configure endpoint command (sec 4.3.5).
241 xhci_cmd_t cmd;
242 xhci_cmd_init(&cmd);
243
244 cmd.slot_id = dev->slot_id;
245 xhci_send_configure_endpoint_command(dev->hc, &cmd, ictx);
246 if ((err = xhci_cmd_wait(&cmd, XHCI_DEFAULT_TIMEOUT)) != EOK)
247 goto err_ictx;
248
249 xhci_cmd_fini(&cmd);
250
251 free32(ictx);
252 return EOK;
253
254err_ictx:
255 free32(ictx);
256err:
257 dev->endpoints[ep_idx] = NULL;
258 dev->active_endpoint_count--;
259 return err;
260}
261
262int xhci_device_remove_endpoint(xhci_device_t *dev, xhci_endpoint_t *ep)
263{
264 assert(&dev->base == ep->base.device);
265 assert(dev->base.address == ep->base.target.address);
266 assert(dev->endpoints[ep->base.target.endpoint]);
267
268 // TODO: Issue configure endpoint command to drop this endpoint.
269
270 dev->endpoints[ep->base.target.endpoint] = NULL;
271 --dev->active_endpoint_count;
272 return EOK;
273}
274
275xhci_endpoint_t * xhci_device_get_endpoint(xhci_device_t *dev, usb_endpoint_t ep)
276{
277 return dev->endpoints[ep];
278}
279
280int xhci_device_configure(xhci_device_t *dev, xhci_hc_t *hc)
281{
282 int err;
283
284 // Prepare input context.
285 xhci_input_ctx_t *ictx = malloc(sizeof(xhci_input_ctx_t));
286 if (!ictx) {
287 return ENOMEM;
288 }
289
290 memset(ictx, 0, sizeof(xhci_input_ctx_t));
291
292 // Quoting sec. 4.6.6: A1, D0, D1 are down, A0 is up.
293 XHCI_INPUT_CTRL_CTX_ADD_CLEAR(ictx->ctrl_ctx, 1);
294 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 0);
295 XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 1);
296 XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
297
298 // TODO: Set slot context and other flags. (probably forgot a lot of 'em)
299
300 // Issue configure endpoint command (sec 4.3.5).
301 xhci_cmd_t cmd;
302 xhci_cmd_init(&cmd);
303
304 cmd.slot_id = dev->slot_id;
305 xhci_send_configure_endpoint_command(hc, &cmd, ictx);
306 if ((err = xhci_cmd_wait(&cmd, XHCI_DEFAULT_TIMEOUT)) != EOK)
307 goto err_cmd;
308
309 xhci_cmd_fini(&cmd);
310 return EOK;
311
312err_cmd:
313 free(ictx);
314 return err;
315}
316
317/**
318 * @}
319 */
Note: See TracBrowser for help on using the repository browser.