1 /*****************************************************************************
2 * Copyright (c) 2013 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
20 #define dprintf(_x ...) do { printf(_x); } while(0)
22 #define dprintf(_x ...)
27 * 11.16.2 Class-specific Requests
32 } __attribute__((packed));
34 #define HUB_PS_CONNECTION (1 << 0)
35 #define HUB_PS_ENABLE (1 << 1)
36 #define HUB_PS_SUSPEND (1 << 2)
37 #define HUB_PS_OVER_CURRENT (1 << 3)
38 #define HUB_PS_RESET (1 << 4)
39 #define HUB_PS_POWER (1 << 8)
40 #define HUB_PS_LOW_SPEED (1 << 9)
42 #define HUB_PF_CONNECTION 0
43 #define HUB_PF_ENABLE 1
44 #define HUB_PF_SUSPEND 2
45 #define HUB_PF_OVER_CURRENT 3
46 #define HUB_PF_RESET 4
47 #define HUB_PF_POWER 8
48 #define HUB_PF_LOWSPEED 9
49 #define HUB_PF_C_CONNECTION 16
50 #define HUB_PF_C_ENABLE 17
51 #define HUB_PF_C_SUSPEND 18
52 #define HUB_PF_C_OVER_CURRENT 19
53 #define HUB_PF_C_RESET 20
55 static int usb_get_hub_desc(struct usb_dev *dev, void *data, size_t size)
57 struct usb_dev_req req;
60 req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_DEVICE;
61 req.bRequest = REQ_GET_DESCRIPTOR;
63 req.wLength = cpu_to_le16((uint16_t) size);
64 req.wValue = cpu_to_le16(DESCR_TYPE_HUB << 8);
65 return usb_send_ctrl(dev->control, &req, data);
68 static int hub_get_port_status(struct usb_dev *dev, int port, void *data, size_t size)
70 struct usb_dev_req req;
73 req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_OTHER;
74 req.bRequest = REQ_GET_STATUS;
76 req.wIndex = cpu_to_le16((uint16_t)(port + 1));
77 req.wLength = cpu_to_le16((uint16_t)size);
78 return usb_send_ctrl(dev->control, &req, data);
81 static int hub_set_port_feature(struct usb_dev *dev, int port, int feature)
83 struct usb_dev_req req;
86 req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
87 req.bRequest = REQ_SET_FEATURE;
89 req.wValue = cpu_to_le16((uint16_t)feature);
90 req.wIndex = cpu_to_le16((uint16_t)(port + 1));
91 return usb_send_ctrl(dev->control, &req, NULL);
95 static int hub_clear_port_feature(struct usb_dev *dev, int port, int feature)
97 struct usb_dev_req req;
100 req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
101 req.bRequest = REQ_CLEAR_FEATURE;
103 req.wValue = cpu_to_le16((uint16_t)feature);
104 req.wIndex = cpu_to_le16((uint16_t)(port + 1));
105 return usb_send_ctrl(dev->control, &req, NULL);
109 static int hub_check_port(struct usb_dev *dev, int port)
111 struct usb_hub_ps ps;
114 if (!hub_get_port_status(dev, port, &ps, sizeof(ps)))
116 dprintf("Port Status %04X Port Change %04X\n",
117 le16_to_cpu(ps.wPortStatus),
118 le16_to_cpu(ps.wPortChange));
120 if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_POWER)) {
121 hub_set_port_feature(dev, port, HUB_PF_POWER);
123 time = SLOF_GetTimer() + USB_TIMEOUT;
124 while (time > SLOF_GetTimer()) {
126 hub_get_port_status(dev, port, &ps, sizeof(ps));
127 if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
128 dprintf("power on Port Status %04X Port Change %04X\n",
129 le16_to_cpu(ps.wPortStatus),
130 le16_to_cpu(ps.wPortChange));
136 if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
137 hub_set_port_feature(dev, port, HUB_PF_RESET);
139 time = SLOF_GetTimer() + USB_TIMEOUT;
140 while (time > SLOF_GetTimer()) {
142 hub_get_port_status(dev, port, &ps, sizeof(ps));
143 if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_RESET)) {
144 dprintf("reset Port Status %04X Port Change %04X\n",
145 le16_to_cpu(ps.wPortStatus),
146 le16_to_cpu(ps.wPortChange));
154 unsigned int usb_hub_init(void *hubdev)
156 struct usb_dev *dev = hubdev;
157 struct usb_dev_hub_descr hub;
158 struct usb_dev *newdev;
161 dprintf("%s: enter %p\n", __func__, dev);
163 printf("usb-hub: NULL\n");
166 memset(&hub, 0, sizeof(hub));
167 usb_get_hub_desc(dev, &hub, sizeof(hub));
168 dprintf("usb-hub: ports connected %d\n", hub.bNbrPorts);
169 for (i = 0; i < hub.bNbrPorts; i++) {
170 dprintf("usb-hub: ports scanning %d\n", i);
171 if (hub_check_port(dev, i)) {
172 dprintf("***********************************************\n");
173 dprintf("\t\tusb-hub: device found %d\n", i);
174 dprintf("***********************************************\n");
175 newdev = usb_devpool_get();
176 dprintf("usb-hub: allocated device %p\n", newdev);
177 newdev->hcidev = dev->hcidev;
178 if (usb_setup_new_device(newdev, i))
179 usb_slof_populate_new_device(newdev);
181 printf("usb-hub: unable to setup device on port %d\n", i);