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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c280d7e was b5c92d7d, checked in by Ondřej Hlavatý <aearsis@…>, 7 years ago

libusbdev: pass correct endpoint index to reset endpoint

… and do not trust that the index is correct in libusbhost.

  • 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 */
70int 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 */
129int 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 */
172int 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 int 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 */
210int 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 */
234int 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 */
262int 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 */
300int 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 int 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 */
366int 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 int 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 */
406int 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 int 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 */
450int 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 */
475int usb_request_get_full_configuration_descriptor_alloc(
476 usb_pipe_t *pipe, int index,
477 const void **descriptor_ptr, size_t *descriptor_size)
478{
479 int 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 */
541int 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 */
567int 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 int 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 */
597int 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 */
616int 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 int 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 */
649int 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 */
668int 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 int 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 */
735int 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 int 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 */
826int 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 */
840int 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
846 uint16_t index = target_pipe->desc.endpoint_no;
847 index |= (target_pipe->desc.direction == USB_DIRECTION_IN) << 7;
848 return usb_request_clear_endpoint_halt(ctrl_pipe, index);
849}
850
851/** Get endpoint status.
852 *
853 * @param[in] ctrl_pipe Control pipe.
854 * @param[in] pipe Of which pipe the status shall be received.
855 * @param[out] status Where to store pipe status (in native endianness).
856 * @return Error code.
857 */
858int usb_request_get_endpoint_status(usb_pipe_t *ctrl_pipe, usb_pipe_t *pipe,
859 uint16_t *status)
860{
861 uint16_t status_tmp;
862 uint16_t pipe_index = (uint16_t) pipe->desc.endpoint_no;
863 int rc = usb_request_get_status(ctrl_pipe,
864 USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index),
865 &status_tmp);
866 if (rc != EOK) {
867 return rc;
868 }
869
870 if (status != NULL) {
871 *status = uint16_usb2host(status_tmp);
872 }
873
874 return EOK;
875}
876
877/**
878 * @}
879 */
Note: See TracBrowser for help on using the repository browser.