- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / usbfront / usbfront-hub.c
1 /*
2  * usbfront-hub.c
3  *
4  * Xen USB Virtual Host Controller - Root Hub Emulations
5  *
6  * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
7  * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  *
22  * or, by your choice,
23  *
24  * When distributed separately from the Linux kernel or incorporated into
25  * other software packages, subject to the following license:
26  *
27  * Permission is hereby granted, free of charge, to any person obtaining a copy
28  * of this software and associated documentation files (the "Software"), to
29  * deal in the Software without restriction, including without limitation the
30  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
31  * sell copies of the Software, and to permit persons to whom the Software is
32  * furnished to do so, subject to the following conditions:
33  *
34  * The above copyright notice and this permission notice shall be included in
35  * all copies or substantial portions of the Software.
36  *
37  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
42  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
43  * DEALINGS IN THE SOFTWARE.
44  */
45
46 /*
47  * set virtual port connection status
48  */
49 void set_connect_state(struct usbfront_info *info, int portnum)
50 {
51         int port;
52
53         port = portnum - 1;
54         if (info->ports[port].status & USB_PORT_STAT_POWER) {
55                 switch (info->devices[port].speed) {
56                 case USB_SPEED_UNKNOWN:
57                         info->ports[port].status &=
58                                 ~(USB_PORT_STAT_CONNECTION |
59                                         USB_PORT_STAT_ENABLE |
60                                         USB_PORT_STAT_LOW_SPEED |
61                                         USB_PORT_STAT_HIGH_SPEED |
62                                         USB_PORT_STAT_SUSPEND);
63                         break;
64                 case USB_SPEED_LOW:
65                         info->ports[port].status |= USB_PORT_STAT_CONNECTION;
66                         info->ports[port].status |= USB_PORT_STAT_LOW_SPEED;
67                         break;
68                 case USB_SPEED_FULL:
69                         info->ports[port].status |= USB_PORT_STAT_CONNECTION;
70                         break;
71                 case USB_SPEED_HIGH:
72                         info->ports[port].status |= USB_PORT_STAT_CONNECTION;
73                         info->ports[port].status |= USB_PORT_STAT_HIGH_SPEED;
74                         break;
75                 default: /* error */
76                         return;
77                 }
78                 info->ports[port].status |= (USB_PORT_STAT_C_CONNECTION << 16);
79         }
80 }
81
82 /*
83  * set virtual device connection status
84  */
85 void rhport_connect(struct usbfront_info *info,
86                                 int portnum, enum usb_device_speed speed)
87 {
88         int port;
89
90         if (portnum < 1 || portnum > info->rh_numports)
91                 return; /* invalid port number */
92
93         port = portnum - 1;
94         if (info->devices[port].speed != speed) {
95                 switch (speed) {
96                 case USB_SPEED_UNKNOWN: /* disconnect */
97                         info->devices[port].status = USB_STATE_NOTATTACHED;
98                         break;
99                 case USB_SPEED_LOW:
100                 case USB_SPEED_FULL:
101                 case USB_SPEED_HIGH:
102                         info->devices[port].status = USB_STATE_ATTACHED;
103                         break;
104                 default: /* error */
105                         return;
106                 }
107                 info->devices[port].speed = speed;
108                 info->ports[port].c_connection = 1;
109
110                 set_connect_state(info, portnum);
111         }
112 }
113
114 /*
115  * SetPortFeature(PORT_SUSPENDED)
116  */
117 void rhport_suspend(struct usbfront_info *info, int portnum)
118 {
119         int port;
120
121         port = portnum - 1;
122         info->ports[port].status |= USB_PORT_STAT_SUSPEND;
123         info->devices[port].status = USB_STATE_SUSPENDED;
124 }
125
126 /*
127  * ClearPortFeature(PORT_SUSPENDED)
128  */
129 void rhport_resume(struct usbfront_info *info, int portnum)
130 {
131         int port;
132
133         port = portnum - 1;
134         if (info->ports[port].status & USB_PORT_STAT_SUSPEND) {
135                 info->ports[port].resuming = 1;
136                 info->ports[port].timeout = jiffies + msecs_to_jiffies(20);
137         }
138 }
139
140 /*
141  * SetPortFeature(PORT_POWER)
142  */
143 void rhport_power_on(struct usbfront_info *info, int portnum)
144 {
145         int port;
146
147         port = portnum - 1;
148         if ((info->ports[port].status & USB_PORT_STAT_POWER) == 0) {
149                 info->ports[port].status |= USB_PORT_STAT_POWER;
150                 if (info->devices[port].status != USB_STATE_NOTATTACHED)
151                         info->devices[port].status = USB_STATE_POWERED;
152                 if (info->ports[port].c_connection)
153                         set_connect_state(info, portnum);
154         }
155 }
156
157 /*
158  * ClearPortFeature(PORT_POWER)
159  * SetConfiguration(non-zero)
160  * Power_Source_Off
161  * Over-current
162  */
163 void rhport_power_off(struct usbfront_info *info, int portnum)
164 {
165         int port;
166
167         port = portnum - 1;
168         if (info->ports[port].status & USB_PORT_STAT_POWER) {
169                 info->ports[port].status = 0;
170                 if (info->devices[port].status != USB_STATE_NOTATTACHED)
171                         info->devices[port].status = USB_STATE_ATTACHED;
172         }
173 }
174
175 /*
176  * ClearPortFeature(PORT_ENABLE)
177  */
178 void rhport_disable(struct usbfront_info *info, int portnum)
179 {
180         int port;
181
182         port = portnum - 1;
183         info->ports[port].status &= ~USB_PORT_STAT_ENABLE;
184         info->ports[port].status &= ~USB_PORT_STAT_SUSPEND;
185         info->ports[port].resuming = 0;
186         if (info->devices[port].status != USB_STATE_NOTATTACHED)
187                 info->devices[port].status = USB_STATE_POWERED;
188 }
189
190 /*
191  * SetPortFeature(PORT_RESET)
192  */
193 void rhport_reset(struct usbfront_info *info, int portnum)
194 {
195         int port;
196
197         port = portnum - 1;
198         info->ports[port].status &= ~(USB_PORT_STAT_ENABLE
199                                         | USB_PORT_STAT_LOW_SPEED
200                                         | USB_PORT_STAT_HIGH_SPEED);
201         info->ports[port].status |= USB_PORT_STAT_RESET;
202
203         if (info->devices[port].status != USB_STATE_NOTATTACHED)
204                 info->devices[port].status = USB_STATE_ATTACHED;
205
206         /* 10msec reset signaling */
207         info->ports[port].timeout = jiffies + msecs_to_jiffies(10);
208 }
209
210 #ifdef XENHCD_PM
211 #ifdef CONFIG_PM
212 static int xenhcd_bus_suspend(struct usb_hcd *hcd)
213 {
214         struct usbfront_info *info = hcd_to_info(hcd);
215         int ret = 0;
216         int i, ports;
217
218         ports = info->rh_numports;
219
220         spin_lock_irq(&info->lock);
221         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
222                 ret = -ESHUTDOWN;
223         else {
224                 /* suspend any active ports*/
225                 for (i = 1; i <= ports; i++)
226                         rhport_suspend(info, i);
227         }
228         spin_unlock_irq(&info->lock);
229
230         del_timer_sync(&info->watchdog);
231
232         return ret;
233 }
234
235 static int xenhcd_bus_resume(struct usb_hcd *hcd)
236 {
237         struct usbfront_info *info = hcd_to_info(hcd);
238         int ret = 0;
239         int i, ports;
240
241         ports = info->rh_numports;
242
243         spin_lock_irq(&info->lock);
244         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
245                 ret = -ESHUTDOWN;
246         else {
247                 /* resume any suspended ports*/
248                 for (i = 1; i <= ports; i++)
249                         rhport_resume(info, i);
250         }
251         spin_unlock_irq(&info->lock);
252
253         return ret;
254 }
255 #endif
256 #endif
257
258 static void xenhcd_hub_descriptor(struct usbfront_info *info,
259                                   struct usb_hub_descriptor *desc)
260 {
261         u16 temp;
262         int ports = info->rh_numports;
263
264         desc->bDescriptorType = 0x29;
265         desc->bPwrOn2PwrGood = 10; /* EHCI says 20ms max */
266         desc->bHubContrCurrent = 0;
267         desc->bNbrPorts = ports;
268
269         /* size of DeviceRemovable and PortPwrCtrlMask fields*/
270         temp = 1 + (ports / 8);
271         desc->bDescLength = 7 + 2 * temp;
272
273         /* bitmaps for DeviceRemovable and PortPwrCtrlMask */
274         memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
275         memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
276
277         /* per-port over current reporting and no power switching */
278         temp = 0x000a;
279         desc->wHubCharacteristics = cpu_to_le16(temp);
280 }
281
282 /* port status change mask for hub_status_data */
283 #define PORT_C_MASK \
284         ((USB_PORT_STAT_C_CONNECTION \
285         | USB_PORT_STAT_C_ENABLE \
286         | USB_PORT_STAT_C_SUSPEND \
287         | USB_PORT_STAT_C_OVERCURRENT \
288         | USB_PORT_STAT_C_RESET) << 16)
289
290 /*
291  * See USB 2.0 Spec, 11.12.4 Hub and Port Status Change Bitmap.
292  * If port status changed, writes the bitmap to buf and return
293  * that length(number of bytes).
294  * If Nothing changed, return 0.
295  */
296 static int xenhcd_hub_status_data(struct usb_hcd *hcd, char *buf)
297 {
298         struct usbfront_info *info = hcd_to_info(hcd);
299
300         int ports;
301         int i;
302         int length;
303
304         unsigned long flags;
305         int ret = 0;
306
307         int changed = 0;
308
309         if (!HC_IS_RUNNING(hcd->state))
310                 return 0;
311
312         /* initialize the status to no-changes */
313         ports = info->rh_numports;
314         length = 1 + (ports / 8);
315         for (i = 0; i < length; i++) {
316                 buf[i] = 0;
317                 ret++;
318         }
319
320         spin_lock_irqsave(&info->lock, flags);
321
322         for (i = 0; i < ports; i++) {
323                 /* check status for each port */
324                 if (info->ports[i].status & PORT_C_MASK) {
325                         if (i < 7)
326                                 buf[0] |= 1 << (i + 1);
327                         else if (i < 15)
328                                 buf[1] |= 1 << (i - 7);
329                         else if (i < 23)
330                                 buf[2] |= 1 << (i - 15);
331                         else
332                                 buf[3] |= 1 << (i - 23);
333                         changed = 1;
334                 }
335         }
336
337         if (!changed)
338                 ret = 0;
339
340         spin_unlock_irqrestore(&info->lock, flags);
341
342         return ret;
343 }
344
345 static int xenhcd_hub_control(struct usb_hcd *hcd,
346                                u16 typeReq,
347                                u16 wValue,
348                                u16 wIndex,
349                                char *buf,
350                                u16 wLength)
351 {
352         struct usbfront_info *info = hcd_to_info(hcd);
353         int ports = info->rh_numports;
354         unsigned long flags;
355         int ret = 0;
356         int i;
357         int changed = 0;
358
359         spin_lock_irqsave(&info->lock, flags);
360         switch (typeReq) {
361         case ClearHubFeature:
362                 /* ignore this request */
363                 break;
364         case ClearPortFeature:
365                 if (!wIndex || wIndex > ports)
366                         goto error;
367
368                 switch (wValue) {
369                 case USB_PORT_FEAT_SUSPEND:
370                         rhport_resume(info, wIndex);
371                         break;
372                 case USB_PORT_FEAT_POWER:
373                         rhport_power_off(info, wIndex);
374                         break;
375                 case USB_PORT_FEAT_ENABLE:
376                         rhport_disable(info, wIndex);
377                         break;
378                 case USB_PORT_FEAT_C_CONNECTION:
379                         info->ports[wIndex-1].c_connection = 0;
380                         /* falling through */
381                 default:
382                         info->ports[wIndex-1].status &= ~(1 << wValue);
383                         break;
384                 }
385                 break;
386         case GetHubDescriptor:
387                 xenhcd_hub_descriptor(info,
388                                       (struct usb_hub_descriptor *) buf);
389                 break;
390         case GetHubStatus:
391                 /* always local power supply good and no over-current exists. */
392                 *(__le32 *)buf = cpu_to_le32(0);
393                 break;
394         case GetPortStatus:
395                 if (!wIndex || wIndex > ports)
396                         goto error;
397
398                 wIndex--;
399
400                 /* resume completion */
401                 if (info->ports[wIndex].resuming &&
402                         time_after_eq(jiffies, info->ports[wIndex].timeout)) {
403                         info->ports[wIndex].status |= (USB_PORT_STAT_C_SUSPEND << 16);
404                         info->ports[wIndex].status &= ~USB_PORT_STAT_SUSPEND;
405                 }
406
407                 /* reset completion */
408                 if ((info->ports[wIndex].status & USB_PORT_STAT_RESET) != 0 &&
409                         time_after_eq(jiffies, info->ports[wIndex].timeout)) {
410                         info->ports[wIndex].status |= (USB_PORT_STAT_C_RESET << 16);
411                         info->ports[wIndex].status &= ~USB_PORT_STAT_RESET;
412
413                         if (info->devices[wIndex].status != USB_STATE_NOTATTACHED) {
414                                 info->ports[wIndex].status |= USB_PORT_STAT_ENABLE;
415                                 info->devices[wIndex].status = USB_STATE_DEFAULT;
416                         }
417
418                         switch (info->devices[wIndex].speed) {
419                         case USB_SPEED_LOW:
420                                 info->ports[wIndex].status |= USB_PORT_STAT_LOW_SPEED;
421                                 break;
422                         case USB_SPEED_HIGH:
423                                 info->ports[wIndex].status |= USB_PORT_STAT_HIGH_SPEED;
424                                 break;
425                         default:
426                                 break;
427                         }
428                 }
429
430                 ((u16 *) buf)[0] = cpu_to_le16 (info->ports[wIndex].status);
431                 ((u16 *) buf)[1] = cpu_to_le16 (info->ports[wIndex].status >> 16);
432                 break;
433         case SetHubFeature:
434                 /* not supported */
435                 goto error;
436         case SetPortFeature:
437                 if (!wIndex || wIndex > ports)
438                         goto error;
439
440                 switch (wValue) {
441                 case USB_PORT_FEAT_POWER:
442                         rhport_power_on(info, wIndex);
443                         break;
444                 case USB_PORT_FEAT_RESET:
445                         rhport_reset(info, wIndex);
446                         break;
447                 case USB_PORT_FEAT_SUSPEND:
448                         rhport_suspend(info, wIndex);
449                         break;
450                 default:
451                         if ((info->ports[wIndex-1].status & USB_PORT_STAT_POWER) != 0)
452                                 info->ports[wIndex-1].status |= (1 << wValue);
453                 }
454                 break;
455
456         default:
457 error:
458                 ret = -EPIPE;
459         }
460         spin_unlock_irqrestore(&info->lock, flags);
461
462         /* check status for each port */
463         for (i = 0; i < ports; i++) {
464                 if (info->ports[i].status & PORT_C_MASK)
465                         changed = 1;
466         }
467         if (changed)
468                 usb_hcd_poll_rh_status(hcd);
469
470         return ret;
471 }