00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00036 #include <usb/usb.h>
00037 #include <usb/dev/pipes.h>
00038 #include <usb/dev/dp.h>
00039 #include <usb/dev/request.h>
00040 #include <usbhc_iface.h>
00041 #include <errno.h>
00042 #include <assert.h>
00043
00044 #define CTRL_PIPE_MIN_PACKET_SIZE 8
00045 #define DEV_DESCR_MAX_PACKET_SIZE_OFFSET 7
00046
00047
00048 #define NESTING(parentname, childname) \
00049 { \
00050 .child = USB_DESCTYPE_##childname, \
00051 .parent = USB_DESCTYPE_##parentname, \
00052 }
00053 #define LAST_NESTING { -1, -1 }
00054
00056 static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
00057 NESTING(CONFIGURATION, INTERFACE),
00058 NESTING(INTERFACE, ENDPOINT),
00059 NESTING(INTERFACE, HUB),
00060 NESTING(INTERFACE, HID),
00061 NESTING(HID, HID_REPORT),
00062 LAST_NESTING
00063 };
00064
00070 static inline bool is_endpoint_descriptor(uint8_t *descriptor)
00071 {
00072 return descriptor[1] == USB_DESCTYPE_ENDPOINT;
00073 }
00074
00081 static bool endpoint_fits_description(const usb_endpoint_description_t *wanted,
00082 usb_endpoint_description_t *found)
00083 {
00084 #define _SAME(fieldname) ((wanted->fieldname) == (found->fieldname))
00085
00086 if (!_SAME(direction)) {
00087 return false;
00088 }
00089
00090 if (!_SAME(transfer_type)) {
00091 return false;
00092 }
00093
00094 if ((wanted->interface_class >= 0) && !_SAME(interface_class)) {
00095 return false;
00096 }
00097
00098 if ((wanted->interface_subclass >= 0) && !_SAME(interface_subclass)) {
00099 return false;
00100 }
00101
00102 if ((wanted->interface_protocol >= 0) && !_SAME(interface_protocol)) {
00103 return false;
00104 }
00105
00106 #undef _SAME
00107
00108 return true;
00109 }
00110
00120 static usb_endpoint_mapping_t *find_endpoint_mapping(
00121 usb_endpoint_mapping_t *mapping, size_t mapping_count,
00122 usb_endpoint_description_t *found_endpoint,
00123 int interface_number, int interface_setting)
00124 {
00125 while (mapping_count > 0) {
00126 bool interface_number_fits = (mapping->interface_no < 0)
00127 || (mapping->interface_no == interface_number);
00128
00129 bool interface_setting_fits = (mapping->interface_setting < 0)
00130 || (mapping->interface_setting == interface_setting);
00131
00132 bool endpoint_descriptions_fits = endpoint_fits_description(
00133 mapping->description, found_endpoint);
00134
00135 if (interface_number_fits
00136 && interface_setting_fits
00137 && endpoint_descriptions_fits) {
00138 return mapping;
00139 }
00140
00141 mapping++;
00142 mapping_count--;
00143 }
00144 return NULL;
00145 }
00146
00156 static int process_endpoint(
00157 usb_endpoint_mapping_t *mapping, size_t mapping_count,
00158 usb_standard_interface_descriptor_t *interface,
00159 usb_standard_endpoint_descriptor_t *endpoint,
00160 usb_device_connection_t *wire)
00161 {
00162 usb_endpoint_description_t description;
00163
00164
00165
00166
00167
00168
00169 usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
00170
00171
00172 description.direction = (endpoint->endpoint_address & 128)
00173 ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
00174
00175 description.transfer_type = endpoint->attributes & 3;
00176
00177
00178
00179
00180 description.interface_class = interface->interface_class;
00181 description.interface_subclass = interface->interface_subclass;
00182 description.interface_protocol = interface->interface_protocol;
00183
00184
00185
00186
00187 usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
00188 mapping_count, &description,
00189 interface->interface_number, interface->alternate_setting);
00190 if (ep_mapping == NULL) {
00191 return ENOENT;
00192 }
00193
00194 if (ep_mapping->pipe == NULL) {
00195 return EBADMEM;
00196 }
00197 if (ep_mapping->present) {
00198 return EEXISTS;
00199 }
00200
00201 int rc = usb_pipe_initialize(ep_mapping->pipe, wire,
00202 ep_no, description.transfer_type, endpoint->max_packet_size,
00203 description.direction);
00204 if (rc != EOK) {
00205 return rc;
00206 }
00207
00208 ep_mapping->present = true;
00209 ep_mapping->descriptor = endpoint;
00210 ep_mapping->interface = interface;
00211
00212 return EOK;
00213 }
00214
00224 static int process_interface(
00225 usb_endpoint_mapping_t *mapping, size_t mapping_count,
00226 usb_dp_parser_t *parser, usb_dp_parser_data_t *parser_data,
00227 uint8_t *interface_descriptor)
00228 {
00229 uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
00230 parser_data, interface_descriptor);
00231
00232 if (descriptor == NULL) {
00233 return ENOENT;
00234 }
00235
00236 do {
00237 if (is_endpoint_descriptor(descriptor)) {
00238 (void) process_endpoint(mapping, mapping_count,
00239 (usb_standard_interface_descriptor_t *)
00240 interface_descriptor,
00241 (usb_standard_endpoint_descriptor_t *)
00242 descriptor,
00243 (usb_device_connection_t *) parser_data->arg);
00244 }
00245
00246 descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
00247 interface_descriptor, descriptor);
00248 } while (descriptor != NULL);
00249
00250 return EOK;
00251 }
00252
00284 int usb_pipe_initialize_from_configuration(
00285 usb_endpoint_mapping_t *mapping, size_t mapping_count,
00286 uint8_t *configuration_descriptor, size_t configuration_descriptor_size,
00287 usb_device_connection_t *connection)
00288 {
00289 assert(connection);
00290
00291 if (configuration_descriptor == NULL) {
00292 return EBADMEM;
00293 }
00294 if (configuration_descriptor_size
00295 < sizeof(usb_standard_configuration_descriptor_t)) {
00296 return ERANGE;
00297 }
00298
00299
00300
00301
00302 size_t i;
00303 for (i = 0; i < mapping_count; i++) {
00304 mapping[i].present = false;
00305 mapping[i].descriptor = NULL;
00306 mapping[i].interface = NULL;
00307 }
00308
00309
00310
00311
00312 usb_dp_parser_t dp_parser = {
00313 .nesting = descriptor_nesting
00314 };
00315 usb_dp_parser_data_t dp_data = {
00316 .data = configuration_descriptor,
00317 .size = configuration_descriptor_size,
00318 .arg = connection
00319 };
00320
00321
00322
00323
00324 uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
00325 &dp_data, configuration_descriptor);
00326 if (interface == NULL) {
00327 return ENOENT;
00328 }
00329 do {
00330 (void) process_interface(mapping, mapping_count,
00331 &dp_parser, &dp_data,
00332 interface);
00333 interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
00334 configuration_descriptor, interface);
00335 } while (interface != NULL);
00336
00337 return EOK;
00338 }
00339
00350 int usb_pipe_initialize(usb_pipe_t *pipe,
00351 usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
00352 usb_transfer_type_t transfer_type, size_t max_packet_size,
00353 usb_direction_t direction)
00354 {
00355 assert(pipe);
00356 assert(connection);
00357
00358 fibril_mutex_initialize(&pipe->guard);
00359 pipe->wire = connection;
00360 pipe->hc_phone = -1;
00361 fibril_mutex_initialize(&pipe->hc_phone_mutex);
00362 pipe->endpoint_no = endpoint_no;
00363 pipe->transfer_type = transfer_type;
00364 pipe->max_packet_size = max_packet_size;
00365 pipe->direction = direction;
00366 pipe->refcount = 0;
00367 pipe->refcount_soft = 0;
00368 pipe->auto_reset_halt = false;
00369
00370 return EOK;
00371 }
00372
00373
00380 int usb_pipe_initialize_default_control(usb_pipe_t *pipe,
00381 usb_device_connection_t *connection)
00382 {
00383 assert(pipe);
00384 assert(connection);
00385
00386 int rc = usb_pipe_initialize(pipe, connection,
00387 0, USB_TRANSFER_CONTROL, CTRL_PIPE_MIN_PACKET_SIZE,
00388 USB_DIRECTION_BOTH);
00389
00390 pipe->auto_reset_halt = true;
00391
00392 return rc;
00393 }
00394
00405 int usb_pipe_probe_default_control(usb_pipe_t *pipe)
00406 {
00407 assert(pipe);
00408 assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE);
00409
00410 if ((pipe->direction != USB_DIRECTION_BOTH) ||
00411 (pipe->transfer_type != USB_TRANSFER_CONTROL) ||
00412 (pipe->endpoint_no != 0)) {
00413 return EINVAL;
00414 }
00415
00416 #define TRY_LOOP(attempt_var) \
00417 for (attempt_var = 0; attempt_var < 3; attempt_var++)
00418
00419 size_t failed_attempts;
00420 int rc;
00421
00422 usb_pipe_start_long_transfer(pipe);
00423
00424 uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];
00425 size_t transferred_size;
00426 TRY_LOOP(failed_attempts) {
00427 rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,
00428 USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,
00429 0, 0, dev_descr_start, CTRL_PIPE_MIN_PACKET_SIZE,
00430 &transferred_size);
00431 if (rc == EOK) {
00432 if (transferred_size != CTRL_PIPE_MIN_PACKET_SIZE) {
00433 rc = ELIMIT;
00434 continue;
00435 }
00436 break;
00437 }
00438 }
00439 usb_pipe_end_long_transfer(pipe);
00440 if (rc != EOK) {
00441 return rc;
00442 }
00443
00444 pipe->max_packet_size
00445 = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET];
00446
00447 return EOK;
00448 }
00449
00457 int usb_pipe_register(usb_pipe_t *pipe,
00458 unsigned int interval,
00459 usb_hc_connection_t *hc_connection)
00460 {
00461 return usb_pipe_register_with_speed(pipe, USB_SPEED_MAX + 1,
00462 interval, hc_connection);
00463 }
00464
00478 int usb_pipe_register_with_speed(usb_pipe_t *pipe, usb_speed_t speed,
00479 unsigned int interval,
00480 usb_hc_connection_t *hc_connection)
00481 {
00482 assert(pipe);
00483 assert(hc_connection);
00484
00485 if (!usb_hc_connection_is_opened(hc_connection)) {
00486 return EBADF;
00487 }
00488
00489 #define _PACK2(high, low) (((high) << 16) + (low))
00490 #define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
00491
00492 return async_req_4_0(hc_connection->hc_phone,
00493 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_REGISTER_ENDPOINT,
00494 _PACK2(pipe->wire->address, pipe->endpoint_no),
00495 _PACK3(speed, pipe->transfer_type, pipe->direction),
00496 _PACK2(pipe->max_packet_size, interval));
00497
00498 #undef _PACK2
00499 #undef _PACK3
00500 }
00501
00508 int usb_pipe_unregister(usb_pipe_t *pipe,
00509 usb_hc_connection_t *hc_connection)
00510 {
00511 assert(pipe);
00512 assert(hc_connection);
00513
00514 if (!usb_hc_connection_is_opened(hc_connection)) {
00515 return EBADF;
00516 }
00517
00518 return async_req_4_0(hc_connection->hc_phone,
00519 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_UNREGISTER_ENDPOINT,
00520 pipe->wire->address, pipe->endpoint_no, pipe->direction);
00521 }
00522