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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10/*
11 * Copyright (c) 2007-2013 ETH Zurich.
12 * All rights reserved.
13 *
14 * This file is distributed under the terms in the attached LICENSE file.
15 * If you do not find this file, copies can be found by writing to:
16 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
17 */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <barrelfish/barrelfish.h>
22
23#include <usb/usb.h>
24
25#include <usb/usb_request.h>
26
27#include <usb_device.h>
28#include <usb_hub.h>
29#include <usb_request.h>
30
31usb_error_t usb_hub_clear_hub_feature(struct usb_device *hub, uint16_t feature)
32{
33    struct usb_device_request req;
34    req.bType.direction = USB_REQUEST_WRITE;
35    req.bType.recipient = USB_REQUEST_RECIPIENT_DEVICE;
36    req.bType.type = USB_REQUEST_TYPE_CLASS;
37    req.bRequest = USB_HUB_REQ_CLEAR_FEATURE;
38    req.wValue = feature;
39    req.wLength = 0;
40    req.wIndex = 0;
41    return (usb_exec_request(hub, 0, &req, NULL, NULL));
42}
43
44usb_error_t usb_hub_clear_port_feature(struct usb_device *hub, uint16_t feature,
45        uint8_t port)
46{
47    struct usb_device_request req;
48    req.bType.direction = USB_REQUEST_WRITE;
49    req.bType.recipient = USB_REQUEST_RECIPIENT_OTHER;
50    req.bType.type = USB_REQUEST_TYPE_CLASS;
51    req.bRequest = USB_HUB_REQ_CLEAR_FEATURE;
52    req.wValue = feature;
53    req.wLength = 0;
54    req.wIndex = port;
55    return (usb_exec_request(hub, 0, &req, NULL, NULL));
56}
57
58usb_error_t usb_hub_clear_tt_buffer(struct usb_device *hub, uint8_t dev_addr,
59        uint8_t ep_num, uint8_t ep_type, uint8_t direction, uint16_t tt_port)
60{
61    struct usb_device_request req;
62
63    if (hub->device_desc.bDeviceClass == USB_HUB_CLASS_CODE
64            && hub->device_desc.bDeviceProtocol == USB_HUB_PROTOCOL_HSHUBSTT) {
65        /*
66         * if there is just a single transaction translator in the hub,
67         * the port should be 1
68         */
69        tt_port = 1;
70    }
71
72    uint16_t wValue = (ep_num & 0xF) | ((dev_addr & 0x7F) << 4)
73            | ((ep_num & 0x80) << 8) | ((ep_type & 0x3) << 12);
74
75    req.bType.direction = USB_REQUEST_WRITE;
76    req.bType.recipient = USB_REQUEST_RECIPIENT_OTHER;
77    req.bType.type = USB_REQUEST_TYPE_CLASS;
78    req.bRequest = USB_HUB_REQ_CLEAR_TT_BUFFER;
79    req.wValue = wValue;
80    req.wLength = 0;
81    req.wIndex = tt_port;
82    return (usb_exec_request(hub, 0, &req, NULL, NULL));
83}
84
85usb_error_t usb_hub_get_hub_status(struct usb_device *hub,
86        struct usb_hub_status *ret_status)
87
88{
89    USB_DEBUG_TR_ENTER;
90    struct usb_device_request req;
91
92    req.bType.direction = USB_REQUEST_READ;
93    req.bType.recipient = USB_REQUEST_RECIPIENT_DEVICE;
94    req.bType.type = USB_REQUEST_TYPE_CLASS;
95    req.bRequest = USB_HUB_REQ_GET_STATUS;
96    req.wValue = 0;
97    req.wLength = sizeof(struct usb_hub_status);
98    req.wIndex = 0;
99    return (usb_exec_request(hub, 0, &req, ret_status, NULL));
100}
101
102usb_error_t usb_hub_get_port_status(struct usb_device *hub, uint16_t port,
103        struct usb_hub_port_status *ret_status)
104{
105    USB_DEBUG_TR_ENTER;
106
107    struct usb_device_request req;
108
109    req.bType.direction = USB_REQUEST_READ;
110    req.bType.recipient = USB_REQUEST_RECIPIENT_OTHER;
111    req.bType.type = USB_REQUEST_TYPE_CLASS;
112    req.bRequest = USB_HUB_REQ_GET_STATUS;
113    req.wValue = 0;
114    req.wLength = sizeof(struct usb_hub_port_status);
115    req.wIndex = port;
116    return (usb_exec_request(hub, 0, &req, ret_status, NULL));
117}
118
119usb_error_t usb_hub_reset_tt(struct usb_device *hub, uint16_t port)
120{
121    USB_DEBUG_TR_ENTER;
122
123    struct usb_device_request req;
124
125    if (hub->device_desc.bDeviceClass == USB_HUB_CLASS_CODE
126            && hub->device_desc.bDeviceProtocol == USB_HUB_PROTOCOL_HSHUBSTT) {
127        /*
128         * if there is just a single transaction translator in the hub,
129         * the port should be 1
130         */
131        port = 1;
132    }
133
134    req.bType.direction = USB_REQUEST_WRITE;
135    req.bType.recipient = USB_REQUEST_RECIPIENT_OTHER;
136    req.bType.type = USB_REQUEST_TYPE_CLASS;
137    req.bRequest = USB_HUB_REQ_RESET_TT;
138    req.wValue = 0;
139    req.wLength = 0;
140    req.wIndex = port;
141    return (usb_exec_request(hub, 0, &req, NULL, NULL));
142}
143
144usb_error_t usb_hub_set_hub_feature(struct usb_device *hub, uint16_t feature)
145{
146    struct usb_device_request req;
147
148    req.bType.direction = USB_REQUEST_WRITE;
149    req.bType.recipient = USB_REQUEST_RECIPIENT_DEVICE;
150    req.bType.type = USB_REQUEST_TYPE_CLASS;
151    req.bRequest = USB_HUB_REQ_SET_FEATURE;
152    req.wValue = feature;
153    req.wLength = 0;
154    req.wIndex = 0;
155    return (usb_exec_request(hub, 0, &req, NULL, NULL));
156}
157
158usb_error_t usb_hub_set_port_feature(struct usb_device *hub, uint16_t feature,
159        uint8_t port)
160{
161    struct usb_device_request req;
162
163    req.bType.direction = USB_REQUEST_WRITE;
164    req.bType.recipient = USB_REQUEST_RECIPIENT_OTHER;
165    req.bType.type = USB_REQUEST_TYPE_CLASS;
166    req.bRequest = USB_HUB_REQ_SET_FEATURE;
167    req.wValue = feature;
168    req.wLength = 0;
169    req.wIndex = port;
170    return (usb_exec_request(hub, 0, &req, NULL, NULL));
171}
172
173usb_error_t usb_hub_get_tt_state(struct usb_device *hub, uint16_t flags,
174        uint16_t port, uint16_t max_length, uint16_t ret_length,
175        void *ret_state)
176{
177    assert(!"NYI: usb_hub_get_tt_state()\n");
178    return (USB_ERR_BAD_REQUEST);
179}
180
181usb_error_t usb_hub_stop_tt(struct usb_device *hub, uint16_t port)
182{
183    assert(!"NYI: usb_hub_stop_tt()\n");
184    return (USB_ERR_BAD_REQUEST);
185}
186
187usb_error_t usb_hub_get_hub_descriptor(struct usb_device *hub, uint16_t nports,
188        struct usb_hub_descriptor *ret_desc)
189{
190    USB_DEBUG_TR_ENTER;
191    struct usb_device_request req;
192
193    uint16_t wLength = (nports + 7 + (8 * 8)) / 8;
194
195    req.bType.direction = USB_REQUEST_READ;
196    req.bType.recipient = USB_REQUEST_RECIPIENT_DEVICE;
197    req.bType.type = USB_REQUEST_TYPE_CLASS;
198    req.bRequest = USB_HUB_REQ_GET_DESCRIPTOR;
199    req.wValue = USB_DESCRIPTOR_TYPE_HUB<<8;
200    req.wLength = wLength;
201    req.wIndex = 0;
202    return (usb_exec_request(hub, 0, &req, ret_desc, NULL));
203}
204
205usb_error_t usb_hub_set_hub_descriptor(struct usb_device *hub,
206        uint16_t desc_length, struct usb_hub_descriptor *desc)
207{
208    return (USB_ERR_BAD_REQUEST);
209}
210
211usb_error_t usb_hub_re_enumerate(struct usb_device *hub)
212{
213    return (USB_ERR_BAD_REQUEST);
214}
215
216usb_error_t usb_hub_reset_port(struct usb_device *hub, uint8_t port)
217{
218    USB_DEBUG_TR_ENTER;
219    usb_error_t err;
220    struct usb_hub_port_status ps;
221
222    /* clear port reset changes (if any) */
223    err = usb_hub_clear_port_feature(hub, USB_HUB_FEATURE_C_PORT_RESET, port);
224    if (err != USB_ERR_OK) {
225        USB_DEBUG("ERROR: could not clear port reset on port %u\n", port);
226        USB_DEBUG_TR_RETURN;
227        return (err);
228    }
229
230    /* initate the rest sequence */
231    err = usb_hub_set_port_feature(hub, USB_HUB_FEATURE_PORT_RESET, port);
232    if (err != USB_ERR_OK) {
233        USB_DEBUG("ERROR: port reset could not reset port %u\n", port);
234        USB_DEBUG_TR_RETURN;
235        return (err);
236    }
237
238    uint16_t timeout = 0;
239
240    /* wait till the reset sequence is over */
241    while (1) {
242        lib_usb_wait(USB_DELAY_PORT_RESET);
243
244        timeout += USB_DELAY_PORT_RESET;
245
246        err = usb_hub_get_port_status(hub, port, &ps);
247        if (err != USB_ERR_OK) {
248            USB_DEBUG("ERROR: could not get port status\n");
249            USB_DEBUG_TR_RETURN;
250            return (err);
251        }
252
253        if (!ps.wPortStatus.connection) {
254            /* the devie has disappeared, so give up */
255            USB_DEBUG("NOTICE: Device %i has disappeared...\n", hub->device_address);
256            USB_DEBUG_TR_RETURN;
257            return (err);
258        }
259
260        if (ps.wPortChange.is_reset) {
261            /* the reset sequence is over */
262            break;
263        }
264
265        if (!ps.wPortStatus.reset) {
266            /* check if reset is no longer asserted */
267            break;
268        }
269
270        if (timeout > 10000) {
271            timeout = 0;
272            break;
273        }
274    }
275
276    /*
277     * clear the port reset feature, just in case it was not cleared
278     * automatically
279     */
280    err = usb_hub_clear_port_feature(hub, USB_HUB_FEATURE_C_PORT_RESET, port);
281    if (err != USB_ERR_OK) {
282        USB_DEBUG("ERROR: Could not reset port feature\n");
283        USB_DEBUG_TR_RETURN;
284        return (err);
285    }
286
287    if (timeout == 0) {
288        USB_DEBUG("ERROR: timeout happened during reset\n");
289        USB_DEBUG_TR_RETURN;
290        return (USB_ERR_TIMEOUT);
291    }
292
293    /* give the device time to recover from reset */
294    lib_usb_wait(USB_DELAY_PORT_RECOVERY);
295
296    USB_DEBUG_TR_RETURN;
297    return (err);
298}
299
300