2 * (C) Copyright 2015 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
5 * SPDX-License-Identifier: GPL-2.0+
11 #include <dm/device-internal.h>
13 DECLARE_GLOBAL_DATA_PTR
;
15 /* We only support up to 8 */
16 #define SANDBOX_NUM_PORTS 2
18 struct sandbox_hub_platdata
{
19 struct usb_dev_platdata plat
;
20 int port
; /* Port number (numbered from 0) */
24 STRING_MANUFACTURER
= 1,
31 static struct usb_string hub_strings
[] = {
32 {STRING_MANUFACTURER
, "sandbox"},
33 {STRING_PRODUCT
, "hub"},
34 {STRING_SERIAL
, "2345"},
37 static struct usb_device_descriptor hub_device_desc
= {
38 .bLength
= sizeof(hub_device_desc
),
39 .bDescriptorType
= USB_DT_DEVICE
,
41 .bcdUSB
= __constant_cpu_to_le16(0x0200),
43 .bDeviceClass
= USB_CLASS_HUB
,
47 .idVendor
= __constant_cpu_to_le16(0x1234),
48 .idProduct
= __constant_cpu_to_le16(0x5678),
49 .iManufacturer
= STRING_MANUFACTURER
,
50 .iProduct
= STRING_PRODUCT
,
51 .iSerialNumber
= STRING_SERIAL
,
52 .bNumConfigurations
= 1,
55 static struct usb_config_descriptor hub_config1
= {
56 .bLength
= sizeof(hub_config1
),
57 .bDescriptorType
= USB_DT_CONFIG
,
59 /* wTotalLength is set up by usb-emul-uclass */
61 .bConfigurationValue
= 0,
63 .bmAttributes
= 1 << 7,
67 static struct usb_interface_descriptor hub_interface0
= {
68 .bLength
= sizeof(hub_interface0
),
69 .bDescriptorType
= USB_DT_INTERFACE
,
71 .bInterfaceNumber
= 0,
72 .bAlternateSetting
= 0,
74 .bInterfaceClass
= USB_CLASS_HUB
,
75 .bInterfaceSubClass
= 0,
76 .bInterfaceProtocol
= US_PR_CB
,
80 static struct usb_endpoint_descriptor hub_endpoint0_in
= {
81 .bLength
= USB_DT_ENDPOINT_SIZE
,
82 .bDescriptorType
= USB_DT_ENDPOINT
,
84 .bEndpointAddress
= 1 | USB_DIR_IN
,
85 .bmAttributes
= USB_ENDPOINT_XFER_INT
,
86 .wMaxPacketSize
= __constant_cpu_to_le16(1024),
90 static struct usb_hub_descriptor hub_desc
= {
91 .bLength
= sizeof(hub_desc
),
92 .bDescriptorType
= USB_DT_HUB
,
93 .bNbrPorts
= SANDBOX_NUM_PORTS
,
94 .wHubCharacteristics
= __constant_cpu_to_le16(1 << 0 | 1 << 3 |
97 .bHubContrCurrent
= 5,
98 .DeviceRemovable
= {0, 0xff}, /* all ports removeable */
99 #if SANDBOX_NUM_PORTS > 8
100 #error "This code sets up an incorrect mask"
104 static void *hub_desc_list
[] = {
113 struct sandbox_hub_priv
{
114 int status
[SANDBOX_NUM_PORTS
];
115 int change
[SANDBOX_NUM_PORTS
];
118 static struct udevice
*hub_find_device(struct udevice
*hub
, int port
)
122 for (device_find_first_child(hub
, &dev
);
124 device_find_next_child(&dev
)) {
125 struct sandbox_hub_platdata
*plat
;
127 plat
= dev_get_parent_platdata(dev
);
128 if (plat
->port
== port
)
135 static int clrset_post_state(struct udevice
*hub
, int port
, int clear
, int set
)
137 struct sandbox_hub_priv
*priv
= dev_get_priv(hub
);
138 int *status
= &priv
->status
[port
];
139 int *change
= &priv
->change
[port
];
142 if ((clear
| set
) & USB_PORT_STAT_POWER
) {
143 struct udevice
*dev
= hub_find_device(hub
, port
);
146 if (set
& USB_PORT_STAT_POWER
) {
147 ret
= device_probe(dev
);
148 debug("%s: %s: power on, probed, ret=%d\n",
149 __func__
, dev
->name
, ret
);
151 set
|= USB_PORT_STAT_CONNECTION
|
152 USB_PORT_STAT_ENABLE
;
155 } else if (clear
& USB_PORT_STAT_POWER
) {
156 debug("%s: %s: power off, removed, ret=%d\n",
157 __func__
, dev
->name
, ret
);
158 ret
= device_remove(dev
);
159 clear
|= USB_PORT_STAT_CONNECTION
;
163 *change
|= *status
& clear
;
164 *change
|= ~*status
& set
;
166 *status
= (*status
& ~clear
) | set
;
171 static int sandbox_hub_submit_control_msg(struct udevice
*bus
,
172 struct usb_device
*udev
,
174 void *buffer
, int length
,
175 struct devrequest
*setup
)
177 struct sandbox_hub_priv
*priv
= dev_get_priv(bus
);
180 if (pipe
== usb_rcvctrlpipe(udev
, 0)) {
181 switch (setup
->requesttype
) {
182 case USB_RT_HUB
| USB_DIR_IN
:
183 switch (setup
->request
) {
184 case USB_REQ_GET_STATUS
: {
185 struct usb_hub_status
*hubsts
= buffer
;
187 hubsts
->wHubStatus
= 0;
188 hubsts
->wHubChange
= 0;
190 udev
->act_len
= sizeof(*hubsts
);
194 debug("%s: rx ctl requesttype=%x, request=%x\n",
195 __func__
, setup
->requesttype
,
199 case USB_RT_PORT
| USB_DIR_IN
:
200 switch (setup
->request
) {
201 case USB_REQ_GET_STATUS
: {
202 struct usb_port_status
*portsts
= buffer
;
205 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
206 portsts
->wPortStatus
= priv
->status
[port
];
207 portsts
->wPortChange
= priv
->change
[port
];
209 udev
->act_len
= sizeof(*portsts
);
214 debug("%s: rx ctl requesttype=%x, request=%x\n",
215 __func__
, setup
->requesttype
, setup
->request
);
218 } else if (pipe
== usb_sndctrlpipe(udev
, 0)) {
219 switch (setup
->requesttype
) {
221 switch (setup
->request
) {
222 case USB_REQ_SET_FEATURE
: {
225 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
226 debug("set feature port=%x, feature=%x\n",
228 if (setup
->value
< USB_PORT_FEAT_C_CONNECTION
) {
229 ret
= clrset_post_state(bus
, port
, 0,
232 debug(" ** Invalid feature\n");
236 case USB_REQ_CLEAR_FEATURE
: {
239 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
240 debug("clear feature port=%x, feature=%x\n",
242 if (setup
->value
< USB_PORT_FEAT_C_CONNECTION
) {
243 ret
= clrset_post_state(bus
, port
,
244 1 << setup
->value
, 0);
246 priv
->change
[port
] &= 1 <<
253 debug("%s: tx ctl requesttype=%x, request=%x\n",
254 __func__
, setup
->requesttype
,
259 debug("%s: tx ctl requesttype=%x, request=%x\n",
260 __func__
, setup
->requesttype
, setup
->request
);
264 debug("pipe=%lx\n", pipe
);
269 static int sandbox_hub_bind(struct udevice
*dev
)
271 return usb_emul_setup_device(dev
, PACKET_SIZE_64
, hub_strings
,
275 static int sandbox_child_post_bind(struct udevice
*dev
)
277 struct sandbox_hub_platdata
*plat
= dev_get_parent_platdata(dev
);
279 plat
->port
= fdtdec_get_int(gd
->fdt_blob
, dev
->of_offset
, "reg", -1);
284 static const struct dm_usb_ops sandbox_usb_hub_ops
= {
285 .control
= sandbox_hub_submit_control_msg
,
288 static const struct udevice_id sandbox_usb_hub_ids
[] = {
289 { .compatible
= "sandbox,usb-hub" },
293 U_BOOT_DRIVER(usb_sandbox_hub
) = {
294 .name
= "usb_sandbox_hub",
295 .id
= UCLASS_USB_EMUL
,
296 .of_match
= sandbox_usb_hub_ids
,
297 .bind
= sandbox_hub_bind
,
298 .ops
= &sandbox_usb_hub_ops
,
299 .priv_auto_alloc_size
= sizeof(struct sandbox_hub_priv
),
300 .per_child_platdata_auto_alloc_size
=
301 sizeof(struct sandbox_hub_platdata
),
302 .child_post_bind
= sandbox_child_post_bind
,