root/drivers/usb/gadget/udc/aspeed-vhub/hub.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ast_vhub_patch_dev_desc_usb1
  2. ast_vhub_hub_dev_status
  3. ast_vhub_hub_ep_status
  4. ast_vhub_hub_dev_feature
  5. ast_vhub_hub_ep_feature
  6. ast_vhub_rep_desc
  7. ast_vhub_rep_string
  8. ast_vhub_std_hub_request
  9. ast_vhub_update_hub_ep1
  10. ast_vhub_change_port_stat
  11. ast_vhub_send_host_wakeup
  12. ast_vhub_device_connect
  13. ast_vhub_wake_work
  14. ast_vhub_hub_wake_all
  15. ast_vhub_port_reset
  16. ast_vhub_set_port_feature
  17. ast_vhub_clr_port_feature
  18. ast_vhub_get_port_stat
  19. ast_vhub_class_hub_request
  20. ast_vhub_hub_suspend
  21. ast_vhub_hub_resume
  22. ast_vhub_hub_reset
  23. ast_vhub_init_hub

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * aspeed-vhub -- Driver for Aspeed SoC "vHub" USB gadget
   4  *
   5  * hub.c - virtual hub handling
   6  *
   7  * Copyright 2017 IBM Corporation
   8  *
   9  * This program is free software; you can redistribute it and/or modify
  10  * it under the terms of the GNU General Public License as published by
  11  * the Free Software Foundation; either version 2 of the License, or
  12  * (at your option) any later version.
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/delay.h>
  19 #include <linux/ioport.h>
  20 #include <linux/slab.h>
  21 #include <linux/errno.h>
  22 #include <linux/list.h>
  23 #include <linux/interrupt.h>
  24 #include <linux/proc_fs.h>
  25 #include <linux/prefetch.h>
  26 #include <linux/clk.h>
  27 #include <linux/usb/gadget.h>
  28 #include <linux/of.h>
  29 #include <linux/of_gpio.h>
  30 #include <linux/regmap.h>
  31 #include <linux/dma-mapping.h>
  32 #include <linux/bcd.h>
  33 #include <linux/version.h>
  34 #include <linux/usb.h>
  35 #include <linux/usb/hcd.h>
  36 
  37 #include "vhub.h"
  38 
  39 /* usb 2.0 hub device descriptor
  40  *
  41  * A few things we may want to improve here:
  42  *
  43  *    - We may need to indicate TT support
  44  *    - We may need a device qualifier descriptor
  45  *      as devices can pretend to be usb1 or 2
  46  *    - Make vid/did overridable
  47  *    - make it look like usb1 if usb1 mode forced
  48  */
  49 #define KERNEL_REL      bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
  50 #define KERNEL_VER      bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
  51 
  52 enum {
  53         AST_VHUB_STR_MANUF = 3,
  54         AST_VHUB_STR_PRODUCT = 2,
  55         AST_VHUB_STR_SERIAL = 1,
  56 };
  57 
  58 static const struct usb_device_descriptor ast_vhub_dev_desc = {
  59         .bLength                = USB_DT_DEVICE_SIZE,
  60         .bDescriptorType        = USB_DT_DEVICE,
  61         .bcdUSB                 = cpu_to_le16(0x0200),
  62         .bDeviceClass           = USB_CLASS_HUB,
  63         .bDeviceSubClass        = 0,
  64         .bDeviceProtocol        = 1,
  65         .bMaxPacketSize0        = 64,
  66         .idVendor               = cpu_to_le16(0x1d6b),
  67         .idProduct              = cpu_to_le16(0x0107),
  68         .bcdDevice              = cpu_to_le16(0x0100),
  69         .iManufacturer          = AST_VHUB_STR_MANUF,
  70         .iProduct               = AST_VHUB_STR_PRODUCT,
  71         .iSerialNumber          = AST_VHUB_STR_SERIAL,
  72         .bNumConfigurations     = 1,
  73 };
  74 
  75 /* Patches to the above when forcing USB1 mode */
  76 static void ast_vhub_patch_dev_desc_usb1(struct usb_device_descriptor *desc)
  77 {
  78         desc->bcdUSB = cpu_to_le16(0x0100);
  79         desc->bDeviceProtocol = 0;
  80 }
  81 
  82 /*
  83  * Configuration descriptor: same comments as above
  84  * regarding handling USB1 mode.
  85  */
  86 
  87 /*
  88  * We don't use sizeof() as Linux definition of
  89  * struct usb_endpoint_descriptor contains 2
  90  * extra bytes
  91  */
  92 #define AST_VHUB_CONF_DESC_SIZE (USB_DT_CONFIG_SIZE + \
  93                                  USB_DT_INTERFACE_SIZE + \
  94                                  USB_DT_ENDPOINT_SIZE)
  95 
  96 static const struct ast_vhub_full_cdesc {
  97         struct usb_config_descriptor    cfg;
  98         struct usb_interface_descriptor intf;
  99         struct usb_endpoint_descriptor  ep;
 100 } __attribute__ ((packed)) ast_vhub_conf_desc = {
 101         .cfg = {
 102                 .bLength                = USB_DT_CONFIG_SIZE,
 103                 .bDescriptorType        = USB_DT_CONFIG,
 104                 .wTotalLength           = cpu_to_le16(AST_VHUB_CONF_DESC_SIZE),
 105                 .bNumInterfaces         = 1,
 106                 .bConfigurationValue    = 1,
 107                 .iConfiguration         = 0,
 108                 .bmAttributes           = USB_CONFIG_ATT_ONE |
 109                                           USB_CONFIG_ATT_SELFPOWER |
 110                                           USB_CONFIG_ATT_WAKEUP,
 111                 .bMaxPower              = 0,
 112         },
 113         .intf = {
 114                 .bLength                = USB_DT_INTERFACE_SIZE,
 115                 .bDescriptorType        = USB_DT_INTERFACE,
 116                 .bInterfaceNumber       = 0,
 117                 .bAlternateSetting      = 0,
 118                 .bNumEndpoints          = 1,
 119                 .bInterfaceClass        = USB_CLASS_HUB,
 120                 .bInterfaceSubClass     = 0,
 121                 .bInterfaceProtocol     = 0,
 122                 .iInterface             = 0,
 123         },
 124         .ep = {
 125                 .bLength                = USB_DT_ENDPOINT_SIZE,
 126                 .bDescriptorType        = USB_DT_ENDPOINT,
 127                 .bEndpointAddress       = 0x81,
 128                 .bmAttributes           = USB_ENDPOINT_XFER_INT,
 129                 .wMaxPacketSize         = cpu_to_le16(1),
 130                 .bInterval              = 0x0c,
 131         },
 132 };
 133 
 134 #define AST_VHUB_HUB_DESC_SIZE  (USB_DT_HUB_NONVAR_SIZE + 2)
 135 
 136 static const struct usb_hub_descriptor ast_vhub_hub_desc = {
 137         .bDescLength                    = AST_VHUB_HUB_DESC_SIZE,
 138         .bDescriptorType                = USB_DT_HUB,
 139         .bNbrPorts                      = AST_VHUB_NUM_PORTS,
 140         .wHubCharacteristics            = cpu_to_le16(HUB_CHAR_NO_LPSM),
 141         .bPwrOn2PwrGood                 = 10,
 142         .bHubContrCurrent               = 0,
 143         .u.hs.DeviceRemovable[0]        = 0,
 144         .u.hs.DeviceRemovable[1]        = 0xff,
 145 };
 146 
 147 /*
 148  * These strings converted to UTF-16 must be smaller than
 149  * our EP0 buffer.
 150  */
 151 static const struct usb_string ast_vhub_str_array[] = {
 152         {
 153                 .id = AST_VHUB_STR_SERIAL,
 154                 .s = "00000000"
 155         },
 156         {
 157                 .id = AST_VHUB_STR_PRODUCT,
 158                 .s = "USB Virtual Hub"
 159         },
 160         {
 161                 .id = AST_VHUB_STR_MANUF,
 162                 .s = "Aspeed"
 163         },
 164         { }
 165 };
 166 
 167 static const struct usb_gadget_strings ast_vhub_strings = {
 168         .language = 0x0409,
 169         .strings = (struct usb_string *)ast_vhub_str_array
 170 };
 171 
 172 static int ast_vhub_hub_dev_status(struct ast_vhub_ep *ep,
 173                                    u16 wIndex, u16 wValue)
 174 {
 175         u8 st0;
 176 
 177         EPDBG(ep, "GET_STATUS(dev)\n");
 178 
 179         /*
 180          * Mark it as self-powered, I doubt the BMC is powered off
 181          * the USB bus ...
 182          */
 183         st0 = 1 << USB_DEVICE_SELF_POWERED;
 184 
 185         /*
 186          * Need to double check how remote wakeup actually works
 187          * on that chip and what triggers it.
 188          */
 189         if (ep->vhub->wakeup_en)
 190                 st0 |= 1 << USB_DEVICE_REMOTE_WAKEUP;
 191 
 192         return ast_vhub_simple_reply(ep, st0, 0);
 193 }
 194 
 195 static int ast_vhub_hub_ep_status(struct ast_vhub_ep *ep,
 196                                   u16 wIndex, u16 wValue)
 197 {
 198         int ep_num;
 199         u8 st0 = 0;
 200 
 201         ep_num = wIndex & USB_ENDPOINT_NUMBER_MASK;
 202         EPDBG(ep, "GET_STATUS(ep%d)\n", ep_num);
 203 
 204         /* On the hub we have only EP 0 and 1 */
 205         if (ep_num == 1) {
 206                 if (ep->vhub->ep1_stalled)
 207                         st0 |= 1 << USB_ENDPOINT_HALT;
 208         } else if (ep_num != 0)
 209                 return std_req_stall;
 210 
 211         return ast_vhub_simple_reply(ep, st0, 0);
 212 }
 213 
 214 static int ast_vhub_hub_dev_feature(struct ast_vhub_ep *ep,
 215                                     u16 wIndex, u16 wValue,
 216                                     bool is_set)
 217 {
 218         EPDBG(ep, "%s_FEATURE(dev val=%02x)\n",
 219               is_set ? "SET" : "CLEAR", wValue);
 220 
 221         if (wValue != USB_DEVICE_REMOTE_WAKEUP)
 222                 return std_req_stall;
 223 
 224         ep->vhub->wakeup_en = is_set;
 225         EPDBG(ep, "Hub remote wakeup %s\n",
 226               is_set ? "enabled" : "disabled");
 227 
 228         return std_req_complete;
 229 }
 230 
 231 static int ast_vhub_hub_ep_feature(struct ast_vhub_ep *ep,
 232                                    u16 wIndex, u16 wValue,
 233                                    bool is_set)
 234 {
 235         int ep_num;
 236         u32 reg;
 237 
 238         ep_num = wIndex & USB_ENDPOINT_NUMBER_MASK;
 239         EPDBG(ep, "%s_FEATURE(ep%d val=%02x)\n",
 240               is_set ? "SET" : "CLEAR", ep_num, wValue);
 241 
 242         if (ep_num > 1)
 243                 return std_req_stall;
 244         if (wValue != USB_ENDPOINT_HALT)
 245                 return std_req_stall;
 246         if (ep_num == 0)
 247                 return std_req_complete;
 248 
 249         EPDBG(ep, "%s stall on EP 1\n",
 250               is_set ? "setting" : "clearing");
 251 
 252         ep->vhub->ep1_stalled = is_set;
 253         reg = readl(ep->vhub->regs + AST_VHUB_EP1_CTRL);
 254         if (is_set) {
 255                 reg |= VHUB_EP1_CTRL_STALL;
 256         } else {
 257                 reg &= ~VHUB_EP1_CTRL_STALL;
 258                 reg |= VHUB_EP1_CTRL_RESET_TOGGLE;
 259         }
 260         writel(reg, ep->vhub->regs + AST_VHUB_EP1_CTRL);
 261 
 262         return std_req_complete;
 263 }
 264 
 265 static int ast_vhub_rep_desc(struct ast_vhub_ep *ep,
 266                              u8 desc_type, u16 len)
 267 {
 268         size_t dsize;
 269 
 270         EPDBG(ep, "GET_DESCRIPTOR(type:%d)\n", desc_type);
 271 
 272         /*
 273          * Copy first to EP buffer and send from there, so
 274          * we can do some in-place patching if needed. We know
 275          * the EP buffer is big enough but ensure that doesn't
 276          * change. We do that now rather than later after we
 277          * have checked sizes etc... to avoid a gcc bug where
 278          * it thinks len is constant and barfs about read
 279          * overflows in memcpy.
 280          */
 281         switch(desc_type) {
 282         case USB_DT_DEVICE:
 283                 dsize = USB_DT_DEVICE_SIZE;
 284                 memcpy(ep->buf, &ast_vhub_dev_desc, dsize);
 285                 BUILD_BUG_ON(dsize > sizeof(ast_vhub_dev_desc));
 286                 BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET);
 287                 break;
 288         case USB_DT_CONFIG:
 289                 dsize = AST_VHUB_CONF_DESC_SIZE;
 290                 memcpy(ep->buf, &ast_vhub_conf_desc, dsize);
 291                 BUILD_BUG_ON(dsize > sizeof(ast_vhub_conf_desc));
 292                 BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET);
 293                 break;
 294         case USB_DT_HUB:
 295                 dsize = AST_VHUB_HUB_DESC_SIZE;
 296                 memcpy(ep->buf, &ast_vhub_hub_desc, dsize);
 297                 BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc));
 298                 BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET);
 299                 break;
 300         default:
 301                 return std_req_stall;
 302         }
 303 
 304         /* Crop requested length */
 305         if (len > dsize)
 306                 len = dsize;
 307 
 308         /* Patch it if forcing USB1 */
 309         if (desc_type == USB_DT_DEVICE && ep->vhub->force_usb1)
 310                 ast_vhub_patch_dev_desc_usb1(ep->buf);
 311 
 312         /* Shoot it from the EP buffer */
 313         return ast_vhub_reply(ep, NULL, len);
 314 }
 315 
 316 static int ast_vhub_rep_string(struct ast_vhub_ep *ep,
 317                                u8 string_id, u16 lang_id,
 318                                u16 len)
 319 {
 320         int rc = usb_gadget_get_string (&ast_vhub_strings, string_id, ep->buf);
 321 
 322         /*
 323          * This should never happen unless we put too big strings in
 324          * the array above
 325          */
 326         BUG_ON(rc >= AST_VHUB_EP0_MAX_PACKET);
 327 
 328         if (rc < 0)
 329                 return std_req_stall;
 330 
 331         /* Shoot it from the EP buffer */
 332         return ast_vhub_reply(ep, NULL, min_t(u16, rc, len));
 333 }
 334 
 335 enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep,
 336                                          struct usb_ctrlrequest *crq)
 337 {
 338         struct ast_vhub *vhub = ep->vhub;
 339         u16 wValue, wIndex, wLength;
 340 
 341         wValue = le16_to_cpu(crq->wValue);
 342         wIndex = le16_to_cpu(crq->wIndex);
 343         wLength = le16_to_cpu(crq->wLength);
 344 
 345         /* First packet, grab speed */
 346         if (vhub->speed == USB_SPEED_UNKNOWN) {
 347                 u32 ustat = readl(vhub->regs + AST_VHUB_USBSTS);
 348                 if (ustat & VHUB_USBSTS_HISPEED)
 349                         vhub->speed = USB_SPEED_HIGH;
 350                 else
 351                         vhub->speed = USB_SPEED_FULL;
 352                 UDCDBG(vhub, "USB status=%08x speed=%s\n", ustat,
 353                        vhub->speed == USB_SPEED_HIGH ? "high" : "full");
 354         }
 355 
 356         switch ((crq->bRequestType << 8) | crq->bRequest) {
 357                 /* SET_ADDRESS */
 358         case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 359                 EPDBG(ep, "SET_ADDRESS: Got address %x\n", wValue);
 360                 writel(wValue, vhub->regs + AST_VHUB_CONF);
 361                 return std_req_complete;
 362 
 363                 /* GET_STATUS */
 364         case DeviceRequest | USB_REQ_GET_STATUS:
 365                 return ast_vhub_hub_dev_status(ep, wIndex, wValue);
 366         case InterfaceRequest | USB_REQ_GET_STATUS:
 367                 return ast_vhub_simple_reply(ep, 0, 0);
 368         case EndpointRequest | USB_REQ_GET_STATUS:
 369                 return ast_vhub_hub_ep_status(ep, wIndex, wValue);
 370 
 371                 /* SET/CLEAR_FEATURE */
 372         case DeviceOutRequest | USB_REQ_SET_FEATURE:
 373                 return ast_vhub_hub_dev_feature(ep, wIndex, wValue, true);
 374         case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 375                 return ast_vhub_hub_dev_feature(ep, wIndex, wValue, false);
 376         case EndpointOutRequest | USB_REQ_SET_FEATURE:
 377                 return ast_vhub_hub_ep_feature(ep, wIndex, wValue, true);
 378         case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
 379                 return ast_vhub_hub_ep_feature(ep, wIndex, wValue, false);
 380 
 381                 /* GET/SET_CONFIGURATION */
 382         case DeviceRequest | USB_REQ_GET_CONFIGURATION:
 383                 return ast_vhub_simple_reply(ep, 1);
 384         case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
 385                 if (wValue != 1)
 386                         return std_req_stall;
 387                 return std_req_complete;
 388 
 389                 /* GET_DESCRIPTOR */
 390         case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
 391                 switch (wValue >> 8) {
 392                 case USB_DT_DEVICE:
 393                 case USB_DT_CONFIG:
 394                         return ast_vhub_rep_desc(ep, wValue >> 8,
 395                                                  wLength);
 396                 case USB_DT_STRING:
 397                         return ast_vhub_rep_string(ep, wValue & 0xff,
 398                                                    wIndex, wLength);
 399                 }
 400                 return std_req_stall;
 401 
 402                 /* GET/SET_INTERFACE */
 403         case DeviceRequest | USB_REQ_GET_INTERFACE:
 404                 return ast_vhub_simple_reply(ep, 0);
 405         case DeviceOutRequest | USB_REQ_SET_INTERFACE:
 406                 if (wValue != 0 || wIndex != 0)
 407                         return std_req_stall;
 408                 return std_req_complete;
 409         }
 410         return std_req_stall;
 411 }
 412 
 413 static void ast_vhub_update_hub_ep1(struct ast_vhub *vhub,
 414                                     unsigned int port)
 415 {
 416         /* Update HW EP1 response */
 417         u32 reg = readl(vhub->regs + AST_VHUB_EP1_STS_CHG);
 418         u32 pmask = (1 << (port + 1));
 419         if (vhub->ports[port].change)
 420                 reg |= pmask;
 421         else
 422                 reg &= ~pmask;
 423         writel(reg, vhub->regs + AST_VHUB_EP1_STS_CHG);
 424 }
 425 
 426 static void ast_vhub_change_port_stat(struct ast_vhub *vhub,
 427                                       unsigned int port,
 428                                       u16 clr_flags,
 429                                       u16 set_flags,
 430                                       bool set_c)
 431 {
 432         struct ast_vhub_port *p = &vhub->ports[port];
 433         u16 prev;
 434 
 435         /* Update port status */
 436         prev = p->status;
 437         p->status = (prev & ~clr_flags) | set_flags;
 438         DDBG(&p->dev, "port %d status %04x -> %04x (C=%d)\n",
 439              port + 1, prev, p->status, set_c);
 440 
 441         /* Update change bits if needed */
 442         if (set_c) {
 443                 u16 chg = p->status ^ prev;
 444 
 445                 /* Only these are relevant for change */
 446                 chg &= USB_PORT_STAT_C_CONNECTION |
 447                        USB_PORT_STAT_C_ENABLE |
 448                        USB_PORT_STAT_C_SUSPEND |
 449                        USB_PORT_STAT_C_OVERCURRENT |
 450                        USB_PORT_STAT_C_RESET |
 451                        USB_PORT_STAT_C_L1;
 452 
 453                 /*
 454                  * We only set USB_PORT_STAT_C_ENABLE if we are disabling
 455                  * the port as per USB spec, otherwise MacOS gets upset
 456                  */
 457                 if (p->status & USB_PORT_STAT_ENABLE)
 458                         chg &= ~USB_PORT_STAT_C_ENABLE;
 459 
 460                 p->change = chg;
 461                 ast_vhub_update_hub_ep1(vhub, port);
 462         }
 463 }
 464 
 465 static void ast_vhub_send_host_wakeup(struct ast_vhub *vhub)
 466 {
 467         u32 reg = readl(vhub->regs + AST_VHUB_CTRL);
 468         UDCDBG(vhub, "Waking up host !\n");
 469         reg |= VHUB_CTRL_MANUAL_REMOTE_WAKEUP;
 470         writel(reg, vhub->regs + AST_VHUB_CTRL);
 471 }
 472 
 473 void ast_vhub_device_connect(struct ast_vhub *vhub,
 474                              unsigned int port, bool on)
 475 {
 476         if (on)
 477                 ast_vhub_change_port_stat(vhub, port, 0,
 478                                           USB_PORT_STAT_CONNECTION, true);
 479         else
 480                 ast_vhub_change_port_stat(vhub, port,
 481                                           USB_PORT_STAT_CONNECTION |
 482                                           USB_PORT_STAT_ENABLE,
 483                                           0, true);
 484 
 485         /*
 486          * If the hub is set to wakup the host on connection events
 487          * then send a wakeup.
 488          */
 489         if (vhub->wakeup_en)
 490                 ast_vhub_send_host_wakeup(vhub);
 491 }
 492 
 493 static void ast_vhub_wake_work(struct work_struct *work)
 494 {
 495         struct ast_vhub *vhub = container_of(work,
 496                                              struct ast_vhub,
 497                                              wake_work);
 498         unsigned long flags;
 499         unsigned int i;
 500 
 501         /*
 502          * Wake all sleeping ports. If a port is suspended by
 503          * the host suspend (without explicit state suspend),
 504          * we let the normal host wake path deal with it later.
 505          */
 506         spin_lock_irqsave(&vhub->lock, flags);
 507         for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
 508                 struct ast_vhub_port *p = &vhub->ports[i];
 509 
 510                 if (!(p->status & USB_PORT_STAT_SUSPEND))
 511                         continue;
 512                 ast_vhub_change_port_stat(vhub, i,
 513                                           USB_PORT_STAT_SUSPEND,
 514                                           0, true);
 515                 ast_vhub_dev_resume(&p->dev);
 516         }
 517         ast_vhub_send_host_wakeup(vhub);
 518         spin_unlock_irqrestore(&vhub->lock, flags);
 519 }
 520 
 521 void ast_vhub_hub_wake_all(struct ast_vhub *vhub)
 522 {
 523         /*
 524          * A device is trying to wake the world, because this
 525          * can recurse into the device, we break the call chain
 526          * using a work queue
 527          */
 528         schedule_work(&vhub->wake_work);
 529 }
 530 
 531 static void ast_vhub_port_reset(struct ast_vhub *vhub, u8 port)
 532 {
 533         struct ast_vhub_port *p = &vhub->ports[port];
 534         u16 set, clr, speed;
 535 
 536         /* First mark disabled */
 537         ast_vhub_change_port_stat(vhub, port,
 538                                   USB_PORT_STAT_ENABLE |
 539                                   USB_PORT_STAT_SUSPEND,
 540                                   USB_PORT_STAT_RESET,
 541                                   false);
 542 
 543         if (!p->dev.driver)
 544                 return;
 545 
 546         /*
 547          * This will either "start" the port or reset the
 548          * device if already started...
 549          */
 550         ast_vhub_dev_reset(&p->dev);
 551 
 552         /* Grab the right speed */
 553         speed = p->dev.driver->max_speed;
 554         if (speed == USB_SPEED_UNKNOWN || speed > vhub->speed)
 555                 speed = vhub->speed;
 556 
 557         switch (speed) {
 558         case USB_SPEED_LOW:
 559                 set = USB_PORT_STAT_LOW_SPEED;
 560                 clr = USB_PORT_STAT_HIGH_SPEED;
 561                 break;
 562         case USB_SPEED_FULL:
 563                 set = 0;
 564                 clr = USB_PORT_STAT_LOW_SPEED |
 565                         USB_PORT_STAT_HIGH_SPEED;
 566                 break;
 567         case USB_SPEED_HIGH:
 568                 set = USB_PORT_STAT_HIGH_SPEED;
 569                 clr = USB_PORT_STAT_LOW_SPEED;
 570                 break;
 571         default:
 572                 UDCDBG(vhub, "Unsupported speed %d when"
 573                        " connecting device\n",
 574                        speed);
 575                 return;
 576         }
 577         clr |= USB_PORT_STAT_RESET;
 578         set |= USB_PORT_STAT_ENABLE;
 579 
 580         /* This should ideally be delayed ... */
 581         ast_vhub_change_port_stat(vhub, port, clr, set, true);
 582 }
 583 
 584 static enum std_req_rc ast_vhub_set_port_feature(struct ast_vhub_ep *ep,
 585                                                  u8 port, u16 feat)
 586 {
 587         struct ast_vhub *vhub = ep->vhub;
 588         struct ast_vhub_port *p;
 589 
 590         if (port == 0 || port > AST_VHUB_NUM_PORTS)
 591                 return std_req_stall;
 592         port--;
 593         p = &vhub->ports[port];
 594 
 595         switch(feat) {
 596         case USB_PORT_FEAT_SUSPEND:
 597                 if (!(p->status & USB_PORT_STAT_ENABLE))
 598                         return std_req_complete;
 599                 ast_vhub_change_port_stat(vhub, port,
 600                                           0, USB_PORT_STAT_SUSPEND,
 601                                           false);
 602                 ast_vhub_dev_suspend(&p->dev);
 603                 return std_req_complete;
 604         case USB_PORT_FEAT_RESET:
 605                 EPDBG(ep, "Port reset !\n");
 606                 ast_vhub_port_reset(vhub, port);
 607                 return std_req_complete;
 608         case USB_PORT_FEAT_POWER:
 609                 /*
 610                  * On Power-on, we mark the connected flag changed,
 611                  * if there's a connected device, some hosts will
 612                  * otherwise fail to detect it.
 613                  */
 614                 if (p->status & USB_PORT_STAT_CONNECTION) {
 615                         p->change |= USB_PORT_STAT_C_CONNECTION;
 616                         ast_vhub_update_hub_ep1(vhub, port);
 617                 }
 618                 return std_req_complete;
 619         case USB_PORT_FEAT_TEST:
 620         case USB_PORT_FEAT_INDICATOR:
 621                 /* We don't do anything with these */
 622                 return std_req_complete;
 623         }
 624         return std_req_stall;
 625 }
 626 
 627 static enum std_req_rc ast_vhub_clr_port_feature(struct ast_vhub_ep *ep,
 628                                                  u8 port, u16 feat)
 629 {
 630         struct ast_vhub *vhub = ep->vhub;
 631         struct ast_vhub_port *p;
 632 
 633         if (port == 0 || port > AST_VHUB_NUM_PORTS)
 634                 return std_req_stall;
 635         port--;
 636         p = &vhub->ports[port];
 637 
 638         switch(feat) {
 639         case USB_PORT_FEAT_ENABLE:
 640                 ast_vhub_change_port_stat(vhub, port,
 641                                           USB_PORT_STAT_ENABLE |
 642                                           USB_PORT_STAT_SUSPEND, 0,
 643                                           false);
 644                 ast_vhub_dev_suspend(&p->dev);
 645                 return std_req_complete;
 646         case USB_PORT_FEAT_SUSPEND:
 647                 if (!(p->status & USB_PORT_STAT_SUSPEND))
 648                         return std_req_complete;
 649                 ast_vhub_change_port_stat(vhub, port,
 650                                           USB_PORT_STAT_SUSPEND, 0,
 651                                           false);
 652                 ast_vhub_dev_resume(&p->dev);
 653                 return std_req_complete;
 654         case USB_PORT_FEAT_POWER:
 655                 /* We don't do power control */
 656                 return std_req_complete;
 657         case USB_PORT_FEAT_INDICATOR:
 658                 /* We don't have indicators */
 659                 return std_req_complete;
 660         case USB_PORT_FEAT_C_CONNECTION:
 661         case USB_PORT_FEAT_C_ENABLE:
 662         case USB_PORT_FEAT_C_SUSPEND:
 663         case USB_PORT_FEAT_C_OVER_CURRENT:
 664         case USB_PORT_FEAT_C_RESET:
 665                 /* Clear state-change feature */
 666                 p->change &= ~(1u << (feat - 16));
 667                 ast_vhub_update_hub_ep1(vhub, port);
 668                 return std_req_complete;
 669         }
 670         return std_req_stall;
 671 }
 672 
 673 static enum std_req_rc ast_vhub_get_port_stat(struct ast_vhub_ep *ep,
 674                                               u8 port)
 675 {
 676         struct ast_vhub *vhub = ep->vhub;
 677         u16 stat, chg;
 678 
 679         if (port == 0 || port > AST_VHUB_NUM_PORTS)
 680                 return std_req_stall;
 681         port--;
 682 
 683         stat = vhub->ports[port].status;
 684         chg = vhub->ports[port].change;
 685 
 686         /* We always have power */
 687         stat |= USB_PORT_STAT_POWER;
 688 
 689         EPDBG(ep, " port status=%04x change=%04x\n", stat, chg);
 690 
 691         return ast_vhub_simple_reply(ep,
 692                                      stat & 0xff,
 693                                      stat >> 8,
 694                                      chg & 0xff,
 695                                      chg >> 8);
 696 }
 697 
 698 enum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep,
 699                                            struct usb_ctrlrequest *crq)
 700 {
 701         u16 wValue, wIndex, wLength;
 702 
 703         wValue = le16_to_cpu(crq->wValue);
 704         wIndex = le16_to_cpu(crq->wIndex);
 705         wLength = le16_to_cpu(crq->wLength);
 706 
 707         switch ((crq->bRequestType << 8) | crq->bRequest) {
 708         case GetHubStatus:
 709                 EPDBG(ep, "GetHubStatus\n");
 710                 return ast_vhub_simple_reply(ep, 0, 0, 0, 0);
 711         case GetPortStatus:
 712                 EPDBG(ep, "GetPortStatus(%d)\n", wIndex & 0xff);
 713                 return ast_vhub_get_port_stat(ep, wIndex & 0xf);
 714         case GetHubDescriptor:
 715                 if (wValue != (USB_DT_HUB << 8))
 716                         return std_req_stall;
 717                 EPDBG(ep, "GetHubDescriptor(%d)\n", wIndex & 0xff);
 718                 return ast_vhub_rep_desc(ep, USB_DT_HUB, wLength);
 719         case SetHubFeature:
 720         case ClearHubFeature:
 721                 EPDBG(ep, "Get/SetHubFeature(%d)\n", wValue);
 722                 /* No feature, just complete the requests */
 723                 if (wValue == C_HUB_LOCAL_POWER ||
 724                     wValue == C_HUB_OVER_CURRENT)
 725                         return std_req_complete;
 726                 return std_req_stall;
 727         case SetPortFeature:
 728                 EPDBG(ep, "SetPortFeature(%d,%d)\n", wIndex & 0xf, wValue);
 729                 return ast_vhub_set_port_feature(ep, wIndex & 0xf, wValue);
 730         case ClearPortFeature:
 731                 EPDBG(ep, "ClearPortFeature(%d,%d)\n", wIndex & 0xf, wValue);
 732                 return ast_vhub_clr_port_feature(ep, wIndex & 0xf, wValue);
 733         case ClearTTBuffer:
 734         case ResetTT:
 735         case StopTT:
 736                 return std_req_complete;
 737         case GetTTState:
 738                 return ast_vhub_simple_reply(ep, 0, 0, 0, 0);
 739         default:
 740                 EPDBG(ep, "Unknown class request\n");
 741         }
 742         return std_req_stall;
 743 }
 744 
 745 void ast_vhub_hub_suspend(struct ast_vhub *vhub)
 746 {
 747         unsigned int i;
 748 
 749         UDCDBG(vhub, "USB bus suspend\n");
 750 
 751         if (vhub->suspended)
 752                 return;
 753 
 754         vhub->suspended = true;
 755 
 756         /*
 757          * Forward to unsuspended ports without changing
 758          * their connection status.
 759          */
 760         for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
 761                 struct ast_vhub_port *p = &vhub->ports[i];
 762 
 763                 if (!(p->status & USB_PORT_STAT_SUSPEND))
 764                         ast_vhub_dev_suspend(&p->dev);
 765         }
 766 }
 767 
 768 void ast_vhub_hub_resume(struct ast_vhub *vhub)
 769 {
 770         unsigned int i;
 771 
 772         UDCDBG(vhub, "USB bus resume\n");
 773 
 774         if (!vhub->suspended)
 775                 return;
 776 
 777         vhub->suspended = false;
 778 
 779         /*
 780          * Forward to unsuspended ports without changing
 781          * their connection status.
 782          */
 783         for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
 784                 struct ast_vhub_port *p = &vhub->ports[i];
 785 
 786                 if (!(p->status & USB_PORT_STAT_SUSPEND))
 787                         ast_vhub_dev_resume(&p->dev);
 788         }
 789 }
 790 
 791 void ast_vhub_hub_reset(struct ast_vhub *vhub)
 792 {
 793         unsigned int i;
 794 
 795         UDCDBG(vhub, "USB bus reset\n");
 796 
 797         /*
 798          * Is the speed known ? If not we don't care, we aren't
 799          * initialized yet and ports haven't been enabled.
 800          */
 801         if (vhub->speed == USB_SPEED_UNKNOWN)
 802                 return;
 803 
 804         /* We aren't suspended anymore obviously */
 805         vhub->suspended = false;
 806 
 807         /* No speed set */
 808         vhub->speed = USB_SPEED_UNKNOWN;
 809 
 810         /* Wakeup not enabled anymore */
 811         vhub->wakeup_en = false;
 812 
 813         /*
 814          * Clear all port status, disable gadgets and "suspend"
 815          * them. They will be woken up by a port reset.
 816          */
 817         for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
 818                 struct ast_vhub_port *p = &vhub->ports[i];
 819 
 820                 /* Only keep the connected flag */
 821                 p->status &= USB_PORT_STAT_CONNECTION;
 822                 p->change = 0;
 823 
 824                 /* Suspend the gadget if any */
 825                 ast_vhub_dev_suspend(&p->dev);
 826         }
 827 
 828         /* Cleanup HW */
 829         writel(0, vhub->regs + AST_VHUB_CONF);
 830         writel(0, vhub->regs + AST_VHUB_EP0_CTRL);
 831         writel(VHUB_EP1_CTRL_RESET_TOGGLE |
 832                VHUB_EP1_CTRL_ENABLE,
 833                vhub->regs + AST_VHUB_EP1_CTRL);
 834         writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG);
 835 }
 836 
 837 void ast_vhub_init_hub(struct ast_vhub *vhub)
 838 {
 839         vhub->speed = USB_SPEED_UNKNOWN;
 840         INIT_WORK(&vhub->wake_work, ast_vhub_wake_work);
 841 }
 842 

/* [<][>][^][v][top][bottom][index][help] */