ia64/xen-unstable

changeset 7218:e6ecfb4f4a24

The attached patch places an updated TPM driver into the sparse directory.
This driver allows to build a Xen0 kernel with TPM front- and backend
support and use it as a user domain kernel - something that is not
possible to do with the current TPM driver in the 2.6.12 kernel. Once this
driver appears in similar form in the kernel, I will remove it from the
sparse directory.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
Signed-off-by: Kylene Hall <kjhall@us.ibm.com>
Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Oct 05 13:52:18 2005 +0100 (2005-10-05)
parents 303d51d0d578
children b4b12c9f1200
files linux-2.6-xen-sparse/drivers/char/tpm/Kconfig linux-2.6-xen-sparse/drivers/char/tpm/Makefile linux-2.6-xen-sparse/drivers/char/tpm/tpm.c linux-2.6-xen-sparse/drivers/char/tpm/tpm.h linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig	Wed Oct 05 13:52:18 2005 +0100
     1.3 @@ -0,0 +1,58 @@
     1.4 +#
     1.5 +# TPM device configuration
     1.6 +#
     1.7 +
     1.8 +menu "TPM devices"
     1.9 +
    1.10 +config TCG_TPM
    1.11 +	tristate "TPM Hardware Support"
    1.12 +	depends on EXPERIMENTAL && PCI
    1.13 +	---help---
    1.14 +	  If you have a TPM security chip in your system, which
    1.15 +	  implements the Trusted Computing Group's specification,
    1.16 +	  say Yes and it will be accessible from within Linux.  For
    1.17 +	  more information see <http://www.trustedcomputinggroup.org>. 
    1.18 +	  An implementation of the Trusted Software Stack (TSS), the 
    1.19 +	  userspace enablement piece of the specification, can be 
    1.20 +	  obtained at: <http://sourceforge.net/projects/trousers>.  To 
    1.21 +	  compile this driver as a module, choose M here; the module 
    1.22 +	  will be called tpm. If unsure, say N.
    1.23 +
    1.24 +config TCG_TIS
    1.25 +	tristate "TPM Interface Specification 1.2 Interface"
    1.26 +	depends on TCG_TPM
    1.27 +	---help---
    1.28 +	  If you have a TPM security chip that is compliant with the
    1.29 +	  TCG TIS 1.2 TPM specification say Yes and it will be accessible
    1.30 +	  from within Linux.  To compile this driver as a module, choose
    1.31 +	  M here; the module will be called tpm_tis.
    1.32 +
    1.33 +config TCG_NSC
    1.34 +	tristate "National Semiconductor TPM Interface"
    1.35 +	depends on TCG_TPM
    1.36 +	---help---
    1.37 +	  If you have a TPM security chip from National Semicondutor 
    1.38 +	  say Yes and it will be accessible from within Linux.  To 
    1.39 +	  compile this driver as a module, choose M here; the module 
    1.40 +	  will be called tpm_nsc.
    1.41 +
    1.42 +config TCG_ATMEL
    1.43 +	tristate "Atmel TPM Interface"
    1.44 +	depends on TCG_TPM
    1.45 +	---help---
    1.46 +	  If you have a TPM security chip from Atmel say Yes and it 
    1.47 +	  will be accessible from within Linux.  To compile this driver 
    1.48 +	  as a module, choose M here; the module will be called tpm_atmel.
    1.49 +
    1.50 +config TCG_XEN
    1.51 +	tristate "XEN TPM Interface"
    1.52 +	depends on TCG_TPM && ARCH_XEN && XEN_TPMDEV_FRONTEND
    1.53 +	---help---
    1.54 +	  If you want to make TPM support available to a Xen
    1.55 +	  user domain, say Yes and it will
    1.56 +          be accessible from within Linux. To compile this driver
    1.57 +          as a module, choose M here; the module will be called
    1.58 +          tpm_xen.
    1.59 +
    1.60 +endmenu
    1.61 +
     2.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile	Wed Oct 05 13:41:59 2005 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile	Wed Oct 05 13:52:18 2005 +0100
     2.3 @@ -5,8 +5,9 @@ ifeq ($(CONFIG_XEN_PHYSDEV_ACCESS),y)
     2.4  obj-$(CONFIG_TCG_TPM) += tpm.o
     2.5  obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
     2.6  obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
     2.7 -obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
     2.8 +obj-$(CONFIG_TCG_TIS) += tpm_tis.o
     2.9 +obj-$(CONFIG_TCG_XEN) += tpm_xen.o
    2.10  else
    2.11 -obj-$(CONFIG_TCG_TPM) += tpm_nopci.o
    2.12 +obj-$(CONFIG_TCG_TPM) += tpm.o
    2.13  obj-$(CONFIG_TCG_XEN) += tpm_xen.o
    2.14  endif
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c	Wed Oct 05 13:52:18 2005 +0100
     3.3 @@ -0,0 +1,657 @@
     3.4 +/*
     3.5 + * Copyright (C) 2004 IBM Corporation
     3.6 + *
     3.7 + * Authors:
     3.8 + * Leendert van Doorn <leendert@watson.ibm.com>
     3.9 + * Dave Safford <safford@watson.ibm.com>
    3.10 + * Reiner Sailer <sailer@watson.ibm.com>
    3.11 + * Kylene Hall <kjhall@us.ibm.com>
    3.12 + *
    3.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    3.14 + *
    3.15 + * Device driver for TCG/TCPA TPM (trusted platform module).
    3.16 + * Specifications at www.trustedcomputinggroup.org	 
    3.17 + *
    3.18 + * This program is free software; you can redistribute it and/or
    3.19 + * modify it under the terms of the GNU General Public License as
    3.20 + * published by the Free Software Foundation, version 2 of the
    3.21 + * License.
    3.22 + * 
    3.23 + * Note, the TPM chip is not interrupt driven (only polling)
    3.24 + * and can have very long timeouts (minutes!). Hence the unusual
    3.25 + * calls to msleep.
    3.26 + *
    3.27 + */
    3.28 +
    3.29 +#include <linux/sched.h>
    3.30 +#include <linux/poll.h>
    3.31 +#include <linux/spinlock.h>
    3.32 +#include "tpm.h"
    3.33 +
    3.34 +#define TPM_CHIP_NUM_MASK	0x0000ffff
    3.35 +#define TPM_CHIP_TYPE_SHIFT	16	
    3.36 +
    3.37 +enum tpm_const {
    3.38 +	TPM_MINOR = 224,	/* officially assigned */
    3.39 +	TPM_MIN_BUFSIZE = 2048,
    3.40 +	TPM_MAX_BUFSIZE = 64 * 1024,
    3.41 +	TPM_NUM_DEVICES = 256,
    3.42 +	TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
    3.43 +};
    3.44 +
    3.45 +static LIST_HEAD(tpm_chip_list);
    3.46 +static DEFINE_SPINLOCK(driver_lock);
    3.47 +static int dev_mask[TPM_NUM_MASK_ENTRIES];
    3.48 +
    3.49 +static void user_reader_timeout(unsigned long ptr)
    3.50 +{
    3.51 +	struct tpm_chip *chip = (struct tpm_chip *) ptr;
    3.52 +
    3.53 +	down(&chip->buffer_mutex);
    3.54 +	atomic_set(&chip->data_pending, 0);
    3.55 +	memset(chip->data_buffer, 0, chip->vendor->buffersize);
    3.56 +	up(&chip->buffer_mutex);
    3.57 +}
    3.58 +
    3.59 +/*
    3.60 + * Internal kernel interface to transmit TPM commands
    3.61 + */
    3.62 +static ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
    3.63 +			    size_t bufsiz)
    3.64 +{
    3.65 +	ssize_t rc;
    3.66 +	u32 count;
    3.67 +	unsigned long stop;
    3.68 +
    3.69 +	if (!chip)
    3.70 +		return -ENODEV;
    3.71 +
    3.72 +	if ( !chip )
    3.73 +		return -ENODEV;
    3.74 +
    3.75 +	count = be32_to_cpu(*((__be32 *) (buf + 2)));
    3.76 +
    3.77 +	if (count == 0)
    3.78 +		return -ENODATA;
    3.79 +	if (count > bufsiz) {
    3.80 +		dev_err(chip->dev,
    3.81 +			"invalid count value %x %zx \n", count, bufsiz);
    3.82 +		return -E2BIG;
    3.83 +	}
    3.84 +
    3.85 +	down(&chip->tpm_mutex);
    3.86 +
    3.87 +	if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
    3.88 +		dev_err(chip->dev,
    3.89 +			"tpm_transmit: tpm_send: error %zd\n", rc);
    3.90 +		goto out;
    3.91 +	}
    3.92 +
    3.93 +	stop = jiffies + 2 * 60 * HZ;
    3.94 +	do {
    3.95 +		u8 status = chip->vendor->status(chip);
    3.96 +		if ((status & chip->vendor->req_complete_mask) ==
    3.97 +		    chip->vendor->req_complete_val) {
    3.98 +			goto out_recv;
    3.99 +		}
   3.100 +
   3.101 +		if ((status == chip->vendor->req_canceled)) {
   3.102 +			dev_err(chip->dev, "Operation Canceled\n");
   3.103 +			rc = -ECANCELED;
   3.104 +			goto out;
   3.105 +		}
   3.106 +
   3.107 +		msleep(TPM_TIMEOUT);	/* CHECK */
   3.108 +		rmb();
   3.109 +	} while (time_before(jiffies, stop));
   3.110 +
   3.111 +
   3.112 +	chip->vendor->cancel(chip);
   3.113 +	dev_err(chip->dev, "Operation Timed out\n");
   3.114 +	rc = -ETIME;
   3.115 +	goto out;
   3.116 +
   3.117 +out_recv:
   3.118 +	rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
   3.119 +	if (rc < 0)
   3.120 +		dev_err(chip->dev,
   3.121 +			"tpm_transmit: tpm_recv: error %zd\n", rc);
   3.122 +out:
   3.123 +	up(&chip->tpm_mutex);
   3.124 +	return rc;
   3.125 +}
   3.126 +
   3.127 +#define TPM_DIGEST_SIZE 20
   3.128 +#define CAP_PCR_RESULT_SIZE 18
   3.129 +static const u8 cap_pcr[] = {
   3.130 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.131 +	0, 0, 0, 22,		/* length */
   3.132 +	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   3.133 +	0, 0, 0, 5,
   3.134 +	0, 0, 0, 4,
   3.135 +	0, 0, 1, 1
   3.136 +};
   3.137 +
   3.138 +#define READ_PCR_RESULT_SIZE 30
   3.139 +static const u8 pcrread[] = {
   3.140 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.141 +	0, 0, 0, 14,		/* length */
   3.142 +	0, 0, 0, 21,		/* TPM_ORD_PcrRead */
   3.143 +	0, 0, 0, 0		/* PCR index */
   3.144 +};
   3.145 +
   3.146 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
   3.147 +ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
   3.148 +		      char *buf)
   3.149 +#else
   3.150 +ssize_t tpm_show_pcrs(struct device *dev,
   3.151 +		      char *buf)
   3.152 +#endif
   3.153 +{
   3.154 +	u8 data[READ_PCR_RESULT_SIZE];
   3.155 +	ssize_t len;
   3.156 +	int i, j, num_pcrs;
   3.157 +	__be32 index;
   3.158 +	char *str = buf;
   3.159 +
   3.160 +	struct tpm_chip *chip = dev_get_drvdata(dev);
   3.161 +	if (chip == NULL)
   3.162 +		return -ENODEV;
   3.163 +
   3.164 +	memcpy(data, cap_pcr, sizeof(cap_pcr));
   3.165 +	if ((len = tpm_transmit(chip, data, sizeof(data)))
   3.166 +	    < CAP_PCR_RESULT_SIZE) {
   3.167 +		dev_dbg(chip->dev, "A TPM error (%d) occurred "
   3.168 +				"attempting to determine the number of PCRS\n",
   3.169 +			be32_to_cpu(*((__be32 *) (data + 6))));
   3.170 +		return 0;
   3.171 +	}
   3.172 +
   3.173 +	num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
   3.174 +
   3.175 +	for (i = 0; i < num_pcrs; i++) {
   3.176 +		memcpy(data, pcrread, sizeof(pcrread));
   3.177 +		index = cpu_to_be32(i);
   3.178 +		memcpy(data + 10, &index, 4);
   3.179 +		if ((len = tpm_transmit(chip, data, sizeof(data)))
   3.180 +		    < READ_PCR_RESULT_SIZE){
   3.181 +			dev_dbg(chip->dev, "A TPM error (%d) occurred"
   3.182 +				" attempting to read PCR %d of %d\n",
   3.183 +				be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs);
   3.184 +			goto out;
   3.185 +		}
   3.186 +		str += sprintf(str, "PCR-%02d: ", i);
   3.187 +		for (j = 0; j < TPM_DIGEST_SIZE; j++)
   3.188 +			str += sprintf(str, "%02X ", *(data + 10 + j));
   3.189 +		str += sprintf(str, "\n");
   3.190 +	}
   3.191 +out:
   3.192 +	return str - buf;
   3.193 +}
   3.194 +EXPORT_SYMBOL_GPL(tpm_show_pcrs);
   3.195 +
   3.196 +#define  READ_PUBEK_RESULT_SIZE 314
   3.197 +static const u8 readpubek[] = {
   3.198 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.199 +	0, 0, 0, 30,		/* length */
   3.200 +	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
   3.201 +};
   3.202 +
   3.203 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
   3.204 +ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
   3.205 +		       char *buf)
   3.206 +#else
   3.207 +ssize_t tpm_show_pubek(struct device *dev,
   3.208 +		       char *buf)
   3.209 +#endif
   3.210 +{
   3.211 +	u8 *data;
   3.212 +	ssize_t len;
   3.213 +	int i, rc;
   3.214 +	char *str = buf;
   3.215 +
   3.216 +	struct tpm_chip *chip = dev_get_drvdata(dev);
   3.217 +	if (chip == NULL)
   3.218 +		return -ENODEV;
   3.219 +
   3.220 +	data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
   3.221 +	if (!data)
   3.222 +		return -ENOMEM;
   3.223 +
   3.224 +	memcpy(data, readpubek, sizeof(readpubek));
   3.225 +	memset(data + sizeof(readpubek), 0, 20);	/* zero nonce */
   3.226 +
   3.227 +	if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
   3.228 +	    READ_PUBEK_RESULT_SIZE) {
   3.229 +		dev_dbg(chip->dev, "A TPM error (%d) occurred "
   3.230 +				"attempting to read the PUBEK\n",
   3.231 +			    be32_to_cpu(*((__be32 *) (data + 6))));
   3.232 +		rc = 0;
   3.233 +		goto out;
   3.234 +	}
   3.235 +
   3.236 +	/* 
   3.237 +	   ignore header 10 bytes
   3.238 +	   algorithm 32 bits (1 == RSA )
   3.239 +	   encscheme 16 bits
   3.240 +	   sigscheme 16 bits
   3.241 +	   parameters (RSA 12->bytes: keybit, #primes, expbit)  
   3.242 +	   keylenbytes 32 bits
   3.243 +	   256 byte modulus
   3.244 +	   ignore checksum 20 bytes
   3.245 +	 */
   3.246 +
   3.247 +	str +=
   3.248 +	    sprintf(str,
   3.249 +		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
   3.250 +		    "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
   3.251 +		    " %02X %02X %02X %02X %02X %02X %02X %02X\n"
   3.252 +		    "Modulus length: %d\nModulus: \n",
   3.253 +		    data[10], data[11], data[12], data[13], data[14],
   3.254 +		    data[15], data[16], data[17], data[22], data[23],
   3.255 +		    data[24], data[25], data[26], data[27], data[28],
   3.256 +		    data[29], data[30], data[31], data[32], data[33],
   3.257 +		    be32_to_cpu(*((__be32 *) (data + 34))));
   3.258 +
   3.259 +	for (i = 0; i < 256; i++) {
   3.260 +		str += sprintf(str, "%02X ", data[i + 38]);
   3.261 +		if ((i + 1) % 16 == 0)
   3.262 +			str += sprintf(str, "\n");
   3.263 +	}
   3.264 +	rc = str - buf;
   3.265 +out:
   3.266 +	kfree(data);
   3.267 +	return rc;
   3.268 +}
   3.269 +
   3.270 +EXPORT_SYMBOL_GPL(tpm_show_pubek);
   3.271 +
   3.272 +#define CAP_VER_RESULT_SIZE 18
   3.273 +static const u8 cap_version[] = {
   3.274 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.275 +	0, 0, 0, 18,		/* length */
   3.276 +	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   3.277 +	0, 0, 0, 6,
   3.278 +	0, 0, 0, 0
   3.279 +};
   3.280 +
   3.281 +#define CAP_MANUFACTURER_RESULT_SIZE 18
   3.282 +static const u8 cap_manufacturer[] = {
   3.283 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.284 +	0, 0, 0, 22,		/* length */
   3.285 +	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   3.286 +	0, 0, 0, 5,
   3.287 +	0, 0, 0, 4,
   3.288 +	0, 0, 1, 3
   3.289 +};
   3.290 +
   3.291 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
   3.292 +ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
   3.293 +		      char *buf)
   3.294 +#else
   3.295 +ssize_t tpm_show_caps(struct device *dev,
   3.296 +		      char *buf)
   3.297 +#endif
   3.298 +{
   3.299 +	u8 data[sizeof(cap_manufacturer)];
   3.300 +	ssize_t len;
   3.301 +	char *str = buf;
   3.302 +
   3.303 +	struct tpm_chip *chip = dev_get_drvdata(dev);
   3.304 +	if (chip == NULL)
   3.305 +		return -ENODEV;
   3.306 +
   3.307 +	memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
   3.308 +
   3.309 +	if ((len = tpm_transmit(chip, data, sizeof(data))) <
   3.310 +	    CAP_MANUFACTURER_RESULT_SIZE)
   3.311 +		return len;
   3.312 +
   3.313 +	str += sprintf(str, "Manufacturer: 0x%x\n",
   3.314 +		       be32_to_cpu(*((__be32 *) (data + 14))));
   3.315 +
   3.316 +	memcpy(data, cap_version, sizeof(cap_version));
   3.317 +
   3.318 +	if ((len = tpm_transmit(chip, data, sizeof(data))) <
   3.319 +	    CAP_VER_RESULT_SIZE)
   3.320 +		return len;
   3.321 +
   3.322 +	str +=
   3.323 +	    sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
   3.324 +		    (int) data[14], (int) data[15], (int) data[16],
   3.325 +		    (int) data[17]);
   3.326 +
   3.327 +	return str - buf;
   3.328 +}
   3.329 +EXPORT_SYMBOL_GPL(tpm_show_caps);
   3.330 +
   3.331 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
   3.332 +ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
   3.333 +			const char *buf, size_t count)
   3.334 +#else
   3.335 +ssize_t tpm_store_cancel(struct device *dev,
   3.336 +			const char *buf, size_t count)
   3.337 +#endif
   3.338 +{
   3.339 +	struct tpm_chip *chip = dev_get_drvdata(dev);
   3.340 +	if (chip == NULL)
   3.341 +		return 0;
   3.342 +
   3.343 +	chip->vendor->cancel(chip);
   3.344 +	return count;
   3.345 +}
   3.346 +EXPORT_SYMBOL_GPL(tpm_store_cancel);
   3.347 +
   3.348 +
   3.349 +/*
   3.350 + * Device file system interface to the TPM
   3.351 + */
   3.352 +int tpm_open(struct inode *inode, struct file *file)
   3.353 +{
   3.354 +	int rc = 0, minor = iminor(inode);
   3.355 +	struct tpm_chip *chip = NULL, *pos;
   3.356 +
   3.357 +	spin_lock(&driver_lock);
   3.358 +
   3.359 +	list_for_each_entry(pos, &tpm_chip_list, list) {
   3.360 +		if (pos->vendor->miscdev.minor == minor) {
   3.361 +			chip = pos;
   3.362 +			break;
   3.363 +		}
   3.364 +	}
   3.365 +
   3.366 +	if (chip == NULL) {
   3.367 +		rc = -ENODEV;
   3.368 +		goto err_out;
   3.369 +	}
   3.370 +
   3.371 +	if (chip->num_opens) {
   3.372 +		dev_dbg(chip->dev,
   3.373 +			"Another process owns this TPM\n");
   3.374 +		rc = -EBUSY;
   3.375 +		goto err_out;
   3.376 +	}
   3.377 +
   3.378 +	chip->num_opens++;
   3.379 +	get_device(chip->dev);
   3.380 +
   3.381 +	spin_unlock(&driver_lock);
   3.382 +
   3.383 +	chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), GFP_KERNEL);
   3.384 +	if (chip->data_buffer == NULL) {
   3.385 +		chip->num_opens--;
   3.386 +		put_device(chip->dev);
   3.387 +		return -ENOMEM;
   3.388 +	}
   3.389 +
   3.390 +	atomic_set(&chip->data_pending, 0);
   3.391 +
   3.392 +	file->private_data = chip;
   3.393 +	return 0;
   3.394 +
   3.395 +err_out:
   3.396 +	spin_unlock(&driver_lock);
   3.397 +	return rc;
   3.398 +}
   3.399 +
   3.400 +EXPORT_SYMBOL_GPL(tpm_open);
   3.401 +
   3.402 +int tpm_release(struct inode *inode, struct file *file)
   3.403 +{
   3.404 +	struct tpm_chip *chip = file->private_data;
   3.405 +
   3.406 +	spin_lock(&driver_lock);
   3.407 +	file->private_data = NULL;
   3.408 +	chip->num_opens--;
   3.409 +	del_singleshot_timer_sync(&chip->user_read_timer);
   3.410 +	atomic_set(&chip->data_pending, 0);
   3.411 +	put_device(chip->dev);
   3.412 +	kfree(chip->data_buffer);
   3.413 +	spin_unlock(&driver_lock);
   3.414 +	return 0;
   3.415 +}
   3.416 +
   3.417 +EXPORT_SYMBOL_GPL(tpm_release);
   3.418 +
   3.419 +ssize_t tpm_write(struct file * file, const char __user * buf,
   3.420 +		  size_t size, loff_t * off)
   3.421 +{
   3.422 +	struct tpm_chip *chip = file->private_data;
   3.423 +	int in_size = size, out_size;
   3.424 +
   3.425 +	/* cannot perform a write until the read has cleared
   3.426 +	   either via tpm_read or a user_read_timer timeout */
   3.427 +	while (atomic_read(&chip->data_pending) != 0)
   3.428 +		msleep(TPM_TIMEOUT);
   3.429 +
   3.430 +	down(&chip->buffer_mutex);
   3.431 +
   3.432 +	if (in_size > chip->vendor->buffersize)
   3.433 +		in_size = chip->vendor->buffersize;
   3.434 +
   3.435 +	if (copy_from_user
   3.436 +	    (chip->data_buffer, (void __user *) buf, in_size)) {
   3.437 +		up(&chip->buffer_mutex);
   3.438 +		return -EFAULT;
   3.439 +	}
   3.440 +
   3.441 +	/* atomic tpm command send and result receive */
   3.442 +	out_size = tpm_transmit(chip, chip->data_buffer, 
   3.443 +	                        chip->vendor->buffersize);
   3.444 +
   3.445 +	atomic_set(&chip->data_pending, out_size);
   3.446 +	atomic_set(&chip->data_position, 0);
   3.447 +	up(&chip->buffer_mutex);
   3.448 +
   3.449 +	/* Set a timeout by which the reader must come claim the result */
   3.450 +	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
   3.451 +
   3.452 +	return in_size;
   3.453 +}
   3.454 +
   3.455 +EXPORT_SYMBOL_GPL(tpm_write);
   3.456 +
   3.457 +ssize_t tpm_read(struct file * file, char __user * buf,
   3.458 +		 size_t size, loff_t * off)
   3.459 +{
   3.460 +	struct tpm_chip *chip = file->private_data;
   3.461 +	int ret_size;
   3.462 +	int pos, pending = 0;
   3.463 +
   3.464 +	ret_size = atomic_read(&chip->data_pending);
   3.465 +	if (ret_size > 0) {	/* relay data */
   3.466 +		if (size < ret_size)
   3.467 +			ret_size = size;
   3.468 +
   3.469 +		pos = atomic_read(&chip->data_position);
   3.470 +
   3.471 +		down(&chip->buffer_mutex);
   3.472 +		if (copy_to_user
   3.473 +		    ((void __user *) buf, &chip->data_buffer[pos], ret_size)) {
   3.474 +			ret_size = -EFAULT;
   3.475 +		} else {
   3.476 +			pending = atomic_read(&chip->data_pending) - ret_size;
   3.477 +			if ( pending ) {
   3.478 +				atomic_set( &chip->data_pending, pending );
   3.479 +				atomic_set( &chip->data_position, pos+ret_size );
   3.480 +			}
   3.481 +		}
   3.482 +		up(&chip->buffer_mutex);
   3.483 +	}
   3.484 +	
   3.485 +	if ( ret_size <= 0 || pending == 0 ) {
   3.486 +		atomic_set( &chip->data_pending, 0 );
   3.487 +		del_singleshot_timer_sync(&chip->user_read_timer);
   3.488 +	}
   3.489 +
   3.490 +	return ret_size;
   3.491 +}
   3.492 +
   3.493 +EXPORT_SYMBOL_GPL(tpm_read);
   3.494 +
   3.495 +void tpm_remove_hardware(struct device *dev)
   3.496 +{
   3.497 +	struct tpm_chip *chip = dev_get_drvdata(dev);
   3.498 +
   3.499 +	if (chip == NULL) {
   3.500 +		dev_err(dev, "No device data found\n");
   3.501 +		return;
   3.502 +	}
   3.503 +
   3.504 +	spin_lock(&driver_lock);
   3.505 +
   3.506 +	list_del(&chip->list);
   3.507 +
   3.508 +	spin_unlock(&driver_lock);
   3.509 +
   3.510 +	dev_set_drvdata(dev, NULL);
   3.511 +	misc_deregister(&chip->vendor->miscdev);
   3.512 +	kfree(chip->vendor->miscdev.name);
   3.513 +
   3.514 +	sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
   3.515 +
   3.516 +	dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
   3.517 +
   3.518 +	kfree(chip);
   3.519 +
   3.520 +	put_device(dev);
   3.521 +}
   3.522 +
   3.523 +EXPORT_SYMBOL_GPL(tpm_remove_hardware);
   3.524 +
   3.525 +static u8 savestate[] = {
   3.526 +	0, 193,			/* TPM_TAG_RQU_COMMAND */
   3.527 +	0, 0, 0, 10,		/* blob length (in bytes) */
   3.528 +	0, 0, 0, 152		/* TPM_ORD_SaveState */
   3.529 +};
   3.530 +
   3.531 +/*
   3.532 + * We are about to suspend. Save the TPM state
   3.533 + * so that it can be restored.
   3.534 + */
   3.535 +int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state)
   3.536 +{
   3.537 +	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   3.538 +	if (chip == NULL)
   3.539 +		return -ENODEV;
   3.540 +
   3.541 +	tpm_transmit(chip, savestate, sizeof(savestate));
   3.542 +	return 0;
   3.543 +}
   3.544 +
   3.545 +EXPORT_SYMBOL_GPL(tpm_pm_suspend);
   3.546 +
   3.547 +/*
   3.548 + * Resume from a power safe. The BIOS already restored
   3.549 + * the TPM state.
   3.550 + */
   3.551 +int tpm_pm_resume(struct pci_dev *pci_dev)
   3.552 +{
   3.553 +	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   3.554 +
   3.555 +	if (chip == NULL)
   3.556 +		return -ENODEV;
   3.557 +
   3.558 +	return 0;
   3.559 +}
   3.560 +
   3.561 +EXPORT_SYMBOL_GPL(tpm_pm_resume);
   3.562 +
   3.563 +/*
   3.564 + * Called from tpm_<specific>.c probe function only for devices 
   3.565 + * the driver has determined it should claim.  Prior to calling
   3.566 + * this function the specific probe function has called pci_enable_device
   3.567 + * upon errant exit from this function specific probe function should call
   3.568 + * pci_disable_device
   3.569 + */
   3.570 +int tpm_register_hardware(struct device *dev,
   3.571 +			  struct tpm_vendor_specific *entry)
   3.572 +{
   3.573 +#define DEVNAME_SIZE 7
   3.574 +
   3.575 +	char *devname;
   3.576 +	struct tpm_chip *chip;
   3.577 +	int i, j;
   3.578 +
   3.579 +	/* Driver specific per-device data */
   3.580 +	chip = kmalloc(sizeof(*chip), GFP_KERNEL);
   3.581 +	if (chip == NULL)
   3.582 +		return -ENOMEM;
   3.583 +
   3.584 +	memset(chip, 0, sizeof(struct tpm_chip));
   3.585 +
   3.586 +	init_MUTEX(&chip->buffer_mutex);
   3.587 +	init_MUTEX(&chip->tpm_mutex);
   3.588 +	INIT_LIST_HEAD(&chip->list);
   3.589 +
   3.590 +	init_timer(&chip->user_read_timer);
   3.591 +	chip->user_read_timer.function = user_reader_timeout;
   3.592 +	chip->user_read_timer.data = (unsigned long) chip;
   3.593 +
   3.594 +	chip->vendor = entry;
   3.595 +	
   3.596 +	if (entry->buffersize < TPM_MIN_BUFSIZE) {
   3.597 +		entry->buffersize = TPM_MIN_BUFSIZE;
   3.598 +	} else if (entry->buffersize > TPM_MAX_BUFSIZE) {
   3.599 +		entry->buffersize = TPM_MAX_BUFSIZE;
   3.600 +	}
   3.601 +
   3.602 +	chip->dev_num = -1;
   3.603 +
   3.604 +	for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
   3.605 +		for (j = 0; j < 8 * sizeof(int); j++)
   3.606 +			if ((dev_mask[i] & (1 << j)) == 0) {
   3.607 +				chip->dev_num =
   3.608 +				    i * TPM_NUM_MASK_ENTRIES + j;
   3.609 +				dev_mask[i] |= 1 << j;
   3.610 +				goto dev_num_search_complete;
   3.611 +			}
   3.612 +
   3.613 +dev_num_search_complete:
   3.614 +	if (chip->dev_num < 0) {
   3.615 +		dev_err(dev,
   3.616 +			"No available tpm device numbers\n");
   3.617 +		kfree(chip);
   3.618 +		return -ENODEV;
   3.619 +	} else if (chip->dev_num == 0)
   3.620 +		chip->vendor->miscdev.minor = TPM_MINOR;
   3.621 +	else
   3.622 +		chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
   3.623 +
   3.624 +	devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
   3.625 +	scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
   3.626 +	chip->vendor->miscdev.name = devname;
   3.627 +
   3.628 +	chip->vendor->miscdev.dev = dev;
   3.629 +	chip->dev = get_device(dev);
   3.630 +
   3.631 +	if (misc_register(&chip->vendor->miscdev)) {
   3.632 +		dev_err(chip->dev,
   3.633 +			"unable to misc_register %s, minor %d\n",
   3.634 +			chip->vendor->miscdev.name,
   3.635 +			chip->vendor->miscdev.minor);
   3.636 +		put_device(dev);
   3.637 +		kfree(chip);
   3.638 +		dev_mask[i] &= !(1 << j);
   3.639 +		return -ENODEV;
   3.640 +	}
   3.641 +
   3.642 +	spin_lock(&driver_lock);
   3.643 +
   3.644 +	dev_set_drvdata(dev, chip);
   3.645 +
   3.646 +	list_add(&chip->list, &tpm_chip_list);
   3.647 +
   3.648 +	spin_unlock(&driver_lock);
   3.649 +
   3.650 +	sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
   3.651 +
   3.652 +	return 0;
   3.653 +}
   3.654 +
   3.655 +EXPORT_SYMBOL_GPL(tpm_register_hardware);
   3.656 +
   3.657 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
   3.658 +MODULE_DESCRIPTION("TPM Driver");
   3.659 +MODULE_VERSION("2.0");
   3.660 +MODULE_LICENSE("GPL");
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h	Wed Oct 05 13:52:18 2005 +0100
     4.3 @@ -0,0 +1,118 @@
     4.4 +/*
     4.5 + * Copyright (C) 2004 IBM Corporation
     4.6 + *
     4.7 + * Authors:
     4.8 + * Leendert van Doorn <leendert@watson.ibm.com>
     4.9 + * Dave Safford <safford@watson.ibm.com>
    4.10 + * Reiner Sailer <sailer@watson.ibm.com>
    4.11 + * Kylene Hall <kjhall@us.ibm.com>
    4.12 + *
    4.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    4.14 + *
    4.15 + * Device driver for TCG/TCPA TPM (trusted platform module).
    4.16 + * Specifications at www.trustedcomputinggroup.org	 
    4.17 + *
    4.18 + * This program is free software; you can redistribute it and/or
    4.19 + * modify it under the terms of the GNU General Public License as
    4.20 + * published by the Free Software Foundation, version 2 of the
    4.21 + * License.
    4.22 + * 
    4.23 + */
    4.24 +#include <linux/module.h>
    4.25 +#include <linux/version.h>
    4.26 +#include <linux/pci.h>
    4.27 +#include <linux/delay.h>
    4.28 +#include <linux/fs.h>
    4.29 +#include <linux/miscdevice.h>
    4.30 +
    4.31 +enum tpm_timeout {
    4.32 +	TPM_TIMEOUT = 5,	/* msecs */
    4.33 +};
    4.34 +
    4.35 +/* TPM addresses */
    4.36 +enum tpm_addr {
    4.37 +	TPM_SUPERIO_ADDR = 0x2E,
    4.38 +	TPM_ADDR = 0x4E,
    4.39 +};
    4.40 +
    4.41 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
    4.42 +extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
    4.43 +				char *);
    4.44 +extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
    4.45 +				char *);
    4.46 +extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
    4.47 +				char *);
    4.48 +extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
    4.49 +				const char *, size_t);
    4.50 +#else
    4.51 +extern ssize_t tpm_show_pubek(struct device *,
    4.52 +				char *);
    4.53 +extern ssize_t tpm_show_pcrs(struct device *,
    4.54 +				char *);
    4.55 +extern ssize_t tpm_show_caps(struct device *,
    4.56 +				char *);
    4.57 +extern ssize_t tpm_store_cancel(struct device *,
    4.58 +				const char *, size_t);
    4.59 +#endif
    4.60 +
    4.61 +struct tpm_chip;
    4.62 +
    4.63 +struct tpm_vendor_specific {
    4.64 +	u8 req_complete_mask;
    4.65 +	u8 req_complete_val;
    4.66 +	u8 req_canceled;
    4.67 +	u16 base;		/* TPM base address */
    4.68 +	int drv_type;
    4.69 +	u32 buffersize;
    4.70 +
    4.71 +	int (*recv) (struct tpm_chip *, u8 *, size_t);
    4.72 +	int (*send) (struct tpm_chip *, u8 *, size_t);
    4.73 +	void (*cancel) (struct tpm_chip *);
    4.74 +	u8 (*status) (struct tpm_chip *);
    4.75 +	struct miscdevice miscdev;
    4.76 +	struct attribute_group *attr_group;
    4.77 +};
    4.78 +
    4.79 +struct tpm_chip {
    4.80 +	struct device *dev;	/* Device stuff */
    4.81 +
    4.82 +	int dev_num;		/* /dev/tpm# */
    4.83 +	int num_opens;		/* only one allowed */
    4.84 +	int time_expired;
    4.85 +
    4.86 +	/* Data passed to and from the tpm via the read/write calls */
    4.87 +	u8 *data_buffer;
    4.88 +	atomic_t data_pending;
    4.89 +	atomic_t data_position;
    4.90 +	struct semaphore buffer_mutex;
    4.91 +
    4.92 +	struct timer_list user_read_timer;	/* user needs to claim result */
    4.93 +	struct semaphore tpm_mutex;	/* tpm is processing */
    4.94 +
    4.95 +	struct tpm_vendor_specific *vendor;
    4.96 +
    4.97 +	struct list_head list;
    4.98 +};
    4.99 +
   4.100 +static inline int tpm_read_index(int base, int index)
   4.101 +{
   4.102 +	outb(index, base);
   4.103 +	return inb(base+1) & 0xFF;
   4.104 +}
   4.105 +
   4.106 +static inline void tpm_write_index(int base, int index, int value)
   4.107 +{
   4.108 +	outb(index, base);
   4.109 +	outb(value & 0xFF, base+1);
   4.110 +}
   4.111 +
   4.112 +extern int tpm_register_hardware(struct device *,
   4.113 +				 struct tpm_vendor_specific *);
   4.114 +extern int tpm_open(struct inode *, struct file *);
   4.115 +extern int tpm_release(struct inode *, struct file *);
   4.116 +extern ssize_t tpm_write(struct file *, const char __user *, size_t,
   4.117 +			 loff_t *);
   4.118 +extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
   4.119 +extern void tpm_remove_hardware(struct device *);
   4.120 +extern int tpm_pm_suspend(struct pci_dev *, pm_message_t);
   4.121 +extern int tpm_pm_resume(struct pci_dev *);
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c	Wed Oct 05 13:52:18 2005 +0100
     5.3 @@ -0,0 +1,263 @@
     5.4 +/*
     5.5 + * Copyright (C) 2004 IBM Corporation
     5.6 + *
     5.7 + * Authors:
     5.8 + * Leendert van Doorn <leendert@watson.ibm.com>
     5.9 + * Dave Safford <safford@watson.ibm.com>
    5.10 + * Reiner Sailer <sailer@watson.ibm.com>
    5.11 + * Kylene Hall <kjhall@us.ibm.com>
    5.12 + *
    5.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    5.14 + *
    5.15 + * Device driver for TCG/TCPA TPM (trusted platform module).
    5.16 + * Specifications at www.trustedcomputinggroup.org	 
    5.17 + *
    5.18 + * This program is free software; you can redistribute it and/or
    5.19 + * modify it under the terms of the GNU General Public License as
    5.20 + * published by the Free Software Foundation, version 2 of the
    5.21 + * License.
    5.22 + * 
    5.23 + */
    5.24 +
    5.25 +#include "tpm.h"
    5.26 +
    5.27 +/* Atmel definitions */
    5.28 +enum tpm_atmel_addr {
    5.29 +	TPM_ATMEL_BASE_ADDR_LO = 0x08,
    5.30 +	TPM_ATMEL_BASE_ADDR_HI = 0x09
    5.31 +};
    5.32 +
    5.33 +/* write status bits */
    5.34 +enum tpm_atmel_write_status {
    5.35 +	ATML_STATUS_ABORT = 0x01,
    5.36 +	ATML_STATUS_LASTBYTE = 0x04
    5.37 +};
    5.38 +/* read status bits */
    5.39 +enum tpm_atmel_read_status {
    5.40 +	ATML_STATUS_BUSY = 0x01,
    5.41 +	ATML_STATUS_DATA_AVAIL = 0x02,
    5.42 +	ATML_STATUS_REWRITE = 0x04,
    5.43 +	ATML_STATUS_READY = 0x08
    5.44 +};
    5.45 +
    5.46 +static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
    5.47 +{
    5.48 +	u8 status, *hdr = buf;
    5.49 +	u32 size;
    5.50 +	int i;
    5.51 +	__be32 *native_size;
    5.52 +
    5.53 +	/* start reading header */
    5.54 +	if (count < 6)
    5.55 +		return -EIO;
    5.56 +
    5.57 +	for (i = 0; i < 6; i++) {
    5.58 +		status = inb(chip->vendor->base + 1);
    5.59 +		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
    5.60 +			dev_err(chip->dev,
    5.61 +				"error reading header\n");
    5.62 +			return -EIO;
    5.63 +		}
    5.64 +		*buf++ = inb(chip->vendor->base);
    5.65 +	}
    5.66 +
    5.67 +	/* size of the data received */
    5.68 +	native_size = (__force __be32 *) (hdr + 2);
    5.69 +	size = be32_to_cpu(*native_size);
    5.70 +
    5.71 +	if (count < size) {
    5.72 +		dev_err(chip->dev,
    5.73 +			"Recv size(%d) less than available space\n", size);
    5.74 +		for (; i < size; i++) {	/* clear the waiting data anyway */
    5.75 +			status = inb(chip->vendor->base + 1);
    5.76 +			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
    5.77 +				dev_err(chip->dev,
    5.78 +					"error reading data\n");
    5.79 +				return -EIO;
    5.80 +			}
    5.81 +		}
    5.82 +		return -EIO;
    5.83 +	}
    5.84 +
    5.85 +	/* read all the data available */
    5.86 +	for (; i < size; i++) {
    5.87 +		status = inb(chip->vendor->base + 1);
    5.88 +		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
    5.89 +			dev_err(chip->dev,
    5.90 +				"error reading data\n");
    5.91 +			return -EIO;
    5.92 +		}
    5.93 +		*buf++ = inb(chip->vendor->base);
    5.94 +	}
    5.95 +
    5.96 +	/* make sure data available is gone */
    5.97 +	status = inb(chip->vendor->base + 1);
    5.98 +	if (status & ATML_STATUS_DATA_AVAIL) {
    5.99 +		dev_err(chip->dev, "data available is stuck\n");
   5.100 +		return -EIO;
   5.101 +	}
   5.102 +
   5.103 +	return size;
   5.104 +}
   5.105 +
   5.106 +static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count)
   5.107 +{
   5.108 +	int i;
   5.109 +
   5.110 +	dev_dbg(chip->dev, "tpm_atml_send:\n");
   5.111 +	for (i = 0; i < count; i++) {
   5.112 +		dev_dbg(chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
   5.113 +		outb(buf[i], chip->vendor->base);
   5.114 +	}
   5.115 +
   5.116 +	return count;
   5.117 +}
   5.118 +
   5.119 +static void tpm_atml_cancel(struct tpm_chip *chip)
   5.120 +{
   5.121 +	outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
   5.122 +}
   5.123 +
   5.124 +static u8 tpm_atml_status(struct tpm_chip *chip)
   5.125 +{
   5.126 +	return inb(chip->vendor->base + 1);
   5.127 +}
   5.128 +
   5.129 +static struct file_operations atmel_ops = {
   5.130 +	.owner = THIS_MODULE,
   5.131 +	.llseek = no_llseek,
   5.132 +	.open = tpm_open,
   5.133 +	.read = tpm_read,
   5.134 +	.write = tpm_write,
   5.135 +	.release = tpm_release,
   5.136 +};
   5.137 +
   5.138 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
   5.139 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
   5.140 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
   5.141 +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
   5.142 +
   5.143 +static struct attribute* atmel_attrs[] = {
   5.144 +	&dev_attr_pubek.attr,
   5.145 +	&dev_attr_pcrs.attr,
   5.146 +	&dev_attr_caps.attr,
   5.147 +	&dev_attr_cancel.attr,
   5.148 +	0,
   5.149 +};
   5.150 +
   5.151 +static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
   5.152 +
   5.153 +static struct tpm_vendor_specific tpm_atmel = {
   5.154 +	.recv = tpm_atml_recv,
   5.155 +	.send = tpm_atml_send,
   5.156 +	.cancel = tpm_atml_cancel,
   5.157 +	.status = tpm_atml_status,
   5.158 +	.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
   5.159 +	.req_complete_val = ATML_STATUS_DATA_AVAIL,
   5.160 +	.req_canceled = ATML_STATUS_READY,
   5.161 +	.attr_group = &atmel_attr_grp,
   5.162 +	.miscdev = { .fops = &atmel_ops, },
   5.163 +};
   5.164 +
   5.165 +static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
   5.166 +				   const struct pci_device_id *pci_id)
   5.167 +{
   5.168 +	u8 version[4];
   5.169 +	int rc = 0;
   5.170 +	int lo, hi;
   5.171 +
   5.172 +	if (pci_enable_device(pci_dev))
   5.173 +		return -EIO;
   5.174 +
   5.175 +	lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
   5.176 +	hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
   5.177 +
   5.178 +	tpm_atmel.base = (hi<<8)|lo;
   5.179 +	dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
   5.180 +
   5.181 +	/* verify that it is an Atmel part */
   5.182 +	if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
   5.183 +	    || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
   5.184 +		rc = -ENODEV;
   5.185 +		goto out_err;
   5.186 +	}
   5.187 +
   5.188 +	/* query chip for its version number */
   5.189 +	if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
   5.190 +		version[1] = tpm_read_index(TPM_ADDR, 0x01);
   5.191 +		version[2] = tpm_read_index(TPM_ADDR, 0x02);
   5.192 +		version[3] = tpm_read_index(TPM_ADDR, 0x03);
   5.193 +	} else {
   5.194 +		dev_info(&pci_dev->dev, "version query failed\n");
   5.195 +		rc = -ENODEV;
   5.196 +		goto out_err;
   5.197 +	}
   5.198 +
   5.199 +	if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_atmel)) < 0)
   5.200 +		goto out_err;
   5.201 +
   5.202 +	dev_info(&pci_dev->dev,
   5.203 +		 "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1],
   5.204 +		 version[2], version[3]);
   5.205 +
   5.206 +	return 0;
   5.207 +out_err:
   5.208 +	pci_disable_device(pci_dev);
   5.209 +	return rc;
   5.210 +}
   5.211 +
   5.212 +static void __devexit tpm_atml_remove(struct pci_dev *pci_dev) 
   5.213 +{
   5.214 +	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   5.215 +
   5.216 +	if ( chip )
   5.217 +		tpm_remove_hardware(chip->dev);
   5.218 +}
   5.219 +
   5.220 +static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
   5.221 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
   5.222 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
   5.223 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
   5.224 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
   5.225 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
   5.226 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
   5.227 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
   5.228 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
   5.229 +	{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
   5.230 +#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
   5.231 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
   5.232 +#else
   5.233 +#warning Remove the define of PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
   5.234 +#endif
   5.235 +	{PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
   5.236 +	{0,}
   5.237 +};
   5.238 +
   5.239 +MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
   5.240 +
   5.241 +static struct pci_driver atmel_pci_driver = {
   5.242 +	.name = "tpm_atmel",
   5.243 +	.id_table = tpm_pci_tbl,
   5.244 +	.probe = tpm_atml_init,
   5.245 +	.remove = __devexit_p(tpm_atml_remove),
   5.246 +	.suspend = tpm_pm_suspend,
   5.247 +	.resume = tpm_pm_resume,
   5.248 +};
   5.249 +
   5.250 +static int __init init_atmel(void)
   5.251 +{
   5.252 +	return pci_register_driver(&atmel_pci_driver);
   5.253 +}
   5.254 +
   5.255 +static void __exit cleanup_atmel(void)
   5.256 +{
   5.257 +	pci_unregister_driver(&atmel_pci_driver);
   5.258 +}
   5.259 +
   5.260 +fs_initcall(init_atmel);
   5.261 +module_exit(cleanup_atmel);
   5.262 +
   5.263 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
   5.264 +MODULE_DESCRIPTION("TPM Driver");
   5.265 +MODULE_VERSION("2.0");
   5.266 +MODULE_LICENSE("GPL");
     6.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c	Wed Oct 05 13:41:59 2005 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,751 +0,0 @@
     6.4 -/*
     6.5 - * Copyright (C) 2004 IBM Corporation
     6.6 - *
     6.7 - * Authors:
     6.8 - * Leendert van Doorn <leendert@watson.ibm.com>
     6.9 - * Dave Safford <safford@watson.ibm.com>
    6.10 - * Reiner Sailer <sailer@watson.ibm.com>
    6.11 - * Kylene Hall <kjhall@us.ibm.com>
    6.12 - *
    6.13 - * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    6.14 - *
    6.15 - * Device driver for TCG/TCPA TPM (trusted platform module).
    6.16 - * Specifications at www.trustedcomputinggroup.org
    6.17 - *
    6.18 - * This program is free software; you can redistribute it and/or
    6.19 - * modify it under the terms of the GNU General Public License as
    6.20 - * published by the Free Software Foundation, version 2 of the
    6.21 - * License.
    6.22 - *
    6.23 - * Note, the TPM chip is not interrupt driven (only polling)
    6.24 - * and can have very long timeouts (minutes!). Hence the unusual
    6.25 - * calls to schedule_timeout.
    6.26 - *
    6.27 - */
    6.28 -
    6.29 -#include <linux/sched.h>
    6.30 -#include <linux/poll.h>
    6.31 -#include <linux/spinlock.h>
    6.32 -#include "tpm_nopci.h"
    6.33 -
    6.34 -enum {
    6.35 -	TPM_MINOR = 224,	/* officially assigned */
    6.36 -	TPM_MIN_BUFSIZE = 2048,
    6.37 -	TPM_MAX_BUFSIZE = 65536,
    6.38 -	TPM_NUM_DEVICES = 256,
    6.39 -	TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
    6.40 -};
    6.41 -
    6.42 -  /* PCI configuration addresses */
    6.43 -enum {
    6.44 -	PCI_GEN_PMCON_1 = 0xA0,
    6.45 -	PCI_GEN1_DEC = 0xE4,
    6.46 -	PCI_LPC_EN = 0xE6,
    6.47 -	PCI_GEN2_DEC = 0xEC
    6.48 -};
    6.49 -
    6.50 -enum {
    6.51 -	TPM_LOCK_REG = 0x0D,
    6.52 -	TPM_INTERUPT_REG = 0x0A,
    6.53 -	TPM_BASE_ADDR_LO = 0x08,
    6.54 -	TPM_BASE_ADDR_HI = 0x09,
    6.55 -	TPM_UNLOCK_VALUE = 0x55,
    6.56 -	TPM_LOCK_VALUE = 0xAA,
    6.57 -	TPM_DISABLE_INTERUPT_VALUE = 0x00
    6.58 -};
    6.59 -
    6.60 -static LIST_HEAD(tpm_chip_list);
    6.61 -static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
    6.62 -static int dev_mask[32];
    6.63 -
    6.64 -static void user_reader_timeout(unsigned long ptr)
    6.65 -{
    6.66 -	struct tpm_chip *chip = (struct tpm_chip *) ptr;
    6.67 -
    6.68 -	down(&chip->buffer_mutex);
    6.69 -	atomic_set(&chip->data_pending, 0);
    6.70 -	memset(chip->data_buffer, 0, chip->vendor->buffersize);
    6.71 -	up(&chip->buffer_mutex);
    6.72 -}
    6.73 -
    6.74 -void tpm_time_expired(unsigned long ptr)
    6.75 -{
    6.76 -	int *exp = (int *) ptr;
    6.77 -	*exp = 1;
    6.78 -}
    6.79 -
    6.80 -EXPORT_SYMBOL_GPL(tpm_time_expired);
    6.81 -
    6.82 -
    6.83 -/*
    6.84 - * This function should be used by other kernel subsystems attempting to use the tpm through the tpm_transmit interface.
    6.85 - * A call to this function will return the chip structure corresponding to the TPM you are looking for that can then be sent with your command to tpm_transmit.
    6.86 - * Passing 0 as the argument corresponds to /dev/tpm0 and thus the first and probably primary TPM on the system.  Passing 1 corresponds to /dev/tpm1 and the next TPM discovered.  If a TPM with the given chip_num does not exist NULL will be returned.
    6.87 - */
    6.88 -struct tpm_chip* tpm_chip_lookup(int chip_num)
    6.89 -{
    6.90 -
    6.91 -	struct tpm_chip *pos;
    6.92 -	list_for_each_entry(pos, &tpm_chip_list, list)
    6.93 -		if (pos->dev_num == chip_num ||
    6.94 -		    chip_num == TPM_ANY_NUM)
    6.95 -			return pos;
    6.96 -
    6.97 -	return NULL;
    6.98 -
    6.99 -}
   6.100 -
   6.101 -/*
   6.102 - * Internal kernel interface to transmit TPM commands
   6.103 - */
   6.104 -ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
   6.105 -		     size_t bufsiz)
   6.106 -{
   6.107 -	ssize_t rc;
   6.108 -	u32 count;
   6.109 -	unsigned long stop;
   6.110 -
   6.111 -	count = be32_to_cpu(*((__be32 *) (buf + 2)));
   6.112 -
   6.113 -	if (count == 0)
   6.114 -		return -ENODATA;
   6.115 -	if (count > bufsiz) {
   6.116 -		dev_err(chip->dev,
   6.117 -			"invalid count value %x %x \n", count, bufsiz);
   6.118 -		return -E2BIG;
   6.119 -	}
   6.120 -
   6.121 -	dev_dbg(chip->dev, "TPM Ordinal: %d\n",
   6.122 -		be32_to_cpu(*((__be32 *) (buf + 6))));
   6.123 -	dev_dbg(chip->dev, "Chip Status: %x\n",
   6.124 -		inb(chip->vendor->base + 1));
   6.125 -
   6.126 -	down(&chip->tpm_mutex);
   6.127 -
   6.128 -	if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
   6.129 -		dev_err(chip->dev,
   6.130 -			"tpm_transmit: tpm_send: error %d\n", rc);
   6.131 -		goto out;
   6.132 -	}
   6.133 -
   6.134 -	stop = jiffies + 2 * 60 * HZ;
   6.135 -	do {
   6.136 -		u8 status = chip->vendor->status(chip);
   6.137 -		if ((status & chip->vendor->req_complete_mask) ==
   6.138 -		    chip->vendor->req_complete_val) {
   6.139 -			goto out_recv;
   6.140 -		}
   6.141 -
   6.142 -		if ((status == chip->vendor->req_canceled)) {
   6.143 -			dev_err(chip->dev, "Operation Canceled\n");
   6.144 -			rc = -ECANCELED;
   6.145 -			goto out;
   6.146 -		}
   6.147 -
   6.148 -		msleep(TPM_TIMEOUT);	/* CHECK */
   6.149 -		rmb();
   6.150 -	}
   6.151 -	while (time_before(jiffies, stop));
   6.152 -
   6.153 -
   6.154 -	chip->vendor->cancel(chip);
   6.155 -	dev_err(chip->dev, "Operation Timed out\n");
   6.156 -	rc = -ETIME;
   6.157 -	goto out;
   6.158 -
   6.159 -out_recv:
   6.160 -	rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
   6.161 -	if (rc < 0)
   6.162 -		dev_err(chip->dev,
   6.163 -			"tpm_transmit: tpm_recv: error %d\n", rc);
   6.164 -	atomic_set(&chip->data_position, 0);
   6.165 -
   6.166 -out:
   6.167 -	up(&chip->tpm_mutex);
   6.168 -	return rc;
   6.169 -}
   6.170 -
   6.171 -EXPORT_SYMBOL_GPL(tpm_transmit);
   6.172 -
   6.173 -#define TPM_DIGEST_SIZE 20
   6.174 -#define CAP_PCR_RESULT_SIZE 18
   6.175 -static const u8 cap_pcr[] = {
   6.176 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.177 -	0, 0, 0, 22,		/* length */
   6.178 -	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   6.179 -	0, 0, 0, 5,
   6.180 -	0, 0, 0, 4,
   6.181 -	0, 0, 1, 1
   6.182 -};
   6.183 -
   6.184 -#define READ_PCR_RESULT_SIZE 30
   6.185 -static const u8 pcrread[] = {
   6.186 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.187 -	0, 0, 0, 14,		/* length */
   6.188 -	0, 0, 0, 21,		/* TPM_ORD_PcrRead */
   6.189 -	0, 0, 0, 0		/* PCR index */
   6.190 -};
   6.191 -
   6.192 -ssize_t tpm_show_pcrs(struct device *dev, char *buf)
   6.193 -{
   6.194 -	u8 data[READ_PCR_RESULT_SIZE];
   6.195 -	ssize_t len;
   6.196 -	int i, j, num_pcrs;
   6.197 -	__be32 index;
   6.198 -	char *str = buf;
   6.199 -
   6.200 -	struct tpm_chip *chip = dev_get_drvdata(dev);
   6.201 -	if (chip == NULL)
   6.202 -		return -ENODEV;
   6.203 -
   6.204 -	memcpy(data, cap_pcr, sizeof(cap_pcr));
   6.205 -	if ((len = tpm_transmit(chip, data, sizeof(data)))
   6.206 -	    < CAP_PCR_RESULT_SIZE)
   6.207 -		return len;
   6.208 -
   6.209 -	num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
   6.210 -
   6.211 -	for (i = 0; i < num_pcrs; i++) {
   6.212 -		memcpy(data, pcrread, sizeof(pcrread));
   6.213 -		index = cpu_to_be32(i);
   6.214 -		memcpy(data + 10, &index, 4);
   6.215 -		if ((len = tpm_transmit(chip, data, sizeof(data)))
   6.216 -		    < READ_PCR_RESULT_SIZE)
   6.217 -			return len;
   6.218 -		str += sprintf(str, "PCR-%02d: ", i);
   6.219 -		for (j = 0; j < TPM_DIGEST_SIZE; j++)
   6.220 -			str += sprintf(str, "%02X ", *(data + 10 + j));
   6.221 -		str += sprintf(str, "\n");
   6.222 -	}
   6.223 -	return str - buf;
   6.224 -}
   6.225 -
   6.226 -EXPORT_SYMBOL_GPL(tpm_show_pcrs);
   6.227 -
   6.228 -/*
   6.229 - * Return 0 on success.  On error pass along error code.
   6.230 - * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
   6.231 - * Lower 2 bytes equal tpm idx # or AN&
   6.232 - * res_buf must fit a TPM_PCR (20 bytes) or NULL if you don't care
   6.233 - */
   6.234 -int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size )
   6.235 -{
   6.236 -	u8 data[READ_PCR_RESULT_SIZE];
   6.237 -	int rc;
   6.238 -	__be32 index;
   6.239 -	int chip_num = chip_id & TPM_CHIP_NUM_MASK;
   6.240 -	struct tpm_chip* chip;
   6.241 -
   6.242 -	if ( res_buf && res_buf_size < TPM_DIGEST_SIZE )
   6.243 -		return -ENOSPC;
   6.244 -	if ( (chip = tpm_chip_lookup( chip_num /*,
   6.245 -				       chip_id >> TPM_CHIP_TYPE_SHIFT*/ ) ) == NULL ) {
   6.246 -		printk("chip %d not found.\n",chip_num);
   6.247 -		return -ENODEV;
   6.248 -	}
   6.249 -	memcpy(data, pcrread, sizeof(pcrread));
   6.250 -	index = cpu_to_be32(pcr_idx);
   6.251 -	memcpy(data + 10, &index, 4);
   6.252 -	if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
   6.253 -		rc = be32_to_cpu(*((u32*)(data+6)));
   6.254 -
   6.255 -	if ( rc == 0 && res_buf )
   6.256 -		memcpy(res_buf, data+10, TPM_DIGEST_SIZE);
   6.257 -	return rc;
   6.258 -}
   6.259 -EXPORT_SYMBOL_GPL(tpm_pcr_read);
   6.260 -
   6.261 -#define EXTEND_PCR_SIZE 34
   6.262 -static const u8 pcrextend[] = {
   6.263 -	0, 193,		 		 		 /* TPM_TAG_RQU_COMMAND */
   6.264 -	0, 0, 0, 34,		 		 /* length */
   6.265 -	0, 0, 0, 20,		 		 /* TPM_ORD_Extend */
   6.266 -	0, 0, 0, 0		 		 /* PCR index */
   6.267 -};
   6.268 -
   6.269 -/*
   6.270 - * Return 0 on success.  On error pass along error code.
   6.271 - * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
   6.272 - * Lower 2 bytes equal tpm idx # or ANY
   6.273 - */
   6.274 -int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash)
   6.275 -{
   6.276 -	u8 data[EXTEND_PCR_SIZE];
   6.277 -	int rc;
   6.278 -	__be32 index;
   6.279 -	int chip_num = chip_id & TPM_CHIP_NUM_MASK;
   6.280 -	struct tpm_chip* chip;
   6.281 -
   6.282 -	if ( (chip = tpm_chip_lookup( chip_num /*,
   6.283 -				      chip_id >> TPM_CHIP_TYPE_SHIFT */)) == NULL )
   6.284 -		return -ENODEV;
   6.285 -
   6.286 -	memcpy(data, pcrextend, sizeof(pcrextend));
   6.287 -	index = cpu_to_be32(pcr_idx);
   6.288 -	memcpy(data + 10, &index, 4);
   6.289 -	memcpy( data + 14, hash, TPM_DIGEST_SIZE );
   6.290 -	if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
   6.291 -		rc = be32_to_cpu(*((u32*)(data+6)));
   6.292 -	return rc;
   6.293 -}
   6.294 -EXPORT_SYMBOL_GPL(tpm_pcr_extend);
   6.295 -
   6.296 -
   6.297 -
   6.298 -#define  READ_PUBEK_RESULT_SIZE 314
   6.299 -static const u8 readpubek[] = {
   6.300 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.301 -	0, 0, 0, 30,		/* length */
   6.302 -	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
   6.303 -};
   6.304 -
   6.305 -ssize_t tpm_show_pubek(struct device *dev, char *buf)
   6.306 -{
   6.307 -	u8 *data;
   6.308 -	ssize_t len;
   6.309 -	int i, rc;
   6.310 -	char *str = buf;
   6.311 -
   6.312 -	struct tpm_chip *chip = dev_get_drvdata(dev);
   6.313 -	if (chip == NULL)
   6.314 -		return -ENODEV;
   6.315 -
   6.316 -	data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
   6.317 -	if (!data)
   6.318 -		return -ENOMEM;
   6.319 -
   6.320 -	memcpy(data, readpubek, sizeof(readpubek));
   6.321 -	memset(data + sizeof(readpubek), 0, 20);	/* zero nonce */
   6.322 -
   6.323 -	if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
   6.324 -	    READ_PUBEK_RESULT_SIZE) {
   6.325 -		rc = len;
   6.326 -		goto out;
   6.327 -	}
   6.328 -
   6.329 -	/*
   6.330 -	   ignore header 10 bytes
   6.331 -	   algorithm 32 bits (1 == RSA )
   6.332 -	   encscheme 16 bits
   6.333 -	   sigscheme 16 bits
   6.334 -	   parameters (RSA 12->bytes: keybit, #primes, expbit)
   6.335 -	   keylenbytes 32 bits
   6.336 -	   256 byte modulus
   6.337 -	   ignore checksum 20 bytes
   6.338 -	 */
   6.339 -
   6.340 -	str +=
   6.341 -	    sprintf(str,
   6.342 -		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
   6.343 -		    "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
   6.344 -		    " %02X %02X %02X %02X %02X %02X %02X %02X\n"
   6.345 -		    "Modulus length: %d\nModulus: \n",
   6.346 -		    data[10], data[11], data[12], data[13], data[14],
   6.347 -		    data[15], data[16], data[17], data[22], data[23],
   6.348 -		    data[24], data[25], data[26], data[27], data[28],
   6.349 -		    data[29], data[30], data[31], data[32], data[33],
   6.350 -		    be32_to_cpu(*((__be32 *) (data + 32))));
   6.351 -
   6.352 -	for (i = 0; i < 256; i++) {
   6.353 -		str += sprintf(str, "%02X ", data[i + 39]);
   6.354 -		if ((i + 1) % 16 == 0)
   6.355 -			str += sprintf(str, "\n");
   6.356 -	}
   6.357 -	rc = str - buf;
   6.358 -out:
   6.359 -	kfree(data);
   6.360 -	return rc;
   6.361 -}
   6.362 -
   6.363 -EXPORT_SYMBOL_GPL(tpm_show_pubek);
   6.364 -
   6.365 -#define CAP_VER_RESULT_SIZE 18
   6.366 -static const u8 cap_version[] = {
   6.367 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.368 -	0, 0, 0, 18,		/* length */
   6.369 -	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   6.370 -	0, 0, 0, 6,
   6.371 -	0, 0, 0, 0
   6.372 -};
   6.373 -
   6.374 -#define CAP_MANUFACTURER_RESULT_SIZE 18
   6.375 -static const u8 cap_manufacturer[] = {
   6.376 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.377 -	0, 0, 0, 22,		/* length */
   6.378 -	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
   6.379 -	0, 0, 0, 5,
   6.380 -	0, 0, 0, 4,
   6.381 -	0, 0, 1, 3
   6.382 -};
   6.383 -
   6.384 -ssize_t tpm_show_caps(struct device *dev, char *buf)
   6.385 -{
   6.386 -	u8 data[sizeof(cap_manufacturer)];
   6.387 -	ssize_t len;
   6.388 -	char *str = buf;
   6.389 -
   6.390 -	struct tpm_chip *chip = dev_get_drvdata(dev);
   6.391 -	if (chip == NULL)
   6.392 -		return -ENODEV;
   6.393 -
   6.394 -	memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
   6.395 -
   6.396 -	if ((len = tpm_transmit(chip, data, sizeof(data))) <
   6.397 -	    CAP_MANUFACTURER_RESULT_SIZE)
   6.398 -		return len;
   6.399 -
   6.400 -	str += sprintf(str, "Manufacturer: 0x%x\n",
   6.401 -		       be32_to_cpu(*((__be32 *)(data + 14))));
   6.402 -
   6.403 -	memcpy(data, cap_version, sizeof(cap_version));
   6.404 -
   6.405 -	if ((len = tpm_transmit(chip, data, sizeof(data))) <
   6.406 -	    CAP_VER_RESULT_SIZE)
   6.407 -		return len;
   6.408 -
   6.409 -	str +=
   6.410 -	    sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
   6.411 -		    (int) data[14], (int) data[15], (int) data[16],
   6.412 -		    (int) data[17]);
   6.413 -
   6.414 -	return str - buf;
   6.415 -}
   6.416 -
   6.417 -EXPORT_SYMBOL_GPL(tpm_show_caps);
   6.418 -
   6.419 -ssize_t tpm_store_cancel(struct device * dev, const char *buf,
   6.420 -			 size_t count)
   6.421 -{
   6.422 -	struct tpm_chip *chip = dev_get_drvdata(dev);
   6.423 -	if (chip == NULL)
   6.424 -		return 0;
   6.425 -
   6.426 -	chip->vendor->cancel(chip);
   6.427 -	return count;
   6.428 -}
   6.429 -
   6.430 -EXPORT_SYMBOL_GPL(tpm_store_cancel);
   6.431 -
   6.432 -/*
   6.433 - * Device file system interface to the TPM
   6.434 - */
   6.435 -int tpm_open(struct inode *inode, struct file *file)
   6.436 -{
   6.437 -	int rc = 0, minor = iminor(inode);
   6.438 -	struct tpm_chip *chip = NULL, *pos;
   6.439 -
   6.440 -	spin_lock(&driver_lock);
   6.441 -
   6.442 -	list_for_each_entry(pos, &tpm_chip_list, list) {
   6.443 -		if (pos->vendor->miscdev.minor == minor) {
   6.444 -			chip = pos;
   6.445 -			break;
   6.446 -		}
   6.447 -	}
   6.448 -
   6.449 -	if (chip == NULL) {
   6.450 -		rc = -ENODEV;
   6.451 -		goto err_out;
   6.452 -	}
   6.453 -
   6.454 -	if (chip->num_opens) {
   6.455 -		dev_dbg(chip->dev, "Another process owns this TPM\n");
   6.456 -		rc = -EBUSY;
   6.457 -		goto err_out;
   6.458 -	}
   6.459 -
   6.460 -	chip->num_opens++;
   6.461 -	get_device(chip->dev);
   6.462 -
   6.463 -	spin_unlock(&driver_lock);
   6.464 -
   6.465 -	chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8),
   6.466 -	                            GFP_KERNEL);
   6.467 -	if (chip->data_buffer == NULL) {
   6.468 -		chip->num_opens--;
   6.469 -		put_device(chip->dev);
   6.470 -		return -ENOMEM;
   6.471 -	}
   6.472 -
   6.473 -	atomic_set(&chip->data_pending, 0);
   6.474 -
   6.475 -	file->private_data = chip;
   6.476 -	return 0;
   6.477 -
   6.478 -err_out:
   6.479 -	spin_unlock(&driver_lock);
   6.480 -	return rc;
   6.481 -}
   6.482 -
   6.483 -EXPORT_SYMBOL_GPL(tpm_open);
   6.484 -
   6.485 -int tpm_release(struct inode *inode, struct file *file)
   6.486 -{
   6.487 -	struct tpm_chip *chip = file->private_data;
   6.488 -
   6.489 -	spin_lock(&driver_lock);
   6.490 -	file->private_data = NULL;
   6.491 -	chip->num_opens--;
   6.492 -	del_singleshot_timer_sync(&chip->user_read_timer);
   6.493 -	atomic_set(&chip->data_pending, 0);
   6.494 -	put_device(chip->dev);
   6.495 -	kfree(chip->data_buffer);
   6.496 -	spin_unlock(&driver_lock);
   6.497 -	return 0;
   6.498 -}
   6.499 -
   6.500 -EXPORT_SYMBOL_GPL(tpm_release);
   6.501 -
   6.502 -ssize_t tpm_write(struct file * file, const char __user * buf,
   6.503 -		  size_t size, loff_t * off)
   6.504 -{
   6.505 -	struct tpm_chip *chip = file->private_data;
   6.506 -	int in_size = size, out_size;
   6.507 -
   6.508 -	/* cannot perform a write until the read has cleared
   6.509 -	   either via tpm_read or a user_read_timer timeout */
   6.510 -	while (atomic_read(&chip->data_pending) != 0)
   6.511 -		msleep(TPM_TIMEOUT);
   6.512 -
   6.513 -	down(&chip->buffer_mutex);
   6.514 -
   6.515 -	if (in_size > chip->vendor->buffersize)
   6.516 -		in_size = chip->vendor->buffersize;
   6.517 -
   6.518 -	if (copy_from_user
   6.519 -	    (chip->data_buffer, (void __user *) buf, in_size)) {
   6.520 -		up(&chip->buffer_mutex);
   6.521 -		return -EFAULT;
   6.522 -	}
   6.523 -
   6.524 -	/* atomic tpm command send and result receive */
   6.525 -	out_size = tpm_transmit(chip,
   6.526 -	                        chip->data_buffer,
   6.527 -	                        chip->vendor->buffersize);
   6.528 -
   6.529 -	atomic_set(&chip->data_pending, out_size);
   6.530 -	up(&chip->buffer_mutex);
   6.531 -
   6.532 -	/* Set a timeout by which the reader must come claim the result */
   6.533 -	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
   6.534 -
   6.535 -	return in_size;
   6.536 -}
   6.537 -
   6.538 -EXPORT_SYMBOL_GPL(tpm_write);
   6.539 -
   6.540 -ssize_t tpm_read(struct file * file, char __user * buf,
   6.541 -		 size_t size, loff_t * off)
   6.542 -{
   6.543 -	struct tpm_chip *chip = file->private_data;
   6.544 -	int ret_size;
   6.545 -
   6.546 -	del_singleshot_timer_sync(&chip->user_read_timer);
   6.547 -	ret_size = atomic_read(&chip->data_pending);
   6.548 -
   6.549 -	if (ret_size > 0) {	/* relay data */
   6.550 -		int position = atomic_read(&chip->data_position);
   6.551 -
   6.552 -		if (size < ret_size)
   6.553 -			ret_size = size;
   6.554 -
   6.555 -		down(&chip->buffer_mutex);
   6.556 -
   6.557 -		if (copy_to_user((void __user *) buf,
   6.558 -				 &chip->data_buffer[position],
   6.559 -				 ret_size)) {
   6.560 -			ret_size = -EFAULT;
   6.561 -		} else {
   6.562 -		 	int pending = atomic_read(&chip->data_pending) - ret_size;
   6.563 -			atomic_set(&chip->data_pending,
   6.564 -			           pending);
   6.565 -			atomic_set(&chip->data_position,
   6.566 -			           position + ret_size);
   6.567 -		}
   6.568 -		up(&chip->buffer_mutex);
   6.569 -	}
   6.570 -
   6.571 -	return ret_size;
   6.572 -}
   6.573 -
   6.574 -EXPORT_SYMBOL_GPL(tpm_read);
   6.575 -
   6.576 -void tpm_remove_hardware(struct device *dev)
   6.577 -{
   6.578 -	struct tpm_chip *chip = dev_get_drvdata(dev);
   6.579 -	int i;
   6.580 -
   6.581 -	if (chip == NULL) {
   6.582 -		dev_err(dev, "No device data found\n");
   6.583 -		return;
   6.584 -	}
   6.585 -
   6.586 -	spin_lock(&driver_lock);
   6.587 -
   6.588 -	list_del(&chip->list);
   6.589 -
   6.590 -	spin_unlock(&driver_lock);
   6.591 -
   6.592 -	dev_set_drvdata(dev, NULL);
   6.593 -	misc_deregister(&chip->vendor->miscdev);
   6.594 -
   6.595 -	for (i = 0; i < TPM_NUM_ATTR; i++)
   6.596 -		device_remove_file(dev, &chip->vendor->attr[i]);
   6.597 -
   6.598 -	dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &=
   6.599 -	    !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
   6.600 -
   6.601 -	kfree(chip);
   6.602 -
   6.603 -	put_device(dev);
   6.604 -}
   6.605 -
   6.606 -EXPORT_SYMBOL_GPL(tpm_remove_hardware);
   6.607 -
   6.608 -static const u8 savestate[] = {
   6.609 -	0, 193,			/* TPM_TAG_RQU_COMMAND */
   6.610 -	0, 0, 0, 10,		/* blob length (in bytes) */
   6.611 -	0, 0, 0, 152		/* TPM_ORD_SaveState */
   6.612 -};
   6.613 -
   6.614 -/*
   6.615 - * We are about to suspend. Save the TPM state
   6.616 - * so that it can be restored.
   6.617 - */
   6.618 -int tpm_pm_suspend(struct pci_dev *pci_dev, u32 pm_state)
   6.619 -{
   6.620 -	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   6.621 -	if (chip == NULL)
   6.622 -		return -ENODEV;
   6.623 -
   6.624 -	tpm_transmit(chip, savestate, sizeof(savestate));
   6.625 -	return 0;
   6.626 -}
   6.627 -
   6.628 -EXPORT_SYMBOL_GPL(tpm_pm_suspend);
   6.629 -
   6.630 -/*
   6.631 - * Resume from a power safe. The BIOS already restored
   6.632 - * the TPM state.
   6.633 - */
   6.634 -int tpm_pm_resume(struct pci_dev *pci_dev)
   6.635 -{
   6.636 -	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   6.637 -
   6.638 -	if (chip == NULL)
   6.639 -		return -ENODEV;
   6.640 -
   6.641 -	return 0;
   6.642 -}
   6.643 -
   6.644 -EXPORT_SYMBOL_GPL(tpm_pm_resume);
   6.645 -
   6.646 -/*
   6.647 - * Called from tpm_<specific>.c probe function only for devices
   6.648 - * the driver has determined it should claim.  Prior to calling
   6.649 - * this function the specific probe function has called pci_enable_device
   6.650 - * upon errant exit from this function specific probe function should call
   6.651 - * pci_disable_device
   6.652 - */
   6.653 -int tpm_register_hardware_nopci(struct device *dev,
   6.654 -			        struct tpm_vendor_specific *entry)
   6.655 -{
   6.656 -	char devname[7];
   6.657 -	struct tpm_chip *chip;
   6.658 -	int i, j;
   6.659 -
   6.660 -	/* Driver specific per-device data */
   6.661 -	chip = kmalloc(sizeof(*chip), GFP_KERNEL);
   6.662 -	if (chip == NULL)
   6.663 -		return -ENOMEM;
   6.664 -
   6.665 -	memset(chip, 0, sizeof(struct tpm_chip));
   6.666 -
   6.667 -	init_MUTEX(&chip->buffer_mutex);
   6.668 -	init_MUTEX(&chip->tpm_mutex);
   6.669 -	INIT_LIST_HEAD(&chip->list);
   6.670 -
   6.671 -	init_timer(&chip->user_read_timer);
   6.672 -	chip->user_read_timer.function = user_reader_timeout;
   6.673 -	chip->user_read_timer.data = (unsigned long) chip;
   6.674 -
   6.675 -	chip->vendor = entry;
   6.676 -
   6.677 -	if (entry->buffersize < TPM_MIN_BUFSIZE) {
   6.678 -		entry->buffersize = TPM_MIN_BUFSIZE;
   6.679 -	} else if (entry->buffersize > TPM_MAX_BUFSIZE) {
   6.680 -		entry->buffersize = TPM_MAX_BUFSIZE;
   6.681 -	}
   6.682 -
   6.683 -	chip->dev_num = -1;
   6.684 -
   6.685 -	for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
   6.686 -		for (j = 0; j < 8 * sizeof(int); j++)
   6.687 -			if ((dev_mask[i] & (1 << j)) == 0) {
   6.688 -				chip->dev_num =
   6.689 -				    i * TPM_NUM_MASK_ENTRIES + j;
   6.690 -				dev_mask[i] |= 1 << j;
   6.691 -				goto dev_num_search_complete;
   6.692 -			}
   6.693 -
   6.694 -dev_num_search_complete:
   6.695 -	if (chip->dev_num < 0) {
   6.696 -		dev_err(dev, "No available tpm device numbers\n");
   6.697 -		kfree(chip);
   6.698 -		return -ENODEV;
   6.699 -	} else if (chip->dev_num == 0)
   6.700 -		chip->vendor->miscdev.minor = TPM_MINOR;
   6.701 -	else
   6.702 -		chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
   6.703 -
   6.704 -	snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
   6.705 -	chip->vendor->miscdev.name = devname;
   6.706 -
   6.707 -	chip->vendor->miscdev.dev = dev;
   6.708 -	chip->dev = get_device(dev);
   6.709 -
   6.710 -
   6.711 -	if (misc_register(&chip->vendor->miscdev)) {
   6.712 -		dev_err(chip->dev,
   6.713 -			"unable to misc_register %s, minor %d\n",
   6.714 -			chip->vendor->miscdev.name,
   6.715 -			chip->vendor->miscdev.minor);
   6.716 -		put_device(dev);
   6.717 -		kfree(chip);
   6.718 -		dev_mask[i] &= !(1 << j);
   6.719 -		return -ENODEV;
   6.720 -	}
   6.721 -
   6.722 -	spin_lock(&driver_lock);
   6.723 -
   6.724 -	dev_set_drvdata(dev, chip);
   6.725 -
   6.726 -	list_add(&chip->list, &tpm_chip_list);
   6.727 -
   6.728 -	spin_unlock(&driver_lock);
   6.729 -
   6.730 -	for (i = 0; i < TPM_NUM_ATTR; i++)
   6.731 -		device_create_file(dev, &chip->vendor->attr[i]);
   6.732 -
   6.733 -	return 0;
   6.734 -}
   6.735 -
   6.736 -EXPORT_SYMBOL_GPL(tpm_register_hardware_nopci);
   6.737 -
   6.738 -static int __init init_tpm(void)
   6.739 -{
   6.740 -	return 0;
   6.741 -}
   6.742 -
   6.743 -static void __exit cleanup_tpm(void)
   6.744 -{
   6.745 -
   6.746 -}
   6.747 -
   6.748 -module_init(init_tpm);
   6.749 -module_exit(cleanup_tpm);
   6.750 -
   6.751 -MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
   6.752 -MODULE_DESCRIPTION("TPM Driver");
   6.753 -MODULE_VERSION("2.0");
   6.754 -MODULE_LICENSE("GPL");
     7.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h	Wed Oct 05 13:41:59 2005 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,128 +0,0 @@
     7.4 -/*
     7.5 - * Copyright (C) 2004 IBM Corporation
     7.6 - *
     7.7 - * Authors:
     7.8 - * Leendert van Doorn <leendert@watson.ibm.com>
     7.9 - * Dave Safford <safford@watson.ibm.com>
    7.10 - * Reiner Sailer <sailer@watson.ibm.com>
    7.11 - * Kylene Hall <kjhall@us.ibm.com>
    7.12 - *
    7.13 - * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    7.14 - *
    7.15 - * Device driver for TCG/TCPA TPM (trusted platform module).
    7.16 - * Specifications at www.trustedcomputinggroup.org
    7.17 - *
    7.18 - * This program is free software; you can redistribute it and/or
    7.19 - * modify it under the terms of the GNU General Public License as
    7.20 - * published by the Free Software Foundation, version 2 of the
    7.21 - * License.
    7.22 - *
    7.23 - */
    7.24 -#include <linux/module.h>
    7.25 -#include <linux/version.h>
    7.26 -#include <linux/pci.h>
    7.27 -#include <linux/delay.h>
    7.28 -#include <linux/miscdevice.h>
    7.29 -
    7.30 -enum {
    7.31 -	TPM_TIMEOUT = 5,	/* msecs */
    7.32 -	TPM_NUM_ATTR = 4
    7.33 -};
    7.34 -
    7.35 -/* TPM addresses */
    7.36 -enum {
    7.37 -	TPM_ADDR = 0x4E,
    7.38 -	TPM_DATA = 0x4F
    7.39 -};
    7.40 -
    7.41 -/*
    7.42 - * Chip num is this value or a valid tpm idx in lower two bytes of chip_id
    7.43 - */
    7.44 -enum tpm_chip_num {
    7.45 -	TPM_ANY_NUM = 0xFFFF,
    7.46 -};
    7.47 -
    7.48 -#define TPM_CHIP_NUM_MASK	0x0000ffff
    7.49 -
    7.50 -extern ssize_t tpm_show_pubek(struct device *, char *);
    7.51 -extern ssize_t tpm_show_pcrs(struct device *, char *);
    7.52 -extern ssize_t tpm_show_caps(struct device *, char *);
    7.53 -extern ssize_t tpm_store_cancel(struct device *, const char *, size_t);
    7.54 -
    7.55 -#define TPM_DEVICE_ATTRS { \
    7.56 -	__ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL), \
    7.57 -	__ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL), \
    7.58 -	__ATTR(caps, S_IRUGO, tpm_show_caps, NULL), \
    7.59 -	__ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel) }
    7.60 -
    7.61 -struct tpm_chip;
    7.62 -
    7.63 -struct tpm_vendor_specific {
    7.64 -	u8 req_complete_mask;
    7.65 -	u8 req_complete_val;
    7.66 -	u8 req_canceled;
    7.67 -	u16 base;		/* TPM base address */
    7.68 -	u32 buffersize;         /* The device's requested buffersize */
    7.69 -
    7.70 -	int (*recv) (struct tpm_chip *, u8 *, size_t);
    7.71 -	int (*send) (struct tpm_chip *, u8 *, size_t);
    7.72 -	void (*cancel) (struct tpm_chip *);
    7.73 -	 u8(*status) (struct tpm_chip *);
    7.74 -	struct miscdevice miscdev;
    7.75 -	struct device_attribute attr[TPM_NUM_ATTR];
    7.76 -};
    7.77 -
    7.78 -struct tpm_chip {
    7.79 -	struct device *dev;	/* PCI device stuff */
    7.80 -
    7.81 -	int dev_num;		/* /dev/tpm# */
    7.82 -	int num_opens;		/* only one allowed */
    7.83 -	int time_expired;
    7.84 -
    7.85 -	/* Data passed to and from the tpm via the read/write calls */
    7.86 -	u8 *data_buffer;
    7.87 -	atomic_t data_pending;
    7.88 -	atomic_t data_position;
    7.89 -	struct semaphore buffer_mutex;
    7.90 -
    7.91 -	struct timer_list user_read_timer;	/* user needs to claim result */
    7.92 -	struct semaphore tpm_mutex;	/* tpm is processing */
    7.93 -
    7.94 -	struct tpm_vendor_specific *vendor;
    7.95 -
    7.96 -	struct list_head list;
    7.97 -};
    7.98 -
    7.99 -static inline int tpm_read_index(int index)
   7.100 -{
   7.101 -	outb(index, TPM_ADDR);
   7.102 -	return inb(TPM_DATA) & 0xFF;
   7.103 -}
   7.104 -
   7.105 -static inline void tpm_write_index(int index, int value)
   7.106 -{
   7.107 -	outb(index, TPM_ADDR);
   7.108 -	outb(value & 0xFF, TPM_DATA);
   7.109 -}
   7.110 -
   7.111 -extern void tpm_time_expired(unsigned long);
   7.112 -extern int tpm_lpc_bus_init(struct pci_dev *, u16);
   7.113 -
   7.114 -extern int tpm_register_hardware_nopci(struct device *,
   7.115 -				       struct tpm_vendor_specific *);
   7.116 -extern void tpm_remove_hardware(struct device *);
   7.117 -extern int tpm_open(struct inode *, struct file *);
   7.118 -extern int tpm_release(struct inode *, struct file *);
   7.119 -extern ssize_t tpm_write(struct file *, const char __user *, size_t,
   7.120 -			 loff_t *);
   7.121 -extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
   7.122 -extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash);
   7.123 -extern int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size );
   7.124 -
   7.125 -extern int tpm_pm_suspend(struct pci_dev *, u32);
   7.126 -extern int tpm_pm_resume(struct pci_dev *);
   7.127 -
   7.128 -/* internal kernel interface */
   7.129 -extern ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
   7.130 -			    size_t bufsiz);
   7.131 -extern struct tpm_chip *tpm_chip_lookup(int chip_num);
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c	Wed Oct 05 13:52:18 2005 +0100
     8.3 @@ -0,0 +1,386 @@
     8.4 +/*
     8.5 + * Copyright (C) 2004 IBM Corporation
     8.6 + *
     8.7 + * Authors:
     8.8 + * Leendert van Doorn <leendert@watson.ibm.com>
     8.9 + * Dave Safford <safford@watson.ibm.com>
    8.10 + * Reiner Sailer <sailer@watson.ibm.com>
    8.11 + * Kylene Hall <kjhall@us.ibm.com>
    8.12 + *
    8.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net>
    8.14 + *
    8.15 + * Device driver for TCG/TCPA TPM (trusted platform module).
    8.16 + * Specifications at www.trustedcomputinggroup.org	 
    8.17 + *
    8.18 + * This program is free software; you can redistribute it and/or
    8.19 + * modify it under the terms of the GNU General Public License as
    8.20 + * published by the Free Software Foundation, version 2 of the
    8.21 + * License.
    8.22 + * 
    8.23 + */
    8.24 +
    8.25 +#include "tpm.h"
    8.26 +
    8.27 +/* National definitions */
    8.28 +enum tpm_nsc_addr{
    8.29 +	TPM_NSC_IRQ = 0x07,
    8.30 +	TPM_NSC_BASE0_HI = 0x60,
    8.31 +	TPM_NSC_BASE0_LO = 0x61,
    8.32 +	TPM_NSC_BASE1_HI = 0x62,
    8.33 +	TPM_NSC_BASE1_LO = 0x63
    8.34 +};
    8.35 +
    8.36 +enum tpm_nsc_index {
    8.37 +	NSC_LDN_INDEX = 0x07,
    8.38 +	NSC_SID_INDEX = 0x20,
    8.39 +	NSC_LDC_INDEX = 0x30,
    8.40 +	NSC_DIO_INDEX = 0x60,
    8.41 +	NSC_CIO_INDEX = 0x62,
    8.42 +	NSC_IRQ_INDEX = 0x70,
    8.43 +	NSC_ITS_INDEX = 0x71
    8.44 +};
    8.45 +
    8.46 +enum tpm_nsc_status_loc {
    8.47 +	NSC_STATUS = 0x01,
    8.48 +	NSC_COMMAND = 0x01,
    8.49 +	NSC_DATA = 0x00
    8.50 +};
    8.51 +
    8.52 +/* status bits */
    8.53 +enum tpm_nsc_status {
    8.54 +	NSC_STATUS_OBF = 0x01,	/* output buffer full */
    8.55 +	NSC_STATUS_IBF = 0x02,	/* input buffer full */
    8.56 +	NSC_STATUS_F0 = 0x04,	/* F0 */
    8.57 +	NSC_STATUS_A2 = 0x08,	/* A2 */
    8.58 +	NSC_STATUS_RDY = 0x10,	/* ready to receive command */
    8.59 +	NSC_STATUS_IBR = 0x20	/* ready to receive data */
    8.60 +};
    8.61 +
    8.62 +/* command bits */
    8.63 +enum tpm_nsc_cmd_mode {
    8.64 +	NSC_COMMAND_NORMAL = 0x01,	/* normal mode */
    8.65 +	NSC_COMMAND_EOC = 0x03,
    8.66 +	NSC_COMMAND_CANCEL = 0x22
    8.67 +};
    8.68 +/*
    8.69 + * Wait for a certain status to appear
    8.70 + */
    8.71 +static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
    8.72 +{
    8.73 +	unsigned long stop;
    8.74 +
    8.75 +	/* status immediately available check */
    8.76 +	*data = inb(chip->vendor->base + NSC_STATUS);
    8.77 +	if ((*data & mask) == val)
    8.78 +		return 0;
    8.79 +
    8.80 +	/* wait for status */
    8.81 +	stop = jiffies + 10 * HZ;
    8.82 +	do {
    8.83 +		msleep(TPM_TIMEOUT);
    8.84 +		*data = inb(chip->vendor->base + 1);
    8.85 +		if ((*data & mask) == val)
    8.86 +			return 0;
    8.87 +	}
    8.88 +	while (time_before(jiffies, stop));
    8.89 +
    8.90 +	return -EBUSY;
    8.91 +}
    8.92 +
    8.93 +static int nsc_wait_for_ready(struct tpm_chip *chip)
    8.94 +{
    8.95 +	int status;
    8.96 +	unsigned long stop;
    8.97 +
    8.98 +	/* status immediately available check */
    8.99 +	status = inb(chip->vendor->base + NSC_STATUS);
   8.100 +	if (status & NSC_STATUS_OBF)
   8.101 +		status = inb(chip->vendor->base + NSC_DATA);
   8.102 +	if (status & NSC_STATUS_RDY)
   8.103 +		return 0;
   8.104 +
   8.105 +	/* wait for status */
   8.106 +	stop = jiffies + 100;
   8.107 +	do {
   8.108 +		msleep(TPM_TIMEOUT);
   8.109 +		status = inb(chip->vendor->base + NSC_STATUS);
   8.110 +		if (status & NSC_STATUS_OBF)
   8.111 +			status = inb(chip->vendor->base + NSC_DATA);
   8.112 +		if (status & NSC_STATUS_RDY)
   8.113 +			return 0;
   8.114 +	}
   8.115 +	while (time_before(jiffies, stop));
   8.116 +
   8.117 +	dev_info(chip->dev, "wait for ready failed\n");
   8.118 +	return -EBUSY;
   8.119 +}
   8.120 +
   8.121 +
   8.122 +static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
   8.123 +{
   8.124 +	u8 *buffer = buf;
   8.125 +	u8 data, *p;
   8.126 +	u32 size;
   8.127 +	__be32 *native_size;
   8.128 +
   8.129 +	if (count < 6)
   8.130 +		return -EIO;
   8.131 +
   8.132 +	if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
   8.133 +		dev_err(chip->dev, "F0 timeout\n");
   8.134 +		return -EIO;
   8.135 +	}
   8.136 +	if ((data =
   8.137 +	     inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
   8.138 +		dev_err(chip->dev, "not in normal mode (0x%x)\n",
   8.139 +			data);
   8.140 +		return -EIO;
   8.141 +	}
   8.142 +
   8.143 +	/* read the whole packet */
   8.144 +	for (p = buffer; p < &buffer[count]; p++) {
   8.145 +		if (wait_for_stat
   8.146 +		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
   8.147 +			dev_err(chip->dev,
   8.148 +				"OBF timeout (while reading data)\n");
   8.149 +			return -EIO;
   8.150 +		}
   8.151 +		if (data & NSC_STATUS_F0)
   8.152 +			break;
   8.153 +		*p = inb(chip->vendor->base + NSC_DATA);
   8.154 +	}
   8.155 +
   8.156 +	if ((data & NSC_STATUS_F0) == 0 &&
   8.157 +	(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
   8.158 +		dev_err(chip->dev, "F0 not set\n");
   8.159 +		return -EIO;
   8.160 +	}
   8.161 +	if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
   8.162 +		dev_err(chip->dev,
   8.163 +			"expected end of command(0x%x)\n", data);
   8.164 +		return -EIO;
   8.165 +	}
   8.166 +
   8.167 +	native_size = (__force __be32 *) (buf + 2);
   8.168 +	size = be32_to_cpu(*native_size);
   8.169 +
   8.170 +	if (count < size)
   8.171 +		return -EIO;
   8.172 +
   8.173 +	return size;
   8.174 +}
   8.175 +
   8.176 +static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
   8.177 +{
   8.178 +	u8 data;
   8.179 +	int i;
   8.180 +
   8.181 +	/*
   8.182 +	 * If we hit the chip with back to back commands it locks up
   8.183 +	 * and never set IBF. Hitting it with this "hammer" seems to
   8.184 +	 * fix it. Not sure why this is needed, we followed the flow
   8.185 +	 * chart in the manual to the letter.
   8.186 +	 */
   8.187 +	outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
   8.188 +
   8.189 +	if (nsc_wait_for_ready(chip) != 0)
   8.190 +		return -EIO;
   8.191 +
   8.192 +	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
   8.193 +		dev_err(chip->dev, "IBF timeout\n");
   8.194 +		return -EIO;
   8.195 +	}
   8.196 +
   8.197 +	outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
   8.198 +	if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
   8.199 +		dev_err(chip->dev, "IBR timeout\n");
   8.200 +		return -EIO;
   8.201 +	}
   8.202 +
   8.203 +	for (i = 0; i < count; i++) {
   8.204 +		if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
   8.205 +			dev_err(chip->dev,
   8.206 +				"IBF timeout (while writing data)\n");
   8.207 +			return -EIO;
   8.208 +		}
   8.209 +		outb(buf[i], chip->vendor->base + NSC_DATA);
   8.210 +	}
   8.211 +
   8.212 +	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
   8.213 +		dev_err(chip->dev, "IBF timeout\n");
   8.214 +		return -EIO;
   8.215 +	}
   8.216 +	outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
   8.217 +
   8.218 +	return count;
   8.219 +}
   8.220 +
   8.221 +static void tpm_nsc_cancel(struct tpm_chip *chip)
   8.222 +{
   8.223 +	outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
   8.224 +}
   8.225 +
   8.226 +static u8 tpm_nsc_status(struct tpm_chip *chip)
   8.227 +{
   8.228 +	return inb(chip->vendor->base + NSC_STATUS);
   8.229 +}
   8.230 +
   8.231 +static struct file_operations nsc_ops = {
   8.232 +	.owner = THIS_MODULE,
   8.233 +	.llseek = no_llseek,
   8.234 +	.open = tpm_open,
   8.235 +	.read = tpm_read,
   8.236 +	.write = tpm_write,
   8.237 +	.release = tpm_release,
   8.238 +};
   8.239 +
   8.240 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
   8.241 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
   8.242 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
   8.243 +static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
   8.244 +
   8.245 +static struct attribute * nsc_attrs[] = {
   8.246 +	&dev_attr_pubek.attr,
   8.247 +	&dev_attr_pcrs.attr,
   8.248 +	&dev_attr_caps.attr,
   8.249 +	&dev_attr_cancel.attr,
   8.250 +	0,
   8.251 +};
   8.252 +
   8.253 +static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
   8.254 +
   8.255 +static struct tpm_vendor_specific tpm_nsc = {
   8.256 +	.recv = tpm_nsc_recv,
   8.257 +	.send = tpm_nsc_send,
   8.258 +	.cancel = tpm_nsc_cancel,
   8.259 +	.status = tpm_nsc_status,
   8.260 +	.req_complete_mask = NSC_STATUS_OBF,
   8.261 +	.req_complete_val = NSC_STATUS_OBF,
   8.262 +	.req_canceled = NSC_STATUS_RDY,
   8.263 +	.attr_group = &nsc_attr_grp,
   8.264 +	.miscdev = { .fops = &nsc_ops, },
   8.265 +};
   8.266 +
   8.267 +static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
   8.268 +				  const struct pci_device_id *pci_id)
   8.269 +{
   8.270 +	int rc = 0;
   8.271 +	int lo, hi;
   8.272 +	int nscAddrBase = TPM_ADDR;
   8.273 +
   8.274 +
   8.275 +	if (pci_enable_device(pci_dev))
   8.276 +		return -EIO;
   8.277 +
   8.278 +	/* select PM channel 1 */
   8.279 +	tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
   8.280 +
   8.281 +	/* verify that it is a National part (SID) */
   8.282 +	if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
   8.283 +		nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
   8.284 +			(tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
   8.285 +		if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
   8.286 +			rc = -ENODEV;
   8.287 +			goto out_err;
   8.288 +		}
   8.289 +	}
   8.290 +
   8.291 +	hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
   8.292 +	lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
   8.293 +	tpm_nsc.base = (hi<<8) | lo;
   8.294 +
   8.295 +	dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
   8.296 +	dev_dbg(&pci_dev->dev,
   8.297 +		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
   8.298 +		tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
   8.299 +		tpm_read_index(nscAddrBase,0x27));
   8.300 +	dev_dbg(&pci_dev->dev,
   8.301 +		"NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
   8.302 +		tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
   8.303 +		tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
   8.304 +	dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
   8.305 +		(tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
   8.306 +	dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
   8.307 +		(tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
   8.308 +	dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
   8.309 +		tpm_read_index(nscAddrBase,0x70));
   8.310 +	dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
   8.311 +		tpm_read_index(nscAddrBase,0x71));
   8.312 +	dev_dbg(&pci_dev->dev,
   8.313 +		"NSC DMA channel select0 0x%x, select1 0x%x\n",
   8.314 +		tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
   8.315 +	dev_dbg(&pci_dev->dev,
   8.316 +		"NSC Config "
   8.317 +		"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
   8.318 +		tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
   8.319 +		tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
   8.320 +		tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
   8.321 +		tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
   8.322 +		tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
   8.323 +
   8.324 +	dev_info(&pci_dev->dev,
   8.325 +		 "NSC TPM revision %d\n",
   8.326 +		 tpm_read_index(nscAddrBase, 0x27) & 0x1F);
   8.327 +
   8.328 +	/* enable the DPM module */
   8.329 +	tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
   8.330 +
   8.331 +	if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_nsc)) < 0)
   8.332 +		goto out_err;
   8.333 +
   8.334 +	return 0;
   8.335 +
   8.336 +out_err:
   8.337 +	pci_disable_device(pci_dev);
   8.338 +	return rc;
   8.339 +}
   8.340 +
   8.341 +static void __devexit tpm_nsc_remove(struct pci_dev *pci_dev) 
   8.342 +{
   8.343 +	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
   8.344 +
   8.345 +	if ( chip )
   8.346 +		tpm_remove_hardware(chip->dev);
   8.347 +}
   8.348 +
   8.349 +static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
   8.350 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
   8.351 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
   8.352 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
   8.353 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
   8.354 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
   8.355 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
   8.356 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
   8.357 +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
   8.358 +	{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
   8.359 +	{0,}
   8.360 +};
   8.361 +
   8.362 +MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
   8.363 +
   8.364 +static struct pci_driver nsc_pci_driver = {
   8.365 +	.name = "tpm_nsc",
   8.366 +	.id_table = tpm_pci_tbl,
   8.367 +	.probe = tpm_nsc_init,
   8.368 +	.remove = __devexit_p(tpm_nsc_remove),
   8.369 +	.suspend = tpm_pm_suspend,
   8.370 +	.resume = tpm_pm_resume,
   8.371 +};
   8.372 +
   8.373 +static int __init init_nsc(void)
   8.374 +{
   8.375 +	return pci_register_driver(&nsc_pci_driver);
   8.376 +}
   8.377 +
   8.378 +static void __exit cleanup_nsc(void)
   8.379 +{
   8.380 +	pci_unregister_driver(&nsc_pci_driver);
   8.381 +}
   8.382 +
   8.383 +fs_initcall(init_nsc);
   8.384 +module_exit(cleanup_nsc);
   8.385 +
   8.386 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
   8.387 +MODULE_DESCRIPTION("TPM Driver");
   8.388 +MODULE_VERSION("2.0");
   8.389 +MODULE_LICENSE("GPL");
     9.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c	Wed Oct 05 13:41:59 2005 +0100
     9.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c	Wed Oct 05 13:52:18 2005 +0100
     9.3 @@ -25,7 +25,7 @@
     9.4  #include <linux/tpmfe.h>
     9.5  #include <linux/device.h>
     9.6  #include <linux/interrupt.h>
     9.7 -#include "tpm_nopci.h"
     9.8 +#include "tpm.h"
     9.9  
    9.10  /* read status bits */
    9.11  enum {
    9.12 @@ -434,6 +434,21 @@ static struct file_operations tpm_xen_op
    9.13  	.release = tpm_release,
    9.14  };
    9.15  
    9.16 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
    9.17 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
    9.18 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
    9.19 +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
    9.20 +
    9.21 +static struct attribute* xen_attrs[] = {
    9.22 +	&dev_attr_pubek.attr,
    9.23 +	&dev_attr_pcrs.attr,
    9.24 +	&dev_attr_caps.attr,
    9.25 +	&dev_attr_cancel.attr,
    9.26 +	0,
    9.27 +};
    9.28 +
    9.29 +static struct attribute_group xen_attr_grp = { .attrs = xen_attrs };
    9.30 +
    9.31  static struct tpm_vendor_specific tpm_xen = {
    9.32  	.recv = tpm_xen_recv,
    9.33  	.send = tpm_xen_send,
    9.34 @@ -443,7 +458,7 @@ static struct tpm_vendor_specific tpm_xe
    9.35  	.req_complete_val  = STATUS_DATA_AVAIL,
    9.36  	.req_canceled = STATUS_READY,
    9.37  	.base = 0,
    9.38 -	.attr = TPM_DEVICE_ATTRS,
    9.39 +	.attr_group = &xen_attr_grp,
    9.40  	.miscdev.fops = &tpm_xen_ops,
    9.41  	.buffersize = 64 * 1024,
    9.42  };
    9.43 @@ -480,7 +495,7 @@ static int __init init_xen(void)
    9.44  
    9.45  	tpm_xen.buffersize = tpmfe.max_tx_size;
    9.46  
    9.47 -	if ((rc = tpm_register_hardware_nopci(&tpm_device, &tpm_xen)) < 0) {
    9.48 +	if ((rc = tpm_register_hardware(&tpm_device, &tpm_xen)) < 0) {
    9.49  		device_unregister(&tpm_device);
    9.50  		tpm_fe_unregister_receiver();
    9.51  		return rc;
    10.1 --- a/patches/linux-2.6.12/tpm_partial_read.patch	Wed Oct 05 13:41:59 2005 +0100
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,74 +0,0 @@
    10.4 ---- ref-linux-2.6.12/drivers/char/tpm/tpm.c	2005-06-17 15:48:29.000000000 -0400
    10.5 -+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.c	2005-09-15 14:56:05.000000000 -0400
    10.6 -@@ -473,6 +401,7 @@ ssize_t tpm_write(struct file * file, co
    10.7 - 	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
    10.8 - 
    10.9 - 	atomic_set(&chip->data_pending, out_size);
   10.10 -+	atomic_set(&chip->data_position, 0);
   10.11 - 	up(&chip->buffer_mutex);
   10.12 - 
   10.13 - 	/* Set a timeout by which the reader must come claim the result */
   10.14 -@@ -494,29 +423,34 @@ ssize_t tpm_read(struct file * file, cha
   10.15 - {
   10.16 - 	struct tpm_chip *chip = file->private_data;
   10.17 - 	int ret_size = -ENODATA;
   10.18 -+	int pos, pending = 0;
   10.19 - 
   10.20 --	if (atomic_read(&chip->data_pending) != 0) {	/* Result available */
   10.21 -+	down(&chip->buffer_mutex);
   10.22 -+	ret_size = atomic_read(&chip->data_pending);
   10.23 -+	if ( ret_size > 0 ) {	/* Result available */
   10.24 -+		if (size < ret_size)
   10.25 -+			ret_size = size;
   10.26 -+
   10.27 -+		pos = atomic_read(&chip->data_position);
   10.28 -+
   10.29 -+		if (copy_to_user((void __user *) buf,
   10.30 -+				 &chip->data_buffer[pos], ret_size)) {
   10.31 -+			ret_size = -EFAULT;
   10.32 -+		} else {
   10.33 -+			pending = atomic_read(&chip->data_pending) - ret_size;
   10.34 -+			if ( pending ) {
   10.35 -+				atomic_set( &chip->data_pending, pending );
   10.36 -+				atomic_set( &chip->data_position, pos+ret_size );
   10.37 -+			}
   10.38 -+		}
   10.39 -+	}
   10.40 -+	up(&chip->buffer_mutex);
   10.41 -+
   10.42 -+	if ( ret_size <= 0 || pending == 0 ) {
   10.43 -+		atomic_set( &chip->data_pending, 0 );
   10.44 - 		down(&chip->timer_manipulation_mutex);
   10.45 - 		del_singleshot_timer_sync(&chip->user_read_timer);
   10.46 - 		up(&chip->timer_manipulation_mutex);
   10.47 --
   10.48 --		down(&chip->buffer_mutex);
   10.49 --
   10.50 --		ret_size = atomic_read(&chip->data_pending);
   10.51 --		atomic_set(&chip->data_pending, 0);
   10.52 --
   10.53 --		if (ret_size == 0)	/* timeout just occurred */
   10.54 --			ret_size = -ETIME;
   10.55 --		else if (ret_size > 0) {	/* relay data */
   10.56 --			if (size < ret_size)
   10.57 --				ret_size = size;
   10.58 --
   10.59 --			if (copy_to_user((void __user *) buf,
   10.60 --					 chip->data_buffer, ret_size)) {
   10.61 --				ret_size = -EFAULT;
   10.62 --			}
   10.63 --		}
   10.64 --		up(&chip->buffer_mutex);
   10.65 - 	}
   10.66 - 
   10.67 - 	return ret_size;
   10.68 ---- ref-linux-2.6.12/drivers/char/tpm/tpm.h	2005-06-17 15:48:29.000000000 -0400
   10.69 -+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.h	2005-09-15 14:56:05.000000000 -0400
   10.70 -@@ -54,6 +54,7 @@ struct tpm_chip {
   10.71 - 	/* Data passed to and from the tpm via the read/write calls */
   10.72 - 	u8 *data_buffer;
   10.73 - 	atomic_t data_pending;
   10.74 -+	atomic_t data_position;
   10.75 - 	struct semaphore buffer_mutex;
   10.76 - 
   10.77 - 	struct timer_list user_read_timer;	/* user needs to claim result */