Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a4e26882 in mainline


Ignore:
Timestamp:
2017-10-22T16:37:44Z (4 years ago)
Author:
Petr Manek <petr.manek@…>
Branches:
lfn, master
Children:
4594baa
Parents:
2c091a6
Message:

Very rudimentary support for device disconnection.

Location:
uspace/drv/bus/usb/xhci
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/bus.c

    r2c091a6 ra4e26882  
    118118        xhci_device_t *xhci_dev = xhci_device_get(dev);
    119119
    120         // TODO: Release remaining EPs
     120        /* Release remaining endpoints. */
     121        for (size_t i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
     122                if (!xhci_dev->endpoints[i])
     123                        continue;
     124
     125                // FIXME: ignoring return code
     126                bus_release_endpoint(&bus->base, &xhci_dev->endpoints[i]->base);
     127        }
    121128
    122129        hashed_device_t *hashed_dev;
     
    270277        xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
    271278        assert(bus);
    272        
     279
    273280        xhci_endpoint_t *ep;
    274281        int res = xhci_endpoint_find_by_target(bus, target, &ep);
  • uspace/drv/bus/usb/xhci/endpoint.c

    r2c091a6 ra4e26882  
    182182        assert(ep);
    183183
     184        /* Offline devices don't create new endpoints other than EP0. */
     185        if (!dev->online) {
     186                return EAGAIN;
     187        }
     188
    184189        int err = ENOMEM;
    185190        const usb_endpoint_t ep_num = ep->base.target.endpoint;
  • uspace/drv/bus/usb/xhci/endpoint.h

    r2c091a6 ra4e26882  
    9494        /** Flag indicating whether the device is USB3 (it's USB2 otherwise). */
    9595        bool usb3;
     96
     97        /** True if the device can add new endpoints and schedule transfers. */
     98        volatile bool online;
    9699} xhci_device_t;
    97100
    98101int xhci_endpoint_init(xhci_endpoint_t *, xhci_bus_t *);
    99102void xhci_endpoint_fini(xhci_endpoint_t *);
    100 
    101 int xhci_device_init(xhci_device_t *, xhci_bus_t *, usb_address_t);
    102 void xhci_device_fini(xhci_device_t *);
    103103
    104104uint8_t xhci_endpoint_dci(xhci_endpoint_t *);
  • uspace/drv/bus/usb/xhci/rh.c

    r2c091a6 ra4e26882  
    6868        rh->hc = hc;
    6969        rh->max_ports = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_PORTS);
    70         rh->devices = (xhci_device_t **) malloc(rh->max_ports * sizeof(xhci_device_t *));
     70        rh->devices = (xhci_device_t **) calloc(rh->max_ports, sizeof(xhci_device_t *));
    7171        hc->rh.hc_device = device;
    72 
    73         memset(rh->devices, 0, rh->max_ports * sizeof(xhci_device_t *));
    7472
    7573        return device_init(&hc->rh.device);
     
    149147        usb_log_debug2("Obtained USB address: %d.\n", dev->address);
    150148
     149        /* From now on, the device is officially online, yay! */
     150        fibril_mutex_lock(&dev->guard);
     151        xhci_dev->online = true;
     152        fibril_mutex_unlock(&dev->guard);
     153
    151154        // XXX: Going around bus, duplicating code
    152155        ep0_base->device = dev;
     
    264267static int handle_disconnected_device(xhci_rh_t *rh, uint8_t port_id)
    265268{
     269        assert(rh);
     270        int err;
     271
    266272        /* Find XHCI device by the port. */
    267273        xhci_device_t *dev = rh->devices[port_id - 1];
    268274        if (!dev) {
    269                 /* Must be extraneous call */
     275                /* Must be extraneous call. */
    270276                return EOK;
    271277        }
    272278
    273         usb_log_info("Device at port %u has been disconnected.", port_id);
    274 
    275         // TODO: Destroy DDF function using _gone.
    276         // TODO: Remove device endpoints on the bus.
     279        usb_log_info("Device '%s' at port %u has been disconnected.", ddf_fun_get_name(dev->base.fun), port_id);
     280
     281        /* Block creation of new endpoints and transfers. */
     282        fibril_mutex_lock(&dev->base.guard);
     283        dev->online = false;
     284        fibril_mutex_unlock(&dev->base.guard);
     285
     286        fibril_mutex_lock(&rh->device.guard);
     287        list_remove(&dev->base.link);
     288        fibril_mutex_unlock(&rh->device.guard);
     289
     290        rh->devices[port_id - 1] = NULL;
     291        usb_log_debug2("Aborting all active transfers to '%s'.", ddf_fun_get_name(dev->base.fun));
     292
     293        /* Abort running transfers. */
     294        for (size_t i = 0; i < ARRAY_SIZE(dev->endpoints); ++i) {
     295                xhci_endpoint_t *ep = dev->endpoints[i];
     296                if (!ep || !ep->base.active)
     297                        continue;
     298
     299                if ((err = xhci_transfer_abort(&ep->active_transfer))) {
     300                        usb_log_warning("Failed to abort active %s transfer to "
     301                            " endpoint %d of detached device '%s': %s",
     302                            usb_str_transfer_type(ep->base.transfer_type),
     303                            ep->base.target.endpoint, ddf_fun_get_name(dev->base.fun),
     304                            str_error(err));
     305                }
     306        }
     307
     308        /* Make DDF (and all drivers) forget about the device. */
     309        if ((err = ddf_fun_unbind(dev->base.fun))) {
     310                usb_log_warning("Failed to unbind DDF function of detached device '%s': %s",
     311                    ddf_fun_get_name(dev->base.fun), str_error(err));
     312        }
     313
     314        /* FIXME:
     315         * A deadlock happens on the previous line. For some reason, the HID driver
     316         * does not fully release its DDF function (tracked it down to release_endpoint
     317         * in usb_remote.c so far).
     318         *
     319         * For that reason as well, the following 3 lines are untested.
     320         */
     321
     322        xhci_bus_remove_device(&rh->hc->bus, rh->hc, &dev->base);
     323        hc_disable_slot(rh->hc, dev->slot_id);
     324        hcd_ddf_device_destroy(&dev->base);
     325
    277326        // TODO: Free device context.
    278327        // TODO: Free TRB rings.
  • uspace/drv/bus/usb/xhci/transfers.c

    r2c091a6 ra4e26882  
    248248}
    249249
     250int xhci_transfer_abort(xhci_transfer_t *transfer)
     251{
     252        usb_transfer_batch_t *batch = &transfer->batch;
     253        batch->error = EAGAIN;
     254        batch->transfered_size = 0;
     255        usb_transfer_batch_finish(batch);
     256        return EOK;
     257}
     258
    250259int xhci_handle_transfer_event(xhci_hc_t* hc, xhci_trb_t* trb)
    251260{
     
    304313        assert(xhci_ep);
    305314
     315        xhci_device_t *xhci_dev = xhci_ep_to_dev(xhci_ep);
     316
     317        /* Offline devices don't schedule transfers other than on EP0. */
     318        if (!xhci_dev->online && xhci_ep->base.target.endpoint) {
     319                return EAGAIN;
     320        }
     321
    306322        const usb_transfer_type_t type = batch->ep->transfer_type;
    307323        assert(type >= 0 && type < ARRAY_SIZE(transfer_handlers));
     
    321337                return err;
    322338
    323         const uint8_t slot_id = xhci_ep_to_dev(xhci_ep)->slot_id;
     339        const uint8_t slot_id = xhci_dev->slot_id;
    324340        const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
    325341        return hc_ring_doorbell(hc, slot_id, target);
  • uspace/drv/bus/usb/xhci/transfers.h

    r2c091a6 ra4e26882  
    5555
    5656xhci_transfer_t* xhci_transfer_create(endpoint_t *);
    57 int xhci_transfer_schedule(xhci_hc_t*, usb_transfer_batch_t *);
    58 int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*);
    59 void xhci_transfer_destroy(xhci_transfer_t*);
     57int xhci_transfer_schedule(xhci_hc_t *, usb_transfer_batch_t *);
     58int xhci_transfer_abort(xhci_transfer_t *);
     59int xhci_handle_transfer_event(xhci_hc_t *, xhci_trb_t *);
     60void xhci_transfer_destroy(xhci_transfer_t *);
    6061
    6162static inline xhci_transfer_t *xhci_transfer_from_batch(usb_transfer_batch_t *batch)
Note: See TracChangeset for help on using the changeset viewer.