3e66ca46988dec536e597c4d5275555b08488e55
[platform/kernel/u-boot.git] / drivers / usb / emul / sandbox_hub.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <log.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      = sizeof(struct sandbox_hub_priv),
332         .per_child_platdata_auto        =
333                         sizeof(struct sandbox_hub_platdata),
334         .child_post_bind = sandbox_child_post_bind,
335 };