ia64/linux-2.6.18-xen.hg

view drivers/xen/usbback/xenbus.c @ 829:f799db0570f2

PVUSB: backend driver

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 18 11:43:24 2009 +0000 (2009-03-18)
parents
children 4c7eb2e71e9d
line source
1 /*
2 * xenbus.c
3 *
4 * Xenbus interface for USB backend 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,
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 <xen/xenbus.h>
47 #include "usbback.h"
49 static int start_xenusbd(usbif_t *usbif)
50 {
51 int err = 0;
52 char name[TASK_COMM_LEN];
54 snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, usbif->handle);
55 usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
56 if (IS_ERR(usbif->xenusbd)) {
57 err = PTR_ERR(usbif->xenusbd);
58 usbif->xenusbd = NULL;
59 xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
60 }
61 return err;
62 }
64 static int usbback_remove(struct xenbus_device *dev)
65 {
66 usbif_t *usbif = dev->dev.driver_data;
68 if (usbif) {
69 usbif_disconnect(usbif);
70 usbif_free(usbif);;
71 }
72 dev->dev.driver_data = NULL;
74 return 0;
75 }
77 static int usbback_probe(struct xenbus_device *dev,
78 const struct xenbus_device_id *id)
79 {
80 usbif_t *usbif;
81 unsigned int handle;
82 int err;
84 if (usb_disabled())
85 return -ENODEV;
87 handle = simple_strtoul(strrchr(dev->otherend,'/')+1, NULL, 0);
88 usbif = usbif_alloc(dev->otherend_id, handle);
89 if (!usbif) {
90 xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface");
91 return -ENOMEM;
92 }
93 usbif->xbdev = dev;
94 dev->dev.driver_data = usbif;
96 err = xenbus_switch_state(dev, XenbusStateInitWait);
97 if (err)
98 goto fail;
100 return 0;
102 fail:
103 usbback_remove(dev);
104 return err;
105 }
107 static int connect_ring(usbif_t *usbif)
108 {
109 struct xenbus_device *dev = usbif->xbdev;
110 unsigned long ring_ref;
111 unsigned int evtchn;
112 int err;
114 err = xenbus_gather(XBT_NIL, dev->otherend,
115 "ring-ref", "%lu", &ring_ref,
116 "event-channel", "%u", &evtchn, NULL);
117 if (err) {
118 xenbus_dev_fatal(dev, err,
119 "reading %s/ring-ref and event-channel",
120 dev->otherend);
121 return err;
122 }
124 printk("usbback: ring-ref %ld, event-channel %d\n",
125 ring_ref, evtchn);
127 err = usbif_map(usbif, ring_ref, evtchn);
128 if (err) {
129 xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
130 ring_ref, evtchn);
131 return err;
132 }
134 return 0;
135 }
137 void usbback_do_hotplug(usbif_t *usbif)
138 {
139 struct xenbus_transaction xbt;
140 struct xenbus_device *dev = usbif->xbdev;
141 struct usbstub *stub = NULL;
142 int err;
143 char port_str[8];
144 int i;
145 int num_ports;
146 int state;
148 again:
149 err = xenbus_transaction_start(&xbt);
150 if (err) {
151 xenbus_dev_fatal(dev, err, "starting transaction");
152 return;
153 }
155 err = xenbus_scanf(xbt, dev->nodename,
156 "num-ports", "%d", &num_ports);
158 for (i = 1; i <= num_ports; i++) {
159 stub = find_attached_device(usbif, i);
160 if (stub)
161 state = stub->udev->speed;
162 else
163 state = 0;
164 sprintf(port_str, "port-%d", i);
165 err = xenbus_printf(xbt, dev->nodename, port_str, "%d", state);
166 if (err) {
167 xenbus_dev_fatal(dev, err, "writing port-%d state", i);
168 goto abort;
169 }
170 }
172 err = xenbus_transaction_end(xbt, 0);
173 if (err == -EAGAIN)
174 goto again;
175 if (err)
176 xenbus_dev_fatal(dev, err, "completing transaction");
178 return;
180 abort:
181 xenbus_transaction_end(xbt, 1);
182 }
184 void usbback_reconfigure(usbif_t *usbif)
185 {
186 struct xenbus_device *dev = usbif->xbdev;
188 if (dev->state == XenbusStateConnected)
189 xenbus_switch_state(dev, XenbusStateReconfiguring);
190 }
192 void frontend_changed(struct xenbus_device *dev,
193 enum xenbus_state frontend_state)
194 {
195 usbif_t *usbif = dev->dev.driver_data;
196 int err;
198 switch (frontend_state) {
199 case XenbusStateInitialising:
200 if (dev->state == XenbusStateClosed) {
201 printk("%s: %s: prepare for reconnect\n",
202 __FUNCTION__, dev->nodename);
203 xenbus_switch_state(dev, XenbusStateInitWait);
204 }
205 break;
207 case XenbusStateInitialised:
208 err = connect_ring(usbif);
209 if (err)
210 break;
211 start_xenusbd(usbif);
212 usbback_do_hotplug(usbif);
213 xenbus_switch_state(dev, XenbusStateConnected);
214 break;
216 case XenbusStateConnected:
217 if (dev->state == XenbusStateConnected)
218 break;
219 xenbus_switch_state(dev, XenbusStateConnected);
220 break;
222 case XenbusStateClosing:
223 usbif_disconnect(usbif);
224 xenbus_switch_state(dev, XenbusStateClosing);
225 break;
227 case XenbusStateClosed:
228 xenbus_switch_state(dev, XenbusStateClosed);
229 break;
231 case XenbusStateReconfiguring:
232 usbback_do_hotplug(usbif);
233 xenbus_switch_state(dev, XenbusStateReconfigured);
234 break;
236 case XenbusStateUnknown:
237 device_unregister(&dev->dev);
238 break;
240 default:
241 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
242 frontend_state);
243 break;
244 }
245 }
247 static const struct xenbus_device_id usbback_ids[] = {
248 { "vusb" },
249 { "" },
250 };
252 static struct xenbus_driver usbback_driver = {
253 .name = "vusb",
254 .owner = THIS_MODULE,
255 .ids = usbback_ids,
256 .probe = usbback_probe,
257 .otherend_changed = frontend_changed,
258 .remove = usbback_remove,
259 };
261 void usbback_xenbus_init(void)
262 {
263 xenbus_register_backend(&usbback_driver);
264 }
266 void usbback_xenbus_exit(void)
267 {
268 xenbus_unregister_driver(&usbback_driver);
269 }