1 /* 2 * (C) Copyright 2015 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <usb.h> 11 #include <dm/device-internal.h> 12 13 DECLARE_GLOBAL_DATA_PTR; 14 15 /* We only support up to 8 */ 16 #define SANDBOX_NUM_PORTS 4 17 18 struct sandbox_hub_platdata { 19 struct usb_dev_platdata plat; 20 int port; /* Port number (numbered from 0) */ 21 }; 22 23 enum { 24 STRING_MANUFACTURER = 1, 25 STRING_PRODUCT, 26 STRING_SERIAL, 27 28 STRING_count, 29 }; 30 31 static struct usb_string hub_strings[] = { 32 {STRING_MANUFACTURER, "sandbox"}, 33 {STRING_PRODUCT, "hub"}, 34 {STRING_SERIAL, "2345"}, 35 {}, 36 }; 37 38 static struct usb_device_descriptor hub_device_desc = { 39 .bLength = sizeof(hub_device_desc), 40 .bDescriptorType = USB_DT_DEVICE, 41 42 .bcdUSB = __constant_cpu_to_le16(0x0200), 43 44 .bDeviceClass = USB_CLASS_HUB, 45 .bDeviceSubClass = 0, 46 .bDeviceProtocol = 0, 47 48 .idVendor = __constant_cpu_to_le16(0x1234), 49 .idProduct = __constant_cpu_to_le16(0x5678), 50 .iManufacturer = STRING_MANUFACTURER, 51 .iProduct = STRING_PRODUCT, 52 .iSerialNumber = STRING_SERIAL, 53 .bNumConfigurations = 1, 54 }; 55 56 static struct usb_config_descriptor hub_config1 = { 57 .bLength = sizeof(hub_config1), 58 .bDescriptorType = USB_DT_CONFIG, 59 60 /* wTotalLength is set up by usb-emul-uclass */ 61 .bNumInterfaces = 1, 62 .bConfigurationValue = 0, 63 .iConfiguration = 0, 64 .bmAttributes = 1 << 7, 65 .bMaxPower = 50, 66 }; 67 68 static struct usb_interface_descriptor hub_interface0 = { 69 .bLength = sizeof(hub_interface0), 70 .bDescriptorType = USB_DT_INTERFACE, 71 72 .bInterfaceNumber = 0, 73 .bAlternateSetting = 0, 74 .bNumEndpoints = 1, 75 .bInterfaceClass = USB_CLASS_HUB, 76 .bInterfaceSubClass = 0, 77 .bInterfaceProtocol = US_PR_CB, 78 .iInterface = 0, 79 }; 80 81 static struct usb_endpoint_descriptor hub_endpoint0_in = { 82 .bLength = USB_DT_ENDPOINT_SIZE, 83 .bDescriptorType = USB_DT_ENDPOINT, 84 85 .bEndpointAddress = 1 | USB_DIR_IN, 86 .bmAttributes = USB_ENDPOINT_XFER_INT, 87 .wMaxPacketSize = __constant_cpu_to_le16(1024), 88 .bInterval = 0, 89 }; 90 91 static struct usb_hub_descriptor hub_desc = { 92 .bLength = sizeof(hub_desc), 93 .bDescriptorType = USB_DT_HUB, 94 .bNbrPorts = SANDBOX_NUM_PORTS, 95 .wHubCharacteristics = __constant_cpu_to_le16(1 << 0 | 1 << 3 | 96 1 << 7), 97 .bPwrOn2PwrGood = 2, 98 .bHubContrCurrent = 5, 99 { 100 { 101 /* all ports removeable */ 102 .DeviceRemovable = {0, 0xff} 103 } 104 } 105 #if SANDBOX_NUM_PORTS > 8 106 #error "This code sets up an incorrect mask" 107 #endif 108 }; 109 110 static void *hub_desc_list[] = { 111 &hub_device_desc, 112 &hub_config1, 113 &hub_interface0, 114 &hub_endpoint0_in, 115 &hub_desc, 116 NULL, 117 }; 118 119 struct sandbox_hub_priv { 120 int status[SANDBOX_NUM_PORTS]; 121 int change[SANDBOX_NUM_PORTS]; 122 }; 123 124 static struct udevice *hub_find_device(struct udevice *hub, int port, 125 enum usb_device_speed *speed) 126 { 127 struct udevice *dev; 128 struct usb_generic_descriptor **gen_desc; 129 struct usb_device_descriptor **dev_desc; 130 131 for (device_find_first_child(hub, &dev); 132 dev; 133 device_find_next_child(&dev)) { 134 struct sandbox_hub_platdata *plat; 135 136 plat = dev_get_parent_platdata(dev); 137 if (plat->port == port) { 138 gen_desc = plat->plat.desc_list; 139 gen_desc = usb_emul_find_descriptor(gen_desc, 140 USB_DT_DEVICE, 0); 141 dev_desc = (struct usb_device_descriptor **)gen_desc; 142 143 switch (le16_to_cpu((*dev_desc)->bcdUSB)) { 144 case 0x0100: 145 *speed = USB_SPEED_LOW; 146 break; 147 case 0x0101: 148 *speed = USB_SPEED_FULL; 149 break; 150 case 0x0200: 151 default: 152 *speed = USB_SPEED_HIGH; 153 break; 154 } 155 156 return dev; 157 } 158 } 159 160 return NULL; 161 } 162 163 static int clrset_post_state(struct udevice *hub, int port, int clear, int set) 164 { 165 struct sandbox_hub_priv *priv = dev_get_priv(hub); 166 int *status = &priv->status[port]; 167 int *change = &priv->change[port]; 168 int ret = 0; 169 170 if ((clear | set) & USB_PORT_STAT_POWER) { 171 enum usb_device_speed speed; 172 struct udevice *dev = hub_find_device(hub, port, &speed); 173 174 if (dev) { 175 if (set & USB_PORT_STAT_POWER) { 176 ret = device_probe(dev); 177 debug("%s: %s: power on, probed, ret=%d\n", 178 __func__, dev->name, ret); 179 if (!ret) { 180 set |= USB_PORT_STAT_CONNECTION | 181 USB_PORT_STAT_ENABLE; 182 if (speed == USB_SPEED_LOW) 183 set |= USB_PORT_STAT_LOW_SPEED; 184 else if (speed == USB_SPEED_HIGH) 185 set |= USB_PORT_STAT_HIGH_SPEED; 186 } 187 188 } else if (clear & USB_PORT_STAT_POWER) { 189 debug("%s: %s: power off, removed, ret=%d\n", 190 __func__, dev->name, ret); 191 ret = device_remove(dev, DM_REMOVE_NORMAL); 192 clear |= USB_PORT_STAT_CONNECTION; 193 } 194 } 195 } 196 *change |= *status & clear; 197 *change |= ~*status & set; 198 *change &= 0x1f; 199 *status = (*status & ~clear) | set; 200 201 return ret; 202 } 203 204 static int sandbox_hub_submit_control_msg(struct udevice *bus, 205 struct usb_device *udev, 206 unsigned long pipe, 207 void *buffer, int length, 208 struct devrequest *setup) 209 { 210 struct sandbox_hub_priv *priv = dev_get_priv(bus); 211 int ret = 0; 212 213 if (pipe == usb_rcvctrlpipe(udev, 0)) { 214 switch (setup->requesttype) { 215 case USB_RT_HUB | USB_DIR_IN: 216 switch (setup->request) { 217 case USB_REQ_GET_STATUS: { 218 struct usb_hub_status *hubsts = buffer; 219 220 hubsts->wHubStatus = 0; 221 hubsts->wHubChange = 0; 222 udev->status = 0; 223 udev->act_len = sizeof(*hubsts); 224 return 0; 225 } 226 default: 227 debug("%s: rx ctl requesttype=%x, request=%x\n", 228 __func__, setup->requesttype, 229 setup->request); 230 break; 231 } 232 case USB_RT_PORT | USB_DIR_IN: 233 switch (setup->request) { 234 case USB_REQ_GET_STATUS: { 235 struct usb_port_status *portsts = buffer; 236 int port; 237 238 port = (setup->index & USB_HUB_PORT_MASK) - 1; 239 portsts->wPortStatus = priv->status[port]; 240 portsts->wPortChange = priv->change[port]; 241 udev->status = 0; 242 udev->act_len = sizeof(*portsts); 243 return 0; 244 } 245 } 246 default: 247 debug("%s: rx ctl requesttype=%x, request=%x\n", 248 __func__, setup->requesttype, setup->request); 249 break; 250 } 251 } else if (pipe == usb_sndctrlpipe(udev, 0)) { 252 switch (setup->requesttype) { 253 case USB_RT_PORT: 254 switch (setup->request) { 255 case USB_REQ_SET_FEATURE: { 256 int port; 257 258 port = (setup->index & USB_HUB_PORT_MASK) - 1; 259 debug("set feature port=%x, feature=%x\n", 260 port, setup->value); 261 if (setup->value < USB_PORT_FEAT_C_CONNECTION) { 262 ret = clrset_post_state(bus, port, 0, 263 1 << setup->value); 264 } else { 265 debug(" ** Invalid feature\n"); 266 } 267 return ret; 268 } 269 case USB_REQ_CLEAR_FEATURE: { 270 int port; 271 272 port = (setup->index & USB_HUB_PORT_MASK) - 1; 273 debug("clear feature port=%x, feature=%x\n", 274 port, setup->value); 275 if (setup->value < USB_PORT_FEAT_C_CONNECTION) { 276 ret = clrset_post_state(bus, port, 277 1 << setup->value, 0); 278 } else { 279 priv->change[port] &= 1 << 280 (setup->value - 16); 281 } 282 udev->status = 0; 283 return 0; 284 } 285 default: 286 debug("%s: tx ctl requesttype=%x, request=%x\n", 287 __func__, setup->requesttype, 288 setup->request); 289 break; 290 } 291 default: 292 debug("%s: tx ctl requesttype=%x, request=%x\n", 293 __func__, setup->requesttype, setup->request); 294 break; 295 } 296 } 297 debug("pipe=%lx\n", pipe); 298 299 return -EIO; 300 } 301 302 static int sandbox_hub_bind(struct udevice *dev) 303 { 304 return usb_emul_setup_device(dev, hub_strings, hub_desc_list); 305 } 306 307 static int sandbox_child_post_bind(struct udevice *dev) 308 { 309 struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev); 310 struct usb_emul_platdata *emul = dev_get_uclass_platdata(dev); 311 312 plat->port = dev_read_u32_default(dev, "reg", -1); 313 emul->port1 = plat->port + 1; 314 315 return 0; 316 } 317 318 static const struct dm_usb_ops sandbox_usb_hub_ops = { 319 .control = sandbox_hub_submit_control_msg, 320 }; 321 322 static const struct udevice_id sandbox_usb_hub_ids[] = { 323 { .compatible = "sandbox,usb-hub" }, 324 { } 325 }; 326 327 U_BOOT_DRIVER(usb_sandbox_hub) = { 328 .name = "usb_sandbox_hub", 329 .id = UCLASS_USB_EMUL, 330 .of_match = sandbox_usb_hub_ids, 331 .bind = sandbox_hub_bind, 332 .ops = &sandbox_usb_hub_ops, 333 .priv_auto_alloc_size = sizeof(struct sandbox_hub_priv), 334 .per_child_platdata_auto_alloc_size = 335 sizeof(struct sandbox_hub_platdata), 336 .child_post_bind = sandbox_child_post_bind, 337 }; 338