pipesinit.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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          * Get endpoint characteristics.
00166          */
00167 
00168         /* Actual endpoint number is in bits 0..3 */
00169         usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
00170 
00171         /* Endpoint direction is set by bit 7 */
00172         description.direction = (endpoint->endpoint_address & 128)
00173             ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
00174         /* Transfer type is in bits 0..2 and the enum values corresponds 1:1 */
00175         description.transfer_type = endpoint->attributes & 3;
00176 
00177         /*
00178          * Get interface characteristics.
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          * Find the most fitting mapping and initialize the pipe.
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          * Go through the mapping and set all endpoints to not present.
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          * Prepare the descriptor parser.
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          * Iterate through all interfaces.
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 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7