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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1cf26ab was 1cf26ab, checked in by Jakub Jermar <jakub@…>, 9 years ago

Use static assert instead of regular ones

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