virthubops.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 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 
00035 #include <errno.h>
00036 #include <usb/classes/hub.h>
00037 #include <usbvirt/device.h>
00038 #include "virthub.h"
00039 #include "hub.h"
00040 
00042 static void on_state_change(usbvirt_device_t *dev,
00043     usbvirt_device_state_t old_state, usbvirt_device_state_t new_state)
00044 {
00045         hub_t *hub = (hub_t *)dev->device_data;
00046 
00047         hub_acquire(hub);
00048 
00049         switch (new_state) {
00050                 case USBVIRT_STATE_CONFIGURED:
00051                         hub_set_port_state_all(hub, HUB_PORT_STATE_POWERED_OFF);
00052                         break;
00053                 case USBVIRT_STATE_ADDRESS:
00054                         hub_set_port_state_all(hub, HUB_PORT_STATE_NOT_CONFIGURED);
00055                         break;
00056                 default:
00057                         break;
00058         }
00059 
00060         hub_release(hub);
00061 }
00062 
00064 static int req_on_status_change_pipe(usbvirt_device_t *dev,
00065     usb_endpoint_t endpoint, usb_transfer_type_t tr_type,
00066     void *buffer, size_t buffer_size, size_t *actual_size)
00067 {
00068         if (endpoint != HUB_STATUS_CHANGE_PIPE) {
00069                 return ESTALL;
00070         }
00071         if (tr_type != USB_TRANSFER_INTERRUPT) {
00072                 return ESTALL;
00073         }
00074         
00075         hub_t *hub = dev->device_data;
00076 
00077         hub_acquire(hub);
00078 
00079         if (!hub->signal_changes) {
00080                 hub_release(hub);
00081 
00082                 return ENAK;
00083         }
00084 
00085 
00086         uint8_t change_map = hub_get_status_change_bitmap(hub);
00087 
00088         uint8_t *b = (uint8_t *) buffer;
00089         if (buffer_size > 0) {
00090                 *b = change_map;
00091                 *actual_size = 1;
00092         } else {
00093                 *actual_size = 0;
00094         }
00095         
00096         hub->signal_changes = false;
00097 
00098         hub_release(hub);
00099 
00100         return EOK;
00101 }
00102 
00110 static int req_clear_hub_feature(usbvirt_device_t *dev,
00111     const usb_device_request_setup_packet_t *request, uint8_t *data,
00112     size_t *act_size)
00113 {
00114         return ENOTSUP;
00115 }
00116 
00124 static int req_clear_port_feature(usbvirt_device_t *dev,
00125     const usb_device_request_setup_packet_t *request, uint8_t *data,
00126     size_t *act_size)
00127 {
00128         int rc;
00129         size_t port = request->index - 1;
00130         usb_hub_class_feature_t feature = request->value;
00131         hub_t *hub = (hub_t *) dev->device_data;
00132 
00133         hub_acquire(hub);
00134 
00135         hub_port_state_t port_state = hub_get_port_state(hub, port);
00136 
00137         switch (feature) {
00138                 case USB_HUB_FEATURE_PORT_ENABLE:
00139                         if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
00140                             && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
00141                                 hub_set_port_state(hub, port, HUB_PORT_STATE_DISABLED);
00142                         }
00143                         rc = EOK;
00144                         break;
00145 
00146                 case USB_HUB_FEATURE_PORT_SUSPEND:
00147                         if (port_state != HUB_PORT_STATE_SUSPENDED) {
00148                                 rc = EOK;
00149                                 break;
00150                         }
00151                         hub_set_port_state(hub, port, HUB_PORT_STATE_RESUMING);
00152                         rc = EOK;
00153                         break;
00154 
00155                 case USB_HUB_FEATURE_PORT_POWER:
00156                         if (port_state != HUB_PORT_STATE_NOT_CONFIGURED) {
00157                                 hub_set_port_state(hub, port, HUB_PORT_STATE_POWERED_OFF);
00158                         }
00159                         rc = EOK;
00160                         break;
00161 
00162                 case USB_HUB_FEATURE_C_PORT_CONNECTION:
00163                         hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_CONNECTION);
00164                         rc = EOK;
00165                         break;
00166 
00167                 case USB_HUB_FEATURE_C_PORT_ENABLE:
00168                         hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
00169                         rc = EOK;
00170                         break;
00171 
00172                 case USB_HUB_FEATURE_C_PORT_SUSPEND:
00173                         hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
00174                         rc = EOK;
00175                         break;
00176 
00177                 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
00178                         hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_OVER_CURRENT);
00179                         rc = EOK;
00180                         break;
00181 
00182                 case USB_HUB_FEATURE_C_PORT_RESET:
00183                         hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_RESET);
00184                         rc = EOK;
00185                         break;
00186 
00187                 default:
00188                         rc = ENOTSUP;
00189                         break;
00190         }
00191 
00192         hub_release(hub);
00193 
00194         return rc;
00195 }
00196 
00204 static int req_get_bus_state(usbvirt_device_t *dev,
00205     const usb_device_request_setup_packet_t *request, uint8_t *data,
00206     size_t *act_size)
00207 {
00208         return ENOTSUP;
00209 }
00210 
00218 static int req_get_descriptor(usbvirt_device_t *dev,
00219     const usb_device_request_setup_packet_t *request, uint8_t *data,
00220     size_t *act_size)
00221 {
00222         if (request->value_high == USB_DESCTYPE_HUB) {
00223                 usbvirt_control_reply_helper(request, data, act_size,
00224                     &hub_descriptor, hub_descriptor.length);
00225 
00226                 return EOK;
00227         }
00228         /* Let the framework handle all the rest. */
00229         return EFORWARD;
00230 }
00231 
00239 static int req_get_hub_status(usbvirt_device_t *dev,
00240     const usb_device_request_setup_packet_t *request, uint8_t *data,
00241     size_t *act_size)
00242 {
00243         uint32_t hub_status = 0;
00244 
00245         usbvirt_control_reply_helper(request, data, act_size,
00246             &hub_status, sizeof(hub_status));
00247 
00248         return EOK;
00249 }
00250 
00258 static int req_get_port_status(usbvirt_device_t *dev,
00259     const usb_device_request_setup_packet_t *request, uint8_t *data,
00260     size_t *act_size)
00261 {
00262         hub_t *hub = (hub_t *) dev->device_data;
00263 
00264         hub_acquire(hub);
00265 
00266         uint32_t status = hub_get_port_status(hub, request->index - 1);
00267 
00268         hub_release(hub);
00269 
00270         usbvirt_control_reply_helper(request, data, act_size,
00271             &status, sizeof(status));
00272 
00273         return EOK;
00274 }
00275 
00283 static int req_set_hub_feature(usbvirt_device_t *dev,
00284     const usb_device_request_setup_packet_t *request, uint8_t *data,
00285     size_t *act_size)
00286 {
00287         return ENOTSUP;
00288 }
00289 
00297 static int req_set_port_feature(usbvirt_device_t *dev,
00298     const usb_device_request_setup_packet_t *request, uint8_t *data,
00299     size_t *act_size)
00300 {
00301         int rc;
00302         size_t port = request->index - 1;
00303         usb_hub_class_feature_t feature = request->value;
00304         hub_t *hub = (hub_t *) dev->device_data;
00305 
00306         hub_acquire(hub);
00307 
00308         hub_port_state_t port_state = hub_get_port_state(hub, port);
00309 
00310         switch (feature) {
00311                 case USB_HUB_FEATURE_PORT_RESET:
00312                         if (port_state != HUB_PORT_STATE_POWERED_OFF) {
00313                                 hub_set_port_state(hub, port, HUB_PORT_STATE_RESETTING);
00314                         }
00315                         rc = EOK;
00316                         break;
00317 
00318                 case USB_HUB_FEATURE_PORT_SUSPEND:
00319                         if (port_state == HUB_PORT_STATE_ENABLED) {
00320                                 hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
00321                         }
00322                         rc = EOK;
00323                         break;
00324 
00325                 case USB_HUB_FEATURE_PORT_POWER:
00326                         if (port_state == HUB_PORT_STATE_POWERED_OFF) {
00327                                 hub_set_port_state(hub, port, HUB_PORT_STATE_DISCONNECTED);
00328                         }
00329                         rc = EOK;
00330                         break;
00331 
00332                 default:
00333                         break;
00334         }
00335 
00336         hub_release(hub);
00337 
00338         return rc;
00339 }
00340 
00341 
00343 #define CLASS_REQ_IN(recipient) \
00344         USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
00345         USBVIRT_REQUEST_TYPE_CLASS, recipient)
00346 
00347 #define CLASS_REQ_OUT(recipient) \
00348         USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
00349         USBVIRT_REQUEST_TYPE_CLASS, recipient)
00350 
00352 #define REC_OTHER USB_REQUEST_RECIPIENT_OTHER
00353 
00354 #define REC_DEVICE USB_REQUEST_RECIPIENT_DEVICE
00355 
00356 #define DIR_IN USB_DIRECTION_IN
00357 
00358 #define DIR_OUT USB_DIRECTION_OUT
00359 
00360 
00367 #define CLASS_REQ(direction, recipient, req) \
00368         .req_direction = direction, \
00369         .req_recipient = recipient, \
00370         .req_type = USB_REQUEST_TYPE_CLASS, \
00371         .request = req
00372 
00379 #define STD_REQ(direction, recipient, req) \
00380         .req_direction = direction, \
00381         .req_recipient = recipient, \
00382         .req_type = USB_REQUEST_TYPE_STANDARD, \
00383         .request = req
00384 
00386 static usbvirt_control_request_handler_t endpoint_zero_handlers[] = {
00387         {
00388                 STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
00389                 .name = "GetDescriptor",
00390                 .callback = req_get_descriptor
00391         },
00392         {
00393                 CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
00394                 .name = "GetDescriptor",
00395                 .callback = req_get_descriptor
00396         },
00397         {
00398                 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
00399                 .name = "GetPortStatus",
00400                 .callback = req_get_port_status
00401         },
00402         {
00403                 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
00404                 .name = "ClearHubFeature",
00405                 .callback = req_clear_hub_feature
00406         },
00407         {
00408                 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
00409                 .name = "ClearPortFeature",
00410                 .callback = req_clear_port_feature
00411         },
00412         {
00413                 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
00414                 .name = "GetBusState",
00415                 .callback = req_get_bus_state
00416         },
00417         {
00418                 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
00419                 .name = "GetHubDescriptor",
00420                 .callback = req_get_descriptor
00421         },
00422         {
00423                 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
00424                 .name = "GetHubStatus",
00425                 .callback = req_get_hub_status
00426         },
00427         {
00428                 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
00429                 .name = "GetPortStatus",
00430                 .callback = req_get_port_status
00431         },
00432         {
00433                 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
00434                 .name = "SetHubFeature",
00435                 .callback = req_set_hub_feature
00436         },
00437         {
00438                 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
00439                 .name = "SetPortFeature",
00440                 .callback = req_set_port_feature
00441         },
00442         {
00443                 .callback = NULL
00444         }
00445 };
00446 
00447 
00449 usbvirt_device_ops_t hub_ops = {
00450         .control = endpoint_zero_handlers,
00451         .data_in[HUB_STATUS_CHANGE_PIPE] = req_on_status_change_pipe,
00452         .state_changed = on_state_change,
00453 };
00454 

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