xen-vtx-unstable

annotate linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 9ead08216805 cdfa7dd00c44
children e7c7196fa329 8ca0f98ba8e2
rev   line source
shand@6556 1 /* Xenbus code for tpmif backend
shand@6556 2 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
shand@6556 3
shand@6556 4 This program is free software; you can redistribute it and/or modify
shand@6556 5 it under the terms of the GNU General Public License as published by
shand@6556 6 the Free Software Foundation; either version 2 of the License, or
shand@6556 7 (at your option) any later version.
shand@6556 8
shand@6556 9 This program is distributed in the hope that it will be useful,
shand@6556 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
shand@6556 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
shand@6556 12 GNU General Public License for more details.
shand@6556 13
shand@6556 14 You should have received a copy of the GNU General Public License
shand@6556 15 along with this program; if not, write to the Free Software
shand@6556 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
shand@6556 17 */
shand@6556 18 #include <stdarg.h>
shand@6556 19 #include <linux/module.h>
shand@6556 20 #include <asm-xen/xenbus.h>
shand@6556 21 #include "common.h"
shand@6556 22
shand@6556 23 struct backend_info
shand@6556 24 {
shand@6556 25 struct xenbus_device *dev;
shand@6556 26
shand@6556 27 /* our communications channel */
shand@6556 28 tpmif_t *tpmif;
shand@6556 29
shand@6556 30 long int frontend_id;
shand@6556 31 long int instance; // instance of TPM
shand@6556 32
shand@6556 33 /* watch front end for changes */
shand@6556 34 struct xenbus_watch backend_watch;
shand@6556 35
shand@6556 36 struct xenbus_watch watch;
shand@6556 37 char * frontpath;
shand@6556 38 };
shand@6556 39
shand@6556 40 static int tpmback_remove(struct xenbus_device *dev)
shand@6556 41 {
shand@6556 42 struct backend_info *be = dev->data;
shand@6556 43
shand@6556 44 if (be->watch.node) {
shand@6556 45 unregister_xenbus_watch(&be->watch);
shand@6556 46 }
shand@6556 47 unregister_xenbus_watch(&be->backend_watch);
shand@6556 48
shand@6556 49 tpmif_vtpm_close(be->instance);
shand@6556 50
shand@6556 51 if (be->tpmif) {
shand@6556 52 tpmif_put(be->tpmif);
shand@6556 53 }
shand@6556 54
shand@6556 55 if (be->frontpath)
shand@6556 56 kfree(be->frontpath);
shand@6556 57 kfree(be);
shand@6556 58 return 0;
shand@6556 59 }
shand@6556 60
shand@6556 61
shand@6556 62 static void frontend_changed(struct xenbus_watch *watch, const char *node)
shand@6556 63 {
shand@6556 64 unsigned long ringref;
shand@6556 65 unsigned int evtchn;
shand@6556 66 unsigned long ready = 1;
shand@6556 67 int err;
shand@6556 68 struct backend_info *be
shand@6556 69 = container_of(watch, struct backend_info, watch);
shand@6556 70
shand@6556 71 /* If other end is gone, delete ourself. */
shand@6556 72 if (node && !xenbus_exists(be->frontpath, "")) {
shand@6556 73 xenbus_rm(be->dev->nodename, "");
shand@6556 74 device_unregister(&be->dev->dev);
shand@6556 75 return;
shand@6556 76 }
shand@6556 77
shand@6556 78 if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
shand@6556 79 return;
shand@6556 80
shand@6556 81 err = xenbus_gather(be->frontpath,
shand@6556 82 "ring-ref", "%lu", &ringref,
shand@6556 83 "event-channel", "%u", &evtchn, NULL);
shand@6556 84 if (err) {
shand@6556 85 xenbus_dev_error(be->dev, err,
cl349@6697 86 "reading %s/ring-ref and event-channel",
shand@6556 87 be->frontpath);
shand@6556 88 return;
shand@6556 89 }
shand@6556 90
shand@6556 91
shand@6556 92 /*
shand@6556 93 * Tell the front-end that we are ready to go -
shand@6556 94 * unless something bad happens
shand@6556 95 */
shand@6556 96 err = xenbus_transaction_start(be->dev->nodename);
shand@6556 97 if (err) {
shand@6556 98 xenbus_dev_error(be->dev, err, "starting transaction");
shand@6556 99 return;
shand@6556 100 }
shand@6556 101
shand@6556 102 err = xenbus_printf(be->dev->nodename,
shand@6556 103 "ready", "%lu", ready);
shand@6556 104 if (err) {
shand@6556 105 xenbus_dev_error(be->dev, err, "writing 'ready'");
shand@6556 106 goto abort;
shand@6556 107 }
shand@6556 108
shand@6556 109 err = tpmif_map(be->tpmif, ringref, evtchn);
shand@6556 110 if (err) {
shand@6556 111 xenbus_dev_error(be->dev, err,
shand@6556 112 "mapping shared-frame %lu port %u",
shand@6556 113 ringref, evtchn);
shand@6556 114 goto abort;
shand@6556 115 }
shand@6556 116
shand@6556 117 err = tpmif_vtpm_open(be->tpmif,
shand@6556 118 be->frontend_id,
shand@6556 119 be->instance);
shand@6556 120 if (err) {
shand@6556 121 xenbus_dev_error(be->dev, err,
shand@6556 122 "queueing vtpm open packet");
shand@6556 123 /*
shand@6556 124 * Should close down this device and notify FE
shand@6556 125 * about closure.
shand@6556 126 */
shand@6556 127 goto abort;
shand@6556 128 }
shand@6556 129
shand@6556 130 xenbus_transaction_end(0);
shand@6556 131 xenbus_dev_ok(be->dev);
shand@6556 132 return;
shand@6556 133 abort:
shand@6556 134 xenbus_transaction_end(1);
shand@6556 135 }
shand@6556 136
shand@6556 137
shand@6556 138 static void backend_changed(struct xenbus_watch *watch, const char *node)
shand@6556 139 {
shand@6556 140 int err;
shand@6556 141 long int instance;
shand@6556 142 struct backend_info *be
shand@6556 143 = container_of(watch, struct backend_info, backend_watch);
shand@6556 144 struct xenbus_device *dev = be->dev;
shand@6556 145
shand@6556 146 err = xenbus_scanf(dev->nodename, "instance", "%li", &instance);
shand@6556 147 if (XENBUS_EXIST_ERR(err))
shand@6556 148 return;
shand@6556 149 if (err < 0) {
shand@6556 150 xenbus_dev_error(dev, err, "reading 'instance' variable");
shand@6556 151 return;
shand@6556 152 }
shand@6556 153
shand@6556 154 if (be->instance != -1 && be->instance != instance) {
shand@6556 155 printk(KERN_WARNING
shand@6556 156 "cannot change the instance\n");
shand@6556 157 return;
shand@6556 158 }
shand@6556 159 be->instance = instance;
shand@6556 160
shand@6556 161 if (be->tpmif == NULL) {
shand@6556 162 be->tpmif = tpmif_find(be->frontend_id,
shand@6556 163 instance);
shand@6556 164 if (IS_ERR(be->tpmif)) {
shand@6556 165 err = PTR_ERR(be->tpmif);
shand@6556 166 be->tpmif = NULL;
shand@6556 167 xenbus_dev_error(dev, err, "creating interface");
shand@6556 168 return;
shand@6556 169 }
shand@6556 170
shand@6556 171 /* Pass in NULL node to skip exist test. */
shand@6556 172 frontend_changed(&be->watch, be->frontpath);
shand@6556 173 }
shand@6556 174 }
shand@6556 175
shand@6556 176
shand@6556 177 static int tpmback_probe(struct xenbus_device *dev,
shand@6556 178 const struct xenbus_device_id *id)
shand@6556 179 {
shand@6556 180 struct backend_info *be;
shand@6556 181 char *frontend;
shand@6556 182 int err;
shand@6556 183
shand@6556 184 be = kmalloc(sizeof(*be), GFP_KERNEL);
shand@6556 185 if (!be) {
shand@6556 186 xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
shand@6556 187 err = -ENOMEM;
shand@6556 188 }
shand@6556 189
shand@6556 190 memset(be, 0, sizeof(*be));
shand@6556 191
shand@6556 192 frontend = NULL;
shand@6556 193 err = xenbus_gather(dev->nodename,
shand@6556 194 "frontend-id", "%li", &be->frontend_id,
shand@6556 195 "frontend", NULL, &frontend,
shand@6556 196 NULL);
shand@6556 197 if (XENBUS_EXIST_ERR(err))
shand@6556 198 goto free_be;
shand@6556 199 if (err < 0) {
shand@6556 200 xenbus_dev_error(dev, err,
shand@6556 201 "reading %s/frontend or frontend-id",
shand@6556 202 dev->nodename);
shand@6556 203 goto free_be;
shand@6556 204 }
shand@6556 205 if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
shand@6556 206 /* If we can't get a frontend path and a frontend-id,
shand@6556 207 * then our bus-id is no longer valid and we need to
shand@6556 208 * destroy the backend device.
shand@6556 209 */
shand@6556 210 err = -ENOENT;
shand@6556 211 goto free_be;
shand@6556 212 }
shand@6556 213
shand@6556 214 be->dev = dev;
shand@6556 215 be->backend_watch.node = dev->nodename;
shand@6556 216 be->backend_watch.callback = backend_changed;
shand@6556 217 be->instance = -1;
shand@6556 218 err = register_xenbus_watch(&be->backend_watch);
shand@6556 219 if (err) {
shand@6556 220 be->backend_watch.node = NULL;
shand@6556 221 xenbus_dev_error(dev, err, "adding backend watch on %s",
shand@6556 222 dev->nodename);
shand@6556 223 goto free_be;
shand@6556 224 }
shand@6556 225
shand@6556 226 be->frontpath = frontend;
shand@6556 227 be->watch.node = be->frontpath;
shand@6556 228 be->watch.callback = frontend_changed;
shand@6556 229 err = register_xenbus_watch(&be->watch);
shand@6556 230 if (err) {
shand@6556 231 be->watch.node = NULL;
shand@6556 232 xenbus_dev_error(dev, err,
shand@6556 233 "adding frontend watch on %s",
shand@6556 234 be->frontpath);
shand@6556 235 goto free_be;
shand@6556 236 }
shand@6556 237
shand@6556 238 dev->data = be;
shand@6556 239
shand@6556 240 backend_changed(&be->backend_watch, dev->nodename);
shand@6556 241 return err;
shand@6556 242
shand@6556 243 free_be:
shand@6556 244 if (be->backend_watch.node)
shand@6556 245 unregister_xenbus_watch(&be->backend_watch);
shand@6556 246 if (frontend)
shand@6556 247 kfree(frontend);
shand@6556 248 kfree(be);
shand@6556 249 return err;
shand@6556 250 }
shand@6556 251
shand@6556 252
shand@6556 253 static struct xenbus_device_id tpmback_ids[] = {
shand@6556 254 { "vtpm" },
shand@6556 255 { "" }
shand@6556 256 };
shand@6556 257
shand@6556 258
shand@6556 259 static struct xenbus_driver tpmback = {
shand@6556 260 .name = "vtpm",
shand@6556 261 .owner = THIS_MODULE,
shand@6556 262 .ids = tpmback_ids,
shand@6556 263 .probe = tpmback_probe,
shand@6556 264 .remove = tpmback_remove,
shand@6556 265 };
shand@6556 266
shand@6556 267
shand@6556 268 void tpmif_xenbus_init(void)
shand@6556 269 {
shand@6556 270 xenbus_register_backend(&tpmback);
shand@6556 271 }