Changeset 501e5df in mainline


Ignore:
Timestamp:
2011-04-09T20:56:50Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ba038f4
Parents:
8790650 (diff), 709e868 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Development changes

Location:
uspace
Files:
2 added
32 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/usbinfo/dev.c

    r8790650 r501e5df  
    5050
    5151        int rc;
     52        bool transfer_started = false;
    5253
    5354        rc = usb_device_connection_initialize(&dev->wire, hc_handle, dev_addr);
     
    7677        }
    7778
    78         rc = usb_pipe_start_session(&dev->ctrl_pipe);
     79        rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
    7980        if (rc != EOK) {
    8081                fprintf(stderr,
    81                     NAME ": failed to start session on control pipe: %s.\n",
     82                    NAME ": failed to start transfer on control pipe: %s.\n",
    8283                    str_error(rc));
    8384                goto leave;
    8485        }
     86        transfer_started = true;
    8587
    8688        rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
     
    107109
    108110leave:
    109         if (usb_pipe_is_session_started(&dev->ctrl_pipe)) {
    110                 usb_pipe_end_session(&dev->ctrl_pipe);
     111        if (transfer_started) {
     112                usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    111113        }
    112114
     
    118120void destroy_device(usbinfo_device_t *dev)
    119121{
    120         usb_pipe_end_session(&dev->ctrl_pipe);
     122        usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    121123        free(dev);
    122124}
  • uspace/doc/doxygroups.h

    r8790650 r501e5df  
    269269
    270270        /**
     271         * @defgroup drvusbohci OHCI driver
     272         * @ingroup usb
     273         * @brief Driver for OHCI host controller.
     274         */
     275
     276        /**
    271277         * @defgroup drvusbehci EHCI driver
    272278         * @ingroup usb
     
    275281
    276282        /**
    277          * @defgroup drvusbfallback USB fallback driver.
     283         * @defgroup drvusbfallback USB fallback driver
    278284         * @ingroup usb
    279285         * @brief Fallback driver for any USB device.
  • uspace/drv/ehci-hcd/hc_iface.c

    r8790650 r501e5df  
    123123 * @param[in] fun Device function the action was invoked on.
    124124 * @param[in] address USB address of the device.
     125 * @param[in] speed Endpoint speed (invalid means to use device one).
    125126 * @param[in] endpoint Endpoint number.
    126127 * @param[in] transfer_type USB transfer type.
     
    131132 */
    132133static int register_endpoint(ddf_fun_t *fun,
    133     usb_address_t address, usb_endpoint_t endpoint,
     134    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
    134135    usb_transfer_type_t transfer_type, usb_direction_t direction,
    135136    size_t max_packet_size, unsigned int interval)
     
    165166 * @param[in] fun Device function the action was invoked on.
    166167 * @param[in] target Target pipe (address and endpoint number) specification.
    167  * @param[in] max_packet_size Max packet size for the transfer.
    168168 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
    169169 *      by the caller).
     
    174174 */
    175175static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
    176     size_t max_packet_size, void *data, size_t size,
     176    void *data, size_t size,
    177177    usbhc_iface_transfer_out_callback_t callback, void *arg)
    178178{
     
    191191 * @param[in] fun Device function the action was invoked on.
    192192 * @param[in] target Target pipe (address and endpoint number) specification.
    193  * @param[in] max_packet_size Max packet size for the transfer.
    194193 * @param[in] data Buffer where to store the data (in USB endianess,
    195194 *      allocated and deallocated by the caller).
     
    200199 */
    201200static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
    202     size_t max_packet_size, void *data, size_t size,
     201    void *data, size_t size,
    203202    usbhc_iface_transfer_in_callback_t callback, void *arg)
    204203{
     
    217216 * @param[in] fun Device function the action was invoked on.
    218217 * @param[in] target Target pipe (address and endpoint number) specification.
    219  * @param[in] max_packet_size Max packet size for the transfer.
    220218 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
    221219 *      by the caller).
     
    226224 */
    227225static int bulk_out(ddf_fun_t *fun, usb_target_t target,
    228     size_t max_packet_size, void *data, size_t size,
     226    void *data, size_t size,
    229227    usbhc_iface_transfer_out_callback_t callback, void *arg)
    230228{
     
    243241 * @param[in] fun Device function the action was invoked on.
    244242 * @param[in] target Target pipe (address and endpoint number) specification.
    245  * @param[in] max_packet_size Max packet size for the transfer.
    246243 * @param[in] data Buffer where to store the data (in USB endianess,
    247244 *      allocated and deallocated by the caller).
     
    252249 */
    253250static int bulk_in(ddf_fun_t *fun, usb_target_t target,
    254     size_t max_packet_size, void *data, size_t size,
     251    void *data, size_t size,
    255252    usbhc_iface_transfer_in_callback_t callback, void *arg)
    256253{
     
    269266 * @param[in] fun Device function the action was invoked on.
    270267 * @param[in] target Target pipe (address and endpoint number) specification.
    271  * @param[in] max_packet_size Max packet size for the transfer.
    272268 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
    273269 *      and deallocated by the caller).
     
    281277 */
    282278static int control_write(ddf_fun_t *fun, usb_target_t target,
    283     size_t max_packet_size,
    284279    void *setup_packet, size_t setup_packet_size,
    285280    void *data_buffer, size_t data_buffer_size,
     
    300295 * @param[in] fun Device function the action was invoked on.
    301296 * @param[in] target Target pipe (address and endpoint number) specification.
    302  * @param[in] max_packet_size Max packet size for the transfer.
    303297 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
    304298 *      and deallocated by the caller).
     
    312306 */
    313307static int control_read(ddf_fun_t *fun, usb_target_t target,
    314     size_t max_packet_size,
    315308    void *setup_packet, size_t setup_packet_size,
    316309    void *data_buffer, size_t data_buffer_size,
  • uspace/drv/ohci/iface.c

    r8790650 r501e5df  
    197197}
    198198/*----------------------------------------------------------------------------*/
    199 static int register_endpoint(
    200     ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
     199/** Register endpoint for bandwidth reservation.
     200 *
     201 * @param[in] fun Device function the action was invoked on.
     202 * @param[in] address USB address of the device.
     203 * @param[in] ep_speed Endpoint speed (invalid means to use device one).
     204 * @param[in] endpoint Endpoint number.
     205 * @param[in] transfer_type USB transfer type.
     206 * @param[in] direction Endpoint data direction.
     207 * @param[in] max_packet_size Max packet size of the endpoint.
     208 * @param[in] interval Polling interval.
     209 * @return Error code.
     210 */
     211static int register_endpoint(ddf_fun_t *fun,
     212    usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint,
    201213    usb_transfer_type_t transfer_type, usb_direction_t direction,
    202214    size_t max_packet_size, unsigned int interval)
     
    204216        hc_t *hc = fun_to_hc(fun);
    205217        assert(hc);
    206         const usb_speed_t speed =
    207             usb_device_keeper_get_speed(&hc->manager, address);
     218        if (address == hc->rh.address)
     219                return EOK;
     220        usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
     221        if (speed >= USB_SPEED_MAX) {
     222                speed = ep_speed;
     223        }
    208224        const size_t size =
    209225            (transfer_type == USB_TRANSFER_INTERRUPT
     
    243259        usb_log_debug("Unregister endpoint %d:%d %d.\n",
    244260            address, endpoint, direction);
     261        endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
     262            address, endpoint, direction, NULL);
     263        if (ep != NULL) {
     264                usb_device_keeper_del_ep(&hc->manager, address, ep);
     265        }
    245266        return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
    246267            endpoint, direction);
    247268}
    248269/*----------------------------------------------------------------------------*/
    249 /** Interrupt out transaction interface function
    250  *
    251  * @param[in] fun DDF function that was called.
    252  * @param[in] target USB device to write to.
    253  * @param[in] max_packet_size maximum size of data packet the device accepts
    254  * @param[in] data Source of data.
    255  * @param[in] size Size of data source.
    256  * @param[in] callback Function to call on transaction completion
    257  * @param[in] arg Additional for callback function.
     270/** Schedule interrupt out transfer.
     271 *
     272 * The callback is supposed to be called once the transfer (on the wire) is
     273 * complete regardless of the outcome.
     274 * However, the callback could be called only when this function returns
     275 * with success status (i.e. returns EOK).
     276 *
     277 * @param[in] fun Device function the action was invoked on.
     278 * @param[in] target Target pipe (address and endpoint number) specification.
     279 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
     280 *      by the caller).
     281 * @param[in] size Size of the @p data buffer in bytes.
     282 * @param[in] callback Callback to be issued once the transfer is complete.
     283 * @param[in] arg Pass-through argument to the callback.
    258284 * @return Error code.
    259285 */
    260286static int interrupt_out(
    261     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     287    ddf_fun_t *fun, usb_target_t target, void *data,
    262288    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
    263289{
     
    276302}
    277303/*----------------------------------------------------------------------------*/
    278 /** Interrupt in transaction interface function
    279  *
    280  * @param[in] fun DDF function that was called.
    281  * @param[in] target USB device to write to.
    282  * @param[in] max_packet_size maximum size of data packet the device accepts
    283  * @param[out] data Data destination.
    284  * @param[in] size Size of data source.
    285  * @param[in] callback Function to call on transaction completion
    286  * @param[in] arg Additional for callback function.
     304/** Schedule interrupt in transfer.
     305 *
     306 * The callback is supposed to be called once the transfer (on the wire) is
     307 * complete regardless of the outcome.
     308 * However, the callback could be called only when this function returns
     309 * with success status (i.e. returns EOK).
     310 *
     311 * @param[in] fun Device function the action was invoked on.
     312 * @param[in] target Target pipe (address and endpoint number) specification.
     313 * @param[in] data Buffer where to store the data (in USB endianess,
     314 *      allocated and deallocated by the caller).
     315 * @param[in] size Size of the @p data buffer in bytes.
     316 * @param[in] callback Callback to be issued once the transfer is complete.
     317 * @param[in] arg Pass-through argument to the callback.
    287318 * @return Error code.
    288319 */
    289320static int interrupt_in(
    290     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     321    ddf_fun_t *fun, usb_target_t target, void *data,
    291322    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
    292323{
     
    305336}
    306337/*----------------------------------------------------------------------------*/
    307 /** Bulk out transaction interface function
    308  *
    309  * @param[in] fun DDF function that was called.
    310  * @param[in] target USB device to write to.
    311  * @param[in] max_packet_size maximum size of data packet the device accepts
    312  * @param[in] data Source of data.
    313  * @param[in] size Size of data source.
    314  * @param[in] callback Function to call on transaction completion
    315  * @param[in] arg Additional for callback function.
     338/** Schedule bulk out transfer.
     339 *
     340 * The callback is supposed to be called once the transfer (on the wire) is
     341 * complete regardless of the outcome.
     342 * However, the callback could be called only when this function returns
     343 * with success status (i.e. returns EOK).
     344 *
     345 * @param[in] fun Device function the action was invoked on.
     346 * @param[in] target Target pipe (address and endpoint number) specification.
     347 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
     348 *      by the caller).
     349 * @param[in] size Size of the @p data buffer in bytes.
     350 * @param[in] callback Callback to be issued once the transfer is complete.
     351 * @param[in] arg Pass-through argument to the callback.
    316352 * @return Error code.
    317353 */
    318354static int bulk_out(
    319     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     355    ddf_fun_t *fun, usb_target_t target, void *data,
    320356    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
    321357{
     
    334370}
    335371/*----------------------------------------------------------------------------*/
    336 /** Bulk in transaction interface function
    337  *
    338  * @param[in] fun DDF function that was called.
    339  * @param[in] target USB device to write to.
    340  * @param[in] max_packet_size maximum size of data packet the device accepts
    341  * @param[out] data Data destination.
    342  * @param[in] size Size of data source.
    343  * @param[in] callback Function to call on transaction completion
    344  * @param[in] arg Additional for callback function.
     372/** Schedule bulk in transfer.
     373 *
     374 * The callback is supposed to be called once the transfer (on the wire) is
     375 * complete regardless of the outcome.
     376 * However, the callback could be called only when this function returns
     377 * with success status (i.e. returns EOK).
     378 *
     379 * @param[in] fun Device function the action was invoked on.
     380 * @param[in] target Target pipe (address and endpoint number) specification.
     381 * @param[in] data Buffer where to store the data (in USB endianess,
     382 *      allocated and deallocated by the caller).
     383 * @param[in] size Size of the @p data buffer in bytes.
     384 * @param[in] callback Callback to be issued once the transfer is complete.
     385 * @param[in] arg Pass-through argument to the callback.
    345386 * @return Error code.
    346387 */
    347388static int bulk_in(
    348     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     389    ddf_fun_t *fun, usb_target_t target, void *data,
    349390    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
    350391{
     
    363404}
    364405/*----------------------------------------------------------------------------*/
    365 /** Control write transaction interface function
    366  *
    367  * @param[in] fun DDF function that was called.
    368  * @param[in] target USB device to write to.
    369  * @param[in] max_packet_size maximum size of data packet the device accepts.
    370  * @param[in] setup_data Data to send with SETUP transfer.
    371  * @param[in] setup_size Size of data to send with SETUP transfer (always 8B).
    372  * @param[in] data Source of data.
    373  * @param[in] size Size of data source.
    374  * @param[in] callback Function to call on transaction completion.
    375  * @param[in] arg Additional for callback function.
     406/** Schedule control write transfer.
     407 *
     408 * The callback is supposed to be called once the transfer (on the wire) is
     409 * complete regardless of the outcome.
     410 * However, the callback could be called only when this function returns
     411 * with success status (i.e. returns EOK).
     412 *
     413 * @param[in] fun Device function the action was invoked on.
     414 * @param[in] target Target pipe (address and endpoint number) specification.
     415 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
     416 *      and deallocated by the caller).
     417 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
     418 * @param[in] data_buffer Data buffer (in USB endianess, allocated and
     419 *      deallocated by the caller).
     420 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
     421 * @param[in] callback Callback to be issued once the transfer is complete.
     422 * @param[in] arg Pass-through argument to the callback.
    376423 * @return Error code.
    377424 */
    378425static int control_write(
    379     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
     426    ddf_fun_t *fun, usb_target_t target,
    380427    void *setup_data, size_t setup_size, void *data, size_t size,
    381428    usbhc_iface_transfer_out_callback_t callback, void *arg)
     
    397444}
    398445/*----------------------------------------------------------------------------*/
    399 /** Control read transaction interface function
    400  *
    401  * @param[in] fun DDF function that was called.
    402  * @param[in] target USB device to write to.
    403  * @param[in] max_packet_size maximum size of data packet the device accepts.
    404  * @param[in] setup_data Data to send with SETUP packet.
    405  * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
    406  * @param[out] data Source of data.
    407  * @param[in] size Size of data source.
    408  * @param[in] callback Function to call on transaction completion.
    409  * @param[in] arg Additional for callback function.
     446/** Schedule control read transfer.
     447 *
     448 * The callback is supposed to be called once the transfer (on the wire) is
     449 * complete regardless of the outcome.
     450 * However, the callback could be called only when this function returns
     451 * with success status (i.e. returns EOK).
     452 *
     453 * @param[in] fun Device function the action was invoked on.
     454 * @param[in] target Target pipe (address and endpoint number) specification.
     455 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
     456 *      and deallocated by the caller).
     457 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
     458 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
     459 *      allocated and deallocated by the caller).
     460 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
     461 * @param[in] callback Callback to be issued once the transfer is complete.
     462 * @param[in] arg Pass-through argument to the callback.
    410463 * @return Error code.
    411464 */
    412465static int control_read(
    413     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
     466    ddf_fun_t *fun, usb_target_t target,
    414467    void *setup_data, size_t setup_size, void *data, size_t size,
    415468    usbhc_iface_transfer_in_callback_t callback, void *arg)
  • uspace/drv/ohci/root_hub.c

    r8790650 r501e5df  
    115115
    116116static const uint32_t hub_set_feature_valid_mask =
    117         (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
     117        (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT) |
     118(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
    118119
    119120
     
    587588        if (!((1 << feature) & hub_set_feature_valid_mask))
    588589                return EINVAL;
     590        if(feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
     591                feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
    589592        instance->registers->rh_status =
    590593                (instance->registers->rh_status | (1 << feature))
  • uspace/drv/uhci-hcd/iface.c

    r8790650 r501e5df  
    7474            name, target.address, target.endpoint, size, ep->max_packet_size);
    7575
    76         assert(ep->speed ==
    77             usb_device_keeper_get_speed(&(*hc)->manager, target.address));
     76//      assert(ep->speed ==
     77//          usb_device_keeper_get_speed(&(*hc)->manager, target.address));
    7878//      assert(ep->max_packet_size == max_packet_size);
    7979//      assert(ep->transfer_type == USB_TRANSFER_CONTROL);
     
    198198/*----------------------------------------------------------------------------*/
    199199static int register_endpoint(
    200     ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
     200    ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
     201    usb_endpoint_t endpoint,
    201202    usb_transfer_type_t transfer_type, usb_direction_t direction,
    202203    size_t max_packet_size, unsigned int interval)
     
    204205        hc_t *hc = fun_to_hc(fun);
    205206        assert(hc);
    206         const usb_speed_t speed =
    207             usb_device_keeper_get_speed(&hc->manager, address);
    208         const size_t size = max_packet_size;
     207        usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
     208        if (speed >= USB_SPEED_MAX) {
     209                speed = ep_speed;
     210        }
     211        const size_t size =
     212            (transfer_type == USB_TRANSFER_INTERRUPT
     213            || transfer_type == USB_TRANSFER_ISOCHRONOUS) ?
     214            max_packet_size : 0;
    209215        int ret;
    210216
     
    240246        usb_log_debug("Unregister endpoint %d:%d %d.\n",
    241247            address, endpoint, direction);
     248        endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
     249            address, endpoint, direction, NULL);
     250        if (ep != NULL) {
     251                usb_device_keeper_del_ep(&hc->manager, address, ep);
     252        }
    242253        return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
    243254            endpoint, direction);
     
    248259 * @param[in] fun DDF function that was called.
    249260 * @param[in] target USB device to write to.
    250  * @param[in] max_packet_size maximum size of data packet the device accepts
    251261 * @param[in] data Source of data.
    252262 * @param[in] size Size of data source.
     
    256266 */
    257267static int interrupt_out(
    258     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     268    ddf_fun_t *fun, usb_target_t target, void *data,
    259269    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
    260270{
     
    277287 * @param[in] fun DDF function that was called.
    278288 * @param[in] target USB device to write to.
    279  * @param[in] max_packet_size maximum size of data packet the device accepts
    280289 * @param[out] data Data destination.
    281290 * @param[in] size Size of data source.
     
    285294 */
    286295static int interrupt_in(
    287     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     296    ddf_fun_t *fun, usb_target_t target, void *data,
    288297    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
    289298{
     
    306315 * @param[in] fun DDF function that was called.
    307316 * @param[in] target USB device to write to.
    308  * @param[in] max_packet_size maximum size of data packet the device accepts
    309317 * @param[in] data Source of data.
    310318 * @param[in] size Size of data source.
     
    314322 */
    315323static int bulk_out(
    316     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     324    ddf_fun_t *fun, usb_target_t target, void *data,
    317325    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
    318326{
     
    335343 * @param[in] fun DDF function that was called.
    336344 * @param[in] target USB device to write to.
    337  * @param[in] max_packet_size maximum size of data packet the device accepts
    338345 * @param[out] data Data destination.
    339346 * @param[in] size Size of data source.
     
    343350 */
    344351static int bulk_in(
    345     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
     352    ddf_fun_t *fun, usb_target_t target, void *data,
    346353    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
    347354{
     
    364371 * @param[in] fun DDF function that was called.
    365372 * @param[in] target USB device to write to.
    366  * @param[in] max_packet_size maximum size of data packet the device accepts.
    367373 * @param[in] setup_data Data to send with SETUP transfer.
    368374 * @param[in] setup_size Size of data to send with SETUP transfer (always 8B).
     
    374380 */
    375381static int control_write(
    376     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
     382    ddf_fun_t *fun, usb_target_t target,
    377383    void *setup_data, size_t setup_size, void *data, size_t size,
    378384    usbhc_iface_transfer_out_callback_t callback, void *arg)
     
    398404 * @param[in] fun DDF function that was called.
    399405 * @param[in] target USB device to write to.
    400  * @param[in] max_packet_size maximum size of data packet the device accepts.
    401406 * @param[in] setup_data Data to send with SETUP packet.
    402407 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
     
    408413 */
    409414static int control_read(
    410     ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
     415    ddf_fun_t *fun, usb_target_t target,
    411416    void *setup_data, size_t setup_size, void *data, size_t size,
    412417    usbhc_iface_transfer_in_callback_t callback, void *arg)
  • uspace/drv/usbhub/Makefile

    r8790650 r501e5df  
    3434SOURCES = \
    3535        main.c \
    36         ports.c \
    3736        utils.c \
    38         usbhub.c
     37        usbhub.c \
     38        ports.c
    3939
    4040include $(USPACE_PREFIX)/Makefile.common
  • uspace/drv/usbhub/port_status.h

    r8790650 r501e5df  
    4949
    5050/**
     51 * structure holding hub status and changes flags.
     52 * should not be accessed directly, use supplied getter/setter methods.
     53 *
     54 * For more information refer to table 11.16.2.5 in
     55 * "Universal Serial Bus Specification Revision 1.1"
     56 *
     57 */
     58typedef uint32_t usb_hub_status_t;
     59
     60/**
    5161 * set values in request to be it a port status request
    5262 * @param request
     
    5464 */
    5565static inline void usb_hub_set_port_status_request(
    56 usb_device_request_setup_packet_t * request, uint16_t port
    57 ){
     66        usb_device_request_setup_packet_t * request, uint16_t port
     67        ) {
    5868        request->index = port;
    5969        request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS;
     
    6373}
    6474
     75/**
     76 * set values in request to be it a port status request
     77 * @param request
     78 * @param port
     79 */
     80static inline void usb_hub_set_hub_status_request(
     81        usb_device_request_setup_packet_t * request
     82        ) {
     83        request->index = 0;
     84        request->request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS;
     85        request->request = USB_HUB_REQUEST_GET_STATUS;
     86        request->value = 0;
     87        request->length = 4;
     88}
    6589
    6690/**
     
    7094 */
    7195static inline usb_device_request_setup_packet_t *
    72 usb_hub_create_port_status_request(uint16_t port){
     96usb_hub_create_port_status_request(uint16_t port) {
    7397        usb_device_request_setup_packet_t * result =
    74                 usb_new(usb_device_request_setup_packet_t);
    75         usb_hub_set_port_status_request(result,port);
     98                malloc(sizeof(usb_device_request_setup_packet_t));
     99        usb_hub_set_port_status_request(result, port);
    76100        return result;
    77101}
    78102
    79 
    80103/**
    81104 * set the device request to be a port feature enable request
     
    85108 */
    86109static inline void usb_hub_set_enable_port_feature_request(
    87 usb_device_request_setup_packet_t * request, uint16_t port,
    88                 uint16_t feature_selector
    89 ){
     110        usb_device_request_setup_packet_t * request, uint16_t port,
     111        uint16_t feature_selector
     112        ) {
    90113        request->index = port;
    91114        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    102125 */
    103126static inline void usb_hub_set_disable_port_feature_request(
    104 usb_device_request_setup_packet_t * request, uint16_t port,
    105                 uint16_t feature_selector
    106 ){
     127        usb_device_request_setup_packet_t * request, uint16_t port,
     128        uint16_t feature_selector
     129        ) {
    107130        request->index = port;
    108131        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    118141 */
    119142static inline void usb_hub_set_enable_port_request(
    120 usb_device_request_setup_packet_t * request, uint16_t port
    121 ){
     143        usb_device_request_setup_packet_t * request, uint16_t port
     144        ) {
    122145        request->index = port;
    123146        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    133156 */
    134157static inline usb_device_request_setup_packet_t *
    135 usb_hub_create_enable_port_request(uint16_t port){
     158usb_hub_create_enable_port_request(uint16_t port) {
    136159        usb_device_request_setup_packet_t * result =
    137                 usb_new(usb_device_request_setup_packet_t);
    138         usb_hub_set_enable_port_request(result,port);
     160                malloc(sizeof(usb_device_request_setup_packet_t));
     161        usb_hub_set_enable_port_request(result, port);
    139162        return result;
    140163}
     
    146169 */
    147170static inline void usb_hub_set_disable_port_request(
    148 usb_device_request_setup_packet_t * request, uint16_t port
    149 ){
     171        usb_device_request_setup_packet_t * request, uint16_t port
     172        ) {
    150173        request->index = port;
    151174        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    161184 */
    162185static inline usb_device_request_setup_packet_t *
    163 usb_hub_create_disable_port_request(uint16_t port){
     186usb_hub_create_disable_port_request(uint16_t port) {
    164187        usb_device_request_setup_packet_t * result =
    165                 usb_new(usb_device_request_setup_packet_t);
    166         usb_hub_set_disable_port_request(result,port);
     188                malloc(sizeof(usb_device_request_setup_packet_t));
     189        usb_hub_set_disable_port_request(result, port);
    167190        return result;
    168191}
     
    174197 */
    175198static inline void usb_hub_set_reset_port_request(
    176 usb_device_request_setup_packet_t * request, uint16_t port
    177 ){
     199        usb_device_request_setup_packet_t * request, uint16_t port
     200        ) {
    178201        request->index = port;
    179202        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    189212 */
    190213static inline usb_device_request_setup_packet_t *
    191 usb_hub_create_reset_port_request(uint16_t port){
     214usb_hub_create_reset_port_request(uint16_t port) {
    192215        usb_device_request_setup_packet_t * result =
    193                 usb_new(usb_device_request_setup_packet_t);
    194         usb_hub_set_reset_port_request(result,port);
     216                malloc(sizeof(usb_device_request_setup_packet_t));
     217        usb_hub_set_reset_port_request(result, port);
    195218        return result;
    196219}
     
    202225 */
    203226static inline void usb_hub_set_power_port_request(
    204 usb_device_request_setup_packet_t * request, uint16_t port
    205 ){
     227        usb_device_request_setup_packet_t * request, uint16_t port
     228        ) {
    206229        request->index = port;
    207230        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    217240 */
    218241static inline void usb_hub_unset_power_port_request(
    219 usb_device_request_setup_packet_t * request, uint16_t port
    220 ){
     242        usb_device_request_setup_packet_t * request, uint16_t port
     243        ) {
    221244        request->index = port;
    222245        request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
     
    226249}
    227250
    228 
    229 /** get i`th bit of port status */
    230 static inline bool usb_port_get_bit(usb_port_status_t * status, int idx)
    231 {
    232         return (((*status)>>(idx))%2);
    233 }
    234 
    235 /** set i`th bit of port status */
    236 static inline void usb_port_set_bit(
    237         usb_port_status_t * status, int idx, bool value)
    238 {
    239         (*status) = value?
    240                                ((*status)|(1<<(idx))):
    241                                ((*status)&(~(1<<(idx))));
    242 }
    243 
    244 //device connnected on port
    245 static inline bool usb_port_dev_connected(usb_port_status_t * status){
    246         return usb_port_get_bit(status,0);
    247 }
    248 
    249 static inline void usb_port_set_dev_connected(usb_port_status_t * status,bool connected){
    250         usb_port_set_bit(status,0,connected);
     251/**
     252 * get i`th bit of port status
     253 *
     254 * @param status
     255 * @param idx
     256 * @return
     257 */
     258static inline bool usb_port_is_status(usb_port_status_t status, int idx) {
     259        return (status&(1 << idx))!=0;
     260}
     261
     262/**
     263 * set i`th bit of port status
     264 *
     265 * @param status
     266 * @param idx
     267 * @param value
     268 */
     269static inline void usb_port_status_set_bit(
     270        usb_port_status_t * status, int idx, bool value) {
     271        (*status) = value ?
     272                ((*status) | (1 << (idx))) :
     273                ((*status)&(~(1 << (idx))));
     274}
     275
     276/**
     277 * get i`th bit of hub status
     278 *
     279 * @param status
     280 * @param idx
     281 * @return
     282 */
     283static inline bool usb_hub_is_status(usb_hub_status_t status, int idx) {
     284        return (status&(1 << idx))!=0;
     285}
     286
     287/**
     288 * set i`th bit of hub status
     289 *
     290 * @param status
     291 * @param idx
     292 * @param value
     293 */
     294static inline void usb_hub_status_set_bit(
     295        usb_hub_status_t * status, int idx, bool value) {
     296        (*status) = value ?
     297                ((*status) | (1 << (idx))) :
     298                ((*status)&(~(1 << (idx))));
     299}
     300
     301
     302#if 0
     303/**
     304 * connection status geter for port status
     305 *
     306 * @param status
     307 * @return true if there is something connected
     308 */
     309static inline bool usb_port_dev_connected(usb_port_status_t * status) {
     310        return usb_port_get_bit(status, 0);
     311}
     312
     313/**
     314 * set device connected bit in port status
     315 *
     316 * @param status
     317 * @param connected value of the bit
     318 */
     319static inline void usb_port_set_dev_connected(usb_port_status_t * status, bool connected) {
     320        usb_port_set_bit(status, 0, connected);
    251321}
    252322
    253323//port enabled
    254 static inline bool usb_port_enabled(usb_port_status_t * status){
    255         return usb_port_get_bit(status,1);
    256 }
    257 
    258 static inline void usb_port_set_enabled(usb_port_status_t * status,bool enabled){
    259         usb_port_set_bit(status,1,enabled);
     324
     325/**
     326 * port enabled getter for port status
     327 *
     328 * @param status
     329 * @return true if the port is enabled
     330 */
     331static inline bool usb_port_enabled(usb_port_status_t * status) {
     332        return usb_port_get_bit(status, 1);
     333}
     334
     335/**
     336 * set port enabled bit in port status
     337 *
     338 * @param status
     339 * @param enabled value of the bit
     340 */
     341static inline void usb_port_set_enabled(usb_port_status_t * status, bool enabled) {
     342        usb_port_set_bit(status, 1, enabled);
    260343}
    261344
    262345//port suspended
    263 static inline bool usb_port_suspended(usb_port_status_t * status){
    264         return usb_port_get_bit(status,2);
    265 }
    266 
    267 static inline void usb_port_set_suspended(usb_port_status_t * status,bool suspended){
    268         usb_port_set_bit(status,2,suspended);
     346/**
     347 * port suspended getter for port status
     348 *
     349 * @param status
     350 * @return true if port is suspended
     351 */
     352static inline bool usb_port_suspended(usb_port_status_t * status) {
     353        return usb_port_get_bit(status, 2);
     354}
     355
     356/**
     357 * set port suspended bit in port status
     358 *
     359 * @param status
     360 * @param suspended value of the bit
     361 */
     362static inline void usb_port_set_suspended(usb_port_status_t * status, bool suspended) {
     363        usb_port_set_bit(status, 2, suspended);
    269364}
    270365
    271366//over currect
    272 static inline bool usb_port_over_current(usb_port_status_t * status){
    273         return usb_port_get_bit(status,3);
    274 }
    275 
    276 static inline void usb_port_set_over_current(usb_port_status_t * status,bool value){
    277         usb_port_set_bit(status,3,value);
     367/**
     368 * over current condition indicator getter for port status
     369 *
     370 * @param status
     371 * @return true if there is opver-current condition on the hub
     372 */
     373static inline bool usb_port_over_current(usb_port_status_t * status) {
     374        return usb_port_get_bit(status, 3);
     375}
     376
     377/**
     378 * set over current indicator bit in port status
     379 *
     380 * @param status
     381 * @param value value of the bit
     382 */
     383static inline void usb_port_set_over_current(usb_port_status_t * status, bool value) {
     384        usb_port_set_bit(status, 3, value);
    278385}
    279386
    280387//port reset
    281 static inline bool usb_port_reset(usb_port_status_t * status){
    282         return usb_port_get_bit(status,4);
    283 }
    284 
    285 static inline void usb_port_set_reset(usb_port_status_t * status,bool value){
    286         usb_port_set_bit(status,4,value);
     388/**
     389 * port reset indicator getter for port status
     390 *
     391 * @param status
     392 * @return true if port is reset
     393 */
     394static inline bool usb_port_reset(usb_port_status_t * status) {
     395        return usb_port_get_bit(status, 4);
     396}
     397
     398/**
     399 * set port reset bit in port status
     400 *
     401 * @param status
     402 * @param value value of the bit
     403 */
     404static inline void usb_port_set_reset(usb_port_status_t * status, bool value) {
     405        usb_port_set_bit(status, 4, value);
    287406}
    288407
    289408//powered
    290 static inline bool usb_port_powered(usb_port_status_t * status){
    291         return usb_port_get_bit(status,8);
    292 }
    293 
    294 static inline void usb_port_set_powered(usb_port_status_t * status,bool powered){
    295         usb_port_set_bit(status,8,powered);
    296 }
     409/**
     410 * power state getter for port status
     411 *
     412 * @param status
     413 * @return true if port is powered
     414 */
     415static inline bool usb_port_powered(usb_port_status_t * status) {
     416        return usb_port_get_bit(status, 8);
     417}
     418
     419/**
     420 * set port powered bit in port status
     421 *
     422 * @param status
     423 * @param powered value of the bit
     424 */
     425static inline void usb_port_set_powered(usb_port_status_t * status, bool powered) {
     426        usb_port_set_bit(status, 8, powered);
     427}
     428
     429#endif
    297430
    298431//low speed device attached
    299 static inline bool usb_port_low_speed(usb_port_status_t * status){
    300         return usb_port_get_bit(status,9);
    301 }
    302 
    303 static inline void usb_port_set_low_speed(usb_port_status_t * status,bool low_speed){
    304         usb_port_set_bit(status,9,low_speed);
    305 }
    306 
    307 //low speed device attached
    308 static inline bool usb_port_high_speed(usb_port_status_t * status){
    309         return usb_port_get_bit(status,10);
    310 }
    311 
    312 static inline void usb_port_set_high_speed(usb_port_status_t * status,bool high_speed){
    313         usb_port_set_bit(status,10,high_speed);
    314 }
    315 
    316 static inline usb_speed_t usb_port_speed(usb_port_status_t * status){
    317         if(usb_port_low_speed(status))
     432/**
     433 * low speed device on the port indicator
     434 *
     435 * @param status
     436 * @return true if low speed device is attached
     437 */
     438static inline bool usb_port_low_speed(usb_port_status_t status) {
     439        return usb_port_is_status(status, 9);
     440}
     441
     442/**
     443 * set low speed device connected bit in port status
     444 *
     445 * @param status
     446 * @param low_speed value of the bit
     447 */
     448static inline void usb_port_set_low_speed(usb_port_status_t * status, bool low_speed) {
     449        usb_port_status_set_bit(status, 9, low_speed);
     450}
     451
     452//high speed device attached
     453/**
     454 * high speed device on the port indicator
     455 *
     456 * @param status
     457 * @return true if high speed device is on port
     458 */
     459static inline bool usb_port_high_speed(usb_port_status_t status) {
     460        return usb_port_is_status(status, 10);
     461}
     462
     463/**
     464 * set high speed device bit in port status
     465 *
     466 * @param status
     467 * @param high_speed value of the bit
     468 */
     469static inline void usb_port_set_high_speed(usb_port_status_t * status, bool high_speed) {
     470        usb_port_status_set_bit(status, 10, high_speed);
     471}
     472
     473/**
     474 * speed getter for port status
     475 *
     476 * @param status
     477 * @return speed of usb device (for more see usb specification)
     478 */
     479static inline usb_speed_t usb_port_speed(usb_port_status_t status) {
     480        if (usb_port_low_speed(status))
    318481                return USB_SPEED_LOW;
    319         if(usb_port_high_speed(status))
     482        if (usb_port_high_speed(status))
    320483                return USB_SPEED_HIGH;
    321484        return USB_SPEED_FULL;
    322485}
    323486
    324 
     487#if 0
    325488//connect change
    326 static inline bool usb_port_connect_change(usb_port_status_t * status){
    327         return usb_port_get_bit(status,16);
    328 }
    329 
    330 static inline void usb_port_set_connect_change(usb_port_status_t * status,bool change){
    331         usb_port_set_bit(status,16,change);
     489/**
     490 * port connect change indicator
     491 *
     492 * @param status
     493 * @return true if connection has changed
     494 */
     495static inline bool usb_port_connect_change(usb_port_status_t * status) {
     496        return usb_port_get_bit(status, 16);
     497}
     498
     499/**
     500 * set connection change bit in port status
     501 * @param status
     502 * @param change value of the bit
     503 */
     504static inline void usb_port_set_connect_change(usb_port_status_t * status, bool change) {
     505        usb_port_set_bit(status, 16, change);
    332506}
    333507
    334508//port enable change
    335 static inline bool usb_port_enabled_change(usb_port_status_t * status){
    336         return usb_port_get_bit(status,17);
    337 }
    338 
    339 static inline void usb_port_set_enabled_change(usb_port_status_t * status,bool change){
    340         usb_port_set_bit(status,17,change);
     509/**
     510 * port enable change for port status
     511 *
     512 * @param status
     513 * @return true if the port has been enabled/disabled
     514 */
     515static inline bool usb_port_enabled_change(usb_port_status_t * status) {
     516        return usb_port_get_bit(status, 17);
     517}
     518
     519/**
     520 * set port enable change bit in port status
     521 *
     522 * @param status
     523 * @param change value of the bit
     524 */
     525static inline void usb_port_set_enabled_change(usb_port_status_t * status, bool change) {
     526        usb_port_set_bit(status, 17, change);
    341527}
    342528
    343529//suspend change
    344 static inline bool usb_port_suspend_change(usb_port_status_t * status){
    345         return usb_port_get_bit(status,18);
    346 }
    347 
    348 static inline void usb_port_set_suspend_change(usb_port_status_t * status,bool change){
    349         usb_port_set_bit(status,18,change);
     530/**
     531 * port suspend change for port status
     532 *
     533 * @param status
     534 * @return ture if suspend status has changed
     535 */
     536static inline bool usb_port_suspend_change(usb_port_status_t * status) {
     537        return usb_port_get_bit(status, 18);
     538}
     539
     540/**
     541 * set port suspend change bit in port status
     542 *
     543 * @param status
     544 * @param change value of the bit
     545 */
     546static inline void usb_port_set_suspend_change(usb_port_status_t * status, bool change) {
     547        usb_port_set_bit(status, 18, change);
    350548}
    351549
    352550//over current change
    353 static inline bool usb_port_overcurrent_change(usb_port_status_t * status){
    354         return usb_port_get_bit(status,19);
    355 }
    356 
    357 static inline void usb_port_set_overcurrent_change(usb_port_status_t * status,bool change){
    358         usb_port_set_bit(status,19,change);
     551/**
     552 * over current change indicator
     553 *
     554 * @param status
     555 * @return true if over-current condition on port has changed
     556 */
     557static inline bool usb_port_overcurrent_change(usb_port_status_t * status) {
     558        return usb_port_get_bit(status, 19);
     559}
     560
     561/**
     562 * set port over current change bit in port status
     563 *
     564 * @param status
     565 * @param change value of the bit
     566 */
     567static inline void usb_port_set_overcurrent_change(usb_port_status_t * status, bool change) {
     568        usb_port_set_bit(status, 19, change);
    359569}
    360570
    361571//reset change
    362 static inline bool usb_port_reset_completed(usb_port_status_t * status){
    363         return usb_port_get_bit(status,20);
    364 }
    365 
    366 static inline void usb_port_set_reset_completed(usb_port_status_t * status,bool completed){
    367         usb_port_set_bit(status,20,completed);
    368 }
    369 
     572/**
     573 * port reset change indicator
     574 * @param status
     575 * @return true if port has been reset
     576 */
     577static inline bool usb_port_reset_completed(usb_port_status_t * status) {
     578        return usb_port_get_bit(status, 20);
     579}
     580
     581/**
     582 * set port reset completed bit in port status
     583 *
     584 * @param status
     585 * @param change value of the bit
     586 */
     587static inline void usb_port_set_reset_completed(usb_port_status_t * status, bool completed) {
     588        usb_port_set_bit(status, 20, completed);
     589}
     590
     591//local power status
     592/**
     593 * local power lost indicator for hub status
     594 *
     595 * @param status
     596 * @return true if hub is not powered
     597 */
     598static inline bool usb_hub_local_power_lost(usb_hub_status_t * status) {
     599        return usb_hub_get_bit(status, 0);
     600}
     601
     602/**
     603 * set hub power lost bit in hub status
     604 *
     605 * @param status
     606 * @param change value of the bit
     607 */
     608static inline void usb_hub_set_local_power_lost(usb_port_status_t * status,
     609        bool power_lost) {
     610        usb_hub_set_bit(status, 0, power_lost);
     611}
     612
     613//over current ocndition
     614/**
     615 * hub over-current indicator
     616 *
     617 * @param status
     618 * @return true if over-current condition occurred on hub
     619 */
     620static inline bool usb_hub_over_current(usb_hub_status_t * status) {
     621        return usb_hub_get_bit(status, 1);
     622}
     623
     624/**
     625 * set hub over current bit in hub status
     626 *
     627 * @param status
     628 * @param change value of the bit
     629 */
     630static inline void usb_hub_set_over_current(usb_port_status_t * status,
     631        bool over_current) {
     632        usb_hub_set_bit(status, 1, over_current);
     633}
     634
     635//local power change
     636/**
     637 * hub power change indicator
     638 *
     639 * @param status
     640 * @return true if local power status has been changed - power has been
     641 * dropped or re-established
     642 */
     643static inline bool usb_hub_local_power_change(usb_hub_status_t * status) {
     644        return usb_hub_get_bit(status, 16);
     645}
     646
     647/**
     648 * set hub power change bit in hub status
     649 *
     650 * @param status
     651 * @param change value of the bit
     652 */
     653static inline void usb_hub_set_local_power_change(usb_port_status_t * status,
     654        bool change) {
     655        usb_hub_set_bit(status, 16, change);
     656}
     657
     658//local power status
     659/**
     660 * hub over-current condition change indicator
     661 *
     662 * @param status
     663 * @return true if over-current condition has changed
     664 */
     665static inline bool usb_hub_over_current_change(usb_hub_status_t * status) {
     666        return usb_hub_get_bit(status, 17);
     667}
     668
     669/**
     670 * set hub over current change bit in hub status
     671 *
     672 * @param status
     673 * @param change value of the bit
     674 */
     675static inline void usb_hub_set_over_current_change(usb_port_status_t * status,
     676        bool change) {
     677        usb_hub_set_bit(status, 17, change);
     678}
     679#endif
    370680
    371681
  • uspace/drv/usbhub/ports.c

    r8790650 r501e5df  
    3333 * Hub ports functions.
    3434 */
    35 #include "port_status.h"
    36 #include <inttypes.h>
     35
     36#include <bool.h>
    3737#include <errno.h>
    3838#include <str_error.h>
    39 #include <usb/request.h>
     39#include <inttypes.h>
     40#include <fibril_synch.h>
     41
    4042#include <usb/debug.h>
     43
     44#include "ports.h"
     45#include "usbhub.h"
     46#include "usbhub_private.h"
     47#include "port_status.h"
     48
     49
     50/** Information for fibril for device discovery. */
     51struct add_device_phase1 {
     52        usb_hub_info_t *hub;
     53        size_t port;
     54        usb_speed_t speed;
     55};
     56
     57static void usb_hub_removed_device(
     58        usb_hub_info_t * hub, uint16_t port);
     59
     60static void usb_hub_port_reset_completed(usb_hub_info_t * hub,
     61        uint16_t port, uint32_t status);
     62
     63static void usb_hub_port_over_current(usb_hub_info_t * hub,
     64        uint16_t port, uint32_t status);
     65
     66static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
     67    usb_port_status_t *status);
     68
     69static int enable_port_callback(int port_no, void *arg);
     70
     71static int add_device_phase1_worker_fibril(void *arg);
     72
     73static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
     74    usb_speed_t speed);
     75
     76/**
     77 * Process interrupts on given hub port
     78 *
     79 * Accepts connection, over current and port reset change.
     80 * @param hub hub representation
     81 * @param port port number, starting from 1
     82 */
     83void usb_hub_process_interrupt(usb_hub_info_t * hub,
     84        uint16_t port) {
     85        usb_log_debug("interrupt at port %d\n", port);
     86        //determine type of change
     87        //usb_pipe_t *pipe = hub->control_pipe;
     88
     89        int opResult;
     90
     91        usb_port_status_t status;
     92        opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status);
     93        if (opResult != EOK) {
     94                usb_log_error("Failed to get port %zu status: %s.\n",
     95                    port, str_error(opResult));
     96                return;
     97        }
     98        //connection change
     99        if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) {
     100                bool device_connected = usb_port_is_status(status,
     101                    USB_HUB_FEATURE_PORT_CONNECTION);
     102                usb_log_debug("Connection change on port %zu: %s.\n", port,
     103                    device_connected ? "device attached" : "device removed");
     104
     105                if (device_connected) {
     106                        opResult = create_add_device_fibril(hub, port,
     107                            usb_port_speed(status));
     108                        if (opResult != EOK) {
     109                                usb_log_error(
     110                                    "Cannot handle change on port %zu: %s.\n",
     111                                    str_error(opResult));
     112                        }
     113                } else {
     114                        usb_hub_removed_device(hub, port);
     115                }
     116        }
     117        //over current
     118        if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) {
     119                //check if it was not auto-resolved
     120                usb_log_debug("overcurrent change on port\n");
     121                usb_hub_port_over_current(hub, port, status);
     122        }
     123        //port reset
     124        if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) {
     125                usb_hub_port_reset_completed(hub, port, status);
     126        }
     127        usb_log_debug("status x%x : %d\n ", status, status);
     128
     129        usb_port_status_set_bit(
     130            &status, USB_HUB_FEATURE_C_PORT_CONNECTION,false);
     131        usb_port_status_set_bit(
     132            &status, USB_HUB_FEATURE_PORT_RESET,false);
     133        usb_port_status_set_bit(
     134            &status, USB_HUB_FEATURE_C_PORT_RESET,false);
     135        usb_port_status_set_bit(
     136            &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT,false);
     137        /// \TODO what about port power change?
     138        if (status >> 16) {
     139                usb_log_info("there was unsupported change on port %d: %X\n",
     140                        port, status);
     141
     142        }
     143}
     144
     145
     146/**
     147 * routine called when a device on port has been removed
     148 *
     149 * If the device on port had default address, it releases default address.
     150 * Otherwise does not do anything, because DDF does not allow to remove device
     151 * from it`s device tree.
     152 * @param hub hub representation
     153 * @param port port number, starting from 1
     154 */
     155static void usb_hub_removed_device(
     156        usb_hub_info_t * hub, uint16_t port) {
     157
     158        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
     159                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
     160        if (opResult != EOK) {
     161                usb_log_warning("could not clear port-change-connection flag\n");
     162        }
     163        /** \TODO remove device from device manager - not yet implemented in
     164         * devide manager
     165         */
     166
     167        //close address
     168        //if (hub->attached_devs[port].address != 0) {
     169        if(hub->ports[port].attached_device.address >= 0){
     170                /*uncomment this code to use it when DDF allows device removal
     171                opResult = usb_hc_unregister_device(
     172                        &hub->connection,
     173                        hub->attached_devs[port].address);
     174                if(opResult != EOK) {
     175                        dprintf(USB_LOG_LEVEL_WARNING, "could not release "
     176                                "address of "
     177                            "removed device: %d", opResult);
     178                }
     179                hub->attached_devs[port].address = 0;
     180                hub->attached_devs[port].handle = 0;
     181                 */
     182        } else {
     183                usb_log_warning("this is strange, disconnected device had "
     184                        "no address\n");
     185                //device was disconnected before it`s port was reset -
     186                //return default address
     187                usb_hub_release_default_address(hub);
     188        }
     189}
     190
     191
     192/**
     193 * Process port reset change
     194 *
     195 * After this change port should be enabled, unless some problem occured.
     196 * This functions triggers second phase of enabling new device.
     197 * @param hub
     198 * @param port
     199 * @param status
     200 */
     201static void usb_hub_port_reset_completed(usb_hub_info_t * hub,
     202        uint16_t port, uint32_t status){
     203        usb_log_debug("Port %zu reset complete.\n", port);
     204        if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) {
     205                /* Finalize device adding. */
     206                usb_hub_port_t *the_port = hub->ports + port;
     207                fibril_mutex_lock(&the_port->reset_mutex);
     208                the_port->reset_completed = true;
     209                fibril_condvar_broadcast(&the_port->reset_cv);
     210                fibril_mutex_unlock(&the_port->reset_mutex);
     211        } else {
     212                usb_log_warning(
     213                    "Port %zu reset complete but port not enabled.\n",
     214                    port);
     215        }
     216}
     217
     218/**
     219 * Process over current condition on port.
     220 *
     221 * Turn off the power on the port.
     222 *
     223 * @param hub hub representation
     224 * @param port port number, starting from 1
     225 */
     226static void usb_hub_port_over_current(usb_hub_info_t * hub,
     227        uint16_t port, uint32_t status) {
     228        int opResult;
     229        if(usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)){
     230                opResult = usb_hub_clear_port_feature(hub->control_pipe,
     231                        port, USB_HUB_FEATURE_PORT_POWER);
     232                if (opResult != EOK) {
     233                        usb_log_error("cannot power off port %d;  %d\n",
     234                                port, opResult);
     235                }
     236        }else{
     237                opResult = usb_hub_set_port_feature(hub->control_pipe,
     238                        port, USB_HUB_FEATURE_PORT_POWER);
     239                if (opResult != EOK) {
     240                        usb_log_error("cannot power on port %d;  %d\n",
     241                                port, opResult);
     242                }
     243        }
     244}
    41245
    42246/** Retrieve port status.
     
    73277}
    74278
    75 /** Information for fibril for device discovery. */
    76 struct add_device_phase1 {
    77         usb_hub_info_t *hub;
    78         size_t port;
    79         usb_speed_t speed;
    80 };
    81 
    82279/** Callback for enabling a specific port.
    83280 *
     
    91288static int enable_port_callback(int port_no, void *arg)
    92289{
    93         usb_hub_info_t *hub = (usb_hub_info_t *) arg;
     290        usb_hub_info_t *hub = arg;
    94291        int rc;
    95292        usb_device_request_setup_packet_t request;
     
    156353        data->hub->ports[data->port].attached_device.address = new_address;
    157354
    158         usb_log_info("Detected new device on `%s' (port %zu), " \
     355        usb_log_info("Detected new device on `%s' (port %zu), "
    159356            "address %d (handle %" PRIun ").\n",
    160357            data->hub->usb_device->ddf_dev->name, data->port,
     
    166363        return EOK;
    167364}
     365
    168366
    169367/** Start device adding when connection change is detected.
     
    176374 * @return Error code.
    177375 */
    178 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,
     376static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
    179377    usb_speed_t speed)
    180378{
     
    213411}
    214412
    215 /** Process change on a single port.
    216  *
    217  * @param hub Hub to which the port belongs.
    218  * @param port Port index (starting at 1).
    219  */
    220 static void process_port_change(usb_hub_info_t *hub, size_t port)
    221 {
    222         int rc;
    223 
    224         usb_port_status_t port_status;
    225 
    226         rc = get_port_status(&hub->usb_device->ctrl_pipe, port, &port_status);
    227         if (rc != EOK) {
    228                 usb_log_error("Failed to get port %zu status: %s.\n",
    229                     port, str_error(rc));
    230                 return;
    231         }
    232 
    233         /*
    234          * Check exact nature of the change.
    235          */
    236         usb_log_debug("Port %zu change status: %x.\n", port,
    237             (unsigned int) port_status);
    238 
    239         if (usb_port_connect_change(&port_status)) {
    240                 bool device_connected = usb_port_dev_connected(&port_status);
    241                 usb_log_debug("Connection change on port %zu: %s.\n", port,
    242                     device_connected ? "device attached" : "device removed");
    243 
    244                 if (device_connected) {
    245                         rc = add_device_phase1_new_fibril(hub, port,
    246                             usb_port_speed(&port_status));
    247                         if (rc != EOK) {
    248                                 usb_log_error(
    249                                     "Cannot handle change on port %zu: %s.\n",
    250                                     str_error(rc));
    251                         }
    252                 } else {
    253                         usb_hub_removed_device(hub, port);
    254                 }
    255         }
    256 
    257         if (usb_port_overcurrent_change(&port_status)) {
    258                 if (usb_port_over_current(&port_status)) {
    259                         usb_log_warning("Overcurrent on port %zu.\n", port);
    260                         usb_hub_over_current(hub, port);
    261                 } else {
    262                         usb_log_debug("Overcurrent on port %zu autoresolved.\n",
    263                             port);
    264                 }
    265         }
    266 
    267         if (usb_port_reset_completed(&port_status)) {
    268                 usb_log_debug("Port %zu reset complete.\n", port);
    269                 if (usb_port_enabled(&port_status)) {
    270                         /* Finalize device adding. */
    271                         usb_hub_port_t *the_port = hub->ports + port;
    272                         fibril_mutex_lock(&the_port->reset_mutex);
    273                         the_port->reset_completed = true;
    274                         fibril_condvar_broadcast(&the_port->reset_cv);
    275                         fibril_mutex_unlock(&the_port->reset_mutex);
    276                 } else {
    277                         usb_log_warning(
    278                             "Port %zu reset complete but port not enabled.\n",
    279                             port);
    280                 }
    281         }
    282 
    283         usb_port_set_connect_change(&port_status, false);
    284         usb_port_set_reset(&port_status, false);
    285         usb_port_set_reset_completed(&port_status, false);
    286         usb_port_set_dev_connected(&port_status, false);
    287         if (port_status >> 16) {
    288                 usb_log_warning("Unsupported change on port %zu: %x.\n",
    289                     port, (unsigned int) port_status);
    290         }
    291 }
    292 
    293 
    294 /** Callback for polling hub for port changes.
    295  *
    296  * @param dev Device where the change occured.
    297  * @param change_bitmap Bitmap of changed ports.
    298  * @param change_bitmap_size Size of the bitmap in bytes.
    299  * @param arg Custom argument, points to @c usb_hub_info_t.
    300  * @return Whether to continue polling.
    301  */
    302 bool hub_port_changes_callback(usb_device_t *dev,
    303     uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)
    304 {
    305         usb_hub_info_t *hub = (usb_hub_info_t *) arg;
    306 
    307         /* FIXME: check that we received enough bytes. */
    308         if (change_bitmap_size == 0) {
    309                 goto leave;
    310         }
    311 
    312         size_t port;
    313         for (port = 1; port < hub->port_count + 1; port++) {
    314                 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
    315                 if (change) {
    316                         process_port_change(hub, port);
    317                 }
    318         }
    319 
    320 
    321 leave:
    322         /* FIXME: proper interval. */
    323         async_usleep(1000 * 1000 * 10 );
    324 
    325         return true;
    326 }
    327 
    328 
    329413/**
    330414 * @}
  • uspace/drv/usbhub/ports.h

    r8790650 r501e5df  
    3636#define DRV_USBHUB_PORTS_H
    3737
    38 #include <ipc/devman.h>
    39 #include <usb/usb.h>
    40 #include <ddf/driver.h>
    41 #include <fibril_synch.h>
    42 
     38#include <usb/devdrv.h>
    4339#include <usb/hub.h>
    4440
    45 #include <usb/pipes.h>
    46 #include <usb/devdrv.h>
     41typedef struct usb_hub_info_t usb_hub_info_t;
    4742
    4843/** Information about single port on a hub. */
     
    7267}
    7368
    74 bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *);
     69
     70void usb_hub_process_interrupt(usb_hub_info_t * hub,
     71        uint16_t port);
     72
    7573
    7674
  • uspace/drv/usbhub/usbhub.c

    r8790650 r501e5df  
    3737#include <errno.h>
    3838#include <str_error.h>
     39#include <inttypes.h>
    3940
    4041#include <usb_iface.h>
     
    5354#include "usb/classes/classes.h"
    5455
    55 static int usb_hub_trigger_connecting_non_removable_devices(
    56                 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
    57 
     56
     57static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev);
     58
     59static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info);
     60
     61static int usb_hub_set_configuration(usb_hub_info_t * hub_info);
     62
     63static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info);
     64
     65static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
     66    usb_hub_status_t status);
     67
     68static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
     69    usb_hub_status_t status);
     70
     71static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info);
     72
     73
     74/// \TODO malloc checking
    5875
    5976//*********************************************
    6077//
    6178//  hub driver code, initialization
     79//
     80//*********************************************
     81
     82/**
     83 * Initialize hub device driver fibril
     84 *
     85 * Creates hub representation and fibril that periodically checks hub`s status.
     86 * Hub representation is passed to the fibril.
     87 * @param usb_dev generic usb device information
     88 * @return error code
     89 */
     90int usb_hub_add_device(usb_device_t * usb_dev) {
     91        if (!usb_dev) return EINVAL;
     92        usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
     93        //create hc connection
     94        usb_log_debug("Initializing USB wire abstraction.\n");
     95        int opResult = usb_hc_connection_initialize_from_device(
     96            &hub_info->connection,
     97            hub_info->usb_device->ddf_dev);
     98        if (opResult != EOK) {
     99                usb_log_error("could not initialize connection to device, "
     100                    "errno %d\n",
     101                    opResult);
     102                free(hub_info);
     103                return opResult;
     104        }
     105
     106        usb_pipe_start_session(hub_info->control_pipe);
     107        //set hub configuration
     108        opResult = usb_hub_set_configuration(hub_info);
     109        if (opResult != EOK) {
     110                usb_log_error("could not set hub configuration, errno %d\n",
     111                    opResult);
     112                free(hub_info);
     113                return opResult;
     114        }
     115        //get port count and create attached_devs
     116        opResult = usb_hub_process_hub_specific_info(hub_info);
     117        if (opResult != EOK) {
     118                usb_log_error("could process hub specific info, errno %d\n",
     119                    opResult);
     120                free(hub_info);
     121                return opResult;
     122        }
     123        usb_pipe_end_session(hub_info->control_pipe);
     124
     125        /// \TODO what is this?
     126        usb_log_debug("Creating `hub' function.\n");
     127        ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
     128            fun_exposed, "hub");
     129        assert(hub_fun != NULL);
     130        hub_fun->ops = NULL;
     131
     132        opResult = ddf_fun_bind(hub_fun);
     133        assert(opResult == EOK);
     134        opResult = ddf_fun_add_to_class(hub_fun, "hub");
     135        assert(opResult == EOK);
     136
     137        opResult = usb_hub_start_hub_fibril(hub_info);
     138        if(opResult!=EOK)
     139                free(hub_info);
     140        return opResult;
     141}
     142
     143
     144/** Callback for polling hub for changes.
     145 *
     146 * @param dev Device where the change occured.
     147 * @param change_bitmap Bitmap of changed ports.
     148 * @param change_bitmap_size Size of the bitmap in bytes.
     149 * @param arg Custom argument, points to @c usb_hub_info_t.
     150 * @return Whether to continue polling.
     151 */
     152bool hub_port_changes_callback(usb_device_t *dev,
     153    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
     154        usb_hub_info_t *hub = (usb_hub_info_t *) arg;
     155
     156        /* FIXME: check that we received enough bytes. */
     157        if (change_bitmap_size == 0) {
     158                goto leave;
     159        }
     160
     161        bool change;
     162        change = ((uint8_t*) change_bitmap)[0] & 1;
     163        if (change) {
     164                usb_hub_process_global_interrupt(hub);
     165        }
     166
     167        size_t port;
     168        for (port = 1; port < hub->port_count + 1; port++) {
     169                bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
     170                if (change) {
     171                        usb_hub_process_interrupt(hub, port);
     172                }
     173        }
     174leave:
     175        /* FIXME: proper interval. */
     176        async_usleep(1000 * 1000 * 10);
     177
     178        return true;
     179}
     180
     181/**
     182 * release default address used by given hub
     183 *
     184 * Also unsets hub->is_default_address_used. Convenience wrapper function.
     185 * @note hub->connection MUST be open for communication
     186 * @param hub hub representation
     187 * @return error code
     188 */
     189int usb_hub_release_default_address(usb_hub_info_t * hub) {
     190        int opResult = usb_hc_release_default_address(&hub->connection);
     191        if (opResult != EOK) {
     192                usb_log_error("could not release default address, errno %d\n",
     193                    opResult);
     194                return opResult;
     195        }
     196        hub->is_default_address_used = false;
     197        return EOK;
     198}
     199
     200
     201//*********************************************
     202//
     203//  support functions
    62204//
    63205//*********************************************
     
    71213 */
    72214static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
    73         usb_hub_info_t * result = usb_new(usb_hub_info_t);
    74         if(!result) return NULL;
     215        usb_hub_info_t * result = malloc(sizeof(usb_hub_info_t));
     216        if (!result) return NULL;
    75217        result->usb_device = usb_dev;
    76218        result->status_change_pipe = usb_dev->pipes[0].pipe;
     
    90232 * @return error code
    91233 */
    92 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info){
     234static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {
    93235        // get hub descriptor
    94236        usb_log_debug("creating serialized descriptor\n");
    95237        void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
    96238        usb_hub_descriptor_t * descriptor;
    97 
    98         /* this was one fix of some bug, should not be needed anymore
    99          * these lines allow to reset hub once more, it can be used as
    100          * brute-force initialization for non-removable devices
    101         int opResult = usb_request_set_configuration(&result->endpoints.control, 1);
    102         if(opResult!=EOK){
    103                 usb_log_error("could not set default configuration, errno %d",opResult);
    104                 return opResult;
    105         }
    106          */
     239        int opResult;
     240
    107241        size_t received_size;
    108         int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,
    109                         USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    110                         USB_DESCTYPE_HUB,
    111                         0, 0, serialized_descriptor,
    112                         USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
    113 
    114         if (opResult != EOK) {
    115                 usb_log_error("failed when receiving hub descriptor, badcode = %d\n",
    116                                 opResult);
     242        opResult = usb_request_get_descriptor(hub_info->control_pipe,
     243            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
     244            USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
     245            USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
     246
     247        if (opResult != EOK) {
     248                usb_log_error("failed when receiving hub descriptor, "
     249                    "badcode = %d\n",
     250                    opResult);
    117251                free(serialized_descriptor);
    118252                return opResult;
     
    120254        usb_log_debug2("deserializing descriptor\n");
    121255        descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
    122         if(descriptor==NULL){
     256        if (descriptor == NULL) {
    123257                usb_log_warning("could not deserialize descriptor \n");
    124258                return opResult;
    125259        }
    126         usb_log_debug("setting port count to %d\n",descriptor->ports_count);
     260        usb_log_debug("setting port count to %d\n", descriptor->ports_count);
    127261        hub_info->port_count = descriptor->ports_count;
    128         hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
     262        /// \TODO this is not semantically correct
     263        hub_info->ports = malloc(
     264            sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
    129265        size_t port;
    130266        for (port = 0; port < hub_info->port_count + 1; port++) {
    131267                usb_hub_port_init(&hub_info->ports[port]);
    132268        }
    133         //handle non-removable devices
    134         usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
    135269        usb_log_debug2("freeing data\n");
    136270        free(serialized_descriptor);
     
    139273        return EOK;
    140274}
     275
    141276/**
    142277 * Set configuration of hub
     
    147282 * @return error code
    148283 */
    149 static int usb_hub_set_configuration(usb_hub_info_t * hub_info){
     284static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {
    150285        //device descriptor
    151286        usb_standard_device_descriptor_t *std_descriptor
     
    153288        usb_log_debug("hub has %d configurations\n",
    154289            std_descriptor->configuration_count);
    155         if(std_descriptor->configuration_count<1){
     290        if (std_descriptor->configuration_count < 1) {
    156291                usb_log_error("there are no configurations available\n");
    157292                return EINVAL;
     
    173308        }
    174309        usb_log_debug("\tused configuration %d\n",
    175                         config_descriptor->configuration_number);
     310            config_descriptor->configuration_number);
    176311
    177312        return EOK;
     
    179314
    180315/**
    181  * Initialize hub device driver fibril
    182  *
    183  * Creates hub representation and fibril that periodically checks hub`s status.
    184  * Hub representation is passed to the fibril.
    185  * @param usb_dev generic usb device information
    186  * @return error code
    187  */
    188 int usb_hub_add_device(usb_device_t * usb_dev){
    189         if(!usb_dev) return EINVAL;
    190         usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
    191         //create hc connection
    192         usb_log_debug("Initializing USB wire abstraction.\n");
    193         int opResult = usb_hc_connection_initialize_from_device(
    194                         &hub_info->connection,
    195                         hub_info->usb_device->ddf_dev);
    196         if(opResult != EOK){
    197                 usb_log_error("could not initialize connection to device, errno %d\n",
    198                                 opResult);
    199                 free(hub_info);
    200                 return opResult;
    201         }
    202        
    203         usb_pipe_start_session(hub_info->control_pipe);
    204         //set hub configuration
    205         opResult = usb_hub_set_configuration(hub_info);
    206         if(opResult!=EOK){
    207                 usb_log_error("could not set hub configuration, errno %d\n",opResult);
    208                 free(hub_info);
    209                 return opResult;
    210         }
    211         //get port count and create attached_devs
    212         opResult = usb_hub_process_hub_specific_info(hub_info);
    213         if(opResult!=EOK){
    214                 usb_log_error("could not set hub configuration, errno %d\n",opResult);
    215                 free(hub_info);
    216                 return opResult;
    217         }
    218         usb_pipe_end_session(hub_info->control_pipe);
    219 
    220 
    221         /// \TODO what is this?
    222         usb_log_debug("Creating `hub' function.\n");
    223         ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
    224                         fun_exposed, "hub");
    225         assert(hub_fun != NULL);
    226         hub_fun->ops = NULL;
    227 
    228         int rc = ddf_fun_bind(hub_fun);
    229         assert(rc == EOK);
    230         rc = ddf_fun_add_to_class(hub_fun, "hub");
    231         assert(rc == EOK);
    232 
     316 * create and start fibril with hub control loop
     317 *
     318 * Before the fibril is started, the control pipe and host controller
     319 * connection of the hub is open.
     320 *
     321 * @param hub_info hub representing structure
     322 * @return error code
     323 */
     324static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info){
    233325        /*
    234326         * The processing will require opened control pipe and connection
     
    239331         * auto destruction, this could work better.
    240332         */
    241         rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);
     333        int rc = usb_pipe_start_session(hub_info->control_pipe);
    242334        if (rc != EOK) {
    243335                usb_log_error("Failed to start session on control pipe: %s.\n",
    244336                    str_error(rc));
    245                 goto leave;
     337                return rc;
    246338        }
    247339        rc = usb_hc_connection_open(&hub_info->connection);
    248340        if (rc != EOK) {
    249                 usb_pipe_end_session(&usb_dev->ctrl_pipe);
     341                usb_pipe_end_session(hub_info->control_pipe);
    250342                usb_log_error("Failed to open connection to HC: %s.\n",
    251343                    str_error(rc));
    252                 goto leave;
     344                return rc;
    253345        }
    254346
    255347        rc = usb_device_auto_poll(hub_info->usb_device, 0,
    256             hub_port_changes_callback, ((hub_info->port_count+1) / 8) + 1,
     348            hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
    257349            NULL, hub_info);
    258350        if (rc != EOK) {
     
    266358            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    267359        return EOK;
    268 
    269 leave:
    270         free(hub_info);
    271 
    272         return rc;
    273 }
    274 
    275 
    276 //*********************************************
    277 //
    278 //  hub driver code, main loop and port handling
    279 //
    280 //*********************************************
    281 
    282 /**
    283  * triggers actions to connect non0removable devices
    284  *
    285  * This will trigger operations leading to activated non-removable device.
    286  * Control pipe of the hub must be open fo communication.
    287  * @param hub hub representation
    288  * @param descriptor usb hub descriptor
    289  * @return error code
    290  */
    291 static int usb_hub_trigger_connecting_non_removable_devices(usb_hub_info_t * hub,
    292                 usb_hub_descriptor_t * descriptor)
    293 {
    294         usb_log_info("attaching non-removable devices(if any)\n");
    295         usb_device_request_setup_packet_t request;
     360}
     361
     362//*********************************************
     363//
     364//  change handling functions
     365//
     366//*********************************************
     367
     368
     369/**
     370 * process hub over current change
     371 *
     372 * This means either to power off the hub or power it on.
     373 * @param hub_info hub instance
     374 * @param status hub status bitmask
     375 * @return error code
     376 */
     377static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
     378    usb_hub_status_t status) {
    296379        int opResult;
    297         size_t rcvd_size;
    298         usb_port_status_t status;
    299         uint8_t * non_removable_dev_bitmap = descriptor->devices_removable;
    300         int port;
    301         for(port=1;port<=descriptor->ports_count;++port){
    302                 bool is_non_removable =
    303                                 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
    304                 if(is_non_removable){
    305                         usb_log_debug("non-removable device on port %d\n",port);
    306                         usb_hub_set_port_status_request(&request, port);
    307                         opResult = usb_pipe_control_read(
    308                                         hub->control_pipe,
    309                                         &request, sizeof(usb_device_request_setup_packet_t),
    310                                         &status, 4, &rcvd_size
    311                                         );
     380        if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_OVER_CURRENT)){
     381                opResult = usb_hub_clear_feature(hub_info->control_pipe,
     382                    USB_HUB_FEATURE_HUB_LOCAL_POWER);
     383                if (opResult != EOK) {
     384                        usb_log_error("cannot power off hub: %d\n",
     385                            opResult);
     386                }
     387        } else {
     388                opResult = usb_hub_set_feature(hub_info->control_pipe,
     389                    USB_HUB_FEATURE_HUB_LOCAL_POWER);
     390                if (opResult != EOK) {
     391                        usb_log_error("cannot power on hub: %d\n",
     392                            opResult);
     393                }
     394        }
     395        return opResult;
     396}
     397
     398/**
     399 * process hub power change
     400 *
     401 * If the power has been lost, reestablish it.
     402 * If it was reestablished, re-power all ports.
     403 * @param hub_info hub instance
     404 * @param status hub status bitmask
     405 * @return error code
     406 */
     407static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
     408    usb_hub_status_t status) {
     409        int opResult;
     410        if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_LOCAL_POWER)) {
     411                //restart power on hub
     412                opResult = usb_hub_set_feature(hub_info->control_pipe,
     413                    USB_HUB_FEATURE_HUB_LOCAL_POWER);
     414                if (opResult != EOK) {
     415                        usb_log_error("cannot power on hub: %d\n",
     416                            opResult);
     417                }
     418        } else {//power reestablished on hub- restart ports
     419                size_t port;
     420                for (port = 0; port < hub_info->port_count; ++port) {
     421                        opResult = usb_hub_set_port_feature(
     422                            hub_info->control_pipe,
     423                            port, USB_HUB_FEATURE_PORT_POWER);
    312424                        if (opResult != EOK) {
    313                                 usb_log_error("could not get port status of port %d errno:%d\n",
    314                                                 port, opResult);
    315                                 return opResult;
    316                         }
    317                         //set the status change bit, so it will be noticed in driver loop
    318                         if(usb_port_dev_connected(&status)){
    319                                 usb_hub_set_disable_port_feature_request(&request, port,
    320                                                 USB_HUB_FEATURE_PORT_CONNECTION);
    321                                 opResult = usb_pipe_control_read(
    322                                                 hub->control_pipe,
    323                                                 &request, sizeof(usb_device_request_setup_packet_t),
    324                                                 &status, 4, &rcvd_size
    325                                                 );
    326                                 if (opResult != EOK) {
    327                                         usb_log_warning(
    328                                                         "could not clear port connection on port %d errno:%d\n",
    329                                                         port, opResult);
    330                                 }
    331                                 usb_log_debug("cleared port connection\n");
    332                                 usb_hub_set_enable_port_feature_request(&request, port,
    333                                                 USB_HUB_FEATURE_PORT_ENABLE);
    334                                 opResult = usb_pipe_control_read(
    335                                                 hub->control_pipe,
    336                                                 &request, sizeof(usb_device_request_setup_packet_t),
    337                                                 &status, 4, &rcvd_size
    338                                                 );
    339                                 if (opResult != EOK) {
    340                                         usb_log_warning(
    341                                                         "could not set port enabled on port %d errno:%d\n",
    342                                                         port, opResult);
    343                                 }
    344                                 usb_log_debug("port set to enabled - should lead to connection change\n");
     425                                usb_log_error("cannot power on port %d;  %d\n",
     426                                    port, opResult);
    345427                        }
    346428                }
    347429        }
    348         /// \TODO this is just a debug code
    349         for(port=1;port<=descriptor->ports_count;++port){
    350                 bool is_non_removable =
    351                                 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
    352                 if(is_non_removable){
    353                         usb_log_debug("port %d is non-removable\n",port);
    354                         usb_port_status_t status;
    355                         size_t rcvd_size;
    356                         usb_device_request_setup_packet_t request;
    357                         //int opResult;
    358                         usb_hub_set_port_status_request(&request, port);
    359                         //endpoint 0
    360                         opResult = usb_pipe_control_read(
    361                                         hub->control_pipe,
    362                                         &request, sizeof(usb_device_request_setup_packet_t),
    363                                         &status, 4, &rcvd_size
    364                                         );
    365                         if (opResult != EOK) {
    366                                 usb_log_error("could not get port status %d\n",opResult);
    367                         }
    368                         if (rcvd_size != sizeof (usb_port_status_t)) {
    369                                 usb_log_error("received status has incorrect size\n");
    370                         }
    371                         //something connected/disconnected
    372                         if (usb_port_connect_change(&status)) {
    373                                 usb_log_debug("some connection changed\n");
    374                         }
    375                         usb_log_debug("status: %s\n",usb_debug_str_buffer(
    376                                         (uint8_t *)&status,4,4));
    377                 }
    378         }
    379         return EOK;
    380 }
    381 
    382 
    383 /**
    384  * release default address used by given hub
    385  *
    386  * Also unsets hub->is_default_address_used. Convenience wrapper function.
    387  * @note hub->connection MUST be open for communication
    388  * @param hub hub representation
    389  * @return error code
    390  */
    391 static int usb_hub_release_default_address(usb_hub_info_t * hub){
    392         int opResult = usb_hc_release_default_address(&hub->connection);
    393         if(opResult!=EOK){
    394                 usb_log_error("could not release default address, errno %d\n",opResult);
    395                 return opResult;
    396         }
    397         hub->is_default_address_used = false;
    398         return EOK;
    399 }
    400 
    401 /**
    402  * routine called when a device on port has been removed
    403  *
    404  * If the device on port had default address, it releases default address.
    405  * Otherwise does not do anything, because DDF does not allow to remove device
    406  * from it`s device tree.
    407  * @param hub hub representation
    408  * @param port port number, starting from 1
    409  */
    410 void usb_hub_removed_device(
    411     usb_hub_info_t * hub,uint16_t port) {
    412 
    413         int opResult = usb_hub_clear_port_feature(hub->control_pipe,
    414                                 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
    415         if(opResult != EOK){
    416                 usb_log_warning("could not clear port-change-connection flag\n");
    417         }
    418         /** \TODO remove device from device manager - not yet implemented in
    419          * devide manager
    420          */
    421        
    422         //close address
    423         if(hub->ports[port].attached_device.address >= 0){
    424                 /*uncomment this code to use it when DDF allows device removal
    425                 opResult = usb_hc_unregister_device(
    426                                 &hub->connection, hub->attached_devs[port].address);
    427                 if(opResult != EOK) {
    428                         dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
    429                             "removed device: %d", opResult);
    430                 }
    431                 hub->attached_devs[port].address = 0;
    432                 hub->attached_devs[port].handle = 0;
    433                  */
    434         }else{
    435                 usb_log_warning("this is strange, disconnected device had no address\n");
    436                 //device was disconnected before it`s port was reset - return default address
    437                 usb_hub_release_default_address(hub);
    438         }
    439 }
    440 
    441 
    442 /**
    443  * Process over current condition on port.
    444  *
    445  * Turn off the power on the port.
    446  *
    447  * @param hub hub representation
    448  * @param port port number, starting from 1
    449  */
    450 void usb_hub_over_current( usb_hub_info_t * hub,
    451                 uint16_t port){
     430        return opResult;
     431}
     432
     433/**
     434 * process hub interrupts
     435 *
     436 * The change can be either in the over-current condition or
     437 * local-power lost condition.
     438 * @param hub_info hub instance
     439 */
     440static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info) {
     441        usb_log_debug("global interrupt on a hub\n");
     442        usb_pipe_t *pipe = hub_info->control_pipe;
    452443        int opResult;
    453         opResult = usb_hub_clear_port_feature(hub->control_pipe,
    454             port, USB_HUB_FEATURE_PORT_POWER);
    455         if(opResult!=EOK){
    456                 usb_log_error("cannot power off port %d;  %d\n",
    457                                 port, opResult);
    458         }
    459 }
    460 
     444
     445        usb_port_status_t status;
     446        size_t rcvd_size;
     447        usb_device_request_setup_packet_t request;
     448        //int opResult;
     449        usb_hub_set_hub_status_request(&request);
     450        //endpoint 0
     451
     452        opResult = usb_pipe_control_read(
     453            pipe,
     454            &request, sizeof (usb_device_request_setup_packet_t),
     455            &status, 4, &rcvd_size
     456            );
     457        if (opResult != EOK) {
     458                usb_log_error("could not get hub status\n");
     459                return;
     460        }
     461        if (rcvd_size != sizeof (usb_port_status_t)) {
     462                usb_log_error("received status has incorrect size\n");
     463                return;
     464        }
     465        //port reset
     466        if (
     467            usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
     468                usb_process_hub_over_current(hub_info, status);
     469        }
     470        if (
     471            usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
     472                usb_process_hub_power_change(hub_info, status);
     473        }
     474}
    461475
    462476/**
  • uspace/drv/usbhub/usbhub.h

    r8790650 r501e5df  
    3737
    3838#include <ipc/devman.h>
    39 #include <usb/usb.h>
    4039#include <ddf/driver.h>
    4140
    42 #define NAME "usbhub"
    43 
    4441#include <usb/hub.h>
     42#include <usb/classes/hub.h>
    4543
    4644#include <usb/pipes.h>
    4745#include <usb/devdrv.h>
     46
     47#include <fibril_synch.h>
     48
     49#define NAME "usbhub"
    4850
    4951#include "ports.h"
     
    5254
    5355/** Information about attached hub. */
    54 typedef struct {
     56struct usb_hub_info_t{
    5557        /** Number of ports. */
    5658        size_t port_count;
    5759
    58         /** Ports. */
     60        /** attached device handles, for each port one */
    5961        usb_hub_port_t *ports;
    60        
     62
    6163        /** connection to hcd */
    6264        usb_hc_connection_t connection;
     
    8789        /** generic usb device data*/
    8890        usb_device_t * usb_device;
    89 } usb_hub_info_t;
     91};
    9092
    91 /**
    92  * function running the hub-controlling loop.
    93  * @param hub_info_param hub info pointer
    94  */
    95 int usb_hub_control_loop(void * hub_info_param);
    96 
    97 /**
    98  * Check changes on specified hub
    99  * @param hub_info_param pointer to usb_hub_info_t structure
    100  * @return error code if there is problem when initializing communication with
    101  * hub, EOK otherwise
    102  */
    103 int usb_hub_check_hub_changes(usb_hub_info_t * hub_info_param);
    104 
    105 void usb_hub_removed_device(usb_hub_info_t *, uint16_t);
    106 void usb_hub_over_current(usb_hub_info_t *, uint16_t);
     93//int usb_hub_control_loop(void * hub_info_param);
    10794
    10895int usb_hub_add_device(usb_device_t * usb_dev);
     96
     97bool hub_port_changes_callback(usb_device_t *dev,
     98    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg);
     99
     100int usb_hub_release_default_address(usb_hub_info_t * hub);
    109101
    110102#endif
  • uspace/drv/usbhub/usbhub_private.h

    r8790650 r501e5df  
    5454//
    5555//************
    56 #define usb_new(type) (type*)malloc(sizeof(type))
    5756
    5857
    59 /**
    60  * Create hub structure instance
    61  *
    62  * Set the address and port count information most importantly.
    63  *
    64  * @param device
    65  * @param hc host controller phone
    66  * @return
    67  */
    6858usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device);
    6959
     
    110100
    111101/**
     102 * Clear feature on hub port.
     103 *
     104 * @param hc Host controller telephone
     105 * @param address Hub address
     106 * @param port_index Port
     107 * @param feature Feature selector
     108 * @return Operation result
     109 */
     110static inline int usb_hub_set_port_feature(usb_pipe_t *pipe,
     111    int port_index,
     112    usb_hub_class_feature_t feature) {
     113
     114        usb_device_request_setup_packet_t clear_request = {
     115                .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
     116                .request = USB_DEVREQ_SET_FEATURE,
     117                .length = 0,
     118                .index = port_index
     119        };
     120        clear_request.value = feature;
     121        return usb_pipe_control_write(pipe, &clear_request,
     122            sizeof(clear_request), NULL, 0);
     123}
     124
     125
     126/**
     127 * Clear feature on hub port.
     128 *
     129 * @param pipe pipe to hub control endpoint
     130 * @param feature Feature selector
     131 * @return Operation result
     132 */
     133static inline int usb_hub_clear_feature(usb_pipe_t *pipe,
     134    usb_hub_class_feature_t feature) {
     135
     136        usb_device_request_setup_packet_t clear_request = {
     137                .request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
     138                .request = USB_DEVREQ_CLEAR_FEATURE,
     139                .length = 0,
     140                .index = 0
     141        };
     142        clear_request.value = feature;
     143        return usb_pipe_control_write(pipe, &clear_request,
     144            sizeof(clear_request), NULL, 0);
     145}
     146
     147/**
     148 * Clear feature on hub port.
     149 *
     150 * @param pipe pipe to hub control endpoint
     151 * @param feature Feature selector
     152 * @return Operation result
     153 */
     154static inline int usb_hub_set_feature(usb_pipe_t *pipe,
     155    usb_hub_class_feature_t feature) {
     156
     157        usb_device_request_setup_packet_t clear_request = {
     158                .request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
     159                .request = USB_DEVREQ_SET_FEATURE,
     160                .length = 0,
     161                .index = 0
     162        };
     163        clear_request.value = feature;
     164        return usb_pipe_control_write(pipe, &clear_request,
     165            sizeof(clear_request), NULL, 0);
     166}
     167
     168/**
    112169 * create uint8_t array with serialized descriptor
    113170 *
  • uspace/drv/usbhub/utils.c

    r8790650 r501e5df  
    6060        size_t size = 7;
    6161        //variable size according to port count
    62         size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
     62        size_t var_size = (descriptor->ports_count+7)/8;
    6363        size += 2 * var_size;
    64         uint8_t * result = (uint8_t*) malloc(size);
     64        uint8_t * result = malloc(size);
    6565        //size
    6666        result[0] = size;
     
    8484}
    8585
    86 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
    87         uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
     86usb_hub_descriptor_t * usb_deserialize_hub_desriptor(
     87void * serialized_descriptor) {
     88        uint8_t * sdescriptor = serialized_descriptor;
    8889
    8990        if (sdescriptor[1] != USB_DESCTYPE_HUB) {
    90                 usb_log_warning("trying to deserialize wrong descriptor %x\n",sdescriptor[1]);
     91                usb_log_warning("trying to deserialize wrong descriptor %x\n",
     92                    sdescriptor[1]);
    9193                return NULL;
    9294        }
    9395
    94         usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t);
     96        usb_hub_descriptor_t * result = malloc(sizeof(usb_hub_descriptor_t));
    9597       
    9698
     
    100102        result->pwr_on_2_good_time = sdescriptor[5];
    101103        result->current_requirement = sdescriptor[6];
    102         size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0)
    103                         ? 1 : 0);
     104        size_t var_size = (result->ports_count+7) / 8;
    104105        result->devices_removable = (uint8_t*) malloc(var_size);
    105106
  • uspace/drv/usbmid/main.c

    r8790650 r501e5df  
    5555        int rc;
    5656
    57         rc = usb_pipe_start_session(&dev->ctrl_pipe);
     57        rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
    5858        if (rc != EOK) {
    59                 usb_log_error("Failed to start session on control pipe: %s.\n",
     59                usb_log_error("Failed to start transfer on control pipe: %s.\n",
    6060                    str_error(rc));
    6161                return rc;
     
    6464        bool accept = usbmid_explore_device(dev);
    6565
    66         rc = usb_pipe_end_session(&dev->ctrl_pipe);
    67         if (rc != EOK) {
    68                 usb_log_warning("Failed to end session on control pipe: %s.\n",
    69                     str_error(rc));
    70         }
     66        usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    7167
    7268        if (!accept) {
  • uspace/drv/vhc/connhost.c

    r8790650 r501e5df  
    257257
    258258static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
    259     size_t max_packet_size,
    260259    void *data, size_t size,
    261260    usbhc_iface_transfer_out_callback_t callback, void *arg)
     
    267266
    268267static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
    269     size_t max_packet_size,
    270268    void *data, size_t size,
    271269    usbhc_iface_transfer_in_callback_t callback, void *arg)
     
    277275
    278276static int control_write(ddf_fun_t *fun, usb_target_t target,
    279     size_t max_packet_size,
    280277    void *setup_packet, size_t setup_packet_size,
    281278    void *data, size_t data_size,
     
    295292
    296293static int control_read(ddf_fun_t *fun, usb_target_t target,
    297     size_t max_packet_size,
    298294    void *setup_packet, size_t setup_packet_size,
    299295    void *data, size_t data_size,
  • uspace/lib/drv/generic/remote_usbhc.c

    r8790650 r501e5df  
    270270        }
    271271
    272         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    273272        usb_target_t target = {
    274273                .address = DEV_IPC_GET_ARG1(*call),
     
    300299        trans->size = len;
    301300
    302         rc = transfer_func(fun, target, max_packet_size,
     301        rc = transfer_func(fun, target,
    303302            buffer, len,
    304303            callback_out, trans);
     
    326325        }
    327326
    328         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    329327        usb_target_t target = {
    330328                .address = DEV_IPC_GET_ARG1(*call),
     
    348346        trans->size = len;
    349347
    350         int rc = transfer_func(fun, target, max_packet_size,
     348        int rc = transfer_func(fun, target,
    351349            trans->buffer, len,
    352350            callback_in, trans);
     
    414412        };
    415413        size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
    416         size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
    417414
    418415        int rc;
     
    450447        trans->size = data_buffer_len;
    451448
    452         rc = usb_iface->control_write(fun, target, max_packet_size,
     449        rc = usb_iface->control_write(fun, target,
    453450            setup_packet, setup_packet_len,
    454451            data_buffer, data_buffer_len,
     
    477474                .endpoint = DEV_IPC_GET_ARG2(*call)
    478475        };
    479         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    480476
    481477        int rc;
     
    515511        }
    516512
    517         rc = usb_iface->control_read(fun, target, max_packet_size,
     513        rc = usb_iface->control_read(fun, target,
    518514            setup_packet, setup_packet_len,
    519515            trans->buffer, trans->size,
     
    537533        }
    538534
    539 #define INIT_FROM_HIGH_DATA(type, var, arg_no) \
    540         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / 256
    541 #define INIT_FROM_LOW_DATA(type, var, arg_no) \
    542         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % 256
    543 
    544         INIT_FROM_HIGH_DATA(usb_address_t, address, 1);
    545         INIT_FROM_LOW_DATA(usb_endpoint_t, endpoint, 1);
    546         INIT_FROM_HIGH_DATA(usb_transfer_type_t, transfer_type, 2);
    547         INIT_FROM_LOW_DATA(usb_direction_t, direction, 2);
    548 
    549 #undef INIT_FROM_HIGH_DATA
    550 #undef INIT_FROM_LOW_DATA
    551 
    552         size_t max_packet_size = (size_t) DEV_IPC_GET_ARG3(*call);
    553         unsigned int interval  = (unsigned int) DEV_IPC_GET_ARG4(*call);
    554 
    555         int rc = usb_iface->register_endpoint(fun, address, endpoint,
     535#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
     536        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
     537#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
     538        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
     539#define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
     540        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
     541#define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
     542        type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
     543#define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
     544        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
     545
     546        _INIT_FROM_HIGH_DATA2(usb_address_t, address, 1);
     547        _INIT_FROM_LOW_DATA2(usb_endpoint_t, endpoint, 1);
     548
     549        _INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
     550        _INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
     551        _INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
     552
     553        _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
     554        _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
     555
     556#undef _INIT_FROM_HIGH_DATA2
     557#undef _INIT_FROM_LOW_DATA2
     558#undef _INIT_FROM_HIGH_DATA3
     559#undef _INIT_FROM_MIDDLE_DATA3
     560#undef _INIT_FROM_LOW_DATA3
     561
     562        int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
    556563            transfer_type, direction, max_packet_size, interval);
    557564
  • uspace/lib/drv/include/usbhc_iface.h

    r8790650 r501e5df  
    6666 *   - argument #1 is target address
    6767 *   - argument #2 is target endpoint
    68  *   - argument #3 is max packet size of the endpoint
    6968 * - this call is immediately followed by IPC data read (async version)
    7069 * - the call is not answered until the device returns some data (or until
     
    169168        /** Register endpoint attributes at host controller.
    170169         * This is used to reserve portion of USB bandwidth.
     170         * When speed is invalid, speed of the device is used.
    171171         * Parameters:
    172          * - USB address + endpoint number (ADDR * 256 + EP)
    173          * - transfer type + direction (TYPE * 256 + DIR)
    174          * - maximum packet size
    175          * - interval (in milliseconds)
     172         * - USB address + endpoint number
     173         *   - packed as ADDR << 16 + EP
     174         * - speed + transfer type + direction
     175         *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
     176         * - maximum packet size + interval (in milliseconds)
     177         *   - packed as MPS << 16 + INT
    176178         * Answer:
    177179         * - EOK - reservation successful
     
    202204
    203205/** Out transfer processing function prototype. */
    204 typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t, size_t,
     206typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t,
    205207    void *, size_t,
    206208    usbhc_iface_transfer_out_callback_t, void *);
     
    210212
    211213/** In transfer processing function prototype. */
    212 typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t, size_t,
     214typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t,
    213215    void *, size_t,
    214216    usbhc_iface_transfer_in_callback_t, void *);
     
    222224        int (*release_address)(ddf_fun_t *, usb_address_t);
    223225
    224         int (*register_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
     226        int (*register_endpoint)(ddf_fun_t *,
     227            usb_address_t, usb_speed_t, usb_endpoint_t,
    225228            usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
    226229        int (*unregister_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
     
    234237
    235238        int (*control_write)(ddf_fun_t *, usb_target_t,
    236             size_t,
    237239            void *, size_t, void *, size_t,
    238240            usbhc_iface_transfer_out_callback_t, void *);
    239241
    240242        int (*control_read)(ddf_fun_t *, usb_target_t,
    241             size_t,
    242243            void *, size_t, void *, size_t,
    243244            usbhc_iface_transfer_in_callback_t, void *);
  • uspace/lib/usb/Makefile

    r8790650 r501e5df  
    4343        src/hidparser.c \
    4444        src/hub.c \
     45        src/pipepriv.c \
    4546        src/pipes.c \
    4647        src/pipesinit.c \
  • uspace/lib/usb/include/usb/classes/hub.h

    r8790650 r501e5df  
    4343 */
    4444typedef enum {
     45        USB_HUB_FEATURE_HUB_LOCAL_POWER = 0,
     46        USB_HUB_FEATURE_HUB_OVER_CURRENT = 1,
    4547        USB_HUB_FEATURE_C_HUB_LOCAL_POWER = 0,
    4648        USB_HUB_FEATURE_C_HUB_OVER_CURRENT = 1,
     
    5961        /* USB_HUB_FEATURE_ = , */
    6062} usb_hub_class_feature_t;
     63
    6164
    6265/** Header of standard hub descriptor without the "variadic" part. */
  • uspace/lib/usb/include/usb/devdrv.h

    r8790650 r501e5df  
    169169    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
    170170
     171int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
     172int usb_device_create_pipes(ddf_dev_t *, usb_device_connection_t *,
     173    usb_endpoint_description_t **, uint8_t *, size_t, int, int,
     174    usb_endpoint_mapping_t **, size_t *);
     175int usb_device_destroy_pipes(ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
     176
     177size_t usb_interface_count_alternates(uint8_t *, size_t, uint8_t);
     178
    171179#endif
    172180/**
  • uspace/lib/usb/include/usb/host/device_keeper.h

    r8790650 r501e5df  
    7373void usb_device_keeper_add_ep(
    7474    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep);
     75void usb_device_keeper_del_ep(
     76    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep);
    7577
    7678void usb_device_keeper_reserve_default_address(
  • uspace/lib/usb/include/usb/pipes.h

    r8790650 r501e5df  
    4242#include <ipc/devman.h>
    4343#include <ddf/driver.h>
     44#include <fibril_synch.h>
    4445
    4546/** Abstraction of a physical connection to the device.
     
    5960 * This endpoint must be bound with existing usb_device_connection_t
    6061 * (i.e. the wire to send data over).
     62 *
     63 * Locking order: if you want to lock both mutexes
     64 * (@c guard and @c hc_phone_mutex), lock @c guard first.
     65 * It is not necessary to lock @c guard if you want to lock @c hc_phone_mutex
     66 * only.
    6167 */
    6268typedef struct {
     69        /** Guard of the whole pipe. */
     70        fibril_mutex_t guard;
     71
    6372        /** The connection used for sending the data. */
    6473        usb_device_connection_t *wire;
     
    7887        /** Phone to the host controller.
    7988         * Negative when no session is active.
     89         * It is an error to access this member without @c hc_phone_mutex
     90         * being locked.
     91         * If call over the phone is to be made, it must be preceeded by
     92         * call to pipe_add_ref() [internal libusb function].
    8093         */
    8194        int hc_phone;
     95
     96        /** Guard for serialization of requests over the phone. */
     97        fibril_mutex_t hc_phone_mutex;
     98
     99        /** Number of active transfers over the pipe. */
     100        int refcount;
    82101} usb_pipe_t;
    83102
     
    134153int usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *,
    135154    size_t, uint8_t *, size_t, usb_device_connection_t *);
     155int usb_pipe_register_with_speed(usb_pipe_t *, usb_speed_t,
     156    unsigned int, usb_hc_connection_t *);
    136157int usb_pipe_register(usb_pipe_t *, unsigned int, usb_hc_connection_t *);
    137158int usb_pipe_unregister(usb_pipe_t *, usb_hc_connection_t *);
     
    140161int usb_pipe_end_session(usb_pipe_t *);
    141162bool usb_pipe_is_session_started(usb_pipe_t *);
     163
     164int usb_pipe_start_long_transfer(usb_pipe_t *);
     165void usb_pipe_end_long_transfer(usb_pipe_t *);
    142166
    143167int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
  • uspace/lib/usb/include/usb/usb.h

    r8790650 r501e5df  
    7777        USB_SPEED_FULL,
    7878        /** USB 2.0 high speed (480Mbits/s). */
    79         USB_SPEED_HIGH
     79        USB_SPEED_HIGH,
     80        /** Psuedo-speed serving as a boundary. */
     81        USB_SPEED_MAX
    8082} usb_speed_t;
    8183
  • uspace/lib/usb/src/devdrv.c

    r8790650 r501e5df  
    7272}
    7373
    74 /** Log out of memory error on given device.
    75  *
    76  * @param dev Device causing the trouble.
    77  */
    78 static void usb_log_oom(ddf_dev_t *dev)
    79 {
    80         usb_log_error("Out of memory when adding device `%s'.\n",
    81             dev->name);
    82 }
    83 
    8474/** Count number of pipes the driver expects.
    8575 *
     
    10898 */
    10999static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
    110     usb_device_t *dev)
    111 {
    112         int rc;
    113 
    114         size_t pipe_count = count_other_pipes(endpoints);
    115         if (pipe_count == 0) {
    116                 return EOK;
    117         }
    118 
    119         dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
    120         if (dev->pipes == NULL) {
    121                 usb_log_oom(dev->ddf_dev);
    122                 return ENOMEM;
    123         }
    124 
    125         size_t i;
    126 
    127         /* Initialize to NULL first for rollback purposes. */
    128         for (i = 0; i < pipe_count; i++) {
    129                 dev->pipes[i].pipe = NULL;
    130         }
    131 
    132         for (i = 0; i < pipe_count; i++) {
    133                 dev->pipes[i].pipe = malloc(sizeof(usb_pipe_t));
    134                 if (dev->pipes[i].pipe == NULL) {
    135                         usb_log_oom(dev->ddf_dev);
    136                         rc = ENOMEM;
    137                         goto rollback;
    138                 }
    139 
    140                 dev->pipes[i].description = endpoints[i];
    141                 dev->pipes[i].interface_no = dev->interface_no;
    142                 dev->pipes[i].interface_setting = 0;
    143         }
    144 
    145         rc = usb_pipe_initialize_from_configuration(dev->pipes, pipe_count,
     100    usb_device_t *dev, int alternate_setting)
     101{
     102        usb_endpoint_mapping_t *pipes;
     103        size_t pipes_count;
     104
     105        int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
    146106            dev->descriptors.configuration, dev->descriptors.configuration_size,
    147             &dev->wire);
    148         if (rc != EOK) {
    149                 usb_log_error("Failed initializing USB endpoints: %s.\n",
    150                     str_error(rc));
    151                 goto rollback;
    152         }
    153 
    154         /* Register the endpoints. */
    155         usb_hc_connection_t hc_conn;
    156         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
     107            dev->interface_no, alternate_setting,
     108            &pipes, &pipes_count);
     109
    157110        if (rc != EOK) {
    158111                usb_log_error(
    159                     "Failed initializing connection to host controller: %s.\n",
    160                     str_error(rc));
    161                 goto rollback;
    162         }
    163         rc = usb_hc_connection_open(&hc_conn);
    164         if (rc != EOK) {
    165                 usb_log_error("Failed to connect to host controller: %s.\n",
    166                     str_error(rc));
    167                 goto rollback;
    168         }
    169         for (i = 0; i < pipe_count; i++) {
    170                 if (dev->pipes[i].present) {
    171                         rc = usb_pipe_register(dev->pipes[i].pipe,
    172                             dev->pipes[i].descriptor->poll_interval,
    173                             &hc_conn);
    174                         /* Ignore error when operation not supported by HC. */
    175                         if ((rc != EOK) && (rc != ENOTSUP)) {
    176                                 /* FIXME: what shall we do? */
    177                                 dev->pipes[i].present = false;
    178                                 free(dev->pipes[i].pipe);
    179                                 dev->pipes[i].pipe = NULL;
    180                         }
    181                 }
    182         }
    183         /* Ignoring errors here. */
    184         usb_hc_connection_close(&hc_conn);
    185 
    186         dev->pipes_count = pipe_count;
     112                    "Failed to create endpoint pipes for `%s': %s.\n",
     113                    dev->ddf_dev->name, str_error(rc));
     114                return rc;
     115        }
     116
     117        dev->pipes = pipes;
     118        dev->pipes_count = pipes_count;
    187119
    188120        return EOK;
    189 
    190 rollback:
    191         for (i = 0; i < pipe_count; i++) {
    192                 if (dev->pipes[i].pipe != NULL) {
    193                         free(dev->pipes[i].pipe);
    194                 }
    195         }
    196         free(dev->pipes);
    197 
    198         return rc;
    199121}
    200122
     
    239161
    240162        /*
    241          * For further actions, we need open session on default control pipe.
     163         * We will do some querying of the device, it is worth to prepare
     164         * the long transfer.
    242165         */
    243         rc = usb_pipe_start_session(&dev->ctrl_pipe);
    244         if (rc != EOK) {
    245                 usb_log_error("Failed to start an IPC session: %s.\n",
     166        rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
     167        if (rc != EOK) {
     168                usb_log_error("Failed to start transfer: %s.\n",
    246169                    str_error(rc));
    247170                return rc;
    248171        }
    249172
    250         /* Get the device descriptor. */
    251         rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
    252             &dev->descriptors.device);
    253         if (rc != EOK) {
    254                 usb_log_error("Failed to retrieve device descriptor: %s.\n",
    255                     str_error(rc));
    256                 return rc;
    257         }
    258 
    259         /* Get the full configuration descriptor. */
    260         rc = usb_request_get_full_configuration_descriptor_alloc(
    261             &dev->ctrl_pipe, 0, (void **) &dev->descriptors.configuration,
    262             &dev->descriptors.configuration_size);
    263         if (rc != EOK) {
    264                 usb_log_error("Failed retrieving configuration descriptor: %s. %s\n",
     173        /* Retrieve the descriptors. */
     174        rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
     175            &dev->descriptors);
     176        if (rc != EOK) {
     177                usb_log_error("Failed to retrieve standard device " \
     178                    "descriptors of %s: %s.\n",
    265179                    dev->ddf_dev->name, str_error(rc));
    266180                return rc;
    267181        }
    268182
     183
    269184        if (driver->endpoints != NULL) {
    270                 rc = initialize_other_pipes(driver->endpoints, dev);
    271         }
    272 
    273         /* No checking here. */
    274         usb_pipe_end_session(&dev->ctrl_pipe);
     185                rc = initialize_other_pipes(driver->endpoints, dev, 0);
     186        }
     187
     188        usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    275189
    276190        /* Rollback actions. */
     
    291205 * @return Number of alternate interfaces for @p interface_no interface.
    292206 */
    293 static size_t count_alternate_interfaces(uint8_t *config_descr,
    294     size_t config_descr_size, int interface_no)
     207size_t usb_interface_count_alternates(uint8_t *config_descr,
     208    size_t config_descr_size, uint8_t interface_no)
    295209{
    296210        assert(config_descr != NULL);
     211        assert(config_descr_size > 0);
     212
    297213        usb_dp_parser_t dp_parser = {
    298214                .nesting = usb_dp_standard_descriptor_nesting
     
    343259
    344260        alternates->alternative_count
    345             = count_alternate_interfaces(dev->descriptors.configuration,
     261            = usb_interface_count_alternates(dev->descriptors.configuration,
    346262            dev->descriptors.configuration_size, dev->interface_no);
    347263
     
    457373static int destroy_current_pipes(usb_device_t *dev)
    458374{
    459         size_t i;
    460         int rc;
    461 
    462         /* TODO: this shall be done under some device mutex. */
    463 
    464         /* First check that no session is opened. */
    465         for (i = 0; i < dev->pipes_count; i++) {
    466                 if (usb_pipe_is_session_started(dev->pipes[i].pipe)) {
    467                         return EBUSY;
    468                 }
    469         }
    470 
    471         /* Prepare connection to HC. */
    472         usb_hc_connection_t hc_conn;
    473         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
    474         if (rc != EOK) {
    475                 return rc;
    476         }
    477         rc = usb_hc_connection_open(&hc_conn);
    478         if (rc != EOK) {
    479                 return rc;
    480         }
    481 
    482         /* Destroy the pipes. */
    483         for (i = 0; i < dev->pipes_count; i++) {
    484                 usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn);
    485                 free(dev->pipes[i].pipe);
    486         }
    487 
    488         usb_hc_connection_close(&hc_conn);
    489 
    490         free(dev->pipes);
     375        int rc = usb_device_destroy_pipes(dev->ddf_dev,
     376            dev->pipes, dev->pipes_count);
     377        if (rc != EOK) {
     378                return rc;
     379        }
     380
    491381        dev->pipes = NULL;
    492382        dev->pipes_count = 0;
     
    535425
    536426        /* Create new pipes. */
    537         rc = initialize_other_pipes(endpoints, dev);
     427        rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
    538428
    539429        return rc;
     430}
     431
     432/** Retrieve basic descriptors from the device.
     433 *
     434 * @param[in] ctrl_pipe Control pipe with opened session.
     435 * @param[out] descriptors Where to store the descriptors.
     436 * @return Error code.
     437 */
     438int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,
     439    usb_device_descriptors_t *descriptors)
     440{
     441        assert(descriptors != NULL);
     442        assert(usb_pipe_is_session_started(ctrl_pipe));
     443
     444        descriptors->configuration = NULL;
     445
     446        int rc;
     447
     448        /* Get the device descriptor. */
     449        rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
     450        if (rc != EOK) {
     451                return rc;
     452        }
     453
     454        /* Get the full configuration descriptor. */
     455        rc = usb_request_get_full_configuration_descriptor_alloc(
     456            ctrl_pipe, 0, (void **) &descriptors->configuration,
     457            &descriptors->configuration_size);
     458        if (rc != EOK) {
     459                return rc;
     460        }
     461
     462        return EOK;
     463}
     464
     465/** Create pipes for a device.
     466 *
     467 * This is more or less a wrapper that does following actions:
     468 * - allocate and initialize pipes
     469 * - map endpoints to the pipes based on the descriptions
     470 * - registers endpoints with the host controller
     471 *
     472 * @param[in] dev Generic DDF device backing the USB one.
     473 * @param[in] wire Initialized backing connection to the host controller.
     474 * @param[in] endpoints Endpoints description, NULL terminated.
     475 * @param[in] config_descr Configuration descriptor of active configuration.
     476 * @param[in] config_descr_size Size of @p config_descr in bytes.
     477 * @param[in] interface_no Interface to map from.
     478 * @param[in] interface_setting Interface setting (default is usually 0).
     479 * @param[out] pipes_ptr Where to store array of created pipes
     480 *      (not NULL terminated).
     481 * @param[out] pipes_count_ptr Where to store number of pipes
     482 *      (set to if you wish to ignore the count).
     483 * @return Error code.
     484 */
     485int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
     486    usb_endpoint_description_t **endpoints,
     487    uint8_t *config_descr, size_t config_descr_size,
     488    int interface_no, int interface_setting,
     489    usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
     490{
     491        assert(dev != NULL);
     492        assert(wire != NULL);
     493        assert(endpoints != NULL);
     494        assert(config_descr != NULL);
     495        assert(config_descr_size > 0);
     496        assert(pipes_ptr != NULL);
     497
     498        size_t i;
     499        int rc;
     500
     501        size_t pipe_count = count_other_pipes(endpoints);
     502        if (pipe_count == 0) {
     503                *pipes_ptr = NULL;
     504                return EOK;
     505        }
     506
     507        usb_endpoint_mapping_t *pipes
     508            = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
     509        if (pipes == NULL) {
     510                return ENOMEM;
     511        }
     512
     513        /* Initialize to NULL to allow smooth rollback. */
     514        for (i = 0; i < pipe_count; i++) {
     515                pipes[i].pipe = NULL;
     516        }
     517
     518        /* Now allocate and fully initialize. */
     519        for (i = 0; i < pipe_count; i++) {
     520                pipes[i].pipe = malloc(sizeof(usb_pipe_t));
     521                if (pipes[i].pipe == NULL) {
     522                        rc = ENOMEM;
     523                        goto rollback_free_only;
     524                }
     525                pipes[i].description = endpoints[i];
     526                pipes[i].interface_no = interface_no;
     527                pipes[i].interface_setting = interface_setting;
     528        }
     529
     530        /* Find the mapping from configuration descriptor. */
     531        rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,
     532            config_descr, config_descr_size, wire);
     533        if (rc != EOK) {
     534                goto rollback_free_only;
     535        }
     536
     537        /* Register the endpoints with HC. */
     538        usb_hc_connection_t hc_conn;
     539        rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
     540        if (rc != EOK) {
     541                goto rollback_free_only;
     542        }
     543
     544        rc = usb_hc_connection_open(&hc_conn);
     545        if (rc != EOK) {
     546                goto rollback_free_only;
     547        }
     548
     549        for (i = 0; i < pipe_count; i++) {
     550                if (pipes[i].present) {
     551                        rc = usb_pipe_register(pipes[i].pipe,
     552                            pipes[i].descriptor->poll_interval, &hc_conn);
     553                        if (rc != EOK) {
     554                                goto rollback_unregister_endpoints;
     555                        }
     556                }
     557        }
     558
     559        usb_hc_connection_close(&hc_conn);
     560
     561        *pipes_ptr = pipes;
     562        if (pipes_count_ptr != NULL) {
     563                *pipes_count_ptr = pipe_count;
     564        }
     565
     566        return EOK;
     567
     568        /*
     569         * Jump here if something went wrong after endpoints have
     570         * been registered.
     571         * This is also the target when the registration of
     572         * endpoints fails.
     573         */
     574rollback_unregister_endpoints:
     575        for (i = 0; i < pipe_count; i++) {
     576                if (pipes[i].present) {
     577                        usb_pipe_unregister(pipes[i].pipe, &hc_conn);
     578                }
     579        }
     580
     581        usb_hc_connection_close(&hc_conn);
     582
     583        /*
     584         * Jump here if something went wrong before some actual communication
     585         * with HC. Then the only thing that needs to be done is to free
     586         * allocated memory.
     587         */
     588rollback_free_only:
     589        for (i = 0; i < pipe_count; i++) {
     590                if (pipes[i].pipe != NULL) {
     591                        free(pipes[i].pipe);
     592                }
     593        }
     594        free(pipes);
     595
     596        return rc;
     597}
     598
     599/** Destroy pipes previously created by usb_device_create_pipes.
     600 *
     601 * @param[in] dev Generic DDF device backing the USB one.
     602 * @param[in] pipes Endpoint mapping to be destroyed.
     603 * @param[in] pipes_count Number of endpoints.
     604 */
     605int usb_device_destroy_pipes(ddf_dev_t *dev,
     606    usb_endpoint_mapping_t *pipes, size_t pipes_count)
     607{
     608        assert(dev != NULL);
     609        assert(((pipes != NULL) && (pipes_count > 0))
     610            || ((pipes == NULL) && (pipes_count == 0)));
     611
     612        if (pipes_count == 0) {
     613                return EOK;
     614        }
     615
     616        int rc;
     617
     618        /* Prepare connection to HC to allow endpoint unregistering. */
     619        usb_hc_connection_t hc_conn;
     620        rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
     621        if (rc != EOK) {
     622                return rc;
     623        }
     624        rc = usb_hc_connection_open(&hc_conn);
     625        if (rc != EOK) {
     626                return rc;
     627        }
     628
     629        /* Destroy the pipes. */
     630        size_t i;
     631        for (i = 0; i < pipes_count; i++) {
     632                usb_pipe_unregister(pipes[i].pipe, &hc_conn);
     633                free(pipes[i].pipe);
     634        }
     635
     636        usb_hc_connection_close(&hc_conn);
     637
     638        free(pipes);
     639
     640        return EOK;
    540641}
    541642
  • uspace/lib/usb/src/devpoll.c

    r8790650 r501e5df  
    7777                int rc;
    7878
    79                 rc = usb_pipe_start_session(pipe);
    80                 if (rc != EOK) {
    81                         failed_attempts++;
    82                         continue;
    83                 }
    84 
    8579                size_t actual_size;
    8680                rc = usb_pipe_read(pipe, polling_data->buffer,
    8781                    polling_data->request_size, &actual_size);
    8882
    89                 /* Quit the session regardless of errors. */
    90                 usb_pipe_end_session(pipe);
    9183               
    9284//              if (rc == ESTALL) {
  • uspace/lib/usb/src/host/device_keeper.c

    r8790650 r501e5df  
    5656                instance->devices[i].control_used = 0;
    5757                instance->devices[i].handle = 0;
     58                instance->devices[i].speed = USB_SPEED_MAX;
    5859                list_initialize(&instance->devices[i].endpoints);
    5960        }
     61        // TODO: is this hack enough?
     62        // (it is needed to allow smooth registration at default address)
     63        instance->devices[0].occupied = true;
    6064}
    6165/*----------------------------------------------------------------------------*/
     
    6771        assert(instance->devices[address].occupied);
    6872        list_append(&ep->same_device_eps, &instance->devices[address].endpoints);
     73        fibril_mutex_unlock(&instance->guard);
     74}
     75/*----------------------------------------------------------------------------*/
     76void usb_device_keeper_del_ep(
     77    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep)
     78{
     79        assert(instance);
     80        fibril_mutex_lock(&instance->guard);
     81        assert(instance->devices[address].occupied);
     82        list_remove(&ep->same_device_eps);
     83        list_initialize(&ep->same_device_eps);
    6984        fibril_mutex_unlock(&instance->guard);
    7085}
  • uspace/lib/usb/src/hub.c

    r8790650 r501e5df  
    4040#include <errno.h>
    4141#include <assert.h>
     42#include <usb/debug.h>
    4243
    4344/** Check that HC connection is alright.
     
    5556
    5657/** Tell host controller to reserve default address.
     58 * @deprecated
    5759 *
    5860 * @param connection Opened connection to host controller.
     
    6567        CHECK_CONNECTION(connection);
    6668
     69        usb_log_warning("usb_hc_reserve_default_address() considered obsolete");
     70
    6771        return async_req_2_0(connection->hc_phone,
    6872            DEV_IFACE_ID(USBHC_DEV_IFACE),
     
    7175
    7276/** Tell host controller to release default address.
     77 * @deprecated
    7378 *
    7479 * @param connection Opened connection to host controller.
     
    7883{
    7984        CHECK_CONNECTION(connection);
     85
     86        usb_log_warning("usb_hc_release_default_address() considered obsolete");
    8087
    8188        return async_req_1_0(connection->hc_phone,
     
    235242        }
    236243
    237 
    238         /*
    239          * Reserve the default address.
    240          */
    241         rc = usb_hc_reserve_default_address(&hc_conn, dev_speed);
    242         if (rc != EOK) {
    243                 rc = EBUSY;
    244                 goto leave_release_free_address;
    245         }
    246 
    247         /*
    248          * Enable the port (i.e. allow signaling through this port).
    249          */
    250         rc = enable_port(port_no, arg);
    251         if (rc != EOK) {
    252                 goto leave_release_default_address;
    253         }
    254 
    255         /*
    256          * Change the address from default to the free one.
    257          * We need to create a new control pipe for that.
     244        /*
     245         * We will not register control pipe on default address.
     246         * The registration might fail. That means that someone else already
     247         * registered that endpoint. We will simply wait and try again.
     248         * (Someone else already wants to add a new device.)
    258249         */
    259250        usb_device_connection_t dev_conn;
     
    262253        if (rc != EOK) {
    263254                rc = ENOTCONN;
    264                 goto leave_release_default_address;
     255                goto leave_release_free_address;
    265256        }
    266257
     
    270261        if (rc != EOK) {
    271262                rc = ENOTCONN;
     263                goto leave_release_free_address;
     264        }
     265
     266        do {
     267                rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
     268                    &hc_conn);
     269                if (rc != EOK) {
     270                        /* Do not overheat the CPU ;-). */
     271                        async_usleep(10);
     272                }
     273        } while (rc != EOK);
     274
     275        /*
     276         * Endpoint is registered. We can enable the port and change
     277         * device address.
     278         */
     279        rc = enable_port(port_no, arg);
     280        if (rc != EOK) {
    272281                goto leave_release_default_address;
    273282        }
    274283
    275         /* Before sending any traffic, we need to register this
    276          * endpoint.
     284        rc = usb_pipe_probe_default_control(&ctrl_pipe);
     285        if (rc != EOK) {
     286                rc = ESTALL;
     287                goto leave_release_default_address;
     288        }
     289
     290        rc = usb_request_set_address(&ctrl_pipe, dev_addr);
     291        if (rc != EOK) {
     292                rc = ESTALL;
     293                goto leave_release_default_address;
     294        }
     295
     296        /*
     297         * Address changed. We can release the original endpoint, thus
     298         * allowing other to access the default address.
     299         */
     300        unregister_control_endpoint_on_default_address(&hc_conn);
     301
     302        /*
     303         * Time to register the new endpoint.
    277304         */
    278305        rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
    279306        if (rc != EOK) {
    280                 rc = EREFUSED;
    281                 goto leave_release_default_address;
    282         }
    283         rc = usb_pipe_probe_default_control(&ctrl_pipe);
    284         if (rc != EOK) {
    285                 rc = ENOTCONN;
    286                 goto leave_release_default_address;
    287         }
    288 
    289         rc = usb_pipe_start_session(&ctrl_pipe);
    290         if (rc != EOK) {
    291                 rc = ENOTCONN;
    292                 goto leave_unregister_endpoint;
    293         }
    294 
    295         rc = usb_request_set_address(&ctrl_pipe, dev_addr);
    296         if (rc != EOK) {
    297                 rc = ESTALL;
    298                 goto leave_stop_session;
    299         }
    300 
    301         usb_pipe_end_session(&ctrl_pipe);
    302 
    303         /*
    304          * Register the control endpoint for the new device.
    305          */
    306         rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
    307         if (rc != EOK) {
    308                 rc = EREFUSED;
    309                 goto leave_unregister_endpoint;
    310         }
    311 
    312         /*
    313          * Release the original endpoint.
    314          */
    315         unregister_control_endpoint_on_default_address(&hc_conn);
    316 
    317         /*
    318          * Once the address is changed, we can return the default address.
    319          */
    320         usb_hc_release_default_address(&hc_conn);
    321 
     307                goto leave_release_free_address;
     308        }
    322309
    323310        /*
     
    334321        }
    335322
    336 
    337 
    338323        /*
    339324         * And now inform the host controller about the handle.
     
    367352         * Completely ignoring errors here.
    368353         */
    369 
    370 leave_stop_session:
    371         usb_pipe_end_session(&ctrl_pipe);
    372 
    373 leave_unregister_endpoint:
     354leave_release_default_address:
    374355        usb_pipe_unregister(&ctrl_pipe, &hc_conn);
    375 
    376 leave_release_default_address:
    377         usb_hc_release_default_address(&hc_conn);
    378356
    379357leave_release_free_address:
  • uspace/lib/usb/src/pipes.c

    r8790650 r501e5df  
    4141#include <errno.h>
    4242#include <assert.h>
     43#include "pipepriv.h"
    4344
    4445#define IPC_AGAIN_DELAY (1000 * 2) /* 2ms */
     
    241242 * necessary.
    242243 *
     244 * @deprecated
     245 * Obsoleted with introduction of usb_pipe_start_long_transfer
     246 *
    243247 * @param pipe Endpoint pipe to start the session on.
    244248 * @return Error code.
     
    246250int usb_pipe_start_session(usb_pipe_t *pipe)
    247251{
    248         assert(pipe);
    249 
    250         if (usb_pipe_is_session_started(pipe)) {
    251                 return EBUSY;
    252         }
    253 
    254         int phone = devman_device_connect(pipe->wire->hc_handle, 0);
    255         if (phone < 0) {
    256                 return phone;
    257         }
    258 
    259         pipe->hc_phone = phone;
    260 
     252        usb_log_warning("usb_pipe_start_session() was deprecated.\n");
    261253        return EOK;
    262254}
     
    265257/** Ends a session on the endpoint pipe.
    266258 *
     259 * @deprecated
     260 * Obsoleted with introduction of usb_pipe_end_long_transfer
     261 *
    267262 * @see usb_pipe_start_session
    268263 *
     
    272267int usb_pipe_end_session(usb_pipe_t *pipe)
    273268{
    274         assert(pipe);
    275 
    276         if (!usb_pipe_is_session_started(pipe)) {
    277                 return ENOENT;
    278         }
    279 
    280         int rc = async_hangup(pipe->hc_phone);
    281         if (rc != EOK) {
    282                 return rc;
    283         }
    284 
    285         pipe->hc_phone = -1;
    286 
     269        usb_log_warning("usb_pipe_end_session() was deprecated.\n");
    287270        return EOK;
    288271}
     
    298281bool usb_pipe_is_session_started(usb_pipe_t *pipe)
    299282{
    300         return (pipe->hc_phone >= 0);
     283        pipe_acquire(pipe);
     284        bool started = pipe->refcount > 0;
     285        pipe_release(pipe);
     286        return started;
     287}
     288
     289/** Prepare pipe for a long transfer.
     290 *
     291 * By a long transfer is mean transfer consisting of several
     292 * requests to the HC.
     293 * Calling such function is optional and it has positive effect of
     294 * improved performance because IPC session is initiated only once.
     295 *
     296 * @param pipe Pipe over which the transfer will happen.
     297 * @return Error code.
     298 */
     299int usb_pipe_start_long_transfer(usb_pipe_t *pipe)
     300{
     301        return pipe_add_ref(pipe);
     302}
     303
     304/** Terminate a long transfer on a pipe.
     305 *
     306 * @see usb_pipe_start_long_transfer
     307 *
     308 * @param pipe Pipe where to end the long transfer.
     309 */
     310void usb_pipe_end_long_transfer(usb_pipe_t *pipe)
     311{
     312        pipe_drop_ref(pipe);
    301313}
    302314
  • uspace/lib/usb/src/pipesinit.c

    r8790650 r501e5df  
    356356        assert(connection);
    357357
     358        fibril_mutex_initialize(&pipe->guard);
    358359        pipe->wire = connection;
    359360        pipe->hc_phone = -1;
     361        fibril_mutex_initialize(&pipe->hc_phone_mutex);
    360362        pipe->endpoint_no = endpoint_no;
    361363        pipe->transfer_type = transfer_type;
    362364        pipe->max_packet_size = max_packet_size;
    363365        pipe->direction = direction;
     366        pipe->refcount = 0;
    364367
    365368        return EOK;
     
    413416        int rc;
    414417
    415         TRY_LOOP(failed_attempts) {
    416                 rc = usb_pipe_start_session(pipe);
    417                 if (rc == EOK) {
    418                         break;
    419                 }
    420         }
     418        rc = usb_pipe_start_long_transfer(pipe);
    421419        if (rc != EOK) {
    422420                return rc;
     
    439437                }
    440438        }
    441         usb_pipe_end_session(pipe);
     439        usb_pipe_end_long_transfer(pipe);
    442440        if (rc != EOK) {
    443441                return rc;
     
    461459    usb_hc_connection_t *hc_connection)
    462460{
     461        return usb_pipe_register_with_speed(pipe, USB_SPEED_MAX + 1,
     462            interval, hc_connection);
     463}
     464
     465/** Register endpoint with a speed at the host controller.
     466 *
     467 * You will rarely need to use this function because it is needed only
     468 * if the registered endpoint is of address 0 and there is no other way
     469 * to tell speed of the device at address 0.
     470 *
     471 * @param pipe Pipe to be registered.
     472 * @param speed Speed of the device
     473 *      (invalid speed means use previously specified one).
     474 * @param interval Polling interval.
     475 * @param hc_connection Connection to the host controller (must be opened).
     476 * @return Error code.
     477 */
     478int usb_pipe_register_with_speed(usb_pipe_t *pipe, usb_speed_t speed,
     479    unsigned int interval,
     480    usb_hc_connection_t *hc_connection)
     481{
    463482        assert(pipe);
    464483        assert(hc_connection);
     
    468487        }
    469488
    470 #define _PACK(high, low) ((high) * 256 + (low))
    471 
    472         return async_req_5_0(hc_connection->hc_phone,
     489#define _PACK2(high, low) (((high) << 16) + (low))
     490#define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
     491
     492        return async_req_4_0(hc_connection->hc_phone,
    473493            DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_REGISTER_ENDPOINT,
    474             _PACK(pipe->wire->address, pipe->endpoint_no),
    475             _PACK(pipe->transfer_type, pipe->direction),
    476             pipe->max_packet_size, interval);
    477 
    478 #undef _PACK
     494            _PACK2(pipe->wire->address, pipe->endpoint_no),
     495            _PACK3(speed, pipe->transfer_type, pipe->direction),
     496            _PACK2(pipe->max_packet_size, interval));
     497
     498#undef _PACK2
     499#undef _PACK3
    479500}
    480501
  • uspace/lib/usb/src/pipesio.c

    r8790650 r501e5df  
    4949#include <assert.h>
    5050#include <usbhc_iface.h>
     51#include "pipepriv.h"
    5152
    5253/** Request an in transfer, no checking of input parameters.
     
    7879        }
    7980
     81        /* Ensure serialization over the phone. */
     82        pipe_start_transaction(pipe);
     83
    8084        /*
    8185         * Make call identifying target USB device and type of transfer.
    8286         */
    83         aid_t opening_request = async_send_4(pipe->hc_phone,
     87        aid_t opening_request = async_send_3(pipe->hc_phone,
    8488            DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
    8589            pipe->wire->address, pipe->endpoint_no,
    86             pipe->max_packet_size,
    8790            NULL);
    8891        if (opening_request == 0) {
     92                pipe_end_transaction(pipe);
    8993                return ENOMEM;
    9094        }
     
    96100        aid_t data_request = async_data_read(pipe->hc_phone, buffer, size,
    97101            &data_request_call);
     102
     103        /*
     104         * Since now on, someone else might access the backing phone
     105         * without breaking the transfer IPC protocol.
     106         */
     107        pipe_end_transaction(pipe);
    98108
    99109        if (data_request == 0) {
     
    146156
    147157        if (buffer == NULL) {
    148                         return EINVAL;
     158                return EINVAL;
    149159        }
    150160
    151161        if (size == 0) {
    152162                return EINVAL;
    153         }
    154 
    155         if (!usb_pipe_is_session_started(pipe)) {
    156                 return EBADF;
    157163        }
    158164
     
    165171        }
    166172
     173        int rc;
     174        rc = pipe_add_ref(pipe);
     175        if (rc != EOK) {
     176                return rc;
     177        }
     178
     179
    167180        size_t act_size = 0;
    168         int rc;
    169181
    170182        rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
     183
     184        pipe_drop_ref(pipe);
     185
    171186        if (rc != EOK) {
    172187                return rc;
     
    210225        }
    211226
     227        /* Ensure serialization over the phone. */
     228        pipe_start_transaction(pipe);
     229
    212230        /*
    213231         * Make call identifying target USB device and type of transfer.
    214232         */
    215         aid_t opening_request = async_send_4(pipe->hc_phone,
     233        aid_t opening_request = async_send_3(pipe->hc_phone,
    216234            DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
    217235            pipe->wire->address, pipe->endpoint_no,
    218             pipe->max_packet_size,
    219236            NULL);
    220237        if (opening_request == 0) {
     238                pipe_end_transaction(pipe);
    221239                return ENOMEM;
    222240        }
     
    226244         */
    227245        int rc = async_data_write_start(pipe->hc_phone, buffer, size);
     246
     247        /*
     248         * Since now on, someone else might access the backing phone
     249         * without breaking the transfer IPC protocol.
     250         */
     251        pipe_end_transaction(pipe);
     252
    228253        if (rc != EOK) {
    229254                async_wait_for(opening_request, NULL);
     
    260285        }
    261286
    262         if (!usb_pipe_is_session_started(pipe)) {
    263                 return EBADF;
    264         }
    265 
    266287        if (pipe->direction != USB_DIRECTION_OUT) {
    267288                return EBADF;
     
    272293        }
    273294
    274         int rc = usb_pipe_write_no_check(pipe, buffer, size);
     295        int rc;
     296
     297        rc = pipe_add_ref(pipe);
     298        if (rc != EOK) {
     299                return rc;
     300        }
     301
     302        rc = usb_pipe_write_no_check(pipe, buffer, size);
     303
     304        pipe_drop_ref(pipe);
    275305
    276306        return rc;
     
    293323    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
    294324{
     325        /* Ensure serialization over the phone. */
     326        pipe_start_transaction(pipe);
     327
    295328        /*
    296329         * Make call identifying target USB device and control transfer type.
    297330         */
    298         aid_t opening_request = async_send_4(pipe->hc_phone,
     331        aid_t opening_request = async_send_3(pipe->hc_phone,
    299332            DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_READ,
    300333            pipe->wire->address, pipe->endpoint_no,
    301             pipe->max_packet_size,
    302334            NULL);
    303335        if (opening_request == 0) {
     
    311343            setup_buffer, setup_buffer_size);
    312344        if (rc != EOK) {
     345                pipe_end_transaction(pipe);
    313346                async_wait_for(opening_request, NULL);
    314347                return rc;
     
    322355            data_buffer, data_buffer_size,
    323356            &data_request_call);
     357
     358        /*
     359         * Since now on, someone else might access the backing phone
     360         * without breaking the transfer IPC protocol.
     361         */
     362        pipe_end_transaction(pipe);
     363
     364
    324365        if (data_request == 0) {
    325366                async_wait_for(opening_request, NULL);
     
    379420        }
    380421
    381         if (!usb_pipe_is_session_started(pipe)) {
    382                 return EBADF;
    383         }
    384 
    385422        if ((pipe->direction != USB_DIRECTION_BOTH)
    386423            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     
    388425        }
    389426
     427        int rc;
     428
     429        rc = pipe_add_ref(pipe);
     430        if (rc != EOK) {
     431                return rc;
     432        }
     433
    390434        size_t act_size = 0;
    391         int rc = usb_pipe_control_read_no_check(pipe,
     435        rc = usb_pipe_control_read_no_check(pipe,
    392436            setup_buffer, setup_buffer_size,
    393437            data_buffer, data_buffer_size, &act_size);
     438
     439        pipe_drop_ref(pipe);
    394440
    395441        if (rc != EOK) {
     
    418464    void *data_buffer, size_t data_buffer_size)
    419465{
     466        /* Ensure serialization over the phone. */
     467        pipe_start_transaction(pipe);
     468
    420469        /*
    421470         * Make call identifying target USB device and control transfer type.
    422471         */
    423         aid_t opening_request = async_send_5(pipe->hc_phone,
     472        aid_t opening_request = async_send_4(pipe->hc_phone,
    424473            DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_WRITE,
    425474            pipe->wire->address, pipe->endpoint_no,
    426475            data_buffer_size,
    427             pipe->max_packet_size,
    428476            NULL);
    429477        if (opening_request == 0) {
     478                pipe_end_transaction(pipe);
    430479                return ENOMEM;
    431480        }
     
    437486            setup_buffer, setup_buffer_size);
    438487        if (rc != EOK) {
     488                pipe_end_transaction(pipe);
    439489                async_wait_for(opening_request, NULL);
    440490                return rc;
     
    447497                rc = async_data_write_start(pipe->hc_phone,
    448498                    data_buffer, data_buffer_size);
     499
     500                /* All data sent, pipe can be released. */
     501                pipe_end_transaction(pipe);
     502
    449503                if (rc != EOK) {
    450504                        async_wait_for(opening_request, NULL);
    451505                        return rc;
    452506                }
     507        } else {
     508                /* No data to send, we can release the pipe for others. */
     509                pipe_end_transaction(pipe);
    453510        }
    454511
     
    491548        }
    492549
    493         if (!usb_pipe_is_session_started(pipe)) {
    494                 return EBADF;
    495         }
    496 
    497550        if ((pipe->direction != USB_DIRECTION_BOTH)
    498551            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     
    500553        }
    501554
    502         int rc = usb_pipe_control_write_no_check(pipe,
     555        int rc;
     556
     557        rc = pipe_add_ref(pipe);
     558        if (rc != EOK) {
     559                return rc;
     560        }
     561
     562        rc = usb_pipe_control_write_no_check(pipe,
    503563            setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
     564
     565        pipe_drop_ref(pipe);
    504566
    505567        return rc;
  • uspace/lib/usb/src/recognise.c

    r8790650 r501e5df  
    404404        child->driver_data = dev_data;
    405405
    406         rc = usb_pipe_start_session(&ctrl_pipe);
    407         if (rc != EOK) {
    408                 goto failure;
    409         }
    410 
    411406        rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
    412         if (rc != EOK) {
    413                 goto failure;
    414         }
    415 
    416         rc = usb_pipe_end_session(&ctrl_pipe);
    417407        if (rc != EOK) {
    418408                goto failure;
Note: See TracChangeset for help on using the changeset viewer.