source: mainline/uspace/lib/usb/src/usbdrvreq.c@ 276aeda

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 276aeda was 276aeda, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Wrappers for standard device requests

Will add comments later.

  • Property mode set to 100644
File size: 13.5 KB
Line 
1/*
2 * Copyright (c) 2010 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 libusb usb
30 * @{
31 */
32/** @file
33 * @brief USB driver - standard USB requests (implementation).
34 */
35#include <usb/usbdrv.h>
36#include <errno.h>
37
38#define PREPARE_TARGET(name, target_address) \
39 usb_target_t name = { \
40 .address = target_address, \
41 .endpoint = 0 \
42 }
43
44#define PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, p_request, p_value, p_index, p_length) \
45 usb_device_request_setup_packet_t setup_packet = { \
46 .request_type = \
47 ((p_direction) == USB_DIRECTION_IN ? 128 : 0) \
48 | ((p_type) << 5) \
49 | (p_recipient), \
50 .request = (p_request), \
51 { .value = (p_value) }, \
52 .index = (p_index), \
53 .length = (p_length) \
54 }
55
56#define PREPARE_SETUP_PACKET_LOHI(name, p_direction, p_type, p_recipient, p_request, p_value_low, p_value_high, p_index, p_length) \
57 PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, \
58 p_request, (p_value_low) | ((p_value_high) << 8), \
59 p_index, p_length)
60
61/** Retrieve status of a USB device.
62 *
63 * @param hc_phone
64 * @param address
65 * @param recipient
66 * @param recipient_index
67 * @param status
68 * @return
69 */
70int usb_drv_req_get_status(int hc_phone, usb_address_t address,
71 usb_request_recipient_t recipient, uint16_t recipient_index,
72 uint16_t *status)
73{
74 if (status == NULL) {
75 return EBADMEM;
76 }
77
78 PREPARE_TARGET(target, address);
79
80 PREPARE_SETUP_PACKET(setup_packet,
81 USB_DIRECTION_IN, USB_REQUEST_TYPE_STANDARD,
82 recipient, USB_DEVREQ_GET_STATUS, 0, recipient_index, 2);
83
84 size_t transfered;
85 uint16_t tmp_status;
86 int rc = usb_drv_psync_control_read(hc_phone, target,
87 &setup_packet, sizeof(setup_packet), &tmp_status, 2, &transfered);
88 if (rc != EOK) {
89 return rc;
90 }
91 if (transfered != 2) {
92 return ERANGE;
93 }
94
95 *status = tmp_status;
96
97 return EOK;
98}
99
100/** Clear or disable USB device feature.
101 *
102 * @param hc_phone
103 * @param address
104 * @param recipient
105 * @param selector
106 * @param index
107 * @return
108 */
109int usb_drv_req_clear_feature(int hc_phone, usb_address_t address,
110 usb_request_recipient_t recipient,
111 uint16_t selector, uint16_t index)
112{
113 PREPARE_TARGET(target, address);
114
115 PREPARE_SETUP_PACKET(setup_packet,
116 USB_DIRECTION_OUT, USB_REQUEST_TYPE_STANDARD,
117 recipient, USB_DEVREQ_CLEAR_FEATURE, selector, index, 0);
118
119 int rc = usb_drv_psync_control_write(hc_phone, target,
120 &setup_packet, sizeof(setup_packet), NULL, 0);
121
122 return rc;
123}
124
125/** Set or enable USB device feature.
126 *
127 * @param hc_phone
128 * @param address
129 * @param recipient
130 * @param selector
131 * @param index
132 * @return
133 */
134int usb_drv_req_set_feature(int hc_phone, usb_address_t address,
135 usb_request_recipient_t recipient,
136 uint16_t selector, uint16_t index)
137{
138 PREPARE_TARGET(target, address);
139
140 PREPARE_SETUP_PACKET(setup_packet,
141 USB_DIRECTION_OUT, USB_REQUEST_TYPE_STANDARD,
142 recipient, USB_DEVREQ_SET_FEATURE, selector, index, 0);
143
144 int rc = usb_drv_psync_control_write(hc_phone, target,
145 &setup_packet, sizeof(setup_packet), NULL, 0);
146
147 return rc;
148}
149
150/** Change address of connected device.
151 *
152 * @see usb_drv_reserve_default_address
153 * @see usb_drv_release_default_address
154 * @see usb_drv_request_address
155 * @see usb_drv_release_address
156 * @see usb_drv_bind_address
157 *
158 * @param phone Open phone to HC driver.
159 * @param old_address Current address.
160 * @param address Address to be set.
161 * @return Error code.
162 */
163int usb_drv_req_set_address(int phone, usb_address_t old_address,
164 usb_address_t new_address)
165{
166 /* Prepare the target. */
167 usb_target_t target = {
168 .address = old_address,
169 .endpoint = 0
170 };
171
172 /* Prepare the setup packet. */
173 usb_device_request_setup_packet_t setup_packet = {
174 .request_type = 0,
175 .request = USB_DEVREQ_SET_ADDRESS,
176 .index = 0,
177 .length = 0,
178 };
179 setup_packet.value = new_address;
180
181 int rc = usb_drv_psync_control_write(phone, target,
182 &setup_packet, sizeof(setup_packet), NULL, 0);
183
184 return rc;
185}
186
187/** Retrieve USB descriptor of connected USB device.
188 *
189 * @param[in] hc_phone Open phone to HC driver.
190 * @param[in] address Device USB address.
191 * @param[in] request_type Request type (standard/class/vendor).
192 * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
193 * @param[in] descriptor_index Descriptor index.
194 * @param[in] language Language index.
195 * @param[out] buffer Buffer where to store the retrieved descriptor.
196 * @param[in] size Size of the @p buffer.
197 * @param[out] actual_size Number of bytes actually transferred.
198 * @return Error code.
199 */
200int usb_drv_req_get_descriptor(int hc_phone, usb_address_t address,
201 usb_request_type_t request_type,
202 uint8_t descriptor_type, uint8_t descriptor_index,
203 uint16_t language,
204 void *buffer, size_t size, size_t *actual_size)
205{
206 if (buffer == NULL) {
207 return EBADMEM;
208 }
209 if (size == 0) {
210 return EINVAL;
211 }
212
213 /* Prepare the target. */
214 usb_target_t target = {
215 .address = address,
216 .endpoint = 0
217 };
218
219 /* Prepare the setup packet. */
220 usb_device_request_setup_packet_t setup_packet = {
221 .request_type = 128 | (request_type << 5),
222 .request = USB_DEVREQ_GET_DESCRIPTOR,
223 .index = language,
224 .length = (uint16_t) size,
225 };
226 setup_packet.value_high = descriptor_type;
227 setup_packet.value_low = descriptor_index;
228
229 /* Perform CONTROL READ */
230 int rc = usb_drv_psync_control_read(hc_phone, target,
231 &setup_packet, sizeof(setup_packet),
232 buffer, size, actual_size);
233
234 return rc;
235}
236
237/** Retrieve device descriptor of connected USB device.
238 *
239 * @param[in] phone Open phone to HC driver.
240 * @param[in] address Device USB address.
241 * @param[out] descriptor Storage for the device descriptor.
242 * @return Error code.
243 * @retval EBADMEM @p descriptor is NULL.
244 */
245int usb_drv_req_get_device_descriptor(int phone, usb_address_t address,
246 usb_standard_device_descriptor_t *descriptor)
247{
248 if (descriptor == NULL) {
249 return EBADMEM;
250 }
251
252 size_t actually_transferred = 0;
253 usb_standard_device_descriptor_t descriptor_tmp;
254 int rc = usb_drv_req_get_descriptor(phone, address,
255 USB_REQUEST_TYPE_STANDARD,
256 USB_DESCTYPE_DEVICE, 0,
257 0,
258 &descriptor_tmp, sizeof(descriptor_tmp),
259 &actually_transferred);
260
261 if (rc != EOK) {
262 return rc;
263 }
264
265 /* Verify that all data has been transferred. */
266 if (actually_transferred < sizeof(descriptor_tmp)) {
267 return ELIMIT;
268 }
269
270 /* Everything is okay, copy the descriptor. */
271 memcpy(descriptor, &descriptor_tmp,
272 sizeof(descriptor_tmp));
273
274 return EOK;
275}
276
277
278/** Retrieve configuration descriptor of connected USB device.
279 *
280 * The function does not retrieve additional data binded with configuration
281 * descriptor (such as its interface and endpoint descriptors) - use
282 * usb_drv_req_get_full_configuration_descriptor() instead.
283 *
284 * @param[in] phone Open phone to HC driver.
285 * @param[in] address Device USB address.
286 * @param[in] index Configuration descriptor index.
287 * @param[out] descriptor Storage for the configuration descriptor.
288 * @return Error code.
289 * @retval EBADMEM @p descriptor is NULL.
290 */
291int usb_drv_req_get_bare_configuration_descriptor(int phone,
292 usb_address_t address, int index,
293 usb_standard_configuration_descriptor_t *descriptor)
294{
295 if (descriptor == NULL) {
296 return EBADMEM;
297 }
298
299 size_t actually_transferred = 0;
300 usb_standard_configuration_descriptor_t descriptor_tmp;
301 int rc = usb_drv_req_get_descriptor(phone, address,
302 USB_REQUEST_TYPE_STANDARD,
303 USB_DESCTYPE_CONFIGURATION, 0,
304 0,
305 &descriptor_tmp, sizeof(descriptor_tmp),
306 &actually_transferred);
307
308 if (rc != EOK) {
309 return rc;
310 }
311
312 /* Verify that all data has been transferred. */
313 if (actually_transferred < sizeof(descriptor_tmp)) {
314 return ELIMIT;
315 }
316
317 /* Everything is okay, copy the descriptor. */
318 memcpy(descriptor, &descriptor_tmp,
319 sizeof(descriptor_tmp));
320
321 return EOK;
322}
323
324/** Retrieve full configuration descriptor of connected USB device.
325 *
326 * @warning The @p buffer might be touched (i.e. its contents changed)
327 * even when error occurres.
328 *
329 * @param[in] phone Open phone to HC driver.
330 * @param[in] address Device USB address.
331 * @param[in] index Configuration descriptor index.
332 * @param[out] buffer Buffer for the whole configuration descriptor.
333 * @param[in] buffer_size Size of the prepared @p buffer.
334 * @param[out] actual_buffer_size Bytes actually transfered.
335 * @return Error code.
336 * @retval EBADMEM @p descriptor is NULL.
337 */
338int usb_drv_req_get_full_configuration_descriptor(int phone,
339 usb_address_t address, int index,
340 void *buffer, size_t buffer_size, size_t *actual_buffer_size)
341{
342 int rc = usb_drv_req_get_descriptor(phone, address,
343 USB_REQUEST_TYPE_STANDARD,
344 USB_DESCTYPE_CONFIGURATION, 0,
345 0,
346 buffer, buffer_size,
347 actual_buffer_size);
348
349 return rc;
350}
351
352/** Update existing descriptor of a USB device.
353 *
354 * @param hc_phone
355 * @param address
356 * @param descriptor_type
357 * @param descriptor_index
358 * @param language
359 * @param descriptor
360 * @param descriptor_size
361 * @return
362 */
363int usb_drv_req_set_descriptor(int hc_phone, usb_address_t address,
364 uint8_t descriptor_type, uint8_t descriptor_index,
365 uint16_t language,
366 void *descriptor, size_t descriptor_size)
367{
368 PREPARE_TARGET(target, address);
369
370 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
371 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
372 USB_DEVREQ_SET_DESCRIPTOR, descriptor_index, descriptor_type,
373 language, descriptor_size);
374
375 int rc = usb_drv_psync_control_write(hc_phone, target,
376 &setup_packet, sizeof(setup_packet),
377 descriptor, descriptor_size);
378
379 return rc;
380}
381
382/** Determine current configuration value of USB device.
383 *
384 * @param hc_phone
385 * @param address
386 * @param configuration_value
387 * @return
388 */
389int usb_drv_req_get_configuration(int hc_phone, usb_address_t address,
390 uint8_t *configuration_value)
391{
392 if (configuration_value == NULL) {
393 return EBADMEM;
394 }
395
396 PREPARE_TARGET(target, address);
397
398 PREPARE_SETUP_PACKET(setup_packet, USB_DIRECTION_IN,
399 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
400 USB_DEVREQ_GET_CONFIGURATION, 0, 0, 1);
401
402 uint8_t value;
403 size_t transfered;
404 int rc = usb_drv_psync_control_read(hc_phone, target,
405 &setup_packet, sizeof(setup_packet), &value, 1, &transfered);
406
407 if (rc != EOK) {
408 return rc;
409 }
410
411 if (transfered != 1) {
412 return ERANGE;
413 }
414
415 *configuration_value = value;
416
417 return EOK;
418}
419
420/** Set configuration of USB device.
421 *
422 * @param hc_phone
423 * @param address
424 * @param configuration_value
425 * @return
426 */
427int usb_drv_req_set_configuration(int hc_phone, usb_address_t address,
428 uint8_t configuration_value)
429{
430 PREPARE_TARGET(target, address);
431
432 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
433 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
434 USB_DEVREQ_SET_CONFIGURATION, configuration_value, 0,
435 0, 0);
436
437 int rc = usb_drv_psync_control_write(hc_phone, target,
438 &setup_packet, sizeof(setup_packet), NULL, 0);
439
440 return rc;
441}
442
443/** Determine alternate setting of USB device interface.
444 *
445 * @param hc_phone
446 * @param address
447 * @param interface_index
448 * @param alternate_setting
449 * @return
450 */
451int usb_drv_req_get_interface(int hc_phone, usb_address_t address,
452 uint16_t interface_index, uint8_t *alternate_setting)
453{
454 if (alternate_setting == NULL) {
455 return EBADMEM;
456 }
457
458 PREPARE_TARGET(target, address);
459
460 PREPARE_SETUP_PACKET(setup_packet, USB_DIRECTION_IN,
461 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
462 USB_DEVREQ_GET_INTERFACE, 0, interface_index, 1);
463
464 uint8_t alternate;
465 size_t transfered;
466 int rc = usb_drv_psync_control_read(hc_phone, target,
467 &setup_packet, sizeof(setup_packet), &alternate, 1, &transfered);
468
469 if (rc != EOK) {
470 return rc;
471 }
472
473 if (transfered != 1) {
474 return ERANGE;
475 }
476
477 *alternate_setting = alternate;
478
479 return EOK;
480}
481
482/** Select an alternate setting of USB device interface.
483 *
484 * @param hc_phone
485 * @param address
486 * @param interface_index
487 * @param alternate_setting
488 * @return
489 */
490int usb_drv_req_set_interface(int hc_phone, usb_address_t address,
491 uint16_t interface_index, uint8_t alternate_setting)
492{
493 PREPARE_TARGET(target, address);
494
495 PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_OUT,
496 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
497 USB_DEVREQ_SET_INTERFACE, alternate_setting, 0,
498 0, 0);
499
500 int rc = usb_drv_psync_control_write(hc_phone, target,
501 &setup_packet, sizeof(setup_packet), NULL, 0);
502
503 return rc;
504}
505
506/**
507 * @}
508 */
Note: See TracBrowser for help on using the repository browser.