patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / usb / host / ehci-hub.c
1 /*
2  * Copyright (c) 2001-2002 by David Brownell
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /* this file is part of ehci-hcd.c */
20
21 /*-------------------------------------------------------------------------*/
22
23 /*
24  * EHCI Root Hub ... the nonsharable stuff
25  *
26  * Registers don't need cpu_to_le32, that happens transparently
27  */
28
29 /*-------------------------------------------------------------------------*/
30
31 #ifdef  CONFIG_PM
32
33 static int ehci_hub_suspend (struct usb_hcd *hcd)
34 {
35         struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
36         struct usb_device       *root = hcd_to_bus (&ehci->hcd)->root_hub;
37         int                     port;
38         int                     status = 0;
39
40         if (root->dev.power.power_state != 0)
41                 return 0;
42         if (time_before (jiffies, ehci->next_statechange))
43                 return -EAGAIN;
44
45         port = HCS_N_PORTS (ehci->hcs_params);
46         spin_lock_irq (&ehci->lock);
47
48         /* suspend any active/unsuspended ports, maybe allow wakeup */
49         while (port--) {
50                 u32     t1 = readl (&ehci->regs->port_status [port]);
51                 u32     t2 = t1;
52
53                 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
54                         t2 |= PORT_SUSPEND;
55                 if (ehci->hcd.remote_wakeup)
56                         t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
57                 else
58                         t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
59
60                 if (t1 != t2) {
61                         ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
62                                 port + 1, t1, t2);
63                         writel (t2, &ehci->regs->port_status [port]);
64                 }
65         }
66
67         /* stop schedules, then turn off HC and clean any completed work */
68         if (hcd->state == USB_STATE_RUNNING)
69                 ehci_ready (ehci);
70         ehci->command = readl (&ehci->regs->command);
71         writel (ehci->command & ~CMD_RUN, &ehci->regs->command);
72         if (ehci->reclaim)
73                 ehci->reclaim_ready = 1;
74         ehci_work (ehci, 0);
75         (void) handshake (&ehci->regs->status, STS_HALT, STS_HALT, 2000);
76
77         root->dev.power.power_state = 3;
78         ehci->next_statechange = jiffies + msecs_to_jiffies(10);
79         spin_unlock_irq (&ehci->lock);
80         return status;
81 }
82
83
84 /* caller owns root->serialize, and should reset/reinit on error */
85 static int ehci_hub_resume (struct usb_hcd *hcd)
86 {
87         struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
88         struct usb_device       *root = hcd_to_bus (&ehci->hcd)->root_hub;
89         u32                     temp;
90         int                     i;
91
92         if (!root->dev.power.power_state)
93                 return 0;
94         if (time_before (jiffies, ehci->next_statechange))
95                 return -EAGAIN;
96
97         /* re-init operational registers in case we lost power */
98         if (readl (&ehci->regs->intr_enable) == 0) {
99                 writel (INTR_MASK, &ehci->regs->intr_enable);
100                 writel (0, &ehci->regs->segment);
101                 writel (ehci->periodic_dma, &ehci->regs->frame_list);
102                 writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
103                 /* FIXME will this work even (pci) vAUX was lost? */
104         }
105
106         /* restore CMD_RUN, framelist size, and irq threshold */
107         writel (ehci->command, &ehci->regs->command);
108
109         /* take ports out of suspend */
110         i = HCS_N_PORTS (ehci->hcs_params);
111         while (i--) {
112                 temp = readl (&ehci->regs->port_status [i]);
113                 temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
114                 if (temp & PORT_SUSPEND) {
115                         ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
116                         temp |= PORT_RESUME;
117                 }
118                 writel (temp, &ehci->regs->port_status [i]);
119         }
120         i = HCS_N_PORTS (ehci->hcs_params);
121         msleep (20);
122         while (i--) {
123                 temp = readl (&ehci->regs->port_status [i]);
124                 if ((temp & PORT_SUSPEND) == 0)
125                         continue;
126                 temp &= ~PORT_RESUME;
127                 writel (temp, &ehci->regs->port_status [i]);
128                 ehci_vdbg (ehci, "resumed port %d\n", i + 1);
129         }
130         (void) readl (&ehci->regs->command);
131
132         /* maybe re-activate the schedule(s) */
133         temp = 0;
134         if (ehci->async->qh_next.qh)
135                 temp |= CMD_ASE;
136         if (ehci->periodic_sched)
137                 temp |= CMD_PSE;
138         if (temp)
139                 writel (ehci->command | temp, &ehci->regs->command);
140
141         root->dev.power.power_state = 0;
142         ehci->next_statechange = jiffies + msecs_to_jiffies(5);
143         ehci->hcd.state = USB_STATE_RUNNING;
144         return 0;
145 }
146
147 #else
148
149 #define ehci_hub_suspend        0
150 #define ehci_hub_resume         0
151
152 #endif  /* CONFIG_PM */
153
154 /*-------------------------------------------------------------------------*/
155
156 static int check_reset_complete (
157         struct ehci_hcd *ehci,
158         int             index,
159         int             port_status
160 ) {
161         if (!(port_status & PORT_CONNECT)) {
162                 ehci->reset_done [index] = 0;
163                 return port_status;
164         }
165
166         /* if reset finished and it's still not enabled -- handoff */
167         if (!(port_status & PORT_PE)) {
168
169                 /* with integrated TT, there's nobody to hand it to! */
170                 if (ehci_is_ARC(ehci)) {
171                         ehci_dbg (ehci,
172                                 "Failed to enable port %d on root hub TT\n",
173                                 index+1);
174                         return port_status;
175                 }
176
177                 ehci_dbg (ehci, "port %d full speed --> companion\n",
178                         index + 1);
179
180                 // what happens if HCS_N_CC(params) == 0 ?
181                 port_status |= PORT_OWNER;
182                 writel (port_status, &ehci->regs->port_status [index]);
183
184         } else
185                 ehci_dbg (ehci, "port %d high speed\n", index + 1);
186
187         return port_status;
188 }
189
190 /*-------------------------------------------------------------------------*/
191
192
193 /* build "status change" packet (one or two bytes) from HC registers */
194
195 static int
196 ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
197 {
198         struct ehci_hcd *ehci = hcd_to_ehci (hcd);
199         u32             temp, status = 0;
200         int             ports, i, retval = 1;
201         unsigned long   flags;
202
203         /* init status to no-changes */
204         buf [0] = 0;
205         ports = HCS_N_PORTS (ehci->hcs_params);
206         if (ports > 7) {
207                 buf [1] = 0;
208                 retval++;
209         }
210         
211         /* no hub change reports (bit 0) for now (power, ...) */
212
213         /* port N changes (bit N)? */
214         spin_lock_irqsave (&ehci->lock, flags);
215         for (i = 0; i < ports; i++) {
216                 temp = readl (&ehci->regs->port_status [i]);
217                 if (temp & PORT_OWNER) {
218                         /* don't report this in GetPortStatus */
219                         if (temp & PORT_CSC) {
220                                 temp &= ~PORT_CSC;
221                                 writel (temp, &ehci->regs->port_status [i]);
222                         }
223                         continue;
224                 }
225                 if (!(temp & PORT_CONNECT))
226                         ehci->reset_done [i] = 0;
227                 if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0
228                                 // PORT_STAT_C_SUSPEND?
229                                 || ((temp & PORT_RESUME) != 0
230                                         && time_after (jiffies,
231                                                 ehci->reset_done [i]))) {
232                         if (i < 7)
233                             buf [0] |= 1 << (i + 1);
234                         else
235                             buf [1] |= 1 << (i - 7);
236                         status = STS_PCD;
237                 }
238         }
239         spin_unlock_irqrestore (&ehci->lock, flags);
240         return status ? retval : 0;
241 }
242
243 /*-------------------------------------------------------------------------*/
244
245 static void
246 ehci_hub_descriptor (
247         struct ehci_hcd                 *ehci,
248         struct usb_hub_descriptor       *desc
249 ) {
250         int             ports = HCS_N_PORTS (ehci->hcs_params);
251         u16             temp;
252
253         desc->bDescriptorType = 0x29;
254         desc->bPwrOn2PwrGood = 10;      /* ehci 1.0, 2.3.9 says 20ms max */
255         desc->bHubContrCurrent = 0;
256
257         desc->bNbrPorts = ports;
258         temp = 1 + (ports / 8);
259         desc->bDescLength = 7 + 2 * temp;
260
261         /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
262         memset (&desc->bitmap [0], 0, temp);
263         memset (&desc->bitmap [temp], 0xff, temp);
264
265         temp = 0x0008;                  /* per-port overcurrent reporting */
266         if (HCS_PPC (ehci->hcs_params))
267                 temp |= 0x0001;         /* per-port power control */
268         if (HCS_INDICATOR (ehci->hcs_params))
269                 temp |= 0x0080;         /* per-port indicators (LEDs) */
270         desc->wHubCharacteristics = cpu_to_le16 (temp);
271 }
272
273 /*-------------------------------------------------------------------------*/
274
275 #define PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
276
277 static int ehci_hub_control (
278         struct usb_hcd  *hcd,
279         u16             typeReq,
280         u16             wValue,
281         u16             wIndex,
282         char            *buf,
283         u16             wLength
284 ) {
285         struct ehci_hcd *ehci = hcd_to_ehci (hcd);
286         int             ports = HCS_N_PORTS (ehci->hcs_params);
287         u32             temp, status;
288         unsigned long   flags;
289         int             retval = 0;
290
291         /*
292          * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
293          * HCS_INDICATOR may say we can change LEDs to off/amber/green.
294          * (track current state ourselves) ... blink for diagnostics,
295          * power, "this is the one", etc.  EHCI spec supports this.
296          */
297
298         spin_lock_irqsave (&ehci->lock, flags);
299         switch (typeReq) {
300         case ClearHubFeature:
301                 switch (wValue) {
302                 case C_HUB_LOCAL_POWER:
303                 case C_HUB_OVER_CURRENT:
304                         /* no hub-wide feature/status flags */
305                         break;
306                 default:
307                         goto error;
308                 }
309                 break;
310         case ClearPortFeature:
311                 if (!wIndex || wIndex > ports)
312                         goto error;
313                 wIndex--;
314                 temp = readl (&ehci->regs->port_status [wIndex]);
315                 if (temp & PORT_OWNER)
316                         break;
317
318                 switch (wValue) {
319                 case USB_PORT_FEAT_ENABLE:
320                         writel (temp & ~PORT_PE,
321                                 &ehci->regs->port_status [wIndex]);
322                         break;
323                 case USB_PORT_FEAT_C_ENABLE:
324                         writel (temp | PORT_PEC,
325                                 &ehci->regs->port_status [wIndex]);
326                         break;
327                 case USB_PORT_FEAT_SUSPEND:
328                         if (temp & PORT_RESET)
329                                 goto error;
330                         if (temp & PORT_SUSPEND) {
331                                 if ((temp & PORT_PE) == 0)
332                                         goto error;
333                                 /* resume signaling for 20 msec */
334                                 writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
335                                         &ehci->regs->port_status [wIndex]);
336                                 ehci->reset_done [wIndex] = jiffies
337                                                 + msecs_to_jiffies (20);
338                         }
339                         break;
340                 case USB_PORT_FEAT_C_SUSPEND:
341                         /* we auto-clear this feature */
342                         break;
343                 case USB_PORT_FEAT_POWER:
344                         if (HCS_PPC (ehci->hcs_params))
345                                 writel (temp & ~PORT_POWER,
346                                         &ehci->regs->port_status [wIndex]);
347                         break;
348                 case USB_PORT_FEAT_C_CONNECTION:
349                         writel (temp | PORT_CSC,
350                                 &ehci->regs->port_status [wIndex]);
351                         break;
352                 case USB_PORT_FEAT_C_OVER_CURRENT:
353                         writel (temp | PORT_OCC,
354                                 &ehci->regs->port_status [wIndex]);
355                         break;
356                 case USB_PORT_FEAT_C_RESET:
357                         /* GetPortStatus clears reset */
358                         break;
359                 default:
360                         goto error;
361                 }
362                 readl (&ehci->regs->command);   /* unblock posted write */
363                 break;
364         case GetHubDescriptor:
365                 ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
366                         buf);
367                 break;
368         case GetHubStatus:
369                 /* no hub-wide feature/status flags */
370                 memset (buf, 0, 4);
371                 //cpu_to_le32s ((u32 *) buf);
372                 break;
373         case GetPortStatus:
374                 if (!wIndex || wIndex > ports)
375                         goto error;
376                 wIndex--;
377                 status = 0;
378                 temp = readl (&ehci->regs->port_status [wIndex]);
379
380                 // wPortChange bits
381                 if (temp & PORT_CSC)
382                         status |= 1 << USB_PORT_FEAT_C_CONNECTION;
383                 if (temp & PORT_PEC)
384                         status |= 1 << USB_PORT_FEAT_C_ENABLE;
385                 if (temp & PORT_OCC)
386                         status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
387
388                 /* whoever resumes must GetPortStatus to complete it!! */
389                 if ((temp & PORT_RESUME)
390                                 && time_after (jiffies,
391                                         ehci->reset_done [wIndex])) {
392                         status |= 1 << USB_PORT_FEAT_C_SUSPEND;
393                         ehci->reset_done [wIndex] = 0;
394
395                         /* stop resume signaling */
396                         temp = readl (&ehci->regs->port_status [wIndex]);
397                         writel (temp & ~PORT_RESUME,
398                                 &ehci->regs->port_status [wIndex]);
399                         retval = handshake (
400                                         &ehci->regs->port_status [wIndex],
401                                         PORT_RESUME, 0, 2000 /* 2msec */);
402                         if (retval != 0) {
403                                 ehci_err (ehci, "port %d resume error %d\n",
404                                         wIndex + 1, retval);
405                                 goto error;
406                         }
407                         temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
408                 }
409
410                 /* whoever resets must GetPortStatus to complete it!! */
411                 if ((temp & PORT_RESET)
412                                 && time_after (jiffies,
413                                         ehci->reset_done [wIndex])) {
414                         status |= 1 << USB_PORT_FEAT_C_RESET;
415                         ehci->reset_done [wIndex] = 0;
416
417                         /* force reset to complete */
418                         writel (temp & ~PORT_RESET,
419                                         &ehci->regs->port_status [wIndex]);
420                         retval = handshake (
421                                         &ehci->regs->port_status [wIndex],
422                                         PORT_RESET, 0, 500);
423                         if (retval != 0) {
424                                 ehci_err (ehci, "port %d reset error %d\n",
425                                         wIndex + 1, retval);
426                                 goto error;
427                         }
428
429                         /* see what we found out */
430                         temp = check_reset_complete (ehci, wIndex,
431                                 readl (&ehci->regs->port_status [wIndex]));
432                 }
433
434                 // don't show wPortStatus if it's owned by a companion hc
435                 if (!(temp & PORT_OWNER)) {
436                         if (temp & PORT_CONNECT) {
437                                 status |= 1 << USB_PORT_FEAT_CONNECTION;
438                                 // status may be from integrated TT
439                                 status |= ehci_port_speed(ehci, temp);
440                         }
441                         if (temp & PORT_PE)
442                                 status |= 1 << USB_PORT_FEAT_ENABLE;
443                         if (temp & (PORT_SUSPEND|PORT_RESUME))
444                                 status |= 1 << USB_PORT_FEAT_SUSPEND;
445                         if (temp & PORT_OC)
446                                 status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
447                         if (temp & PORT_RESET)
448                                 status |= 1 << USB_PORT_FEAT_RESET;
449                         if (temp & PORT_POWER)
450                                 status |= 1 << USB_PORT_FEAT_POWER;
451                 }
452
453 #ifndef EHCI_VERBOSE_DEBUG
454         if (status & ~0xffff)   /* only if wPortChange is interesting */
455 #endif
456                 dbg_port (ehci, "GetStatus", wIndex + 1, temp);
457                 // we "know" this alignment is good, caller used kmalloc()...
458                 *((u32 *) buf) = cpu_to_le32 (status);
459                 break;
460         case SetHubFeature:
461                 switch (wValue) {
462                 case C_HUB_LOCAL_POWER:
463                 case C_HUB_OVER_CURRENT:
464                         /* no hub-wide feature/status flags */
465                         break;
466                 default:
467                         goto error;
468                 }
469                 break;
470         case SetPortFeature:
471                 if (!wIndex || wIndex > ports)
472                         goto error;
473                 wIndex--;
474                 temp = readl (&ehci->regs->port_status [wIndex]);
475                 if (temp & PORT_OWNER)
476                         break;
477
478                 switch (wValue) {
479                 case USB_PORT_FEAT_SUSPEND:
480                         if ((temp & PORT_PE) == 0
481                                         || (temp & PORT_RESET) != 0)
482                                 goto error;
483                         if (ehci->hcd.remote_wakeup)
484                                 temp |= PORT_WAKE_BITS;
485                         writel (temp | PORT_SUSPEND,
486                                 &ehci->regs->port_status [wIndex]);
487                         break;
488                 case USB_PORT_FEAT_POWER:
489                         if (HCS_PPC (ehci->hcs_params))
490                                 writel (temp | PORT_POWER,
491                                         &ehci->regs->port_status [wIndex]);
492                         break;
493                 case USB_PORT_FEAT_RESET:
494                         if (temp & PORT_RESUME)
495                                 goto error;
496                         /* line status bits may report this as low speed,
497                          * which can be fine if this root hub has a
498                          * transaction translator built in.
499                          */
500                         if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
501                                         && !ehci_is_ARC(ehci)
502                                         && PORT_USB11 (temp)) {
503                                 ehci_dbg (ehci,
504                                         "port %d low speed --> companion\n",
505                                         wIndex + 1);
506                                 temp |= PORT_OWNER;
507                         } else {
508                                 ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
509                                 temp |= PORT_RESET;
510                                 temp &= ~PORT_PE;
511
512                                 /*
513                                  * caller must wait, then call GetPortStatus
514                                  * usb 2.0 spec says 50 ms resets on root
515                                  */
516                                 ehci->reset_done [wIndex] = jiffies
517                                                 + msecs_to_jiffies (50);
518                         }
519                         writel (temp, &ehci->regs->port_status [wIndex]);
520                         break;
521                 default:
522                         goto error;
523                 }
524                 readl (&ehci->regs->command);   /* unblock posted writes */
525                 break;
526
527         default:
528 error:
529                 /* "stall" on error */
530                 retval = -EPIPE;
531         }
532         spin_unlock_irqrestore (&ehci->lock, flags);
533         return retval;
534 }