source: mainline/uspace/lib/usb/src/request.c@ 1b6e52f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1b6e52f was abe8ac5, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Add most needed pipe wrappers for USB requests

Only requests so far needed were implemented now.

This commit might have bugs as no device driver actually uses these
requests.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
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 libusb
30 * @{
31 */
32/** @file
33 * Standard USB requests (implementation).
34 */
35#include <usb/request.h>
36#include <usb/devreq.h>
37#include <errno.h>
38
39#define MAX_DATA_LENGTH ((size_t)(0xFFFF))
40
41/** Generic wrapper for SET requests using standard control request format.
42 *
43 * @see usb_endpoint_pipe_control_write
44 *
45 * @param pipe Pipe used for the communication.
46 * @param request_type Request type (standard/class/vendor).
47 * @param recipient Request recipient (e.g. device or endpoint).
48 * @param request Actual request (e.g. GET_DESCRIPTOR).
49 * @param value Value of @c wValue field of setup packet
50 * (must be in USB endianness).
51 * @param index Value of @c wIndex field of setup packet
52 * (must be in USB endianness).
53 * @param data Data to be sent during DATA stage
54 * (expected to be in USB endianness).
55 * @param data_size Size of the @p data buffer (in native endianness).
56 * @return Error code.
57 * @retval EBADMEM @p pipe is NULL.
58 * @retval EBADMEM @p data is NULL and @p data_size is not zero.
59 * @retval ERANGE Data buffer too large.
60 */
61int usb_control_request_set(usb_endpoint_pipe_t *pipe,
62 usb_request_type_t request_type, usb_request_recipient_t recipient,
63 uint8_t request,
64 uint16_t value, uint16_t index,
65 void *data, size_t data_size)
66{
67 if (pipe == NULL) {
68 return EBADMEM;
69 }
70
71 if (data_size > MAX_DATA_LENGTH) {
72 return ERANGE;
73 }
74
75 if ((data_size > 0) && (data == NULL)) {
76 return EBADMEM;
77 }
78
79 /*
80 * TODO: check that @p request_type and @p recipient are
81 * within ranges.
82 */
83
84 usb_device_request_setup_packet_t setup_packet;
85 setup_packet.request_type = (request_type << 5) | recipient;
86 setup_packet.request = request;
87 setup_packet.value = value;
88 setup_packet.index = index;
89 setup_packet.length = (uint16_t) data_size;
90
91 int rc = usb_endpoint_pipe_control_write(pipe,
92 &setup_packet, sizeof(setup_packet),
93 data, data_size);
94
95 return rc;
96}
97
98 /** Generic wrapper for GET requests using standard control request format.
99 *
100 * @see usb_endpoint_pipe_control_read
101 *
102 * @param pipe Pipe used for the communication.
103 * @param request_type Request type (standard/class/vendor).
104 * @param recipient Request recipient (e.g. device or endpoint).
105 * @param request Actual request (e.g. GET_DESCRIPTOR).
106 * @param value Value of @c wValue field of setup packet
107 * (must be in USB endianness).
108 * @param index Value of @c wIndex field of setup packet
109 * (must be in USB endianness).
110 * @param data Buffer where to store data accepted during the DATA stage.
111 * (they will come in USB endianess).
112 * @param data_size Size of the @p data buffer
113 * (in native endianness).
114 * @param actual_data_size Actual size of transfered data
115 * (in native endianness).
116 * @return Error code.
117 * @retval EBADMEM @p pipe is NULL.
118 * @retval EBADMEM @p data is NULL and @p data_size is not zero.
119 * @retval ERANGE Data buffer too large.
120 */
121int usb_control_request_get(usb_endpoint_pipe_t *pipe,
122 usb_request_type_t request_type, usb_request_recipient_t recipient,
123 uint8_t request,
124 uint16_t value, uint16_t index,
125 void *data, size_t data_size, size_t *actual_data_size)
126{
127 if (pipe == NULL) {
128 return EBADMEM;
129 }
130
131 if (data_size > MAX_DATA_LENGTH) {
132 return ERANGE;
133 }
134
135 if ((data_size > 0) && (data == NULL)) {
136 return EBADMEM;
137 }
138
139 /*
140 * TODO: check that @p request_type and @p recipient are
141 * within ranges.
142 */
143
144 usb_device_request_setup_packet_t setup_packet;
145 setup_packet.request_type = 128 | (request_type << 5) | recipient;
146 setup_packet.request = request;
147 setup_packet.value = value;
148 setup_packet.index = index;
149 setup_packet.length = (uint16_t) data_size;
150
151 int rc = usb_endpoint_pipe_control_read(pipe,
152 &setup_packet, sizeof(setup_packet),
153 data, data_size, actual_data_size);
154
155 return rc;
156}
157
158/** Change address of connected device.
159 * This function automatically updates the backing connection to point to
160 * the new address.
161 *
162 * @see usb_drv_reserve_default_address
163 * @see usb_drv_release_default_address
164 * @see usb_drv_request_address
165 * @see usb_drv_release_address
166 * @see usb_drv_bind_address
167 *
168 * @param pipe Control endpoint pipe (session must be already started).
169 * @param new_address New USB address to be set.
170 * @return Error code.
171 */
172int usb_request_set_address(usb_endpoint_pipe_t *pipe,
173 usb_address_t new_address)
174{
175 if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
176 return EINVAL;
177 }
178
179 int rc = usb_control_request_set(pipe,
180 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
181 USB_DEVREQ_SET_ADDRESS,
182 new_address, 0,
183 NULL, 0);
184
185 if (rc != EOK) {
186 return rc;
187 }
188
189 assert(pipe->wire != NULL);
190 /* TODO: prevent other from accessing wire now. */
191 pipe->wire->address = new_address;
192
193 return EOK;
194}
195
196/** Retrieve USB descriptor of a USB device.
197 *
198 * @param[in] pipe Control endpoint pipe (session must be already started).
199 * @param[in] request_type Request type (standard/class/vendor).
200 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
201 * @param[in] descriptor_index Descriptor index.
202 * @param[in] language Language index.
203 * @param[out] buffer Buffer where to store the retrieved descriptor.
204 * @param[in] size Size of the @p buffer.
205 * @param[out] actual_size Number of bytes actually transferred.
206 * @return Error code.
207 */
208int usb_request_get_descriptor(usb_endpoint_pipe_t *pipe,
209 usb_request_type_t request_type,
210 uint8_t descriptor_type, uint8_t descriptor_index,
211 uint16_t language,
212 void *buffer, size_t size, size_t *actual_size)
213{
214 if (buffer == NULL) {
215 return EBADMEM;
216 }
217 if (size == 0) {
218 return EINVAL;
219 }
220
221 uint16_t wValue = descriptor_index | (descriptor_type << 8);
222
223 return usb_control_request_get(pipe,
224 request_type, USB_REQUEST_RECIPIENT_DEVICE,
225 USB_DEVREQ_GET_DESCRIPTOR,
226 wValue, language,
227 buffer, size, actual_size);
228}
229
230/** Retrieve standard device descriptor of a USB device.
231 *
232 * @param[in] pipe Control endpoint pipe (session must be already started).
233 * @param[out] descriptor Storage for the device descriptor.
234 * @return Error code.
235 */
236int usb_request_get_device_descriptor(usb_endpoint_pipe_t *pipe,
237 usb_standard_device_descriptor_t *descriptor)
238{
239 if (descriptor == NULL) {
240 return EBADMEM;
241 }
242
243 size_t actually_transferred = 0;
244 usb_standard_device_descriptor_t descriptor_tmp;
245 int rc = usb_request_get_descriptor(pipe,
246 USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_DEVICE,
247 0, 0,
248 &descriptor_tmp, sizeof(descriptor_tmp),
249 &actually_transferred);
250
251 if (rc != EOK) {
252 return rc;
253 }
254
255 /* Verify that all data has been transferred. */
256 if (actually_transferred < sizeof(descriptor_tmp)) {
257 return ELIMIT;
258 }
259
260 /* Everything is okay, copy the descriptor. */
261 memcpy(descriptor, &descriptor_tmp,
262 sizeof(descriptor_tmp));
263
264 return EOK;
265}
266
267/** Retrieve configuration descriptor of a USB device.
268 *
269 * The function does not retrieve additional data binded with configuration
270 * descriptor (such as its interface and endpoint descriptors) - use
271 * usb_request_get_full_configuration_descriptor() instead.
272 *
273 * @param[in] pipe Control endpoint pipe (session must be already started).
274 * @param[in] index Descriptor index.
275 * @param[out] descriptor Storage for the device descriptor.
276 * @return Error code.
277 */
278int usb_request_get_bare_configuration_descriptor(usb_endpoint_pipe_t *pipe,
279 int index, usb_standard_configuration_descriptor_t *descriptor)
280{
281 if (descriptor == NULL) {
282 return EBADMEM;
283 }
284
285 if ((index < 0) || (index > 0xFF)) {
286 return ERANGE;
287 }
288
289 size_t actually_transferred = 0;
290 usb_standard_configuration_descriptor_t descriptor_tmp;
291 int rc = usb_request_get_descriptor(pipe,
292 USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_CONFIGURATION,
293 index, 0,
294 &descriptor_tmp, sizeof(descriptor_tmp),
295 &actually_transferred);
296 if (rc != EOK) {
297 return rc;
298 }
299
300 /* Verify that all data has been transferred. */
301 if (actually_transferred < sizeof(descriptor_tmp)) {
302 return ELIMIT;
303 }
304
305 /* Everything is okay, copy the descriptor. */
306 memcpy(descriptor, &descriptor_tmp,
307 sizeof(descriptor_tmp));
308
309 return EOK;
310}
311
312/** Retrieve full configuration descriptor of a USB device.
313 *
314 * @warning The @p buffer might be touched (i.e. its contents changed)
315 * even when error occurs.
316 *
317 * @param[in] pipe Control endpoint pipe (session must be already started).
318 * @param[in] index Descriptor index.
319 * @param[out] descriptor Storage for the device descriptor.
320 * @param[in] descriptor_size Size of @p descriptor buffer.
321 * @param[out] actual_size Number of bytes actually transferred.
322 * @return Error code.
323 */
324int usb_request_get_full_configuration_descriptor(usb_endpoint_pipe_t *pipe,
325 int index, void *descriptor, size_t descriptor_size, size_t *actual_size)
326{
327 if ((index < 0) || (index > 0xFF)) {
328 return ERANGE;
329 }
330
331 return usb_request_get_descriptor(pipe,
332 USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_CONFIGURATION,
333 index, 0,
334 descriptor, descriptor_size, actual_size);
335}
336
337/** Set configuration of USB device.
338 *
339 * @param pipe Control endpoint pipe (session must be already started).
340 * @param configuration_value New configuration value.
341 * @return Error code.
342 */
343int usb_request_set_configuration(usb_endpoint_pipe_t *pipe,
344 uint8_t configuration_value)
345{
346 return usb_control_request_set(pipe,
347 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
348 USB_DEVREQ_SET_CONFIGURATION, configuration_value, 0,
349 NULL, 0);
350}
351
352/**
353 * @}
354 */
Note: See TracBrowser for help on using the repository browser.