1 /* Xenbus code for tpmif backend
2 Copyright (C) 2005 IBM Corporation
3 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <linux/module.h>
21 #include <xen/xenbus.h>
26 struct xenbus_device *dev;
28 /* our communications channel */
32 long int instance; // instance of TPM
33 u8 is_instance_set;// whether instance number has been set
35 /* watch front end for changes */
36 struct xenbus_watch backend_watch;
37 enum xenbus_state frontend_state;
40 static void maybe_connect(struct backend_info *be);
41 static void connect(struct backend_info *be);
42 static int connect_ring(struct backend_info *be);
43 static void backend_changed(struct xenbus_watch *watch,
44 const char **vec, unsigned int len);
45 static void frontend_changed(struct xenbus_device *dev,
46 enum xenbus_state frontend_state);
48 long int tpmback_get_instance(struct backend_info *bi)
51 if (bi && bi->is_instance_set)
56 static int tpmback_remove(struct xenbus_device *dev)
58 struct backend_info *be = dev->dev.driver_data;
62 if (be->backend_watch.node) {
63 unregister_xenbus_watch(&be->backend_watch);
64 kfree(be->backend_watch.node);
65 be->backend_watch.node = NULL;
69 vtpm_release_packets(be->tpmif, 0);
74 dev->dev.driver_data = NULL;
78 static int tpmback_probe(struct xenbus_device *dev,
79 const struct xenbus_device_id *id)
82 struct backend_info *be = kzalloc(sizeof(struct backend_info),
86 xenbus_dev_fatal(dev, -ENOMEM,
87 "allocating backend structure");
91 be->is_instance_set = 0;
93 dev->dev.driver_data = be;
95 err = xenbus_watch_path2(dev, dev->nodename,
96 "instance", &be->backend_watch,
102 err = xenbus_switch_state(dev, XenbusStateInitWait);
113 static void backend_changed(struct xenbus_watch *watch,
114 const char **vec, unsigned int len)
118 struct backend_info *be
119 = container_of(watch, struct backend_info, backend_watch);
120 struct xenbus_device *dev = be->dev;
122 err = xenbus_scanf(XBT_NIL, dev->nodename,
123 "instance","%li", &instance);
124 if (XENBUS_EXIST_ERR(err)) {
129 xenbus_dev_fatal(dev, err, "reading instance");
133 if (be->is_instance_set == 0) {
134 be->instance = instance;
135 be->is_instance_set = 1;
140 static void frontend_changed(struct xenbus_device *dev,
141 enum xenbus_state frontend_state)
143 struct backend_info *be = dev->dev.driver_data;
146 be->frontend_state = frontend_state;
148 switch (frontend_state) {
149 case XenbusStateInitialising:
150 case XenbusStateInitialised:
153 case XenbusStateConnected:
154 err = connect_ring(be);
161 case XenbusStateClosing:
165 case XenbusStateClosed:
166 device_unregister(&be->dev->dev);
170 case XenbusStateUnknown:
171 case XenbusStateInitWait:
173 xenbus_dev_fatal(dev, -EINVAL,
174 "saw state %d at frontend",
182 static void maybe_connect(struct backend_info *be)
184 if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
191 static void connect(struct backend_info *be)
193 struct xenbus_transaction xbt;
195 struct xenbus_device *dev = be->dev;
196 unsigned long ready = 1;
199 err = xenbus_transaction_start(&xbt);
201 xenbus_dev_fatal(be->dev, err, "starting transaction");
205 err = xenbus_printf(xbt, be->dev->nodename,
206 "ready", "%lu", ready);
208 xenbus_dev_fatal(be->dev, err, "writing 'ready'");
212 err = xenbus_transaction_end(xbt, 0);
216 xenbus_dev_fatal(be->dev, err, "end of transaction");
218 err = xenbus_switch_state(dev, XenbusStateConnected);
220 be->tpmif->status = CONNECTED;
223 xenbus_transaction_end(xbt, 1);
227 static int connect_ring(struct backend_info *be)
229 struct xenbus_device *dev = be->dev;
230 unsigned long ring_ref;
234 err = xenbus_gather(XBT_NIL, dev->otherend,
235 "ring-ref", "%lu", &ring_ref,
236 "event-channel", "%u", &evtchn, NULL);
238 xenbus_dev_error(dev, err,
239 "reading %s/ring-ref and event-channel",
245 be->tpmif = tpmif_find(dev->otherend_id, be);
246 if (IS_ERR(be->tpmif)) {
247 err = PTR_ERR(be->tpmif);
249 xenbus_dev_fatal(dev,err,"creating vtpm interface");
254 if (be->tpmif != NULL) {
255 err = tpmif_map(be->tpmif, ring_ref, evtchn);
257 xenbus_dev_error(dev, err,
258 "mapping shared-frame %lu port %u",
267 static struct xenbus_device_id tpmback_ids[] = {
273 static struct xenbus_driver tpmback = {
275 .owner = THIS_MODULE,
277 .probe = tpmback_probe,
278 .remove = tpmback_remove,
279 .otherend_changed = frontend_changed,
283 void tpmif_xenbus_init(void)
285 xenbus_register_backend(&tpmback);
288 void tpmif_xenbus_exit(void)
290 xenbus_unregister_driver(&tpmback);