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