source: mainline/uspace/lib/usbdev/src/request.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: 25.6 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * Copyright (c) 2018 Ondrej Hlavaty
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
30/** @addtogroup libusbdev
31 * @{
32 */
33/** @file
34 * Standard USB requests (implementation).
35 */
36#include <usb/dev/request.h>
37#include <usb/request.h>
38#include <usb/usb.h>
39
40#include <errno.h>
41#include <mem.h>
42#include <stdlib.h>
43#include <str.h>
44
45#define MAX_DATA_LENGTH ((size_t)(0xFFFF))
46
47static_assert(sizeof(usb_device_request_setup_packet_t) == 8);
48
49/** Generic wrapper for SET requests using standard control request format.
50 *
51 * @see usb_pipe_control_write
52 *
53 * @param pipe Pipe used for the communication.
54 * @param request_type Request type (standard/class/vendor).
55 * @param recipient Request recipient (e.g. device or endpoint).
56 * @param request Actual request (e.g. GET_DESCRIPTOR).
57 * @param value Value of @c wValue field of setup packet
58 * (must be in USB endianness).
59 * @param index Value of @c wIndex field of setup packet
60 * (must be in USB endianness).
61 * @param data Data to be sent during DATA stage
62 * (expected to be in USB endianness).
63 * @param data_size Size of the @p data buffer (in native endianness).
64 *
65 * @return Error code.
66 * @retval EBADMEM @p pipe is NULL.
67 * @retval EBADMEM @p data is NULL and @p data_size is not zero.
68 * @retval ERANGE Data buffer too large.
69 *
70 */
71errno_t usb_control_request_set(usb_pipe_t *pipe,
72 usb_request_type_t request_type, usb_request_recipient_t recipient,
73 uint8_t request, uint16_t value, uint16_t index,
74 const void *data, size_t data_size)
75{
76 if (pipe == NULL) {
77 return EBADMEM;
78 }
79
80 if (data_size > MAX_DATA_LENGTH) {
81 return ERANGE;
82 }
83
84 if ((data_size > 0) && (data == NULL)) {
85 return EBADMEM;
86 }
87
88 /*
89 * TODO: check that @p request_type and @p recipient are
90 * within ranges.
91 */
92
93 const usb_device_request_setup_packet_t setup_packet = {
94 .request_type = (request_type << 5) | recipient,
95 .request = request,
96 .value = value,
97 .index = index,
98 .length = (uint16_t) data_size,
99 };
100
101 return usb_pipe_control_write(pipe,
102 &setup_packet, sizeof(setup_packet), data, data_size);
103}
104
105/** Generic wrapper for GET requests using standard control request format.
106 *
107 * @see usb_pipe_control_read
108 *
109 * @param pipe Pipe used for the communication.
110 * @param request_type Request type (standard/class/vendor).
111 * @param recipient Request recipient (e.g. device or endpoint).
112 * @param request Actual request (e.g. GET_DESCRIPTOR).
113 * @param value Value of @c wValue field of setup packet
114 * (must be in USB endianness).
115 * @param index Value of @c wIndex field of setup packet
116 * (must be in USB endianness).
117 * @param data Buffer where to store data accepted during
118 * the DATA stage (they will come in USB endianness).
119 * @param data_size Size of the @p data buffer
120 * (in native endianness).
121 * @param actual_data_size Actual size of transferred data
122 * (in native endianness).
123 *
124 * @return Error code.
125 * @retval EBADMEM @p pipe is NULL.
126 * @retval EBADMEM @p data is NULL and @p data_size is not zero.
127 * @retval ERANGE Data buffer too large.
128 *
129 */
130errno_t usb_control_request_get(usb_pipe_t *pipe,
131 usb_request_type_t request_type, usb_request_recipient_t recipient,
132 uint8_t request, uint16_t value, uint16_t index,
133 void *data, size_t data_size, size_t *actual_data_size)
134{
135 if (pipe == NULL) {
136 return EBADMEM;
137 }
138
139 if (data_size > MAX_DATA_LENGTH) {
140 return ERANGE;
141 }
142
143 if ((data_size > 0) && (data == NULL)) {
144 return EBADMEM;
145 }
146
147 /*
148 * TODO: check that @p request_type and @p recipient are
149 * within ranges.
150 */
151
152 const usb_device_request_setup_packet_t setup_packet = {
153 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST
154 | (request_type << 5) | recipient,
155 .request = request,
156 .value = uint16_host2usb(value),
157 .index = uint16_host2usb(index),
158 .length = uint16_host2usb(data_size),
159 };
160
161 return usb_pipe_control_read(pipe, &setup_packet, sizeof(setup_packet),
162 data, data_size, actual_data_size);
163}
164
165/** Retrieve status of a USB device.
166 *
167 * @param[in] pipe Control endpoint pipe (session must be already started).
168 * @param[in] index Recipient index (in native endianness).
169 * @param[in] recipient Recipient of the GET_STATUS request.
170 * @param[out] status Recipient status (in native endianness).
171 * @return Error code.
172 */
173errno_t usb_request_get_status(usb_pipe_t *pipe,
174 usb_request_recipient_t recipient, uint16_t index,
175 uint16_t *status)
176{
177 if ((recipient == USB_REQUEST_RECIPIENT_DEVICE) && (index != 0)) {
178 return EINVAL;
179 }
180
181 if (status == NULL) {
182 return EBADMEM;
183 }
184
185 uint16_t status_usb_endianess;
186 size_t data_transferred_size;
187 errno_t rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD,
188 recipient, USB_DEVREQ_GET_STATUS, 0, uint16_host2usb(index),
189 &status_usb_endianess, 2, &data_transferred_size);
190 if (rc != EOK) {
191 return rc;
192 }
193 if (data_transferred_size != 2) {
194 return ELIMIT;
195 }
196
197 *status = uint16_usb2host(status_usb_endianess);
198
199 return EOK;
200}
201
202/** Clear or disable specific device feature.
203 *
204 * @param[in] pipe Control endpoint pipe (session must be already started).
205 * @param[in] request_type Request type (standard/class/vendor).
206 * @param[in] recipient Recipient of the CLEAR_FEATURE request.
207 * @param[in] feature_selector Feature selector (in native endianness).
208 * @param[in] index Recipient index (in native endianness).
209 * @return Error code.
210 */
211errno_t usb_request_clear_feature(usb_pipe_t *pipe,
212 usb_request_type_t request_type, usb_request_recipient_t recipient,
213 uint16_t feature_selector, uint16_t index)
214{
215 if (request_type == USB_REQUEST_TYPE_STANDARD) {
216 if ((recipient == USB_REQUEST_RECIPIENT_DEVICE) && (index != 0)) {
217 return EINVAL;
218 }
219 }
220
221 return usb_control_request_set(pipe,
222 request_type, recipient, USB_DEVREQ_CLEAR_FEATURE,
223 uint16_host2usb(feature_selector), uint16_host2usb(index), NULL, 0);
224}
225
226/** Set or enable specific device feature.
227 *
228 * @param[in] pipe Control endpoint pipe (session must be already started).
229 * @param[in] request_type Request type (standard/class/vendor).
230 * @param[in] recipient Recipient of the SET_FEATURE request.
231 * @param[in] feature_selector Feature selector (in native endianness).
232 * @param[in] index Recipient index (in native endianness).
233 * @return Error code.
234 */
235errno_t usb_request_set_feature(usb_pipe_t *pipe,
236 usb_request_type_t request_type, usb_request_recipient_t recipient,
237 uint16_t feature_selector, uint16_t index)
238{
239 if (request_type == USB_REQUEST_TYPE_STANDARD) {
240 if ((recipient == USB_REQUEST_RECIPIENT_DEVICE) && (index != 0)) {
241 return EINVAL;
242 }
243 }
244
245 return usb_control_request_set(pipe,
246 request_type, recipient, USB_DEVREQ_SET_FEATURE,
247 uint16_host2usb(feature_selector), uint16_host2usb(index), NULL, 0);
248}
249
250/** Retrieve USB descriptor of a USB device.
251 *
252 * @param[in] pipe Control endpoint pipe (session must be already started).
253 * @param[in] request_type Request type (standard/class/vendor).
254 * @param[in] recipient Request recipient (device/interface/endpoint).
255 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
256 * @param[in] descriptor_index Descriptor index.
257 * @param[in] language Language index.
258 * @param[out] buffer Buffer where to store the retrieved descriptor.
259 * @param[in] size Size of the @p buffer.
260 * @param[out] actual_size Number of bytes actually transferred.
261 * @return Error code.
262 */
263errno_t usb_request_get_descriptor(usb_pipe_t *pipe,
264 usb_request_type_t request_type, usb_request_recipient_t recipient,
265 uint8_t descriptor_type, uint8_t descriptor_index,
266 uint16_t language,
267 void *buffer, size_t size, size_t *actual_size)
268{
269 if (buffer == NULL) {
270 return EBADMEM;
271 }
272 if (size == 0) {
273 return EINVAL;
274 }
275
276 /*
277 * The wValue field specifies the descriptor type in the high byte
278 * and the descriptor index in the low byte. USB 1.1 spec p. 189
279 */
280 const uint16_t wValue = descriptor_index | (descriptor_type << 8);
281
282 return usb_control_request_get(pipe,
283 request_type, recipient,
284 USB_DEVREQ_GET_DESCRIPTOR,
285 wValue, language,
286 buffer, size, actual_size);
287}
288
289/** Retrieve USB descriptor, allocate space for it.
290 *
291 * @param[in] pipe Control endpoint pipe (session must be already started).
292 * @param[in] request_type Request type (standard/class/vendor).
293 * @param[in] recipient Request recipient (device/interface/endpoint).
294 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
295 * @param[in] descriptor_index Descriptor index.
296 * @param[in] language Language index.
297 * @param[out] buffer_ptr Where to store pointer to allocated buffer.
298 * @param[out] buffer_size Where to store the size of the descriptor.
299 * @return
300 */
301errno_t usb_request_get_descriptor_alloc(usb_pipe_t * pipe,
302 usb_request_type_t request_type, usb_request_recipient_t recipient,
303 uint8_t descriptor_type, uint8_t descriptor_index,
304 uint16_t language,
305 void **buffer_ptr, size_t *buffer_size)
306{
307 if (buffer_ptr == NULL) {
308 return EBADMEM;
309 }
310
311 errno_t rc;
312
313 /*
314 * Get only first byte to retrieve descriptor length.
315 */
316 uint8_t tmp_buffer;
317 size_t bytes_transferred;
318 rc = usb_request_get_descriptor(pipe, request_type, recipient,
319 descriptor_type, descriptor_index, language,
320 &tmp_buffer, sizeof(tmp_buffer), &bytes_transferred);
321 if (rc != EOK) {
322 return rc;
323 }
324 if (bytes_transferred != 1) {
325 return ELIMIT;
326 }
327
328 const size_t size = tmp_buffer;
329 if (size == 0) {
330 return ELIMIT;
331 }
332
333 /*
334 * Allocate buffer and get the descriptor again.
335 */
336 void *buffer = malloc(size);
337 if (buffer == NULL) {
338 return ENOMEM;
339 }
340
341 rc = usb_request_get_descriptor(pipe, request_type, recipient,
342 descriptor_type, descriptor_index, language,
343 buffer, size, &bytes_transferred);
344 if (rc != EOK) {
345 free(buffer);
346 return rc;
347 }
348 if (bytes_transferred != size) {
349 free(buffer);
350 return ELIMIT;
351 }
352
353 *buffer_ptr = buffer;
354 if (buffer_size != NULL) {
355 *buffer_size = size;
356 }
357
358 return EOK;
359}
360
361/** Retrieve standard device descriptor of a USB device.
362 *
363 * @param[in] pipe Control endpoint pipe (session must be already started).
364 * @param[out] descriptor Storage for the device descriptor.
365 * @return Error code.
366 */
367errno_t usb_request_get_device_descriptor(usb_pipe_t *pipe,
368 usb_standard_device_descriptor_t *descriptor)
369{
370 if (descriptor == NULL) {
371 return EBADMEM;
372 }
373
374 size_t actually_transferred = 0;
375 usb_standard_device_descriptor_t descriptor_tmp;
376 errno_t rc = usb_request_get_descriptor(pipe,
377 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
378 USB_DESCTYPE_DEVICE, 0, 0, &descriptor_tmp, sizeof(descriptor_tmp),
379 &actually_transferred);
380
381 if (rc != EOK) {
382 return rc;
383 }
384
385 /* Verify that all data has been transferred. */
386 if (actually_transferred < sizeof(descriptor_tmp)) {
387 return ELIMIT;
388 }
389
390 /* Everything is okay, copy the descriptor. */
391 memcpy(descriptor, &descriptor_tmp, sizeof(descriptor_tmp));
392
393 return EOK;
394}
395
396/** Retrieve configuration descriptor of a USB device.
397 *
398 * The function does not retrieve additional data binded with configuration
399 * descriptor (such as its interface and endpoint descriptors) - use
400 * usb_request_get_full_configuration_descriptor() instead.
401 *
402 * @param[in] pipe Control endpoint pipe (session must be already started).
403 * @param[in] index Descriptor index.
404 * @param[out] descriptor Storage for the device descriptor.
405 * @return Error code.
406 */
407errno_t usb_request_get_bare_configuration_descriptor(usb_pipe_t *pipe,
408 int index, usb_standard_configuration_descriptor_t *descriptor)
409{
410 if (descriptor == NULL) {
411 return EBADMEM;
412 }
413
414 if ((index < 0) || (index > 0xFF)) {
415 return ERANGE;
416 }
417
418 size_t actually_transferred = 0;
419 usb_standard_configuration_descriptor_t descriptor_tmp;
420 const errno_t rc = usb_request_get_descriptor(pipe,
421 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
422 USB_DESCTYPE_CONFIGURATION, index, 0,
423 &descriptor_tmp, sizeof(descriptor_tmp),
424 &actually_transferred);
425 if (rc != EOK) {
426 return rc;
427 }
428
429 /* Verify that all data has been transferred. */
430 if (actually_transferred < sizeof(descriptor_tmp)) {
431 return ELIMIT;
432 }
433
434 /* Everything is okay, copy the descriptor. */
435 memcpy(descriptor, &descriptor_tmp, sizeof(descriptor_tmp));
436 return EOK;
437}
438
439/** Retrieve full configuration descriptor of a USB device.
440 *
441 * @warning The @p buffer might be touched (i.e. its contents changed)
442 * even when error occurs.
443 *
444 * @param[in] pipe Control endpoint pipe (session must be already started).
445 * @param[in] index Descriptor index.
446 * @param[out] descriptor Storage for the device descriptor.
447 * @param[in] descriptor_size Size of @p descriptor buffer.
448 * @param[out] actual_size Number of bytes actually transferred.
449 * @return Error code.
450 */
451errno_t usb_request_get_full_configuration_descriptor(usb_pipe_t *pipe,
452 int index, void *descriptor, size_t descriptor_size, size_t *actual_size)
453{
454 if ((index < 0) || (index > 0xFF)) {
455 return ERANGE;
456 }
457
458 return usb_request_get_descriptor(pipe,
459 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
460 USB_DESCTYPE_CONFIGURATION, index, 0,
461 descriptor, descriptor_size, actual_size);
462}
463
464/** Retrieve full configuration descriptor, allocate space for it.
465 *
466 * The function takes care that full configuration descriptor is returned
467 * (i.e. the function will fail when less data then descriptor.totalLength
468 * is returned).
469 *
470 * @param[in] pipe Control endpoint pipe (session must be already started).
471 * @param[in] index Configuration index.
472 * @param[out] descriptor_ptr Where to store pointer to allocated buffer.
473 * @param[out] descriptor_size Where to store the size of the descriptor.
474 * @return Error code.
475 */
476errno_t usb_request_get_full_configuration_descriptor_alloc(
477 usb_pipe_t *pipe, int index,
478 void **descriptor_ptr, size_t *descriptor_size)
479{
480 errno_t rc;
481
482 if (descriptor_ptr == NULL) {
483 return EBADMEM;
484 }
485
486 usb_standard_configuration_descriptor_t bare_config;
487 rc = usb_request_get_bare_configuration_descriptor(pipe, index,
488 &bare_config);
489 if (rc != EOK) {
490 return rc;
491 }
492 if (bare_config.descriptor_type != USB_DESCTYPE_CONFIGURATION) {
493 return ENOENT;
494 }
495
496 const size_t total_length = uint16_usb2host(bare_config.total_length);
497 if (total_length < sizeof(bare_config)) {
498 return ELIMIT;
499 }
500
501 void *buffer = malloc(total_length);
502 if (buffer == NULL) {
503 return ENOMEM;
504 }
505
506 size_t transferred = 0;
507 rc = usb_request_get_full_configuration_descriptor(pipe, index,
508 buffer, total_length, &transferred);
509 if (rc != EOK) {
510 free(buffer);
511 return rc;
512 }
513
514 if (transferred != total_length) {
515 free(buffer);
516 return ELIMIT;
517 }
518
519 /* Everything looks okay, copy the pointers. */
520
521 *descriptor_ptr = buffer;
522
523 if (descriptor_size != NULL) {
524 *descriptor_size = total_length;
525 }
526
527 return EOK;
528}
529
530/** Update existing or add new USB descriptor to a USB device.
531 *
532 * @param[in] pipe Control endpoint pipe (session must be already started).
533 * @param[in] request_type Request type (standard/class/vendor).
534 * @param[in] recipient Request recipient (device/interface/endpoint).
535 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
536 * @param[in] descriptor_index Descriptor index.
537 * @param[in] language Language index (in native endianness).
538 * @param[in] buffer Buffer with the new descriptor (in USB endianness).
539 * @param[in] size Size of the @p buffer in bytes (in native endianness).
540 * @return Error code.
541 */
542errno_t usb_request_set_descriptor(usb_pipe_t *pipe,
543 usb_request_type_t request_type, usb_request_recipient_t recipient,
544 uint8_t descriptor_type, uint8_t descriptor_index,
545 uint16_t language, const void *buffer, size_t size)
546{
547 if (buffer == NULL) {
548 return EBADMEM;
549 }
550 if (size == 0) {
551 return EINVAL;
552 }
553
554 /* FIXME: proper endianness. */
555 uint16_t wValue = descriptor_index | (descriptor_type << 8);
556
557 return usb_control_request_set(pipe,
558 request_type, recipient, USB_DEVREQ_SET_DESCRIPTOR,
559 wValue, language, buffer, size);
560}
561
562/** Get current configuration value of USB device.
563 *
564 * @param[in] pipe Control endpoint pipe (session must be already started).
565 * @param[out] configuration_value Current configuration value.
566 * @return Error code.
567 */
568errno_t usb_request_get_configuration(usb_pipe_t *pipe,
569 uint8_t *configuration_value)
570{
571 uint8_t value;
572 size_t actual_size;
573
574 const errno_t rc = usb_control_request_get(pipe,
575 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
576 USB_DEVREQ_GET_CONFIGURATION, 0, 0, &value, 1, &actual_size);
577
578 if (rc != EOK) {
579 return rc;
580 }
581 if (actual_size != 1) {
582 return ELIMIT;
583 }
584
585 if (configuration_value != NULL) {
586 *configuration_value = value;
587 }
588
589 return EOK;
590}
591
592/** Set configuration of USB device.
593 *
594 * @param pipe Control endpoint pipe (session must be already started).
595 * @param configuration_value New configuration value.
596 * @return Error code.
597 */
598errno_t usb_request_set_configuration(usb_pipe_t *pipe,
599 uint8_t configuration_value)
600{
601 const uint16_t config_value
602 = uint16_host2usb((uint16_t) configuration_value);
603
604 return usb_control_request_set(pipe,
605 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
606 USB_DEVREQ_SET_CONFIGURATION, config_value, 0,
607 NULL, 0);
608}
609
610/** Get selected alternate setting for USB interface.
611 *
612 * @param[in] pipe Control endpoint pipe (session must be already started).
613 * @param[in] interface_index Interface index.
614 * @param[out] alternate_setting Alternate setting for the interface.
615 * @return Error code.
616 */
617errno_t usb_request_get_interface(usb_pipe_t *pipe,
618 uint8_t interface_index, uint8_t *alternate_setting)
619{
620 uint8_t value;
621 size_t actual_size;
622
623 const errno_t rc = usb_control_request_get(pipe,
624 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
625 USB_DEVREQ_GET_INTERFACE,
626 0, uint16_host2usb((uint16_t) interface_index),
627 &value, sizeof(value), &actual_size);
628
629 if (rc != EOK) {
630 return rc;
631 }
632 if (actual_size != 1) {
633 return ELIMIT;
634 }
635
636 if (alternate_setting != NULL) {
637 *alternate_setting = value;
638 }
639
640 return EOK;
641}
642
643/** Select alternate setting for USB interface.
644 *
645 * @param[in] pipe Control endpoint pipe (session must be already started).
646 * @param[in] interface_index Interface index.
647 * @param[in] alternate_setting Alternate setting to select.
648 * @return Error code.
649 */
650errno_t usb_request_set_interface(usb_pipe_t *pipe,
651 uint8_t interface_index, uint8_t alternate_setting)
652{
653 return usb_control_request_set(pipe,
654 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
655 USB_DEVREQ_SET_INTERFACE,
656 uint16_host2usb((uint16_t) alternate_setting),
657 uint16_host2usb((uint16_t) interface_index),
658 NULL, 0);
659}
660
661/** Get list of supported languages by USB device.
662 *
663 * @param[in] pipe Control endpoint pipe (session must be already started).
664 * @param[out] languages_ptr Where to store pointer to allocated array of
665 * supported languages.
666 * @param[out] languages_count Number of supported languages.
667 * @return Error code.
668 */
669errno_t usb_request_get_supported_languages(usb_pipe_t *pipe,
670 l18_win_locales_t **languages_ptr, size_t *languages_count)
671{
672 if (languages_ptr == NULL || languages_count == NULL) {
673 return EBADMEM;
674 }
675
676 uint8_t *string_descriptor = NULL;
677 size_t string_descriptor_size = 0;
678 const errno_t rc = usb_request_get_descriptor_alloc(pipe,
679 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
680 USB_DESCTYPE_STRING, 0, 0,
681 (void **) &string_descriptor, &string_descriptor_size);
682 if (rc != EOK) {
683 return rc;
684 }
685 if (string_descriptor_size <= 2) {
686 free(string_descriptor);
687 return EEMPTY;
688 }
689 /* Subtract first 2 bytes (length and descriptor type). */
690 string_descriptor_size -= 2;
691
692 /* Odd number of bytes - descriptor is broken? */
693 if ((string_descriptor_size % 2) != 0) {
694 /* FIXME: shall we return with error or silently ignore? */
695 free(string_descriptor);
696 return ESTALL;
697 }
698
699 const size_t langs_count = string_descriptor_size / 2;
700 l18_win_locales_t *langs =
701 calloc(langs_count, sizeof(l18_win_locales_t));
702 if (langs == NULL) {
703 free(string_descriptor);
704 return ENOMEM;
705 }
706
707 for (size_t i = 0; i < langs_count; i++) {
708 /* Language code from the descriptor is in USB endianness. */
709 /* FIXME: is this really correct? */
710 const uint16_t lang_code =
711 (string_descriptor[2 + 2 * i + 1] << 8)
712 + string_descriptor[2 + 2 * i];
713 langs[i] = uint16_usb2host(lang_code);
714 }
715
716 free(string_descriptor);
717
718 *languages_ptr = langs;
719 *languages_count =langs_count;
720
721 return EOK;
722}
723
724/** Get string (descriptor) from USB device.
725 *
726 * The string is returned in native encoding of the operating system.
727 * For HelenOS, that is UTF-8.
728 *
729 * @param[in] pipe Control endpoint pipe (session must be already started).
730 * @param[in] index String index (in native endianness),
731 * first index has number 1 (index from descriptors can be used directly).
732 * @param[in] lang String language (in native endianness).
733 * @param[out] string_ptr Where to store allocated string in native encoding.
734 * @return Error code.
735 */
736errno_t usb_request_get_string(usb_pipe_t *pipe,
737 size_t index, l18_win_locales_t lang, char **string_ptr)
738{
739 if (string_ptr == NULL) {
740 return EBADMEM;
741 }
742 /*
743 * Index is actually one byte value and zero index is used
744 * to retrieve list of supported languages.
745 */
746 if ((index < 1) || (index > 0xFF)) {
747 return ERANGE;
748 }
749 /* Language is actually two byte value. */
750 if (lang > L18N_WIN_LOCALE_MAX) {
751 return ERANGE;
752 }
753
754 errno_t rc;
755
756 /* Prepare dynamically allocated variables. */
757 uint8_t *string = NULL;
758 wchar_t *string_chars = NULL;
759
760 /* Get the actual descriptor. */
761 size_t string_size;
762 rc = usb_request_get_descriptor_alloc(pipe,
763 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
764 USB_DESCTYPE_STRING, index, uint16_host2usb(lang),
765 (void **) &string, &string_size);
766 if (rc != EOK) {
767 goto leave;
768 }
769
770 if (string_size <= 2) {
771 rc = EEMPTY;
772 goto leave;
773 }
774 /* Subtract first 2 bytes (length and descriptor type). */
775 string_size -= 2;
776
777 /* Odd number of bytes - descriptor is broken? */
778 if ((string_size % 2) != 0) {
779 /* FIXME: shall we return with error or silently ignore? */
780 rc = ESTALL;
781 goto leave;
782 }
783
784 const size_t string_char_count = string_size / 2;
785 string_chars = malloc(sizeof(wchar_t) * (string_char_count + 1));
786 if (string_chars == NULL) {
787 rc = ENOMEM;
788 goto leave;
789 }
790
791 /*
792 * Build a wide string.
793 * And do not forget to set NULL terminator (string descriptors
794 * do not have them).
795 */
796 for (size_t i = 0; i < string_char_count; i++) {
797 const uint16_t uni_char = (string[2 + 2 * i + 1] << 8)
798 + string[2 + 2 * i];
799 string_chars[i] = uni_char;
800 }
801 string_chars[string_char_count] = 0;
802
803
804 /* Convert to normal string. */
805 char *str = wstr_to_astr(string_chars);
806 if (str == NULL) {
807 rc = ENOMEM;
808 goto leave;
809 }
810
811 *string_ptr = str;
812 rc = EOK;
813
814leave:
815 free(string);
816 free(string_chars);
817
818 return rc;
819}
820
821/** Clear halt bit of an endpoint pipe (after pipe stall).
822 *
823 * @param pipe Control pipe.
824 * @param ep_index Endpoint index (in native endianness).
825 * @return Error code.
826 */
827static errno_t usb_request_clear_endpoint_halt(usb_pipe_t *pipe, uint16_t ep_index)
828{
829 return usb_request_clear_feature(pipe,
830 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_ENDPOINT,
831 uint16_host2usb(USB_FEATURE_ENDPOINT_HALT),
832 uint16_host2usb(ep_index));
833}
834
835/** Clear halt bit of an endpoint pipe (after pipe stall).
836 *
837 * @param ctrl_pipe Control pipe.
838 * @param target_pipe Which pipe is halted and shall be cleared.
839 * @return Error code.
840 */
841errno_t usb_pipe_clear_halt(usb_pipe_t *ctrl_pipe, usb_pipe_t *target_pipe)
842{
843 if ((ctrl_pipe == NULL) || (target_pipe == NULL)) {
844 return EINVAL;
845 }
846
847 uint16_t index = target_pipe->desc.endpoint_no;
848 index |= (target_pipe->desc.direction == USB_DIRECTION_IN) << 7;
849 return usb_request_clear_endpoint_halt(ctrl_pipe, index);
850}
851
852/** Get endpoint status.
853 *
854 * @param[in] ctrl_pipe Control pipe.
855 * @param[in] pipe Of which pipe the status shall be received.
856 * @param[out] status Where to store pipe status (in native endianness).
857 * @return Error code.
858 */
859errno_t usb_request_get_endpoint_status(usb_pipe_t *ctrl_pipe, usb_pipe_t *pipe,
860 uint16_t *status)
861{
862 uint16_t status_tmp;
863 uint16_t pipe_index = (uint16_t) pipe->desc.endpoint_no;
864 errno_t rc = usb_request_get_status(ctrl_pipe,
865 USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index),
866 &status_tmp);
867 if (rc != EOK) {
868 return rc;
869 }
870
871 if (status != NULL) {
872 *status = uint16_usb2host(status_tmp);
873 }
874
875 return EOK;
876}
877
878/**
879 * @}
880 */
Note: See TracBrowser for help on using the repository browser.