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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f8d43aa was f8d43aa, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

Minor style changes.

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