Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / usbfront / usbfront-hcd.c
1 /*
2  * usbfront-hcd.c
3  *
4  * Xen USB Virtual Host Controller driver
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 #include "usbfront.h"
47 #include "usbfront-dbg.c"
48 #include "usbfront-hub.c"
49 #include "usbfront-q.c"
50
51 static void xenhcd_watchdog(unsigned long param)
52 {
53         struct usbfront_info *info = (struct usbfront_info *) param;
54         unsigned long flags;
55
56         spin_lock_irqsave(&info->lock, flags);
57         if (likely(HC_IS_RUNNING(info_to_hcd(info)->state))) {
58                 timer_action_done(info, TIMER_RING_WATCHDOG);
59                 xenhcd_giveback_unlinked_urbs(info);
60                 xenhcd_kick_pending_urbs(info);
61         }
62         spin_unlock_irqrestore(&info->lock, flags);
63 }
64
65 /*
66  * one-time HC init
67  */
68 static int xenhcd_setup(struct usb_hcd *hcd)
69 {
70         struct usbfront_info *info = hcd_to_info(hcd);
71
72         spin_lock_init(&info->lock);
73         INIT_LIST_HEAD(&info->pending_submit_list);
74         INIT_LIST_HEAD(&info->pending_unlink_list);
75         INIT_LIST_HEAD(&info->in_progress_list);
76         INIT_LIST_HEAD(&info->giveback_waiting_list);
77         init_timer(&info->watchdog);
78         info->watchdog.function = xenhcd_watchdog;
79         info->watchdog.data = (unsigned long) info;
80         return 0;
81 }
82
83 /*
84  * start HC running
85  */
86 static int xenhcd_run(struct usb_hcd *hcd)
87 {
88         hcd->uses_new_polling = 1;
89         clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
90         hcd->state = HC_STATE_RUNNING;
91         create_debug_file(hcd_to_info(hcd));
92         return 0;
93 }
94
95 /*
96  * stop running HC
97  */
98 static void xenhcd_stop(struct usb_hcd *hcd)
99 {
100         struct usbfront_info *info = hcd_to_info(hcd);
101
102         del_timer_sync(&info->watchdog);
103         remove_debug_file(info);
104         spin_lock_irq(&info->lock);
105         /* cancel all urbs */
106         hcd->state = HC_STATE_HALT;
107         xenhcd_cancel_all_enqueued_urbs(info);
108         xenhcd_giveback_unlinked_urbs(info);
109         spin_unlock_irq(&info->lock);
110 }
111
112 /*
113  * called as .urb_enqueue()
114  * non-error returns are promise to giveback the urb later
115  */
116 static int xenhcd_urb_enqueue(struct usb_hcd *hcd,
117                                     struct urb *urb,
118                                     gfp_t mem_flags)
119 {
120         struct usbfront_info *info = hcd_to_info(hcd);
121         struct urb_priv *urbp;
122         unsigned long flags;
123         int ret = 0;
124
125         spin_lock_irqsave(&info->lock, flags);
126
127         urbp = alloc_urb_priv(urb);
128         if (!urbp) {
129                 ret = -ENOMEM;
130                 goto done;
131         }
132         urbp->status = 1;
133
134         ret = xenhcd_submit_urb(info, urbp);
135         if (ret != 0)
136                 free_urb_priv(urbp);
137
138 done:
139         spin_unlock_irqrestore(&info->lock, flags);
140         return ret;
141 }
142
143 /*
144  * called as .urb_dequeue()
145  */
146 static int xenhcd_urb_dequeue(struct usb_hcd *hcd,
147                               struct urb *urb, int status)
148 {
149         struct usbfront_info *info = hcd_to_info(hcd);
150         struct urb_priv *urbp;
151         unsigned long flags;
152         int ret = 0;
153
154         spin_lock_irqsave(&info->lock, flags);
155
156         urbp = urb->hcpriv;
157         if (!urbp)
158                 goto done;
159
160         urbp->status = status;
161         ret = xenhcd_unlink_urb(info, urbp);
162
163 done:
164         spin_unlock_irqrestore(&info->lock, flags);
165         return ret;
166 }
167
168 /*
169  * called from usb_get_current_frame_number(),
170  * but, almost all drivers not use such function.
171  */
172 static int xenhcd_get_frame(struct usb_hcd *hcd)
173 {
174         /* it means error, but probably no problem :-) */
175         return 0;
176 }
177
178 static const char hcd_name[] = "xen_hcd";
179
180 struct hc_driver xen_usb20_hc_driver = {
181         .description = hcd_name,
182         .product_desc = "Xen USB2.0 Virtual Host Controller",
183         .hcd_priv_size = sizeof(struct usbfront_info),
184         .flags = HCD_USB2,
185
186         /* basic HC lifecycle operations */
187         .reset = xenhcd_setup,
188         .start = xenhcd_run,
189         .stop = xenhcd_stop,
190
191         /* managing urb I/O */
192         .urb_enqueue = xenhcd_urb_enqueue,
193         .urb_dequeue = xenhcd_urb_dequeue,
194         .get_frame_number = xenhcd_get_frame,
195
196         /* root hub operations */
197         .hub_status_data = xenhcd_hub_status_data,
198         .hub_control = xenhcd_hub_control,
199 #ifdef XENHCD_PM
200 #ifdef CONFIG_PM
201         .bus_suspend = xenhcd_bus_suspend,
202         .bus_resume = xenhcd_bus_resume,
203 #endif
204 #endif
205 };
206
207 struct hc_driver xen_usb11_hc_driver = {
208         .description = hcd_name,
209         .product_desc = "Xen USB1.1 Virtual Host Controller",
210         .hcd_priv_size = sizeof(struct usbfront_info),
211         .flags = HCD_USB11,
212
213         /* basic HC lifecycle operations */
214         .reset = xenhcd_setup,
215         .start = xenhcd_run,
216         .stop = xenhcd_stop,
217
218         /* managing urb I/O */
219         .urb_enqueue = xenhcd_urb_enqueue,
220         .urb_dequeue = xenhcd_urb_dequeue,
221         .get_frame_number = xenhcd_get_frame,
222
223         /* root hub operations */
224         .hub_status_data = xenhcd_hub_status_data,
225         .hub_control = xenhcd_hub_control,
226 #ifdef XENHCD_PM
227 #ifdef CONFIG_PM
228         .bus_suspend = xenhcd_bus_suspend,
229         .bus_resume = xenhcd_bus_resume,
230 #endif
231 #endif
232 };