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