[PATCH] dvb: DST: reorganize Twinhan DST driver to support CI
[linux-2.6] / 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  */
70 static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
71                 unsigned long port_addr)
72 {
73         int status;
74
75         if (test_bit(port, &uhci->suspended_ports)) {
76                 CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
77                 clear_bit(port, &uhci->suspended_ports);
78                 clear_bit(port, &uhci->resuming_ports);
79                 set_bit(port, &uhci->port_c_suspend);
80
81                 /* The controller won't actually turn off the RD bit until
82                  * it has had a chance to send a low-speed EOP sequence,
83                  * which takes 3 bit times (= 2 microseconds).  We'll delay
84                  * slightly longer for good luck. */
85                 udelay(4);
86         }
87 }
88
89 static void uhci_check_ports(struct uhci_hcd *uhci)
90 {
91         unsigned int port;
92         unsigned long port_addr;
93         int status;
94
95         for (port = 0; port < uhci->rh_numports; ++port) {
96                 port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
97                 status = inw(port_addr);
98                 if (unlikely(status & USBPORTSC_PR)) {
99                         if (time_after_eq(jiffies, uhci->ports_timeout)) {
100                                 CLR_RH_PORTSTAT(USBPORTSC_PR);
101                                 udelay(10);
102
103                                 /* If the port was enabled before, turning
104                                  * reset on caused a port enable change.
105                                  * Turning reset off causes a port connect
106                                  * status change.  Clear these changes. */
107                                 CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
108                                 SET_RH_PORTSTAT(USBPORTSC_PE);
109                         }
110                 }
111                 if (unlikely(status & USBPORTSC_RD)) {
112                         if (!test_bit(port, &uhci->resuming_ports)) {
113
114                                 /* Port received a wakeup request */
115                                 set_bit(port, &uhci->resuming_ports);
116                                 uhci->ports_timeout = jiffies +
117                                                 msecs_to_jiffies(20);
118                         } else if (time_after_eq(jiffies,
119                                                 uhci->ports_timeout)) {
120                                 uhci_finish_suspend(uhci, port, port_addr);
121                         }
122                 }
123         }
124 }
125
126 /* size of returned buffer is part of USB spec */
127 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
128                         u16 wIndex, char *buf, u16 wLength)
129 {
130         struct uhci_hcd *uhci = hcd_to_uhci(hcd);
131         int status, lstatus, retval = 0, len = 0;
132         unsigned int port = wIndex - 1;
133         unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
134         u16 wPortChange, wPortStatus;
135         unsigned long flags;
136
137         spin_lock_irqsave(&uhci->lock, flags);
138         switch (typeReq) {
139
140         case GetHubStatus:
141                 *(__le32 *)buf = cpu_to_le32(0);
142                 OK(4);          /* hub power */
143         case GetPortStatus:
144                 if (port >= uhci->rh_numports)
145                         goto err;
146
147                 uhci_check_ports(uhci);
148                 status = inw(port_addr);
149
150                 /* Intel controllers report the OverCurrent bit active on.
151                  * VIA controllers report it active off, so we'll adjust the
152                  * bit value.  (It's not standardized in the UHCI spec.)
153                  */
154                 if (to_pci_dev(hcd->self.controller)->vendor ==
155                                 PCI_VENDOR_ID_VIA)
156                         status ^= USBPORTSC_OC;
157
158                 /* UHCI doesn't support C_RESET (always false) */
159                 wPortChange = lstatus = 0;
160                 if (status & USBPORTSC_CSC)
161                         wPortChange |= USB_PORT_STAT_C_CONNECTION;
162                 if (status & USBPORTSC_PEC)
163                         wPortChange |= USB_PORT_STAT_C_ENABLE;
164                 if (status & USBPORTSC_OCC)
165                         wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
166
167                 if (test_bit(port, &uhci->port_c_suspend)) {
168                         wPortChange |= USB_PORT_STAT_C_SUSPEND;
169                         lstatus |= 1;
170                 }
171                 if (test_bit(port, &uhci->suspended_ports))
172                         lstatus |= 2;
173                 if (test_bit(port, &uhci->resuming_ports))
174                         lstatus |= 4;
175
176                 /* UHCI has no power switching (always on) */
177                 wPortStatus = USB_PORT_STAT_POWER;
178                 if (status & USBPORTSC_CCS)
179                         wPortStatus |= USB_PORT_STAT_CONNECTION;
180                 if (status & USBPORTSC_PE) {
181                         wPortStatus |= USB_PORT_STAT_ENABLE;
182                         if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
183                                 wPortStatus |= USB_PORT_STAT_SUSPEND;
184                 }
185                 if (status & USBPORTSC_OC)
186                         wPortStatus |= USB_PORT_STAT_OVERCURRENT;
187                 if (status & USBPORTSC_PR)
188                         wPortStatus |= USB_PORT_STAT_RESET;
189                 if (status & USBPORTSC_LSDA)
190                         wPortStatus |= USB_PORT_STAT_LOW_SPEED;
191
192                 if (wPortChange)
193                         dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
194                                         wIndex, status, lstatus);
195
196                 *(__le16 *)buf = cpu_to_le16(wPortStatus);
197                 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
198                 OK(4);
199         case SetHubFeature:             /* We don't implement these */
200         case ClearHubFeature:
201                 switch (wValue) {
202                 case C_HUB_OVER_CURRENT:
203                 case C_HUB_LOCAL_POWER:
204                         OK(0);
205                 default:
206                         goto err;
207                 }
208                 break;
209         case SetPortFeature:
210                 if (port >= uhci->rh_numports)
211                         goto err;
212
213                 switch (wValue) {
214                 case USB_PORT_FEAT_SUSPEND:
215                         set_bit(port, &uhci->suspended_ports);
216                         SET_RH_PORTSTAT(USBPORTSC_SUSP);
217                         OK(0);
218                 case USB_PORT_FEAT_RESET:
219                         SET_RH_PORTSTAT(USBPORTSC_PR);
220
221                         /* Reset terminates Resume signalling */
222                         uhci_finish_suspend(uhci, port, port_addr);
223
224                         /* USB v2.0 7.1.7.5 */
225                         uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
226                         OK(0);
227                 case USB_PORT_FEAT_POWER:
228                         /* UHCI has no power switching */
229                         OK(0);
230                 default:
231                         goto err;
232                 }
233                 break;
234         case ClearPortFeature:
235                 if (port >= uhci->rh_numports)
236                         goto err;
237
238                 switch (wValue) {
239                 case USB_PORT_FEAT_ENABLE:
240                         CLR_RH_PORTSTAT(USBPORTSC_PE);
241
242                         /* Disable terminates Resume signalling */
243                         uhci_finish_suspend(uhci, port, port_addr);
244                         OK(0);
245                 case USB_PORT_FEAT_C_ENABLE:
246                         CLR_RH_PORTSTAT(USBPORTSC_PEC);
247                         OK(0);
248                 case USB_PORT_FEAT_SUSPEND:
249                         if (test_bit(port, &uhci->suspended_ports) &&
250                                         !test_and_set_bit(port,
251                                                 &uhci->resuming_ports)) {
252                                 SET_RH_PORTSTAT(USBPORTSC_RD);
253
254                                 /* The controller won't allow RD to be set
255                                  * if the port is disabled.  When this happens
256                                  * just skip the Resume signalling.
257                                  */
258                                 if (!(inw(port_addr) & USBPORTSC_RD))
259                                         uhci_finish_suspend(uhci, port,
260                                                         port_addr);
261                                 else
262                                         /* USB v2.0 7.1.7.7 */
263                                         uhci->ports_timeout = jiffies +
264                                                 msecs_to_jiffies(20);
265                         }
266                         OK(0);
267                 case USB_PORT_FEAT_C_SUSPEND:
268                         clear_bit(port, &uhci->port_c_suspend);
269                         OK(0);
270                 case USB_PORT_FEAT_POWER:
271                         /* UHCI has no power switching */
272                         goto err;
273                 case USB_PORT_FEAT_C_CONNECTION:
274                         CLR_RH_PORTSTAT(USBPORTSC_CSC);
275                         OK(0);
276                 case USB_PORT_FEAT_C_OVER_CURRENT:
277                         CLR_RH_PORTSTAT(USBPORTSC_OCC);
278                         OK(0);
279                 case USB_PORT_FEAT_C_RESET:
280                         /* this driver won't report these */
281                         OK(0);
282                 default:
283                         goto err;
284                 }
285                 break;
286         case GetHubDescriptor:
287                 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
288                 memcpy(buf, root_hub_hub_des, len);
289                 if (len > 2)
290                         buf[2] = uhci->rh_numports;
291                 OK(len);
292         default:
293 err:
294                 retval = -EPIPE;
295         }
296         spin_unlock_irqrestore(&uhci->lock, flags);
297
298         return retval;
299 }