vserver 1.9.5.x5
[linux-2.6.git] / drivers / usb / host / uhci-hub.c
1 /*
2  * Universal Host Controller Interface driver for USB.
3  *
4  * Maintainer: Alan Stern <stern@rowland.harvard.edu>
5  *
6  * (C) Copyright 1999 Linus Torvalds
7  * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
8  * (C) Copyright 1999 Randy Dunlap
9  * (C) Copyright 1999 Georg Acher, acher@in.tum.de
10  * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
11  * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
12  * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
13  */
14
15 static __u8 root_hub_hub_des[] =
16 {
17         0x09,                   /*  __u8  bLength; */
18         0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
19         0x02,                   /*  __u8  bNbrPorts; */
20         0x0a,                   /* __u16  wHubCharacteristics; */
21         0x00,                   /*   (per-port OC, no power switching) */
22         0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
23         0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
24         0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
25         0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
26 };
27
28 #define UHCI_RH_MAXCHILD        7
29
30 /* must write as zeroes */
31 #define WZ_BITS         (USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4)
32
33 /* status change bits:  nonzero writes will clear */
34 #define RWC_BITS        (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
35
36 static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
37 {
38         struct uhci_hcd *uhci = hcd_to_uhci(hcd);
39         int port;
40
41         *buf = 0;
42         for (port = 0; port < uhci->rh_numports; ++port) {
43                 if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
44                                 test_bit(port, &uhci->port_c_suspend))
45                         *buf |= (1 << (port + 1));
46         }
47         if (*buf && uhci->state == UHCI_SUSPENDED)
48                 uhci->resume_detect = 1;
49         return !!*buf;
50 }
51
52 #define OK(x)                   len = (x); break
53
54 #define CLR_RH_PORTSTAT(x) \
55         status = inw(port_addr); \
56         status &= ~(RWC_BITS|WZ_BITS); \
57         status &= ~(x); \
58         status |= RWC_BITS & (x); \
59         outw(status, port_addr)
60
61 #define SET_RH_PORTSTAT(x) \
62         status = inw(port_addr); \
63         status |= (x); \
64         status &= ~(RWC_BITS|WZ_BITS); \
65         outw(status, port_addr)
66
67 /* UHCI controllers don't automatically stop resume signalling after 20 msec,
68  * so we have to poll and check timeouts in order to take care of it.
69  * FIXME:  Synchronize access to these fields by a spinlock.
70  */
71 static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
72                 unsigned long port_addr)
73 {
74         int status;
75
76         if (test_bit(port, &uhci->suspended_ports)) {
77                 CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
78                 clear_bit(port, &uhci->suspended_ports);
79                 clear_bit(port, &uhci->resuming_ports);
80                 set_bit(port, &uhci->port_c_suspend);
81
82                 /* The controller won't actually turn off the RD bit until
83                  * it has had a chance to send a low-speed EOP sequence,
84                  * which takes 3 bit times (= 2 microseconds).  We'll delay
85                  * slightly longer for good luck. */
86                 udelay(4);
87         }
88 }
89
90 static void uhci_check_resume(struct uhci_hcd *uhci)
91 {
92         unsigned int port;
93         unsigned long port_addr;
94
95         for (port = 0; port < uhci->rh_numports; ++port) {
96                 port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
97                 if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
98                         if (!test_bit(port, &uhci->resuming_ports)) {
99
100                                 /* Port received a wakeup request */
101                                 set_bit(port, &uhci->resuming_ports);
102                                 uhci->resume_timeout = jiffies +
103                                                 msecs_to_jiffies(20);
104                         } else if (time_after_eq(jiffies,
105                                                 uhci->resume_timeout)) {
106                                 uhci_finish_suspend(uhci, port, port_addr);
107                         }
108                 }
109         }
110 }
111
112 /* size of returned buffer is part of USB spec */
113 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
114                         u16 wIndex, char *buf, u16 wLength)
115 {
116         struct uhci_hcd *uhci = hcd_to_uhci(hcd);
117         int status, lstatus, retval = 0, len = 0;
118         unsigned int port = wIndex - 1;
119         unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
120         u16 wPortChange, wPortStatus;
121
122         switch (typeReq) {
123
124         case GetHubStatus:
125                 *(__le32 *)buf = cpu_to_le32(0);
126                 OK(4);          /* hub power */
127         case GetPortStatus:
128                 if (port >= uhci->rh_numports)
129                         goto err;
130
131                 if (uhci->resuming_ports)
132                         uhci_check_resume(uhci);
133
134                 status = inw(port_addr);
135
136                 /* Intel controllers report the OverCurrent bit active on.
137                  * VIA controllers report it active off, so we'll adjust the
138                  * bit value.  (It's not standardized in the UHCI spec.)
139                  */
140                 if (to_pci_dev(hcd->self.controller)->vendor ==
141                                 PCI_VENDOR_ID_VIA)
142                         status ^= USBPORTSC_OC;
143
144                 /* UHCI doesn't support C_RESET (always false) */
145                 wPortChange = lstatus = 0;
146                 if (status & USBPORTSC_CSC)
147                         wPortChange |= USB_PORT_STAT_C_CONNECTION;
148                 if (status & USBPORTSC_PEC)
149                         wPortChange |= USB_PORT_STAT_C_ENABLE;
150                 if (status & USBPORTSC_OCC)
151                         wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
152
153                 if (test_bit(port, &uhci->port_c_suspend)) {
154                         wPortChange |= USB_PORT_STAT_C_SUSPEND;
155                         lstatus |= 1;
156                 }
157                 if (test_bit(port, &uhci->suspended_ports))
158                         lstatus |= 2;
159                 if (test_bit(port, &uhci->resuming_ports))
160                         lstatus |= 4;
161
162                 /* UHCI has no power switching (always on) */
163                 wPortStatus = USB_PORT_STAT_POWER;
164                 if (status & USBPORTSC_CCS)
165                         wPortStatus |= USB_PORT_STAT_CONNECTION;
166                 if (status & USBPORTSC_PE) {
167                         wPortStatus |= USB_PORT_STAT_ENABLE;
168                         if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
169                                 wPortStatus |= USB_PORT_STAT_SUSPEND;
170                 }
171                 if (status & USBPORTSC_OC)
172                         wPortStatus |= USB_PORT_STAT_OVERCURRENT;
173                 if (status & USBPORTSC_PR)
174                         wPortStatus |= USB_PORT_STAT_RESET;
175                 if (status & USBPORTSC_LSDA)
176                         wPortStatus |= USB_PORT_STAT_LOW_SPEED;
177
178                 if (wPortChange)
179                         dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
180                                         wIndex, status, lstatus);
181
182                 *(__le16 *)buf = cpu_to_le16(wPortStatus);
183                 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
184                 OK(4);
185         case SetHubFeature:             /* We don't implement these */
186         case ClearHubFeature:
187                 switch (wValue) {
188                 case C_HUB_OVER_CURRENT:
189                 case C_HUB_LOCAL_POWER:
190                         OK(0);
191                 default:
192                         goto err;
193                 }
194                 break;
195         case SetPortFeature:
196                 if (port >= uhci->rh_numports)
197                         goto err;
198
199                 switch (wValue) {
200                 case USB_PORT_FEAT_SUSPEND:
201                         set_bit(port, &uhci->suspended_ports);
202                         SET_RH_PORTSTAT(USBPORTSC_SUSP);
203                         OK(0);
204                 case USB_PORT_FEAT_RESET:
205                         SET_RH_PORTSTAT(USBPORTSC_PR);
206                         mdelay(50);     /* USB v1.1 7.1.7.3 */
207                         CLR_RH_PORTSTAT(USBPORTSC_PR);
208                         udelay(10);
209
210                         /* Reset terminates Resume signalling */
211                         uhci_finish_suspend(uhci, port, port_addr);
212                         SET_RH_PORTSTAT(USBPORTSC_PE);
213                         mdelay(10);
214                         CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
215                         OK(0);
216                 case USB_PORT_FEAT_POWER:
217                         /* UHCI has no power switching */
218                         OK(0);
219                 default:
220                         goto err;
221                 }
222                 break;
223         case ClearPortFeature:
224                 if (port >= uhci->rh_numports)
225                         goto err;
226
227                 switch (wValue) {
228                 case USB_PORT_FEAT_ENABLE:
229                         CLR_RH_PORTSTAT(USBPORTSC_PE);
230
231                         /* Disable terminates Resume signalling */
232                         uhci_finish_suspend(uhci, port, port_addr);
233                         OK(0);
234                 case USB_PORT_FEAT_C_ENABLE:
235                         CLR_RH_PORTSTAT(USBPORTSC_PEC);
236                         OK(0);
237                 case USB_PORT_FEAT_SUSPEND:
238                         if (test_bit(port, &uhci->suspended_ports) &&
239                                         !test_and_set_bit(port,
240                                                 &uhci->resuming_ports)) {
241                                 uhci->resume_timeout = jiffies +
242                                                 msecs_to_jiffies(20);
243                                 SET_RH_PORTSTAT(USBPORTSC_RD);
244
245                                 /* The controller won't allow RD to be set
246                                  * if the port is disabled.  When this happens
247                                  * just skip the Resume signalling.
248                                  */
249                                 if (!(inw(port_addr) & USBPORTSC_RD))
250                                         uhci_finish_suspend(uhci, port,
251                                                         port_addr);
252                         }
253                         OK(0);
254                 case USB_PORT_FEAT_C_SUSPEND:
255                         clear_bit(port, &uhci->port_c_suspend);
256                         OK(0);
257                 case USB_PORT_FEAT_POWER:
258                         /* UHCI has no power switching */
259                         goto err;
260                 case USB_PORT_FEAT_C_CONNECTION:
261                         CLR_RH_PORTSTAT(USBPORTSC_CSC);
262                         OK(0);
263                 case USB_PORT_FEAT_C_OVER_CURRENT:
264                         CLR_RH_PORTSTAT(USBPORTSC_OCC);
265                         OK(0);
266                 case USB_PORT_FEAT_C_RESET:
267                         /* this driver won't report these */
268                         OK(0);
269                 default:
270                         goto err;
271                 }
272                 break;
273         case GetHubDescriptor:
274                 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
275                 memcpy(buf, root_hub_hub_des, len);
276                 if (len > 2)
277                         buf[2] = uhci->rh_numports;
278                 OK(len);
279         default:
280 err:
281                 retval = -EPIPE;
282         }
283
284         return retval;
285 }