Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / usbback / xenbus.c
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, 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 "usbback.h"
47
48 static int start_xenusbd(usbif_t *usbif)
49 {
50         int err = 0;
51         char name[TASK_COMM_LEN];
52
53         snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid,
54                         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
62         return err;
63 }
64
65 static void backend_changed(struct xenbus_watch *watch,
66                         const char **vec, unsigned int len)
67 {
68         struct xenbus_transaction xbt;
69         int err;
70         int i;
71         char node[8];
72         char *busid;
73         struct vusb_port_id *portid = NULL;
74
75         usbif_t *usbif = container_of(watch, usbif_t, backend_watch);
76         struct xenbus_device *dev = usbif->xbdev;
77
78 again:
79         err = xenbus_transaction_start(&xbt);
80         if (err) {
81                 xenbus_dev_fatal(dev, err, "starting transaction");
82                 return;
83         }
84
85         for (i = 1; i <= usbif->num_ports; i++) {
86                 sprintf(node, "port/%d", i);
87                 busid = xenbus_read(xbt, dev->nodename, node, NULL);
88                 if (IS_ERR(busid)) {
89                         err = PTR_ERR(busid);
90                         xenbus_dev_fatal(dev, err, "reading port/%d", i);
91                         goto abort;
92                 }
93
94                 /*
95                  * remove portid, if the port is not connected,
96                  */
97                 if (strlen(busid) == 0) {
98                         portid = find_portid(usbif->domid, usbif->handle, i);
99                         if (portid) {
100                                 if (portid->is_connected)
101                                         xenbus_dev_fatal(dev, err,
102                                                 "can't remove port/%d, unbind first", i);
103                                 else
104                                         portid_remove(usbif->domid, usbif->handle, i);
105                         }
106                         continue; /* never configured, ignore */
107                 }
108
109                 /*
110                  * add portid,
111                  * if the port is not configured and not used from other usbif.
112                  */
113                 portid = find_portid(usbif->domid, usbif->handle, i);
114                 if (portid) {
115                         if ((strncmp(portid->phys_bus, busid, USBBACK_BUS_ID_SIZE)))
116                                 xenbus_dev_fatal(dev, err,
117                                         "can't add port/%d, remove first", i);
118                         else
119                                 continue; /* already configured, ignore */
120                 } else {
121                         if (find_portid_by_busid(busid))
122                                 xenbus_dev_fatal(dev, err,
123                                         "can't add port/%d, busid already used", i);
124                         else
125                                 portid_add(busid, usbif->domid, usbif->handle, i);
126                 }
127         }
128
129         err = xenbus_transaction_end(xbt, 0);
130         if (err == -EAGAIN)
131                 goto again;
132         if (err)
133                 xenbus_dev_fatal(dev, err, "completing transaction");
134
135         return;
136
137 abort:
138         xenbus_transaction_end(xbt, 1);
139
140         return;
141 }
142
143 static int usbback_remove(struct xenbus_device *dev)
144 {
145         usbif_t *usbif = dev_get_drvdata(&dev->dev);
146         int i;
147
148         if (usbif->backend_watch.node) {
149                 unregister_xenbus_watch(&usbif->backend_watch);
150                 kfree(usbif->backend_watch.node);
151                 usbif->backend_watch.node = NULL;
152         }
153
154         if (usbif) {
155                 /* remove all ports */
156                 for (i = 1; i <= usbif->num_ports; i++)
157                         portid_remove(usbif->domid, usbif->handle, i);
158                 usbif_disconnect(usbif);
159                 usbif_free(usbif);;
160         }
161         dev_set_drvdata(&dev->dev, NULL);
162
163         return 0;
164 }
165
166 static int usbback_probe(struct xenbus_device *dev,
167                           const struct xenbus_device_id *id)
168 {
169         usbif_t *usbif;
170         unsigned int handle;
171         int num_ports;
172         int usb_ver;
173         int err;
174
175         if (usb_disabled())
176                 return -ENODEV;
177
178         handle = simple_strtoul(strrchr(dev->otherend, '/') + 1, NULL, 0);
179         usbif = usbif_alloc(dev->otherend_id, handle);
180         if (!usbif) {
181                 xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface");
182                 return -ENOMEM;
183         }
184         usbif->xbdev = dev;
185         dev_set_drvdata(&dev->dev, usbif);
186
187         err = xenbus_scanf(XBT_NIL, dev->nodename,
188                                 "num-ports", "%d", &num_ports);
189         if (err != 1) {
190                 xenbus_dev_fatal(dev, err, "reading num-ports");
191                 goto fail;
192         }
193         if (num_ports < 1 || num_ports > USB_MAXCHILDREN) {
194                 xenbus_dev_fatal(dev, err, "invalid num-ports");
195                 goto fail;
196         }
197         usbif->num_ports = num_ports;
198
199         err = xenbus_scanf(XBT_NIL, dev->nodename,
200                                 "usb-ver", "%d", &usb_ver);
201         if (err != 1) {
202                 xenbus_dev_fatal(dev, err, "reading usb-ver");
203                 goto fail;
204         }
205         switch (usb_ver) {
206         case USB_VER_USB11:
207         case USB_VER_USB20:
208                 usbif->usb_ver = usb_ver;
209                 break;
210         default:
211                 xenbus_dev_fatal(dev, err, "invalid usb-ver");
212                 goto fail;
213         }
214
215         err = xenbus_switch_state(dev, XenbusStateInitWait);
216         if (err)
217                 goto fail;
218
219         return 0;
220
221 fail:
222         usbback_remove(dev);
223         return err;
224 }
225
226 static int connect_rings(usbif_t *usbif)
227 {
228         struct xenbus_device *dev = usbif->xbdev;
229         unsigned int urb_ring_ref, conn_ring_ref, evtchn;
230         int err;
231
232         err = xenbus_gather(XBT_NIL, dev->otherend,
233                             "urb-ring-ref", "%u", &urb_ring_ref,
234                             "conn-ring-ref", "%u", &conn_ring_ref,
235                             "event-channel", "%u", &evtchn, NULL);
236         if (err) {
237                 xenbus_dev_fatal(dev, err,
238                                  "reading %s/ring-ref and event-channel",
239                                  dev->otherend);
240                 return err;
241         }
242
243         pr_info("usbback: urb-ring-ref %u, conn-ring-ref %u,"
244                 " event-channel %u\n",
245                 urb_ring_ref, conn_ring_ref, evtchn);
246
247         err = usbif_map(usbif, urb_ring_ref, conn_ring_ref, evtchn);
248         if (err) {
249                 xenbus_dev_fatal(dev, err,
250                                 "mapping urb-ring-ref %u conn-ring-ref %u port %u",
251                                 urb_ring_ref, conn_ring_ref, evtchn);
252                 return err;
253         }
254
255         return 0;
256 }
257
258 static void frontend_changed(struct xenbus_device *dev,
259                                      enum xenbus_state frontend_state)
260 {
261         usbif_t *usbif = dev_get_drvdata(&dev->dev);
262         int err;
263
264         switch (frontend_state) {
265         case XenbusStateInitialised:
266         case XenbusStateReconfiguring:
267         case XenbusStateReconfigured:
268                 break;
269
270         case XenbusStateInitialising:
271                 if (dev->state == XenbusStateClosed) {
272                         pr_info("%s: %s: prepare for reconnect\n",
273                                 __FUNCTION__, dev->nodename);
274                         xenbus_switch_state(dev, XenbusStateInitWait);
275                 }
276                 break;
277
278         case XenbusStateConnected:
279                 if (dev->state == XenbusStateConnected)
280                         break;
281                 err = connect_rings(usbif);
282                 if (err)
283                         break;
284                 err = start_xenusbd(usbif);
285                 if (err)
286                         break;
287                 err = xenbus_watch_path2(dev, dev->nodename, "port",
288                                         &usbif->backend_watch, backend_changed);
289                 if (err)
290                         break;
291                 xenbus_switch_state(dev, XenbusStateConnected);
292                 break;
293
294         case XenbusStateClosing:
295                 usbif_disconnect(usbif);
296                 xenbus_switch_state(dev, XenbusStateClosing);
297                 break;
298
299         case XenbusStateClosed:
300                 xenbus_switch_state(dev, XenbusStateClosed);
301                 if (xenbus_dev_is_online(dev))
302                         break;
303                 /* fall through if not online */
304         case XenbusStateUnknown:
305                 device_unregister(&dev->dev);
306                 break;
307
308         default:
309                 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
310                                  frontend_state);
311                 break;
312         }
313 }
314
315 static const struct xenbus_device_id usbback_ids[] = {
316         { "vusb" },
317         { "" },
318 };
319
320 static DEFINE_XENBUS_DRIVER(usbback, ,
321         .probe = usbback_probe,
322         .otherend_changed = frontend_changed,
323         .remove = usbback_remove,
324 );
325
326 int __init usbback_xenbus_init(void)
327 {
328         return xenbus_register_backend(&usbback_driver);
329 }
330
331 void __exit usbback_xenbus_exit(void)
332 {
333         xenbus_unregister_driver(&usbback_driver);
334 }