ia64/linux-2.6.18-xen.hg

view drivers/xen/usbfront/xenbus.c @ 845:4c7eb2e71e9d

pvusb: Fix license headers.

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 31 11:11:23 2009 +0100 (2009-03-31)
parents 8f996719f2ff
children
line source
1 /*
2 * xenbus.c
3 *
4 * Xenbus interface for Xen USB Virtual Host Controller
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 */
46 #include "usbfront.h"
48 extern struct hc_driver usbfront_hc_driver;
49 extern struct kmem_cache *xenhcd_urbp_cachep;
50 extern void xenhcd_rhport_state_change(struct usbfront_info *info,
51 int port, enum usb_device_speed speed);
52 extern int xenhcd_schedule(void *arg);
54 #define GRANT_INVALID_REF 0
56 static void usbif_free(struct usbfront_info *info)
57 {
58 if (info->ring_ref != GRANT_INVALID_REF) {
59 gnttab_end_foreign_access(info->ring_ref,
60 (unsigned long)info->ring.sring);
61 info->ring_ref = GRANT_INVALID_REF;
62 info->ring.sring = NULL;
63 }
64 if (info->irq)
65 unbind_from_irqhandler(info->irq, info);
66 info->irq = 0;
67 }
69 static int setup_usbring(struct xenbus_device *dev,
70 struct usbfront_info *info)
71 {
72 usbif_sring_t *sring;
73 int err;
75 info->ring_ref= GRANT_INVALID_REF;
77 sring = (usbif_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
78 if (!sring) {
79 xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
80 return -ENOMEM;
81 }
82 SHARED_RING_INIT(sring);
83 FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
85 err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
86 if (err < 0) {
87 free_page((unsigned long)sring);
88 info->ring.sring = NULL;
89 goto fail;
90 }
91 info->ring_ref = err;
93 err = bind_listening_port_to_irqhandler(
94 dev->otherend_id, xenhcd_int, SA_SAMPLE_RANDOM, "usbif", info);
95 if (err <= 0) {
96 xenbus_dev_fatal(dev, err,
97 "bind_listening_port_to_irqhandler");
98 goto fail;
99 }
100 info->irq = err;
102 return 0;
103 fail:
104 usbif_free(info);
105 return err;
106 }
108 static int talk_to_backend(struct xenbus_device *dev,
109 struct usbfront_info *info)
110 {
111 const char *message;
112 struct xenbus_transaction xbt;
113 int err;
115 err = setup_usbring(dev, info);
116 if (err)
117 goto out;
119 again:
120 err = xenbus_transaction_start(&xbt);
121 if (err) {
122 xenbus_dev_fatal(dev, err, "starting transaction");
123 goto destroy_ring;
124 }
126 err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
127 info->ring_ref);
128 if (err) {
129 message = "writing ring-ref";
130 goto abort_transaction;
131 }
133 err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
134 irq_to_evtchn_port(info->irq));
135 if (err) {
136 message = "writing event-channel";
137 goto abort_transaction;
138 }
140 err = xenbus_transaction_end(xbt, 0);
141 if (err) {
142 if (err == -EAGAIN)
143 goto again;
144 xenbus_dev_fatal(dev, err, "completing transaction");
145 goto destroy_ring;
146 }
148 xenbus_switch_state(dev, XenbusStateInitialised);
150 return 0;
152 abort_transaction:
153 xenbus_transaction_end(xbt, 1);
154 xenbus_dev_fatal(dev, err, "%s", message);
156 destroy_ring:
157 usbif_free(info);
159 out:
160 return err;
161 }
163 static struct usb_hcd *create_hcd(struct xenbus_device *dev)
164 {
165 int i;
166 int err = 0;
167 int num_ports;
168 struct usb_hcd *hcd = NULL;
169 struct usbfront_info *info = NULL;
171 err = xenbus_scanf(XBT_NIL, dev->otherend,
172 "num-ports", "%d", &num_ports);
173 if (err != 1) {
174 xenbus_dev_fatal(dev, err, "reading num-ports");
175 return ERR_PTR(-EINVAL);
176 }
177 if (num_ports < 1 || num_ports > USB_MAXCHILDREN) {
178 xenbus_dev_fatal(dev, err, "invalid num-ports");
179 return ERR_PTR(-EINVAL);
180 }
182 hcd = usb_create_hcd(&usbfront_hc_driver, &dev->dev, dev->dev.bus_id);
183 if (!hcd) {
184 xenbus_dev_fatal(dev, err, "fail to allocate USB host controller");
185 return ERR_PTR(-ENOMEM);
186 }
187 info = hcd_to_info(hcd);
188 info->xbdev = dev;
189 info->rh_numports = num_ports;
191 for (i = 0; i < USB_RING_SIZE; i++) {
192 info->shadow[i].req.id = i+1;
193 info->shadow[i].urb = NULL;
194 }
195 info->shadow[USB_RING_SIZE-1].req.id = 0x0fff;
197 return hcd;
198 }
200 static int usbfront_probe(struct xenbus_device *dev,
201 const struct xenbus_device_id *id)
202 {
203 int err;
204 struct usb_hcd *hcd;
205 struct usbfront_info *info;
206 char name[TASK_COMM_LEN];
208 if (usb_disabled())
209 return -ENODEV;
211 hcd = create_hcd(dev);
212 if (IS_ERR(hcd)) {
213 err = PTR_ERR(hcd);
214 xenbus_dev_fatal(dev, err, "fail to create usb host controller");
215 goto fail;
216 }
218 info = hcd_to_info(hcd);
219 dev->dev.driver_data = info;
221 err = usb_add_hcd(hcd, 0, 0);
222 if (err != 0) {
223 xenbus_dev_fatal(dev, err, "fail to adding USB host controller");
224 goto fail;
225 }
227 init_waitqueue_head(&info->wq);
228 snprintf(name, TASK_COMM_LEN, "xenhcd.%d", hcd->self.busnum);
229 info->kthread = kthread_run(xenhcd_schedule, info, name);
230 if (IS_ERR(info->kthread)) {
231 err = PTR_ERR(info->kthread);
232 info->kthread = NULL;
233 goto fail;
234 }
236 err = talk_to_backend(dev, info);
237 if (err)
238 goto fail;
240 return 0;
242 fail:
243 usb_put_hcd(hcd);
244 dev->dev.driver_data = NULL;
245 return err;
246 }
248 /*
249 * 0=disconnected, 1=low_speed, 2=full_speed, 3=high_speed
250 */
251 static void usbfront_do_hotplug(struct usbfront_info *info)
252 {
253 char port_str[8];
254 int i;
255 int err;
256 int state;
258 for (i = 1; i <= info->rh_numports; i++) {
259 sprintf(port_str, "port-%d", i);
260 err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
261 port_str, "%d", &state);
262 if (err == 1)
263 xenhcd_rhport_state_change(info, i, state);
264 }
265 }
267 static void backend_changed(struct xenbus_device *dev,
268 enum xenbus_state backend_state)
269 {
270 struct usbfront_info *info = dev->dev.driver_data;
272 switch (backend_state) {
273 case XenbusStateInitialising:
274 case XenbusStateInitWait:
275 case XenbusStateInitialised:
276 case XenbusStateUnknown:
277 case XenbusStateClosed:
278 break;
280 case XenbusStateConnected:
281 if (dev->state == XenbusStateConnected)
282 break;
283 if (dev->state == XenbusStateInitialised)
284 usbfront_do_hotplug(info);
285 xenbus_switch_state(dev, XenbusStateConnected);
286 break;
288 case XenbusStateClosing:
289 xenbus_frontend_closed(dev);
290 break;
292 case XenbusStateReconfiguring:
293 if (dev->state == XenbusStateConnected)
294 xenbus_switch_state(dev, XenbusStateReconfiguring);
295 break;
297 case XenbusStateReconfigured:
298 usbfront_do_hotplug(info);
299 xenbus_switch_state(dev, XenbusStateConnected);
300 break;
302 default:
303 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
304 backend_state);
305 break;
306 }
307 }
309 static int usbfront_remove(struct xenbus_device *dev)
310 {
311 struct usbfront_info *info = dev->dev.driver_data;
312 struct usb_hcd *hcd = info_to_hcd(info);
314 usb_remove_hcd(hcd);
315 if (info->kthread) {
316 kthread_stop(info->kthread);
317 info->kthread = NULL;
318 }
319 usbif_free(info);
320 usb_put_hcd(hcd);
322 return 0;
323 }
325 static const struct xenbus_device_id usbfront_ids[] = {
326 { "vusb" },
327 { "" },
328 };
330 static struct xenbus_driver usbfront_driver = {
331 .name = "vusb",
332 .owner = THIS_MODULE,
333 .ids = usbfront_ids,
334 .probe = usbfront_probe,
335 .otherend_changed = backend_changed,
336 .remove = usbfront_remove,
337 };
339 static int __init usbfront_init(void)
340 {
341 if (!is_running_on_xen())
342 return -ENODEV;
344 xenhcd_urbp_cachep = kmem_cache_create("xenhcd_urb_priv",
345 sizeof(struct urb_priv), 0, 0, NULL, NULL);
346 if (!xenhcd_urbp_cachep) {
347 printk(KERN_ERR "usbfront failed to create kmem cache\n");
348 return -ENOMEM;
349 }
351 return xenbus_register_frontend(&usbfront_driver);
352 }
354 static void __exit usbfront_exit(void)
355 {
356 kmem_cache_destroy(xenhcd_urbp_cachep);
357 xenbus_unregister_driver(&usbfront_driver);
358 }
360 module_init(usbfront_init);
361 module_exit(usbfront_exit);
363 MODULE_AUTHOR("");
364 MODULE_DESCRIPTION(DRIVER_DESC);
365 MODULE_LICENSE("Dual BSD/GPL");