source: mainline/uspace/lib/usbhost/src/usb2_bus.c@ e0a5d4c

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

usb: update copyrights

The data was generated by a script, guided manually. If you feel your
name is missing somewhere, please add it!

The semi-automated process was roughly:

1) Changes per file and author (limited to our team) were counted
2) Trivial numbers were thrown away
3) Authors were sorted by lines added to file
4) All previous copyrights were replaced by the newly generated one
5) Hunks changing only year were discarded

It seems that a lot of my copyrights were added. It is due to me being
both sticking my nose everywhere and lazy to update the copyright right
away :)

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/** @addtogroup libusbhost
30 * @{
31 */
32/** @file
33 *
34 * A bus_t implementation for USB 2 and lower. Implements USB 2 enumeration and
35 * configurable bandwidth counting.
36 */
37
38#include <assert.h>
39#include <errno.h>
40#include <macros.h>
41#include <stdbool.h>
42#include <stdlib.h>
43#include <str_error.h>
44#include <usb/debug.h>
45#include <usb/descriptor.h>
46#include <usb/request.h>
47#include <usb/host/utility.h>
48#include <usb/usb.h>
49
50#include "endpoint.h"
51#include "ddf_helpers.h"
52
53#include "usb2_bus.h"
54
55/**
56 * Request a new address. A free address is found and marked as occupied.
57 *
58 * There's no need to synchronize this method, because it is called only with
59 * default address reserved.
60 *
61 * @param bus usb_device_manager
62 * @param addr Pointer to requested address value, place to store new address
63 */
64static int request_address(usb2_bus_helper_t *helper, usb_address_t *addr)
65{
66 // Find a free address
67 usb_address_t new_address = helper->last_address;
68 do {
69 new_address = (new_address + 1) % USB_ADDRESS_COUNT;
70 if (new_address == USB_ADDRESS_DEFAULT)
71 new_address = 1;
72 if (new_address == helper->last_address)
73 return ENOSPC;
74 } while (helper->address_occupied[new_address]);
75 helper->last_address = new_address;
76
77 *addr = new_address;
78 helper->address_occupied[*addr] = true;
79
80 return EOK;
81}
82
83/**
84 * Mark address as free.
85 */
86static void release_address(usb2_bus_helper_t *helper, usb_address_t address)
87{
88 helper->address_occupied[address] = false;
89}
90
91static const usb_target_t usb2_default_target = {{
92 .address = USB_ADDRESS_DEFAULT,
93 .endpoint = 0,
94}};
95
96/**
97 * Transition the device to the addressed state.
98 *
99 * Reserve address, configure the control EP, issue a SET_ADDRESS command.
100 * Configure the device with the new address,
101 */
102static int address_device(usb2_bus_helper_t *helper, device_t *dev)
103{
104 int err;
105
106 /* The default address is currently reserved for this device */
107 dev->address = USB_ADDRESS_DEFAULT;
108
109 /** Reserve address early, we want pretty log messages */
110 usb_address_t address = USB_ADDRESS_DEFAULT;
111 if ((err = request_address(helper, &address))) {
112 usb_log_error("Failed to reserve new address: %s.",
113 str_error(err));
114 return err;
115 }
116 usb_log_debug("Device(%d): Reserved new address.", address);
117
118 /* Add default pipe on default address */
119 usb_log_debug("Device(%d): Adding default target (0:0)", address);
120
121 usb_endpoint_descriptors_t ep0_desc = {
122 .endpoint.max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,
123 };
124
125 /* Temporary reference */
126 endpoint_t *default_ep;
127 err = bus_endpoint_add(dev, &ep0_desc, &default_ep);
128 if (err != EOK) {
129 usb_log_error("Device(%d): Failed to add default target: %s.",
130 address, str_error(err));
131 goto err_address;
132 }
133
134 if ((err = hc_get_ep0_max_packet_size(&ep0_desc.endpoint.max_packet_size, dev)))
135 goto err_address;
136
137 /* Set new address */
138 const usb_device_request_setup_packet_t set_address = SET_ADDRESS(address);
139
140 usb_log_debug("Device(%d): Setting USB address.", address);
141 err = bus_device_send_batch_sync(dev, usb2_default_target, USB_DIRECTION_OUT,
142 NULL, 0, *(uint64_t *)&set_address, "set address", NULL);
143 if (err) {
144 usb_log_error("Device(%d): Failed to set new address: %s.",
145 address, str_error(err));
146 goto err_default_control_ep;
147 }
148
149 /* We need to remove ep before we change the address */
150 if ((err = bus_endpoint_remove(default_ep))) {
151 usb_log_error("Device(%d): Failed to unregister default target: %s", address, str_error(err));
152 goto err_address;
153 }
154
155 /* Temporary reference */
156 endpoint_del_ref(default_ep);
157
158 dev->address = address;
159
160 /* Register EP on the new address */
161 usb_log_debug("Device(%d): Registering control EP.", address);
162 err = bus_endpoint_add(dev, &ep0_desc, NULL);
163 if (err != EOK) {
164 usb_log_error("Device(%d): Failed to register EP0: %s",
165 address, str_error(err));
166 goto err_address;
167 }
168
169 return EOK;
170
171err_default_control_ep:
172 bus_endpoint_remove(default_ep);
173 /* Temporary reference */
174 endpoint_del_ref(default_ep);
175err_address:
176 release_address(helper, address);
177 return err;
178}
179
180/**
181 * Enumerate a USB device. Move it to the addressed state, then explore it
182 * to create a DDF function node with proper characteristics.
183 */
184int usb2_bus_device_enumerate(usb2_bus_helper_t *helper, device_t *dev)
185{
186 int err;
187 usb_log_debug("Found new %s speed USB device.", usb_str_speed(dev->speed));
188
189 /* Assign an address to the device */
190 if ((err = address_device(helper, dev))) {
191 usb_log_error("Failed to setup address of the new device: %s", str_error(err));
192 return err;
193 }
194
195 /* Read the device descriptor, derive the match ids */
196 if ((err = hc_device_explore(dev))) {
197 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
198 release_address(helper, dev->address);
199 return err;
200 }
201
202 return EOK;
203}
204
205void usb2_bus_device_gone(usb2_bus_helper_t *helper, device_t *dev)
206{
207 release_address(helper, dev->address);
208}
209
210/**
211 * Register an endpoint to the bus. Reserves bandwidth.
212 */
213int usb2_bus_endpoint_register(usb2_bus_helper_t *helper, endpoint_t *ep)
214{
215 assert(ep);
216 assert(fibril_mutex_is_locked(&ep->device->guard));
217
218 size_t bw = helper->bw_accounting->count_bw(ep);
219
220 /* Check for available bandwidth */
221 if (bw > helper->free_bw)
222 return ENOSPC;
223
224 helper->free_bw -= bw;
225
226 return EOK;
227}
228
229/**
230 * Release bandwidth reserved by the given endpoint.
231 */
232void usb2_bus_endpoint_unregister(usb2_bus_helper_t *helper, endpoint_t *ep)
233{
234 assert(helper);
235 assert(ep);
236
237 helper->free_bw += helper->bw_accounting->count_bw(ep);
238}
239
240/**
241 * Initialize to default state.
242 *
243 * @param helper usb_bus_helper structure, non-null.
244 * @param bw_accounting a structure defining bandwidth accounting
245 */
246void usb2_bus_helper_init(usb2_bus_helper_t *helper, const bandwidth_accounting_t *bw_accounting)
247{
248 assert(helper);
249 assert(bw_accounting);
250
251 helper->bw_accounting = bw_accounting;
252 helper->free_bw = bw_accounting->available_bandwidth;
253
254 /*
255 * The first address allocated is for the roothub. This way, its
256 * address will be 127, and the first connected USB device will have
257 * address 1.
258 */
259 helper->last_address = USB_ADDRESS_COUNT - 2;
260}
261
262/**
263 * @}
264 */
Note: See TracBrowser for help on using the repository browser.