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

Last change on this file since e49d0ac was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

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