sandbox_hub.c 7.9 KB

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