source: mainline/uspace/lib/usb/src/request.c@ 0f21c0c

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

Removal of API that use phones directly

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