Changeset 9876e34 in mainline for uspace/drv/bus/usb/xhci/rh.c


Ignore:
Timestamp:
2017-10-05T15:38:02Z (7 years ago)
Author:
Petr Manek <petr.manek@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
916991b
Parents:
44063d17
Message:

Removed previous implementation, forwarding all events to hub, generating status change bitmap, reporting USB features and clearing them.

File:
1 edited

Legend:

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

    r44063d17 r9876e34  
    5151static usbvirt_device_ops_t ops;
    5252
     53/* This mask only lists registers, which imply port change. */
     54static const uint32_t port_change_mask =
     55        XHCI_REG_MASK(XHCI_PORT_CSC) |
     56        XHCI_REG_MASK(XHCI_PORT_PEC) |
     57        XHCI_REG_MASK(XHCI_PORT_WRC) |
     58        XHCI_REG_MASK(XHCI_PORT_OCC) |
     59        XHCI_REG_MASK(XHCI_PORT_PRC) |
     60        XHCI_REG_MASK(XHCI_PORT_PLC) |
     61        XHCI_REG_MASK(XHCI_PORT_CEC);
     62
    5363int xhci_rh_init(xhci_rh_t *rh, xhci_hc_t *hc)
    5464{
     
    5767
    5868        rh->hc = hc;
     69        rh->max_ports = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_PORTS);
    5970
    6071        usb_hub_descriptor_header_t *header = &rh->hub_descriptor.header;
    6172        header->length = sizeof(usb_hub_descriptor_header_t);
    6273        header->descriptor_type = USB_DESCTYPE_HUB;
    63         header->port_count = XHCI_MAX_PORTS;
     74        header->port_count = rh->max_ports;
    6475        header->characteristics =
    6576                    HUB_CHAR_NO_POWER_SWITCH_FLAG | HUB_CHAR_NO_OC_FLAG;
     
    7384// TODO: Check device deallocation, we free device_ctx in hc.c, not
    7485//       sure about the other structs.
    75 static int alloc_dev(xhci_hc_t *hc, uint8_t port, uint32_t route_str)
    76 {
    77         int err;
    78 
    79         xhci_cmd_t cmd;
    80         xhci_cmd_init(&cmd);
    81 
    82         xhci_send_enable_slot_command(hc, &cmd);
    83         if ((err = xhci_cmd_wait(&cmd, 100000)) != EOK)
    84                 return err;
    85 
    86         uint32_t slot_id = cmd.slot_id;
    87 
    88         usb_log_debug2("Obtained slot ID: %u.\n", slot_id);
    89         xhci_cmd_fini(&cmd);
    90 
    91         xhci_input_ctx_t *ictx = malloc32(sizeof(xhci_input_ctx_t));
    92         if (!ictx) {
    93                 return ENOMEM;
    94         }
    95 
    96         memset(ictx, 0, sizeof(xhci_input_ctx_t));
    97 
    98         XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
    99         XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 1);
    100 
    101         /* Initialize slot_ctx according to section 4.3.3 point 3. */
    102         /* Attaching to root hub port, root string equals to 0. */
    103         XHCI_SLOT_ROOT_HUB_PORT_SET(ictx->slot_ctx, port);
    104         XHCI_SLOT_CTX_ENTRIES_SET(ictx->slot_ctx, 1);
    105         XHCI_SLOT_ROUTE_STRING_SET(ictx->slot_ctx, route_str);
    106 
    107         xhci_trb_ring_t *ep_ring = malloc32(sizeof(xhci_trb_ring_t));
    108         if (!ep_ring) {
    109                 err = ENOMEM;
    110                 goto err_ictx;
    111         }
    112 
    113         err = xhci_trb_ring_init(ep_ring, hc);
    114         if (err)
    115                 goto err_ring;
    116 
    117         XHCI_EP_TYPE_SET(ictx->endpoint_ctx[0], EP_TYPE_CONTROL);
    118         // TODO: must be changed with a command after USB descriptor is read
    119         // See 4.6.5 in XHCI specification, first note
    120         XHCI_EP_MAX_PACKET_SIZE_SET(ictx->endpoint_ctx[0],
    121             xhci_is_usb3_port(&hc->rh, port) ? 512 : 8);
    122         XHCI_EP_MAX_BURST_SIZE_SET(ictx->endpoint_ctx[0], 0);
    123         /* FIXME physical pointer? */
    124         XHCI_EP_TR_DPTR_SET(ictx->endpoint_ctx[0], ep_ring->dequeue);
    125         XHCI_EP_DCS_SET(ictx->endpoint_ctx[0], 1);
    126         XHCI_EP_INTERVAL_SET(ictx->endpoint_ctx[0], 0);
    127         XHCI_EP_MAX_P_STREAMS_SET(ictx->endpoint_ctx[0], 0);
    128         XHCI_EP_MULT_SET(ictx->endpoint_ctx[0], 0);
    129         XHCI_EP_ERROR_COUNT_SET(ictx->endpoint_ctx[0], 3);
    130 
    131         // TODO: What's the alignment?
    132         xhci_device_ctx_t *dctx = malloc32(sizeof(xhci_device_ctx_t));
    133         if (!dctx) {
    134                 err = ENOMEM;
    135                 goto err_ring;
    136         }
    137         memset(dctx, 0, sizeof(xhci_device_ctx_t));
    138 
    139         hc->dcbaa[slot_id] = addr_to_phys(dctx);
    140 
    141         memset(&hc->dcbaa_virt[slot_id], 0, sizeof(xhci_virt_device_ctx_t));
    142         hc->dcbaa_virt[slot_id].dev_ctx = dctx;
    143         hc->dcbaa_virt[slot_id].trs[0] = ep_ring;
    144 
    145         xhci_cmd_init(&cmd);
    146         cmd.slot_id = slot_id;
    147         xhci_send_address_device_command(hc, &cmd, ictx);
    148         if ((err = xhci_cmd_wait(&cmd, 100000)) != EOK)
    149                 goto err_dctx;
    150 
    151         xhci_cmd_fini(&cmd);
    152 
    153         // TODO: Issue configure endpoint commands (sec 4.3.5).
    154 
    155         return EOK;
    156 
    157 err_dctx:
    158         if (dctx) {
    159                 free32(dctx);
    160                 hc->dcbaa[slot_id] = 0;
    161                 memset(&hc->dcbaa_virt[slot_id], 0, sizeof(xhci_virt_device_ctx_t));
    162         }
    163 err_ring:
    164         if (ep_ring) {
    165                 xhci_trb_ring_fini(ep_ring);
    166                 free32(ep_ring);
    167         }
    168 err_ictx:
    169         free32(ictx);
    170         return err;
    171 }
    172 
    173 static int handle_connected_device(xhci_hc_t* hc, xhci_port_regs_t* regs, uint8_t port_id)
    174 {
    175         uint8_t link_state = XHCI_REG_RD(regs, XHCI_PORT_PLS);
    176         const xhci_port_speed_t *speed = xhci_get_port_speed(&hc->rh, port_id);
    177 
    178         usb_log_info("Detected new %.4s%u.%u device on port %u.", speed->name, speed->major, speed->minor, port_id);
    179 
    180         if (speed->major == 3) {
    181                 if(link_state == 0) {
    182                         /* USB3 is automatically advanced to enabled. */
    183                         return alloc_dev(hc, port_id, 0);
    184                 }
    185                 else if (link_state == 5) {
    186                         /* USB 3 failed to enable. */
    187                         usb_log_error("USB 3 port couldn't be enabled.");
    188                         return EAGAIN;
    189                 }
    190                 else {
    191                         usb_log_error("USB 3 port is in invalid state %u.", link_state);
    192                         return EINVAL;
    193                 }
    194         }
    195         else {
    196                 usb_log_debug("USB 2 device attached, issuing reset.");
    197                 xhci_reset_hub_port(hc, port_id);
    198                 /*
    199                         FIXME: we need to wait for the event triggered by the reset
    200                         and then alloc_dev()... can't it be done directly instead of
    201                         going around?
    202                 */
    203                 return EOK;
    204         }
    205 }
     86// static int alloc_dev(xhci_hc_t *hc, uint8_t port, uint32_t route_str)
     87// {
     88//      int err;
     89//
     90//      xhci_cmd_t cmd;
     91//      xhci_cmd_init(&cmd);
     92//
     93//      xhci_send_enable_slot_command(hc, &cmd);
     94//      if ((err = xhci_cmd_wait(&cmd, 100000)) != EOK)
     95//              return err;
     96//
     97//      uint32_t slot_id = cmd.slot_id;
     98//
     99//      usb_log_debug2("Obtained slot ID: %u.\n", slot_id);
     100//      xhci_cmd_fini(&cmd);
     101//
     102//      xhci_input_ctx_t *ictx = malloc32(sizeof(xhci_input_ctx_t));
     103//      if (!ictx) {
     104//              return ENOMEM;
     105//      }
     106//
     107//      memset(ictx, 0, sizeof(xhci_input_ctx_t));
     108//
     109//      XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
     110//      XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 1);
     111//
     112//      /* Initialize slot_ctx according to section 4.3.3 point 3. */
     113//      /* Attaching to root hub port, root string equals to 0. */
     114//      XHCI_SLOT_ROOT_HUB_PORT_SET(ictx->slot_ctx, port);
     115//      XHCI_SLOT_CTX_ENTRIES_SET(ictx->slot_ctx, 1);
     116//      XHCI_SLOT_ROUTE_STRING_SET(ictx->slot_ctx, route_str);
     117//
     118//      xhci_trb_ring_t *ep_ring = malloc32(sizeof(xhci_trb_ring_t));
     119//      if (!ep_ring) {
     120//              err = ENOMEM;
     121//              goto err_ictx;
     122//      }
     123//
     124//      err = xhci_trb_ring_init(ep_ring, hc);
     125//      if (err)
     126//              goto err_ring;
     127//
     128//      XHCI_EP_TYPE_SET(ictx->endpoint_ctx[0], EP_TYPE_CONTROL);
     129//      // TODO: must be changed with a command after USB descriptor is read
     130//      // See 4.6.5 in XHCI specification, first note
     131//      XHCI_EP_MAX_PACKET_SIZE_SET(ictx->endpoint_ctx[0],
     132//          xhci_is_usb3_port(&hc->rh, port) ? 512 : 8);
     133//      XHCI_EP_MAX_BURST_SIZE_SET(ictx->endpoint_ctx[0], 0);
     134//      /* FIXME physical pointer? */
     135//      XHCI_EP_TR_DPTR_SET(ictx->endpoint_ctx[0], ep_ring->dequeue);
     136//      XHCI_EP_DCS_SET(ictx->endpoint_ctx[0], 1);
     137//      XHCI_EP_INTERVAL_SET(ictx->endpoint_ctx[0], 0);
     138//      XHCI_EP_MAX_P_STREAMS_SET(ictx->endpoint_ctx[0], 0);
     139//      XHCI_EP_MULT_SET(ictx->endpoint_ctx[0], 0);
     140//      XHCI_EP_ERROR_COUNT_SET(ictx->endpoint_ctx[0], 3);
     141//
     142//      // TODO: What's the alignment?
     143//      xhci_device_ctx_t *dctx = malloc32(sizeof(xhci_device_ctx_t));
     144//      if (!dctx) {
     145//              err = ENOMEM;
     146//              goto err_ring;
     147//      }
     148//      memset(dctx, 0, sizeof(xhci_device_ctx_t));
     149//
     150//      hc->dcbaa[slot_id] = addr_to_phys(dctx);
     151//
     152//      memset(&hc->dcbaa_virt[slot_id], 0, sizeof(xhci_virt_device_ctx_t));
     153//      hc->dcbaa_virt[slot_id].dev_ctx = dctx;
     154//      hc->dcbaa_virt[slot_id].trs[0] = ep_ring;
     155//
     156//      xhci_cmd_init(&cmd);
     157//      cmd.slot_id = slot_id;
     158//      xhci_send_address_device_command(hc, &cmd, ictx);
     159//      if ((err = xhci_cmd_wait(&cmd, 100000)) != EOK)
     160//              goto err_dctx;
     161//
     162//      xhci_cmd_fini(&cmd);
     163//
     164//      // TODO: Issue configure endpoint commands (sec 4.3.5).
     165//
     166//      return EOK;
     167//
     168// err_dctx:
     169//      if (dctx) {
     170//              free32(dctx);
     171//              hc->dcbaa[slot_id] = 0;
     172//              memset(&hc->dcbaa_virt[slot_id], 0, sizeof(xhci_virt_device_ctx_t));
     173//      }
     174// err_ring:
     175//      if (ep_ring) {
     176//              xhci_trb_ring_fini(ep_ring);
     177//              free32(ep_ring);
     178//      }
     179// err_ictx:
     180//      free32(ictx);
     181//      return err;
     182// }
     183
     184// static int handle_connected_device(xhci_hc_t* hc, xhci_port_regs_t* regs, uint8_t port_id)
     185// {
     186//      uint8_t link_state = XHCI_REG_RD(regs, XHCI_PORT_PLS);
     187//      const xhci_port_speed_t *speed = xhci_get_port_speed(&hc->rh, port_id);
     188//
     189//      usb_log_info("Detected new %.4s%u.%u device on port %u.", speed->name, speed->major, speed->minor, port_id);
     190//
     191//      if (speed->major == 3) {
     192//              if(link_state == 0) {
     193//                      /* USB3 is automatically advanced to enabled. */
     194//                      return alloc_dev(hc, port_id, 0);
     195//              }
     196//              else if (link_state == 5) {
     197//                      /* USB 3 failed to enable. */
     198//                      usb_log_error("USB 3 port couldn't be enabled.");
     199//                      return EAGAIN;
     200//              }
     201//              else {
     202//                      usb_log_error("USB 3 port is in invalid state %u.", link_state);
     203//                      return EINVAL;
     204//              }
     205//      }
     206//      else {
     207//              usb_log_debug("USB 2 device attached, issuing reset.");
     208//              xhci_reset_hub_port(hc, port_id);
     209//              /*
     210//                      FIXME: we need to wait for the event triggered by the reset
     211//                      and then alloc_dev()... can't it be done directly instead of
     212//                      going around?
     213//              */
     214//              return EOK;
     215//      }
     216// }
    206217
    207218int xhci_handle_port_status_change_event(xhci_hc_t *hc, xhci_trb_t *trb)
     
    211222        uint8_t port_id = xhci_get_hub_port(trb);
    212223        usb_log_debug("Port status change event detected for port %u.", port_id);
    213         xhci_port_regs_t* regs = &hc->op_regs->portrs[port_id - 1];
    214 
    215         /* Port reset change */
    216         if (XHCI_REG_RD(regs, XHCI_PORT_PRC)) {
    217                 /* Clear the flag. */
    218                 XHCI_REG_WR(regs, XHCI_PORT_PRC, 1);
    219 
    220                 uint8_t port_speed = XHCI_REG_RD(regs, XHCI_PORT_PS);
    221                 usb_log_debug2("Detected port reset on port %u, port speed id %u.", port_id, port_speed);
    222                 /** FIXME: only if that port is not yet initialized */
    223                 if ((err = alloc_dev(hc, port_id, 0)) != EOK)
    224                         return err;
    225         }
    226 
    227         /* Connection status change */
    228         if (XHCI_REG_RD(regs, XHCI_PORT_CSC)) {
    229                 XHCI_REG_WR(regs, XHCI_PORT_CSC, 1);
    230 
    231                 if (XHCI_REG_RD(regs, XHCI_PORT_CCS) == 1) {
    232                         if ((err = handle_connected_device(hc, regs, port_id)) != EOK)
    233                                 return err;
    234                 } else {
    235                         // TODO: Device disconnected
    236                         return ENOTSUP;
    237                 }
    238         }
    239224
    240225        // Interrupt on the virtual hub status change pipe.
    241         usb_target_t target = {
    242                 .address = virthub_base_get_address(&hc->rh.base),
    243                 .endpoint = HUB_STATUS_CHANGE_PIPE
    244         };
    245         usb_direction_t dir = USB_DIRECTION_IN;
    246         usb_device_request_setup_packet_t setup;
    247         uint64_t buffer[2];
    248         size_t real_size = 0;
    249         err = virthub_base_request(&hc->rh.base, target, dir, &setup, &buffer,
    250                 sizeof(buffer), &real_size);
    251 
     226        err = xhci_rh_interrupt(&hc->rh);
    252227        if (err != EOK) {
    253228                usb_log_warning("Invoking interrupt on virtual hub failed: %s",
     
    364339        assert(hub);
    365340
    366         if (!setup_packet->index || setup_packet->index > XHCI_MAX_PORTS) {
     341        if (!setup_packet->index || setup_packet->index > hub->max_ports) {
    367342                return ESTALL;
    368343        }
     
    388363        memcpy(data, &status, sizeof(status));
    389364        *act_size = sizeof(status);
     365
    390366        return EOK;
    391367}
     
    403379    uint8_t *data, size_t *act_size)
    404380{
    405         /* TODO: Implement me! */
    406         usb_log_debug2("Called req_clear_port_feature().");
     381        xhci_rh_t *hub = virthub_get_data(device);
     382        assert(hub);
     383
     384        if (!setup_packet->index || setup_packet->index > hub->max_ports) {
     385                return ESTALL;
     386        }
     387
     388        /* The index is 1-based. */
     389        xhci_port_regs_t* regs = &hub->hc->op_regs->portrs[setup_packet->index - 1];
     390
     391#define USB_MAP_XHCI(a, b) [USB_HUB_FEATURE_##a] = XHCI_REG_MASK(XHCI_PORT_##b)
     392
     393        const usb_hub_class_feature_t feature = uint16_usb2host(setup_packet->value);
     394        static const ioport32_t masks[] = {
     395                USB_MAP_XHCI(C_PORT_CONNECTION, CSC),
     396                USB_MAP_XHCI(C_PORT_ENABLE, PEC),
     397                USB_MAP_XHCI(C_PORT_OVER_CURRENT, OCC),
     398                USB_MAP_XHCI(C_PORT_RESET, PRC)
     399        };
     400
     401#undef USB_MAP_XHCI
     402
     403        usb_log_debug2("RH: ClearPortFeature(%hu) = %d.", setup_packet->index,
     404                feature);
     405
     406        /* Clear the register by writing 1. */
     407        XHCI_REG_WR_FIELD(&regs->portsc, masks[feature], 32);
     408
    407409        return EOK;
    408410}
     
    444446        assert(hub);
    445447
    446         if (buffer_size < 16)
     448        uint8_t status[STATUS_BYTES(hub->max_ports)];
     449        memset(status, 0, sizeof(status));
     450
     451        if (buffer_size < sizeof(status))
    447452                return ESTALL;
    448453
    449         memset(buffer, 0, 16);
    450         *actual_size = 16;
    451         return ENAK;
     454        bool change = false;
     455        for (size_t i = 1; i <= hub->max_ports; ++i) {
     456                xhci_port_regs_t *regs = &hub->hc->op_regs->portrs[i - 1];
     457
     458                if (XHCI_REG_RD_FIELD(&regs->portsc, 32) & port_change_mask) {
     459                        status[i / 8] |= (1 << (i % 8));
     460                        change = true;
     461                }
     462        }
     463
     464        memcpy(buffer, &status, sizeof(status));
     465        *actual_size = sizeof(status);
     466        return change ? EOK : ENAK;
    452467}
    453468
Note: See TracChangeset for help on using the changeset viewer.