source: mainline/uspace/lib/usb/src/usbdrvreq.c@ 3b77628

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

Doxygen comment fixes

Mainly proper subgrouping and some missing @param comments.

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 * Copyright (c) 2010 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 * @brief USB driver - standard USB requests (implementation).
34 */
35#include <usb/usbdrv.h>
36#include <errno.h>
37
38/** Prepare USB target for control endpoint.
39 *
40 * @param name Variable name with the USB target.
41 * @param target_address Target USB address.
42 */
43#define PREPARE_TARGET(name, target_address) \
44 usb_target_t name = { \
45 .address = target_address, \
46 .endpoint = 0 \
47 }
48
49/** Prepare setup packet.
50 *
51 * @param name Variable name with the setup packet.
52 * @param p_direction Data transfer direction.
53 * @param p_type Request type (standard/class/vendor)
54 * @param p_recipient Recipient of the request.
55 * @param p_request Request.
56 * @param p_value wValue field of setup packet.
57 * @param p_index wIndex field of setup packet.
58 * @param p_length Length of extra data.
59 */
60#define PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, \
61 p_request, p_value, p_index, p_length) \
62 usb_device_request_setup_packet_t name = { \
63 .request_type = \
64 ((p_direction) == USB_DIRECTION_IN ? 128 : 0) \
65 | ((p_type) << 5) \
66 | (p_recipient), \
67 .request = (p_request), \
68 { .value = (p_value) }, \
69 .index = (p_index), \
70 .length = (p_length) \
71 }
72
73/** Prepare setup packet.
74 *
75 * @param name Variable name with the setup packet.
76 * @param p_direction Data transfer direction.
77 * @param p_type Request type (standard/class/vendor)
78 * @param p_recipient Recipient of the request.
79 * @param p_request Request.
80 * @param p_value_low wValue field of setup packet (low byte).
81 * @param p_value_high wValue field of setup packet (high byte).
82 * @param p_index wIndex field of setup packet.
83 * @param p_length Length of extra data.
84 */
85#define PREPARE_SETUP_PACKET_LOHI(name, p_direction, p_type, p_recipient, \
86 p_request, p_value_low, p_value_high, p_index, p_length) \
87 PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, \
88 p_request, (p_value_low) | ((p_value_high) << 8), \
89 p_index, p_length)
90
91/** Retrieve status of a USB device.
92 *
93 * @param[in] hc_phone Open phone to HC driver.
94 * @param[in] address Device address.
95 * @param[in] recipient Recipient of the request.
96 * @param[in] recipient_index Index of @p recipient.
97 * @param[out] status Status (see figure 9-4 in USB 1.1 specification).
98 * @return Error code.
99 */
100int usb_drv_req_get_status(int hc_phone, usb_address_t address,
101 usb_request_recipient_t recipient, uint16_t recipient_index,
102 uint16_t *status)
103{
104 if (status == NULL) {
105 return EBADMEM;
106 }
107
108 PREPARE_TARGET(target, address);
109
110 PREPARE_SETUP_PACKET(setup_packet,
111 USB_DIRECTION_IN, USB_REQUEST_TYPE_STANDARD,
112 recipient, USB_DEVREQ_GET_STATUS, 0, recipient_index, 2);
113
114 size_t transfered;
115 uint16_t tmp_status;
116 int rc = usb_drv_psync_control_read(hc_phone, target,
117 &setup_packet, sizeof(setup_packet), &tmp_status, 2, &transfered);
118 if (rc != EOK) {
119 return rc;
120 }
121 if (transfered != 2) {
122 return ERANGE;
123 }
124
125 *status = tmp_status;
126
127 return EOK;
128}
129
130/** Clear or disable USB device feature.
131 *
132 * @param[in] hc_phone Open phone to HC driver.
133 * @param[in] address Device address.
134 * @param[in] recipient Recipient of the request.
135 * @param[in] selector Feature selector.
136 * @param[in] index Index of @p recipient.
137 * @return Error code.
138 */
139int usb_drv_req_clear_feature(int hc_phone, usb_address_t address,
140 usb_request_recipient_t recipient,
141 uint16_t selector, uint16_t index)
142{
143 PREPARE_TARGET(target, address);
144
145 PREPARE_SETUP_PACKET(setup_packet,
146 USB_DIRECTION_OUT, USB_REQUEST_TYPE_STANDARD,
147 recipient, USB_DEVREQ_CLEAR_FEATURE, selector, index, 0);
148
149 int rc = usb_drv_psync_control_write(hc_phone, target,
150 &setup_packet, sizeof(setup_packet), NULL, 0);
151
152 return rc;
153}
154
155/** Set or enable USB device feature.
156 *
157 * @param[in] hc_phone Open phone to HC driver.
158 * @param[in] address Device address.
159 * @param[in] recipient Recipient of the request.
160 * @param[in] selector Feature selector.
161 * @param[in] index Index of @p recipient.
162 * @return Error code.
163 */
164int usb_drv_req_set_feature(int hc_phone, usb_address_t address,
165 usb_request_recipient_t recipient,
166 uint16_t selector, uint16_t index)
167{
168 PREPARE_TARGET(target, address);
169
170 PREPARE_SETUP_PACKET(setup_packet,
171 USB_DIRECTION_OUT, USB_REQUEST_TYPE_STANDARD,
172 recipient, USB_DEVREQ_SET_FEATURE, selector, index, 0);
173
174 int rc = usb_drv_psync_control_write(hc_phone, target,
175 &setup_packet, sizeof(setup_packet), NULL, 0);
176
177 return rc;
178}
179
180/** Change address of connected device.
181 *
182 * @see usb_drv_reserve_default_address
183 * @see usb_drv_release_default_address
184 * @see usb_drv_request_address
185 * @see usb_drv_release_address
186 * @see usb_drv_bind_address
187 *
188 * @param[in] phone Open phone to HC driver.
189 * @param[in] old_address Current address.
190 * @param[in] new_address Address to be set.
191 * @return Error code.
192 */
193int usb_drv_req_set_address(int phone, usb_address_t old_address,
194 usb_address_t new_address)
195{
196 PREPARE_TARGET(target, old_address);
197
198 PREPARE_SETUP_PACKET(setup_packet, USB_DIRECTION_OUT,
199 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
200 USB_DEVREQ_SET_ADDRESS, new_address, 0, 0);
201
202 int rc = usb_drv_psync_control_write(phone, target,
203 &setup_packet, sizeof(setup_packet), NULL, 0);
204
205 return rc;
206}
207
208/** Retrieve USB descriptor of connected USB device.
209 *
210 * @param[in] hc_phone Open phone to HC driver.
211 * @param[in] address Device address.
212 * @param[in] request_type Request type (standard/class/vendor).
213 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
214 * @param[in] descriptor_index Descriptor index.
215 * @param[in] language Language index.
216 * @param[out] buffer Buffer where to store the retrieved descriptor.
217 * @param[in] size Size of the @p buffer.
218 * @param[out] actual_size Number of bytes actually transferred.
219 * @return Error code.
220 */
221int usb_drv_req_get_descriptor(int hc_phone, usb_address_t address,
222 usb_request_type_t request_type,
223 uint8_t descriptor_type, uint8_t descriptor_index,
224 uint16_t language,
225 void *buffer, size_t size, size_t *actual_size)
226{
227 if (buffer == NULL) {
228 return EBADMEM;
229 }
230 if (size == 0) {
231 return EINVAL;
232 }
233
234 // FIXME: check that size is not too big
235
236 PREPARE_TARGET(target, address);
237
238 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_IN,
239 request_type, USB_REQUEST_RECIPIENT_DEVICE,
240 USB_DEVREQ_GET_DESCRIPTOR, descriptor_index, descriptor_type,
241 language, size);
242
243 int rc = usb_drv_psync_control_read(hc_phone, target,
244 &setup_packet, sizeof(setup_packet),
245 buffer, size, actual_size);
246
247 return rc;
248}
249
250/** Retrieve device descriptor of connected USB device.
251 *
252 * @param[in] phone Open phone to HC driver.
253 * @param[in] address Device address.
254 * @param[out] descriptor Storage for the device descriptor.
255 * @return Error code.
256 * @retval EBADMEM @p descriptor is NULL.
257 */
258int usb_drv_req_get_device_descriptor(int phone, usb_address_t address,
259 usb_standard_device_descriptor_t *descriptor)
260{
261 if (descriptor == NULL) {
262 return EBADMEM;
263 }
264
265 size_t actually_transferred = 0;
266 usb_standard_device_descriptor_t descriptor_tmp;
267 int rc = usb_drv_req_get_descriptor(phone, address,
268 USB_REQUEST_TYPE_STANDARD,
269 USB_DESCTYPE_DEVICE, 0,
270 0,
271 &descriptor_tmp, sizeof(descriptor_tmp),
272 &actually_transferred);
273
274 if (rc != EOK) {
275 return rc;
276 }
277
278 /* Verify that all data has been transferred. */
279 if (actually_transferred < sizeof(descriptor_tmp)) {
280 return ELIMIT;
281 }
282
283 /* Everything is okay, copy the descriptor. */
284 memcpy(descriptor, &descriptor_tmp,
285 sizeof(descriptor_tmp));
286
287 return EOK;
288}
289
290
291/** Retrieve configuration descriptor of connected USB device.
292 *
293 * The function does not retrieve additional data binded with configuration
294 * descriptor (such as its interface and endpoint descriptors) - use
295 * usb_drv_req_get_full_configuration_descriptor() instead.
296 *
297 * @param[in] phone Open phone to HC driver.
298 * @param[in] address Device address.
299 * @param[in] index Configuration descriptor index.
300 * @param[out] descriptor Storage for the configuration descriptor.
301 * @return Error code.
302 * @retval EBADMEM @p descriptor is NULL.
303 */
304int usb_drv_req_get_bare_configuration_descriptor(int phone,
305 usb_address_t address, int index,
306 usb_standard_configuration_descriptor_t *descriptor)
307{
308 if (descriptor == NULL) {
309 return EBADMEM;
310 }
311
312 size_t actually_transferred = 0;
313 usb_standard_configuration_descriptor_t descriptor_tmp;
314 int rc = usb_drv_req_get_descriptor(phone, address,
315 USB_REQUEST_TYPE_STANDARD,
316 USB_DESCTYPE_CONFIGURATION, 0,
317 0,
318 &descriptor_tmp, sizeof(descriptor_tmp),
319 &actually_transferred);
320
321 if (rc != EOK) {
322 return rc;
323 }
324
325 /* Verify that all data has been transferred. */
326 if (actually_transferred < sizeof(descriptor_tmp)) {
327 return ELIMIT;
328 }
329
330 /* Everything is okay, copy the descriptor. */
331 memcpy(descriptor, &descriptor_tmp,
332 sizeof(descriptor_tmp));
333
334 return EOK;
335}
336
337/** Retrieve full configuration descriptor of connected USB device.
338 *
339 * @warning The @p buffer might be touched (i.e. its contents changed)
340 * even when error occurs.
341 *
342 * @param[in] phone Open phone to HC driver.
343 * @param[in] address Device address.
344 * @param[in] index Configuration descriptor index.
345 * @param[out] buffer Buffer for the whole configuration descriptor.
346 * @param[in] buffer_size Size of the prepared @p buffer.
347 * @param[out] actual_buffer_size Bytes actually transfered.
348 * @return Error code.
349 * @retval EBADMEM @p descriptor is NULL.
350 */
351int usb_drv_req_get_full_configuration_descriptor(int phone,
352 usb_address_t address, int index,
353 void *buffer, size_t buffer_size, size_t *actual_buffer_size)
354{
355 int rc = usb_drv_req_get_descriptor(phone, address,
356 USB_REQUEST_TYPE_STANDARD,
357 USB_DESCTYPE_CONFIGURATION, 0,
358 0,
359 buffer, buffer_size,
360 actual_buffer_size);
361
362 return rc;
363}
364
365/** Update existing descriptor of a USB device.
366 *
367 * @param[in] hc_phone Open phone to HC driver.
368 * @param[in] address Device address.
369 * @param[in] descriptor_type Descriptor type (device/configuration/...).
370 * @param[in] descriptor_index Descriptor index.
371 * @param[in] language Language index.
372 * @param[in] descriptor Actual descriptor data.
373 * @param[in] descriptor_size Descriptor size.
374 * @return Error code.
375 */
376int usb_drv_req_set_descriptor(int hc_phone, usb_address_t address,
377 uint8_t descriptor_type, uint8_t descriptor_index,
378 uint16_t language,
379 void *descriptor, size_t descriptor_size)
380{
381 // FIXME: check that descriptor is not too big
382
383 PREPARE_TARGET(target, address);
384
385 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
386 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
387 USB_DEVREQ_SET_DESCRIPTOR, descriptor_index, descriptor_type,
388 language, descriptor_size);
389
390 int rc = usb_drv_psync_control_write(hc_phone, target,
391 &setup_packet, sizeof(setup_packet),
392 descriptor, descriptor_size);
393
394 return rc;
395}
396
397/** Determine current configuration value of USB device.
398 *
399 * @param[in] hc_phone Open phone to HC driver.
400 * @param[in] address Device address.
401 * @param[out] configuration_value Current configuration value.
402 * @return Error code.
403 */
404int usb_drv_req_get_configuration(int hc_phone, usb_address_t address,
405 uint8_t *configuration_value)
406{
407 if (configuration_value == NULL) {
408 return EBADMEM;
409 }
410
411 PREPARE_TARGET(target, address);
412
413 PREPARE_SETUP_PACKET(setup_packet, USB_DIRECTION_IN,
414 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
415 USB_DEVREQ_GET_CONFIGURATION, 0, 0, 1);
416
417 uint8_t value;
418 size_t transfered;
419 int rc = usb_drv_psync_control_read(hc_phone, target,
420 &setup_packet, sizeof(setup_packet), &value, 1, &transfered);
421
422 if (rc != EOK) {
423 return rc;
424 }
425
426 if (transfered != 1) {
427 return ERANGE;
428 }
429
430 *configuration_value = value;
431
432 return EOK;
433}
434
435/** Set configuration of USB device.
436 *
437 * @param[in] hc_phone Open phone to HC driver.
438 * @param[in] address Device address.
439 * @param[in] configuration_value New configuration value.
440 * @return Error code.
441 */
442int usb_drv_req_set_configuration(int hc_phone, usb_address_t address,
443 uint8_t configuration_value)
444{
445 PREPARE_TARGET(target, address);
446
447 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
448 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
449 USB_DEVREQ_SET_CONFIGURATION, configuration_value, 0,
450 0, 0);
451
452 int rc = usb_drv_psync_control_write(hc_phone, target,
453 &setup_packet, sizeof(setup_packet), NULL, 0);
454
455 return rc;
456}
457
458/** Determine alternate setting of USB device interface.
459 *
460 * @param[in] hc_phone Open phone to HC driver.
461 * @param[in] address Device address.
462 * @param[in] interface_index Interface index.
463 * @param[out] alternate_setting Value of alternate setting.
464 * @return Error code.
465 */
466int usb_drv_req_get_interface(int hc_phone, usb_address_t address,
467 uint16_t interface_index, uint8_t *alternate_setting)
468{
469 if (alternate_setting == NULL) {
470 return EBADMEM;
471 }
472
473 PREPARE_TARGET(target, address);
474
475 PREPARE_SETUP_PACKET(setup_packet, USB_DIRECTION_IN,
476 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
477 USB_DEVREQ_GET_INTERFACE, 0, interface_index, 1);
478
479 uint8_t alternate;
480 size_t transfered;
481 int rc = usb_drv_psync_control_read(hc_phone, target,
482 &setup_packet, sizeof(setup_packet), &alternate, 1, &transfered);
483
484 if (rc != EOK) {
485 return rc;
486 }
487
488 if (transfered != 1) {
489 return ERANGE;
490 }
491
492 *alternate_setting = alternate;
493
494 return EOK;
495}
496
497/** Select an alternate setting of USB device interface.
498 *
499 * @param[in] hc_phone Open phone to HC driver.
500 * @param[in] address Device address.
501 * @param[in] interface_index Interface index.
502 * @param[in] alternate_setting Value of alternate setting.
503 * @return Error code.
504 */
505int usb_drv_req_set_interface(int hc_phone, usb_address_t address,
506 uint16_t interface_index, uint8_t alternate_setting)
507{
508 PREPARE_TARGET(target, address);
509
510 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
511 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
512 USB_DEVREQ_SET_INTERFACE, alternate_setting, 0,
513 0, 0);
514
515 int rc = usb_drv_psync_control_write(hc_phone, target,
516 &setup_packet, sizeof(setup_packet), NULL, 0);
517
518 return rc;
519}
520
521/**
522 * @}
523 */
Note: See TracBrowser for help on using the repository browser.