source: mainline/uspace/lib/usbvirt/src/stdreq.c@ 6cb58e6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6cb58e6 was 6cb58e6, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Virtual USB layer rewritten

Major changes include

  • IPC sends whole transfers (not transactions)
  • separate transfer queues for each device in host controller
  • possibility to return NAK from virtual device (handled by HC)
  • better implementation of callbacks for non-zero endpoints

Still missing

  • communication for some transfer types (bulk)
  • face-lift ;-)
  • documentation
  • Property mode set to 100644
File size: 4.2 KB
Line 
1#include "private.h"
2#include <usb/request.h>
3#include <assert.h>
4#include <errno.h>
5
6void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
7 uint8_t *data, size_t *act_size,
8 void *actual_data, size_t actual_data_size)
9{
10 size_t expected_size = setup_packet->length;
11 if (expected_size < actual_data_size) {
12 actual_data_size = expected_size;
13 }
14
15 memcpy(data, actual_data, actual_data_size);
16
17 if (act_size != NULL) {
18 *act_size = actual_data_size;
19 }
20}
21
22/** GET_DESCRIPTOR handler. */
23static int req_get_descriptor(usbvirt_device_t *device,
24 const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
25{
26 uint8_t type = setup_packet->value_high;
27 uint8_t index = setup_packet->value_low;
28
29 /*
30 * Standard device descriptor.
31 */
32 if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
33 if (device->descriptors && device->descriptors->device) {
34 usbvirt_control_reply_helper(setup_packet, data, act_size,
35 device->descriptors->device,
36 device->descriptors->device->length);
37 return EOK;
38 } else {
39 return EFORWARD;
40 }
41 }
42
43 /*
44 * Configuration descriptor together with interface, endpoint and
45 * class-specific descriptors.
46 */
47 if (type == USB_DESCTYPE_CONFIGURATION) {
48 if (!device->descriptors) {
49 return EFORWARD;
50 }
51 if (index >= device->descriptors->configuration_count) {
52 return EFORWARD;
53 }
54 /* Copy the data. */
55 usbvirt_device_configuration_t *config = &device->descriptors
56 ->configuration[index];
57 uint8_t *all_data = malloc(config->descriptor->total_length);
58 if (all_data == NULL) {
59 return ENOMEM;
60 }
61
62 uint8_t *ptr = all_data;
63 memcpy(ptr, config->descriptor, config->descriptor->length);
64 ptr += config->descriptor->length;
65 size_t i;
66 for (i = 0; i < config->extra_count; i++) {
67 usbvirt_device_configuration_extras_t *extra
68 = &config->extra[i];
69 memcpy(ptr, extra->data, extra->length);
70 ptr += extra->length;
71 }
72
73 usbvirt_control_reply_helper(setup_packet, data, act_size,
74 all_data, config->descriptor->total_length);
75
76 free(all_data);
77
78 return EOK;
79 }
80
81 return EFORWARD;
82}
83
84static int req_set_address(usbvirt_device_t *device,
85 const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
86{
87 uint16_t new_address = setup_packet->value;
88 uint16_t zero1 = setup_packet->index;
89 uint16_t zero2 = setup_packet->length;
90
91 if ((zero1 != 0) || (zero2 != 0)) {
92 return EINVAL;
93 }
94
95 if (new_address > 127) {
96 return EINVAL;
97 }
98
99 device->address = new_address;
100
101 return EOK;
102}
103
104static int req_set_configuration(usbvirt_device_t *device,
105 const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
106{
107 uint16_t configuration_value = setup_packet->value;
108 uint16_t zero1 = setup_packet->index;
109 uint16_t zero2 = setup_packet->length;
110
111 if ((zero1 != 0) || (zero2 != 0)) {
112 return EINVAL;
113 }
114
115 /*
116 * Configuration value is 1 byte information.
117 */
118 if (configuration_value > 255) {
119 return EINVAL;
120 }
121
122 /*
123 * Do nothing when in default state. According to specification,
124 * this is not specified.
125 */
126 if (device->state == USBVIRT_STATE_DEFAULT) {
127 return EOK;
128 }
129
130 usbvirt_device_state_t new_state;
131 if (configuration_value == 0) {
132 new_state = USBVIRT_STATE_ADDRESS;
133 } else {
134 // FIXME: check that this configuration exists
135 new_state = USBVIRT_STATE_CONFIGURED;
136 }
137
138 if (device->ops && device->ops->state_changed) {
139 device->ops->state_changed(device, device->state, new_state);
140 }
141 device->state = new_state;
142
143 return EOK;
144}
145
146usbvirt_control_request_handler_t library_handlers[] = {
147 {
148 .req_direction = USB_DIRECTION_OUT,
149 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
150 .req_type = USB_REQUEST_TYPE_STANDARD,
151 .request = USB_DEVREQ_SET_ADDRESS,
152 .name = "SetAddress",
153 .callback = req_set_address
154 },
155 {
156 .req_direction = USB_DIRECTION_IN,
157 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
158 .req_type = USB_REQUEST_TYPE_STANDARD,
159 .request = USB_DEVREQ_GET_DESCRIPTOR,
160 .name = "GetDescriptor",
161 .callback = req_get_descriptor
162 },
163 {
164 .req_direction = USB_DIRECTION_OUT,
165 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
166 .req_type = USB_REQUEST_TYPE_STANDARD,
167 .request = USB_DEVREQ_SET_CONFIGURATION,
168 .name = "SetConfiguration",
169 .callback = req_set_configuration
170 },
171
172 { .callback = NULL }
173};
174
Note: See TracBrowser for help on using the repository browser.