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 4
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"},
38 static struct usb_device_descriptor hub_device_desc
= {
39 .bLength
= sizeof(hub_device_desc
),
40 .bDescriptorType
= USB_DT_DEVICE
,
42 .bcdUSB
= __constant_cpu_to_le16(0x0200),
44 .bDeviceClass
= USB_CLASS_HUB
,
48 .idVendor
= __constant_cpu_to_le16(0x1234),
49 .idProduct
= __constant_cpu_to_le16(0x5678),
50 .iManufacturer
= STRING_MANUFACTURER
,
51 .iProduct
= STRING_PRODUCT
,
52 .iSerialNumber
= STRING_SERIAL
,
53 .bNumConfigurations
= 1,
56 static struct usb_config_descriptor hub_config1
= {
57 .bLength
= sizeof(hub_config1
),
58 .bDescriptorType
= USB_DT_CONFIG
,
60 /* wTotalLength is set up by usb-emul-uclass */
62 .bConfigurationValue
= 0,
64 .bmAttributes
= 1 << 7,
68 static struct usb_interface_descriptor hub_interface0
= {
69 .bLength
= sizeof(hub_interface0
),
70 .bDescriptorType
= USB_DT_INTERFACE
,
72 .bInterfaceNumber
= 0,
73 .bAlternateSetting
= 0,
75 .bInterfaceClass
= USB_CLASS_HUB
,
76 .bInterfaceSubClass
= 0,
77 .bInterfaceProtocol
= US_PR_CB
,
81 static struct usb_endpoint_descriptor hub_endpoint0_in
= {
82 .bLength
= USB_DT_ENDPOINT_SIZE
,
83 .bDescriptorType
= USB_DT_ENDPOINT
,
85 .bEndpointAddress
= 1 | USB_DIR_IN
,
86 .bmAttributes
= USB_ENDPOINT_XFER_INT
,
87 .wMaxPacketSize
= __constant_cpu_to_le16(1024),
91 static struct usb_hub_descriptor hub_desc
= {
92 .bLength
= sizeof(hub_desc
),
93 .bDescriptorType
= USB_DT_HUB
,
94 .bNbrPorts
= SANDBOX_NUM_PORTS
,
95 .wHubCharacteristics
= __constant_cpu_to_le16(1 << 0 | 1 << 3 |
98 .bHubContrCurrent
= 5,
99 .DeviceRemovable
= {0, 0xff}, /* all ports removeable */
100 #if SANDBOX_NUM_PORTS > 8
101 #error "This code sets up an incorrect mask"
105 static void *hub_desc_list
[] = {
114 struct sandbox_hub_priv
{
115 int status
[SANDBOX_NUM_PORTS
];
116 int change
[SANDBOX_NUM_PORTS
];
119 static struct udevice
*hub_find_device(struct udevice
*hub
, int port
)
123 for (device_find_first_child(hub
, &dev
);
125 device_find_next_child(&dev
)) {
126 struct sandbox_hub_platdata
*plat
;
128 plat
= dev_get_parent_platdata(dev
);
129 if (plat
->port
== port
)
136 static int clrset_post_state(struct udevice
*hub
, int port
, int clear
, int set
)
138 struct sandbox_hub_priv
*priv
= dev_get_priv(hub
);
139 int *status
= &priv
->status
[port
];
140 int *change
= &priv
->change
[port
];
143 if ((clear
| set
) & USB_PORT_STAT_POWER
) {
144 struct udevice
*dev
= hub_find_device(hub
, port
);
147 if (set
& USB_PORT_STAT_POWER
) {
148 ret
= device_probe(dev
);
149 debug("%s: %s: power on, probed, ret=%d\n",
150 __func__
, dev
->name
, ret
);
152 set
|= USB_PORT_STAT_CONNECTION
|
153 USB_PORT_STAT_ENABLE
;
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
;
164 *change
|= *status
& clear
;
165 *change
|= ~*status
& set
;
167 *status
= (*status
& ~clear
) | set
;
172 static int sandbox_hub_submit_control_msg(struct udevice
*bus
,
173 struct usb_device
*udev
,
175 void *buffer
, int length
,
176 struct devrequest
*setup
)
178 struct sandbox_hub_priv
*priv
= dev_get_priv(bus
);
181 if (pipe
== usb_rcvctrlpipe(udev
, 0)) {
182 switch (setup
->requesttype
) {
183 case USB_RT_HUB
| USB_DIR_IN
:
184 switch (setup
->request
) {
185 case USB_REQ_GET_STATUS
: {
186 struct usb_hub_status
*hubsts
= buffer
;
188 hubsts
->wHubStatus
= 0;
189 hubsts
->wHubChange
= 0;
191 udev
->act_len
= sizeof(*hubsts
);
195 debug("%s: rx ctl requesttype=%x, request=%x\n",
196 __func__
, setup
->requesttype
,
200 case USB_RT_PORT
| USB_DIR_IN
:
201 switch (setup
->request
) {
202 case USB_REQ_GET_STATUS
: {
203 struct usb_port_status
*portsts
= buffer
;
206 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
207 portsts
->wPortStatus
= priv
->status
[port
];
208 portsts
->wPortChange
= priv
->change
[port
];
210 udev
->act_len
= sizeof(*portsts
);
215 debug("%s: rx ctl requesttype=%x, request=%x\n",
216 __func__
, setup
->requesttype
, setup
->request
);
219 } else if (pipe
== usb_sndctrlpipe(udev
, 0)) {
220 switch (setup
->requesttype
) {
222 switch (setup
->request
) {
223 case USB_REQ_SET_FEATURE
: {
226 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
227 debug("set feature port=%x, feature=%x\n",
229 if (setup
->value
< USB_PORT_FEAT_C_CONNECTION
) {
230 ret
= clrset_post_state(bus
, port
, 0,
233 debug(" ** Invalid feature\n");
237 case USB_REQ_CLEAR_FEATURE
: {
240 port
= (setup
->index
& USB_HUB_PORT_MASK
) - 1;
241 debug("clear feature port=%x, feature=%x\n",
243 if (setup
->value
< USB_PORT_FEAT_C_CONNECTION
) {
244 ret
= clrset_post_state(bus
, port
,
245 1 << setup
->value
, 0);
247 priv
->change
[port
] &= 1 <<
254 debug("%s: tx ctl requesttype=%x, request=%x\n",
255 __func__
, setup
->requesttype
,
260 debug("%s: tx ctl requesttype=%x, request=%x\n",
261 __func__
, setup
->requesttype
, setup
->request
);
265 debug("pipe=%lx\n", pipe
);
270 static int sandbox_hub_bind(struct udevice
*dev
)
272 return usb_emul_setup_device(dev
, PACKET_SIZE_64
, hub_strings
,
276 static int sandbox_child_post_bind(struct udevice
*dev
)
278 struct sandbox_hub_platdata
*plat
= dev_get_parent_platdata(dev
);
280 plat
->port
= dev_read_u32_default(dev
, "reg", -1);
285 static const struct dm_usb_ops sandbox_usb_hub_ops
= {
286 .control
= sandbox_hub_submit_control_msg
,
289 static const struct udevice_id sandbox_usb_hub_ids
[] = {
290 { .compatible
= "sandbox,usb-hub" },
294 U_BOOT_DRIVER(usb_sandbox_hub
) = {
295 .name
= "usb_sandbox_hub",
296 .id
= UCLASS_USB_EMUL
,
297 .of_match
= sandbox_usb_hub_ids
,
298 .bind
= sandbox_hub_bind
,
299 .ops
= &sandbox_usb_hub_ops
,
300 .priv_auto_alloc_size
= sizeof(struct sandbox_hub_priv
),
301 .per_child_platdata_auto_alloc_size
=
302 sizeof(struct sandbox_hub_platdata
),
303 .child_post_bind
= sandbox_child_post_bind
,