source: mainline/uspace/lib/usbdev/src/request.c@ 33b8d024

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 33b8d024 was 33b8d024, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Remove const qualifier from the argument of free() and realloc(),
as well as in numerous other variables that hold ownership of memory.

By convention, a pointer that holds ownership is _never_ qualified by const.
This is reflected in the standard type signature of free() and realloc().
Allowing const pointers to hold ownership may seem superficially convenient,
but is actually quite confusing to experienced C programmers.

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