[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] The attached patch places an updated TPM driver into the sparse directory.



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID e6ecfb4f4a24cec27be0bd36af6230004d8e590b
# Parent  303d51d0d57898334b92a66d827afb91b5659ac0
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@xxxxxxxxxx>
Signed-off-by: Kylene Hall <kjhall@xxxxxxxxxx>
Signed-off-by: Leendert van Doorn <leendert@xxxxxxxxxxxxxx>

diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/Makefile
--- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile    Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile    Wed Oct  5 12:52:18 2005
@@ -5,8 +5,9 @@
 obj-$(CONFIG_TCG_TPM) += tpm.o
 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
-obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
+obj-$(CONFIG_TCG_TIS) += tpm_tis.o
+obj-$(CONFIG_TCG_XEN) += tpm_xen.o
 else
-obj-$(CONFIG_TCG_TPM) += tpm_nopci.o
+obj-$(CONFIG_TCG_TPM) += tpm.o
 obj-$(CONFIG_TCG_XEN) += tpm_xen.o
 endif
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c   Wed Oct  5 12:52:18 2005
@@ -25,7 +25,7 @@
 #include <linux/tpmfe.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
-#include "tpm_nopci.h"
+#include "tpm.h"
 
 /* read status bits */
 enum {
@@ -434,6 +434,21 @@
        .release = tpm_release,
 };
 
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* xen_attrs[] = {
+       &dev_attr_pubek.attr,
+       &dev_attr_pcrs.attr,
+       &dev_attr_caps.attr,
+       &dev_attr_cancel.attr,
+       0,
+};
+
+static struct attribute_group xen_attr_grp = { .attrs = xen_attrs };
+
 static struct tpm_vendor_specific tpm_xen = {
        .recv = tpm_xen_recv,
        .send = tpm_xen_send,
@@ -443,7 +458,7 @@
        .req_complete_val  = STATUS_DATA_AVAIL,
        .req_canceled = STATUS_READY,
        .base = 0,
-       .attr = TPM_DEVICE_ATTRS,
+       .attr_group = &xen_attr_grp,
        .miscdev.fops = &tpm_xen_ops,
        .buffersize = 64 * 1024,
 };
@@ -480,7 +495,7 @@
 
        tpm_xen.buffersize = tpmfe.max_tx_size;
 
-       if ((rc = tpm_register_hardware_nopci(&tpm_device, &tpm_xen)) < 0) {
+       if ((rc = tpm_register_hardware(&tpm_device, &tpm_xen)) < 0) {
                device_unregister(&tpm_device);
                tpm_fe_unregister_receiver();
                return rc;
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
--- /dev/null   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig     Wed Oct  5 12:52:18 2005
@@ -0,0 +1,58 @@
+#
+# TPM device configuration
+#
+
+menu "TPM devices"
+
+config TCG_TPM
+       tristate "TPM Hardware Support"
+       depends on EXPERIMENTAL && PCI
+       ---help---
+         If you have a TPM security chip in your system, which
+         implements the Trusted Computing Group's specification,
+         say Yes and it will be accessible from within Linux.  For
+         more information see <http://www.trustedcomputinggroup.org>. 
+         An implementation of the Trusted Software Stack (TSS), the 
+         userspace enablement piece of the specification, can be 
+         obtained at: <http://sourceforge.net/projects/trousers>.  To 
+         compile this driver as a module, choose M here; the module 
+         will be called tpm. If unsure, say N.
+
+config TCG_TIS
+       tristate "TPM Interface Specification 1.2 Interface"
+       depends on TCG_TPM
+       ---help---
+         If you have a TPM security chip that is compliant with the
+         TCG TIS 1.2 TPM specification say Yes and it will be accessible
+         from within Linux.  To compile this driver as a module, choose
+         M here; the module will be called tpm_tis.
+
+config TCG_NSC
+       tristate "National Semiconductor TPM Interface"
+       depends on TCG_TPM
+       ---help---
+         If you have a TPM security chip from National Semicondutor 
+         say Yes and it will be accessible from within Linux.  To 
+         compile this driver as a module, choose M here; the module 
+         will be called tpm_nsc.
+
+config TCG_ATMEL
+       tristate "Atmel TPM Interface"
+       depends on TCG_TPM
+       ---help---
+         If you have a TPM security chip from Atmel say Yes and it 
+         will be accessible from within Linux.  To compile this driver 
+         as a module, choose M here; the module will be called tpm_atmel.
+
+config TCG_XEN
+       tristate "XEN TPM Interface"
+       depends on TCG_TPM && ARCH_XEN && XEN_TPMDEV_FRONTEND
+       ---help---
+         If you want to make TPM support available to a Xen
+         user domain, say Yes and it will
+          be accessible from within Linux. To compile this driver
+          as a module, choose M here; the module will be called
+          tpm_xen.
+
+endmenu
+
diff -r 303d51d0d578 -r e6ecfb4f4a24 linux-2.6-xen-sparse/drivers/char/tpm/tpm.c
--- /dev/null   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c       Wed Oct  5 12:52:18 2005
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org      
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ * 
+ * Note, the TPM chip is not interrupt driven (only polling)
+ * and can have very long timeouts (minutes!). Hence the unusual
+ * calls to msleep.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include "tpm.h"
+
+#define TPM_CHIP_NUM_MASK      0x0000ffff
+#define TPM_CHIP_TYPE_SHIFT    16      
+
+enum tpm_const {
+       TPM_MINOR = 224,        /* officially assigned */
+       TPM_MIN_BUFSIZE = 2048,
+       TPM_MAX_BUFSIZE = 64 * 1024,
+       TPM_NUM_DEVICES = 256,
+       TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
+};
+
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
+
+static void user_reader_timeout(unsigned long ptr)
+{
+       struct tpm_chip *chip = (struct tpm_chip *) ptr;
+
+       down(&chip->buffer_mutex);
+       atomic_set(&chip->data_pending, 0);
+       memset(chip->data_buffer, 0, chip->vendor->buffersize);
+       up(&chip->buffer_mutex);
+}
+
+/*
+ * Internal kernel interface to transmit TPM commands
+ */
+static ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
+                           size_t bufsiz)
+{
+       ssize_t rc;
+       u32 count;
+       unsigned long stop;
+
+       if (!chip)
+               return -ENODEV;
+
+       if ( !chip )
+               return -ENODEV;
+
+       count = be32_to_cpu(*((__be32 *) (buf + 2)));
+
+       if (count == 0)
+               return -ENODATA;
+       if (count > bufsiz) {
+               dev_err(chip->dev,
+                       "invalid count value %x %zx \n", count, bufsiz);
+               return -E2BIG;
+       }
+
+       down(&chip->tpm_mutex);
+
+       if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+               dev_err(chip->dev,
+                       "tpm_transmit: tpm_send: error %zd\n", rc);
+               goto out;
+       }
+
+       stop = jiffies + 2 * 60 * HZ;
+       do {
+               u8 status = chip->vendor->status(chip);
+               if ((status & chip->vendor->req_complete_mask) ==
+                   chip->vendor->req_complete_val) {
+                       goto out_recv;
+               }
+
+               if ((status == chip->vendor->req_canceled)) {
+                       dev_err(chip->dev, "Operation Canceled\n");
+                       rc = -ECANCELED;
+                       goto out;
+               }
+
+               msleep(TPM_TIMEOUT);    /* CHECK */
+               rmb();
+       } while (time_before(jiffies, stop));
+
+
+       chip->vendor->cancel(chip);
+       dev_err(chip->dev, "Operation Timed out\n");
+       rc = -ETIME;
+       goto out;
+
+out_recv:
+       rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+       if (rc < 0)
+               dev_err(chip->dev,
+                       "tpm_transmit: tpm_recv: error %zd\n", rc);
+out:
+       up(&chip->tpm_mutex);
+       return rc;
+}
+
+#define TPM_DIGEST_SIZE 20
+#define CAP_PCR_RESULT_SIZE 18
+static const u8 cap_pcr[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 22,            /* length */
+       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
+       0, 0, 0, 5,
+       0, 0, 0, 4,
+       0, 0, 1, 1
+};
+
+#define READ_PCR_RESULT_SIZE 30
+static const u8 pcrread[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 14,            /* length */
+       0, 0, 0, 21,            /* TPM_ORD_PcrRead */
+       0, 0, 0, 0              /* PCR index */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+                     char *buf)
+#else
+ssize_t tpm_show_pcrs(struct device *dev,
+                     char *buf)
+#endif
+{
+       u8 data[READ_PCR_RESULT_SIZE];
+       ssize_t len;
+       int i, j, num_pcrs;
+       __be32 index;
+       char *str = buf;
+
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       memcpy(data, cap_pcr, sizeof(cap_pcr));
+       if ((len = tpm_transmit(chip, data, sizeof(data)))
+           < CAP_PCR_RESULT_SIZE) {
+               dev_dbg(chip->dev, "A TPM error (%d) occurred "
+                               "attempting to determine the number of PCRS\n",
+                       be32_to_cpu(*((__be32 *) (data + 6))));
+               return 0;
+       }
+
+       num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
+
+       for (i = 0; i < num_pcrs; i++) {
+               memcpy(data, pcrread, sizeof(pcrread));
+               index = cpu_to_be32(i);
+               memcpy(data + 10, &index, 4);
+               if ((len = tpm_transmit(chip, data, sizeof(data)))
+                   < READ_PCR_RESULT_SIZE){
+                       dev_dbg(chip->dev, "A TPM error (%d) occurred"
+                               " attempting to read PCR %d of %d\n",
+                               be32_to_cpu(*((__be32 *) (data + 6))), i, 
num_pcrs);
+                       goto out;
+               }
+               str += sprintf(str, "PCR-%02d: ", i);
+               for (j = 0; j < TPM_DIGEST_SIZE; j++)
+                       str += sprintf(str, "%02X ", *(data + 10 + j));
+               str += sprintf(str, "\n");
+       }
+out:
+       return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_pcrs);
+
+#define  READ_PUBEK_RESULT_SIZE 314
+static const u8 readpubek[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 30,            /* length */
+       0, 0, 0, 124,           /* TPM_ORD_ReadPubek */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+#else
+ssize_t tpm_show_pubek(struct device *dev,
+                      char *buf)
+#endif
+{
+       u8 *data;
+       ssize_t len;
+       int i, rc;
+       char *str = buf;
+
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       memcpy(data, readpubek, sizeof(readpubek));
+       memset(data + sizeof(readpubek), 0, 20);        /* zero nonce */
+
+       if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
+           READ_PUBEK_RESULT_SIZE) {
+               dev_dbg(chip->dev, "A TPM error (%d) occurred "
+                               "attempting to read the PUBEK\n",
+                           be32_to_cpu(*((__be32 *) (data + 6))));
+               rc = 0;
+               goto out;
+       }
+
+       /* 
+          ignore header 10 bytes
+          algorithm 32 bits (1 == RSA )
+          encscheme 16 bits
+          sigscheme 16 bits
+          parameters (RSA 12->bytes: keybit, #primes, expbit)  
+          keylenbytes 32 bits
+          256 byte modulus
+          ignore checksum 20 bytes
+        */
+
+       str +=
+           sprintf(str,
+                   "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+                   "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
+                   " %02X %02X %02X %02X %02X %02X %02X %02X\n"
+                   "Modulus length: %d\nModulus: \n",
+                   data[10], data[11], data[12], data[13], data[14],
+                   data[15], data[16], data[17], data[22], data[23],
+                   data[24], data[25], data[26], data[27], data[28],
+                   data[29], data[30], data[31], data[32], data[33],
+                   be32_to_cpu(*((__be32 *) (data + 34))));
+
+       for (i = 0; i < 256; i++) {
+               str += sprintf(str, "%02X ", data[i + 38]);
+               if ((i + 1) % 16 == 0)
+                       str += sprintf(str, "\n");
+       }
+       rc = str - buf;
+out:
+       kfree(data);
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(tpm_show_pubek);
+
+#define CAP_VER_RESULT_SIZE 18
+static const u8 cap_version[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 18,            /* length */
+       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
+       0, 0, 0, 6,
+       0, 0, 0, 0
+};
+
+#define CAP_MANUFACTURER_RESULT_SIZE 18
+static const u8 cap_manufacturer[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 22,            /* length */
+       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
+       0, 0, 0, 5,
+       0, 0, 0, 4,
+       0, 0, 1, 3
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+                     char *buf)
+#else
+ssize_t tpm_show_caps(struct device *dev,
+                     char *buf)
+#endif
+{
+       u8 data[sizeof(cap_manufacturer)];
+       ssize_t len;
+       char *str = buf;
+
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
+
+       if ((len = tpm_transmit(chip, data, sizeof(data))) <
+           CAP_MANUFACTURER_RESULT_SIZE)
+               return len;
+
+       str += sprintf(str, "Manufacturer: 0x%x\n",
+                      be32_to_cpu(*((__be32 *) (data + 14))));
+
+       memcpy(data, cap_version, sizeof(cap_version));
+
+       if ((len = tpm_transmit(chip, data, sizeof(data))) <
+           CAP_VER_RESULT_SIZE)
+               return len;
+
+       str +=
+           sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
+                   (int) data[14], (int) data[15], (int) data[16],
+                   (int) data[17]);
+
+       return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_caps);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+#else
+ssize_t tpm_store_cancel(struct device *dev,
+                       const char *buf, size_t count)
+#endif
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       if (chip == NULL)
+               return 0;
+
+       chip->vendor->cancel(chip);
+       return count;
+}
+EXPORT_SYMBOL_GPL(tpm_store_cancel);
+
+
+/*
+ * Device file system interface to the TPM
+ */
+int tpm_open(struct inode *inode, struct file *file)
+{
+       int rc = 0, minor = iminor(inode);
+       struct tpm_chip *chip = NULL, *pos;
+
+       spin_lock(&driver_lock);
+
+       list_for_each_entry(pos, &tpm_chip_list, list) {
+               if (pos->vendor->miscdev.minor == minor) {
+                       chip = pos;
+                       break;
+               }
+       }
+
+       if (chip == NULL) {
+               rc = -ENODEV;
+               goto err_out;
+       }
+
+       if (chip->num_opens) {
+               dev_dbg(chip->dev,
+                       "Another process owns this TPM\n");
+               rc = -EBUSY;
+               goto err_out;
+       }
+
+       chip->num_opens++;
+       get_device(chip->dev);
+
+       spin_unlock(&driver_lock);
+
+       chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), 
GFP_KERNEL);
+       if (chip->data_buffer == NULL) {
+               chip->num_opens--;
+               put_device(chip->dev);
+               return -ENOMEM;
+       }
+
+       atomic_set(&chip->data_pending, 0);
+
+       file->private_data = chip;
+       return 0;
+
+err_out:
+       spin_unlock(&driver_lock);
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(tpm_open);
+
+int tpm_release(struct inode *inode, struct file *file)
+{
+       struct tpm_chip *chip = file->private_data;
+
+       spin_lock(&driver_lock);
+       file->private_data = NULL;
+       chip->num_opens--;
+       del_singleshot_timer_sync(&chip->user_read_timer);
+       atomic_set(&chip->data_pending, 0);
+       put_device(chip->dev);
+       kfree(chip->data_buffer);
+       spin_unlock(&driver_lock);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_release);
+
+ssize_t tpm_write(struct file * file, const char __user * buf,
+                 size_t size, loff_t * off)
+{
+       struct tpm_chip *chip = file->private_data;
+       int in_size = size, out_size;
+
+       /* cannot perform a write until the read has cleared
+          either via tpm_read or a user_read_timer timeout */
+       while (atomic_read(&chip->data_pending) != 0)
+               msleep(TPM_TIMEOUT);
+
+       down(&chip->buffer_mutex);
+
+       if (in_size > chip->vendor->buffersize)
+               in_size = chip->vendor->buffersize;
+
+       if (copy_from_user
+           (chip->data_buffer, (void __user *) buf, in_size)) {
+               up(&chip->buffer_mutex);
+               return -EFAULT;
+       }
+
+       /* atomic tpm command send and result receive */
+       out_size = tpm_transmit(chip, chip->data_buffer, 
+                               chip->vendor->buffersize);
+
+       atomic_set(&chip->data_pending, out_size);
+       atomic_set(&chip->data_position, 0);
+       up(&chip->buffer_mutex);
+
+       /* Set a timeout by which the reader must come claim the result */
+       mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
+
+       return in_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_write);
+
+ssize_t tpm_read(struct file * file, char __user * buf,
+                size_t size, loff_t * off)
+{
+       struct tpm_chip *chip = file->private_data;
+       int ret_size;
+       int pos, pending = 0;
+
+       ret_size = atomic_read(&chip->data_pending);
+       if (ret_size > 0) {     /* relay data */
+               if (size < ret_size)
+                       ret_size = size;
+
+               pos = atomic_read(&chip->data_position);
+
+               down(&chip->buffer_mutex);
+               if (copy_to_user
+                   ((void __user *) buf, &chip->data_buffer[pos], ret_size)) {
+                       ret_size = -EFAULT;
+               } else {
+                       pending = atomic_read(&chip->data_pending) - ret_size;
+                       if ( pending ) {
+                               atomic_set( &chip->data_pending, pending );
+                               atomic_set( &chip->data_position, pos+ret_size 
);
+                       }
+               }
+               up(&chip->buffer_mutex);
+       }
+       
+       if ( ret_size <= 0 || pending == 0 ) {
+               atomic_set( &chip->data_pending, 0 );
+               del_singleshot_timer_sync(&chip->user_read_timer);
+       }
+
+       return ret_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_read);
+
+void tpm_remove_hardware(struct device *dev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       if (chip == NULL) {
+               dev_err(dev, "No device data found\n");
+               return;
+       }
+
+       spin_lock(&driver_lock);
+
+       list_del(&chip->list);
+
+       spin_unlock(&driver_lock);
+
+       dev_set_drvdata(dev, NULL);
+       misc_deregister(&chip->vendor->miscdev);
+       kfree(chip->vendor->miscdev.name);
+
+       sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
+
+       dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << 
(chip->dev_num % TPM_NUM_MASK_ENTRIES));
+
+       kfree(chip);
+
+       put_device(dev);
+}
+
+EXPORT_SYMBOL_GPL(tpm_remove_hardware);
+
+static u8 savestate[] = {
+       0, 193,                 /* TPM_TAG_RQU_COMMAND */
+       0, 0, 0, 10,            /* blob length (in bytes) */
+       0, 0, 0, 152            /* TPM_ORD_SaveState */
+};
+
+/*
+ * We are about to suspend. Save the TPM state
+ * so that it can be restored.
+ */
+int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state)
+{
+       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       tpm_transmit(chip, savestate, sizeof(savestate));
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_suspend);
+
+/*
+ * Resume from a power safe. The BIOS already restored
+ * the TPM state.
+ */
+int tpm_pm_resume(struct pci_dev *pci_dev)
+{
+       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+       if (chip == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_resume);
+
+/*
+ * Called from tpm_<specific>.c probe function only for devices 
+ * the driver has determined it should claim.  Prior to calling
+ * this function the specific probe function has called pci_enable_device
+ * upon errant exit from this function specific probe function should call
+ * pci_disable_device
+ */
+int tpm_register_hardware(struct device *dev,
+                         struct tpm_vendor_specific *entry)
+{
+#define DEVNAME_SIZE 7
+
+       char *devname;
+       struct tpm_chip *chip;
+       int i, j;
+
+       /* Driver specific per-device data */
+       chip = kmalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       memset(chip, 0, sizeof(struct tpm_chip));
+
+       init_MUTEX(&chip->buffer_mutex);
+       init_MUTEX(&chip->tpm_mutex);
+       INIT_LIST_HEAD(&chip->list);
+
+       init_timer(&chip->user_read_timer);
+       chip->user_read_timer.function = user_reader_timeout;
+       chip->user_read_timer.data = (unsigned long) chip;
+
+       chip->vendor = entry;
+       
+       if (entry->buffersize < TPM_MIN_BUFSIZE) {
+               entry->buffersize = TPM_MIN_BUFSIZE;
+       } else if (entry->buffersize > TPM_MAX_BUFSIZE) {
+               entry->buffersize = TPM_MAX_BUFSIZE;
+       }
+
+       chip->dev_num = -1;
+
+       for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
+               for (j = 0; j < 8 * sizeof(int); j++)
+                       if ((dev_mask[i] & (1 << j)) == 0) {
+                               chip->dev_num =
+                                   i * TPM_NUM_MASK_ENTRIES + j;
+                               dev_mask[i] |= 1 << j;
+                               goto dev_num_search_complete;
+                       }
+
+dev_num_search_complete:
+       if (chip->dev_num < 0) {
+               dev_err(dev,
+                       "No available tpm device numbers\n");
+               kfree(chip);
+               return -ENODEV;
+       } else if (chip->dev_num == 0)
+               chip->vendor->miscdev.minor = TPM_MINOR;
+       else
+               chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
+
+       devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+       scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
+       chip->vendor->miscdev.name = devname;
+
+       chip->vendor->miscdev.dev = dev;
+       chip->dev = get_device(dev);
+
+       if (misc_register(&chip->vendor->miscdev)) {
+               dev_err(chip->dev,
+                       "unable to misc_register %s, minor %d\n",
+                       chip->vendor->miscdev.name,
+                       chip->vendor->miscdev.minor);
+               put_device(dev);
+               kfree(chip);
+               dev_mask[i] &= !(1 << j);
+               return -ENODEV;
+       }
+
+       spin_lock(&driver_lock);
+
+       dev_set_drvdata(dev, chip);
+
+       list_add(&chip->list, &tpm_chip_list);
+
+       spin_unlock(&driver_lock);
+
+       sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24 linux-2.6-xen-sparse/drivers/char/tpm/tpm.h
--- /dev/null   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h       Wed Oct  5 12:52:18 2005
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org      
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ * 
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+enum tpm_timeout {
+       TPM_TIMEOUT = 5,        /* msecs */
+};
+
+/* TPM addresses */
+enum tpm_addr {
+       TPM_SUPERIO_ADDR = 0x2E,
+       TPM_ADDR = 0x4E,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
+                               const char *, size_t);
+#else
+extern ssize_t tpm_show_pubek(struct device *,
+                               char *);
+extern ssize_t tpm_show_pcrs(struct device *,
+                               char *);
+extern ssize_t tpm_show_caps(struct device *,
+                               char *);
+extern ssize_t tpm_store_cancel(struct device *,
+                               const char *, size_t);
+#endif
+
+struct tpm_chip;
+
+struct tpm_vendor_specific {
+       u8 req_complete_mask;
+       u8 req_complete_val;
+       u8 req_canceled;
+       u16 base;               /* TPM base address */
+       int drv_type;
+       u32 buffersize;
+
+       int (*recv) (struct tpm_chip *, u8 *, size_t);
+       int (*send) (struct tpm_chip *, u8 *, size_t);
+       void (*cancel) (struct tpm_chip *);
+       u8 (*status) (struct tpm_chip *);
+       struct miscdevice miscdev;
+       struct attribute_group *attr_group;
+};
+
+struct tpm_chip {
+       struct device *dev;     /* Device stuff */
+
+       int dev_num;            /* /dev/tpm# */
+       int num_opens;          /* only one allowed */
+       int time_expired;
+
+       /* Data passed to and from the tpm via the read/write calls */
+       u8 *data_buffer;
+       atomic_t data_pending;
+       atomic_t data_position;
+       struct semaphore buffer_mutex;
+
+       struct timer_list user_read_timer;      /* user needs to claim result */
+       struct semaphore tpm_mutex;     /* tpm is processing */
+
+       struct tpm_vendor_specific *vendor;
+
+       struct list_head list;
+};
+
+static inline int tpm_read_index(int base, int index)
+{
+       outb(index, base);
+       return inb(base+1) & 0xFF;
+}
+
+static inline void tpm_write_index(int base, int index, int value)
+{
+       outb(index, base);
+       outb(value & 0xFF, base+1);
+}
+
+extern int tpm_register_hardware(struct device *,
+                                struct tpm_vendor_specific *);
+extern int tpm_open(struct inode *, struct file *);
+extern int tpm_release(struct inode *, struct file *);
+extern ssize_t tpm_write(struct file *, const char __user *, size_t,
+                        loff_t *);
+extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
+extern void tpm_remove_hardware(struct device *);
+extern int tpm_pm_suspend(struct pci_dev *, pm_message_t);
+extern int tpm_pm_resume(struct pci_dev *);
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c
--- /dev/null   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c Wed Oct  5 12:52:18 2005
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org      
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ * 
+ */
+
+#include "tpm.h"
+
+/* Atmel definitions */
+enum tpm_atmel_addr {
+       TPM_ATMEL_BASE_ADDR_LO = 0x08,
+       TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
+
+/* write status bits */
+enum tpm_atmel_write_status {
+       ATML_STATUS_ABORT = 0x01,
+       ATML_STATUS_LASTBYTE = 0x04
+};
+/* read status bits */
+enum tpm_atmel_read_status {
+       ATML_STATUS_BUSY = 0x01,
+       ATML_STATUS_DATA_AVAIL = 0x02,
+       ATML_STATUS_REWRITE = 0x04,
+       ATML_STATUS_READY = 0x08
+};
+
+static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+       u8 status, *hdr = buf;
+       u32 size;
+       int i;
+       __be32 *native_size;
+
+       /* start reading header */
+       if (count < 6)
+               return -EIO;
+
+       for (i = 0; i < 6; i++) {
+               status = inb(chip->vendor->base + 1);
+               if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+                       dev_err(chip->dev,
+                               "error reading header\n");
+                       return -EIO;
+               }
+               *buf++ = inb(chip->vendor->base);
+       }
+
+       /* size of the data received */
+       native_size = (__force __be32 *) (hdr + 2);
+       size = be32_to_cpu(*native_size);
+
+       if (count < size) {
+               dev_err(chip->dev,
+                       "Recv size(%d) less than available space\n", size);
+               for (; i < size; i++) { /* clear the waiting data anyway */
+                       status = inb(chip->vendor->base + 1);
+                       if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+                               dev_err(chip->dev,
+                                       "error reading data\n");
+                               return -EIO;
+                       }
+               }
+               return -EIO;
+       }
+
+       /* read all the data available */
+       for (; i < size; i++) {
+               status = inb(chip->vendor->base + 1);
+               if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+                       dev_err(chip->dev,
+                               "error reading data\n");
+                       return -EIO;
+               }
+               *buf++ = inb(chip->vendor->base);
+       }
+
+       /* make sure data available is gone */
+       status = inb(chip->vendor->base + 1);
+       if (status & ATML_STATUS_DATA_AVAIL) {
+               dev_err(chip->dev, "data available is stuck\n");
+               return -EIO;
+       }
+
+       return size;
+}
+
+static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+       int i;
+
+       dev_dbg(chip->dev, "tpm_atml_send:\n");
+       for (i = 0; i < count; i++) {
+               dev_dbg(chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
+               outb(buf[i], chip->vendor->base);
+       }
+
+       return count;
+}
+
+static void tpm_atml_cancel(struct tpm_chip *chip)
+{
+       outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+}
+
+static u8 tpm_atml_status(struct tpm_chip *chip)
+{
+       return inb(chip->vendor->base + 1);
+}
+
+static struct file_operations atmel_ops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .open = tpm_open,
+       .read = tpm_read,
+       .write = tpm_write,
+       .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* atmel_attrs[] = {
+       &dev_attr_pubek.attr,
+       &dev_attr_pcrs.attr,
+       &dev_attr_caps.attr,
+       &dev_attr_cancel.attr,
+       0,
+};
+
+static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
+static struct tpm_vendor_specific tpm_atmel = {
+       .recv = tpm_atml_recv,
+       .send = tpm_atml_send,
+       .cancel = tpm_atml_cancel,
+       .status = tpm_atml_status,
+       .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
+       .req_complete_val = ATML_STATUS_DATA_AVAIL,
+       .req_canceled = ATML_STATUS_READY,
+       .attr_group = &atmel_attr_grp,
+       .miscdev = { .fops = &atmel_ops, },
+};
+
+static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
+                                  const struct pci_device_id *pci_id)
+{
+       u8 version[4];
+       int rc = 0;
+       int lo, hi;
+
+       if (pci_enable_device(pci_dev))
+               return -EIO;
+
+       lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+       hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+       tpm_atmel.base = (hi<<8)|lo;
+       dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
+
+       /* verify that it is an Atmel part */
+       if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) 
!= 'T'
+           || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 
7) != 'L') {
+               rc = -ENODEV;
+               goto out_err;
+       }
+
+       /* query chip for its version number */
+       if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
+               version[1] = tpm_read_index(TPM_ADDR, 0x01);
+               version[2] = tpm_read_index(TPM_ADDR, 0x02);
+               version[3] = tpm_read_index(TPM_ADDR, 0x03);
+       } else {
+               dev_info(&pci_dev->dev, "version query failed\n");
+               rc = -ENODEV;
+               goto out_err;
+       }
+
+       if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_atmel)) < 0)
+               goto out_err;
+
+       dev_info(&pci_dev->dev,
+                "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1],
+                version[2], version[3]);
+
+       return 0;
+out_err:
+       pci_disable_device(pci_dev);
+       return rc;
+}
+
+static void __devexit tpm_atml_remove(struct pci_dev *pci_dev) 
+{
+       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+       if ( chip )
+               tpm_remove_hardware(chip->dev);
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
+#else
+#warning Remove the define of PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
+#endif
+       {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, 
PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver atmel_pci_driver = {
+       .name = "tpm_atmel",
+       .id_table = tpm_pci_tbl,
+       .probe = tpm_atml_init,
+       .remove = __devexit_p(tpm_atml_remove),
+       .suspend = tpm_pm_suspend,
+       .resume = tpm_pm_resume,
+};
+
+static int __init init_atmel(void)
+{
+       return pci_register_driver(&atmel_pci_driver);
+}
+
+static void __exit cleanup_atmel(void)
+{
+       pci_unregister_driver(&atmel_pci_driver);
+}
+
+fs_initcall(init_atmel);
+module_exit(cleanup_atmel);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c
--- /dev/null   Wed Oct  5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c   Wed Oct  5 12:52:18 2005
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org      
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ * 
+ */
+
+#include "tpm.h"
+
+/* National definitions */
+enum tpm_nsc_addr{
+       TPM_NSC_IRQ = 0x07,
+       TPM_NSC_BASE0_HI = 0x60,
+       TPM_NSC_BASE0_LO = 0x61,
+       TPM_NSC_BASE1_HI = 0x62,
+       TPM_NSC_BASE1_LO = 0x63
+};
+
+enum tpm_nsc_index {
+       NSC_LDN_INDEX = 0x07,
+       NSC_SID_INDEX = 0x20,
+       NSC_LDC_INDEX = 0x30,
+       NSC_DIO_INDEX = 0x60,
+       NSC_CIO_INDEX = 0x62,
+       NSC_IRQ_INDEX = 0x70,
+       NSC_ITS_INDEX = 0x71
+};
+
+enum tpm_nsc_status_loc {
+       NSC_STATUS = 0x01,
+       NSC_COMMAND = 0x01,
+       NSC_DATA = 0x00
+};
+
+/* status bits */
+enum tpm_nsc_status {
+       NSC_STATUS_OBF = 0x01,  /* output buffer full */
+       NSC_STATUS_IBF = 0x02,  /* input buffer full */
+       NSC_STATUS_F0 = 0x04,   /* F0 */
+       NSC_STATUS_A2 = 0x08,   /* A2 */
+       NSC_STATUS_RDY = 0x10,  /* ready to receive command */
+       NSC_STATUS_IBR = 0x20   /* ready to receive data */
+};
+
+/* command bits */
+enum tpm_nsc_cmd_mode {
+       NSC_COMMAND_NORMAL = 0x01,      /* normal mode */
+       NSC_COMMAND_EOC = 0x03,
+       NSC_COMMAND_CANCEL = 0x22
+};
+/*
+ * Wait for a certain status to appear
+ */
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
+{
+       unsigned long stop;
+
+       /* status immediately available check */
+       *data = inb(chip->vendor->base + NSC_STATUS);
+       if ((*data & mask) == val)
+               return 0;
+
+       /* wait for status */
+       stop = jiffies + 10 * HZ;
+       do {
+               msleep(TPM_TIMEOUT);
+               *data = inb(chip->vendor->base + 1);
+               if ((*data & mask) == val)
+                       return 0;
+       }
+       while (time_before(jiffies, stop));
+
+       return -EBUSY;
+}
+
+static int nsc_wait_for_ready(struct tpm_chip *chip)
+{
+       int status;
+       unsigned long stop;
+
+       /* status immediately available check */
+       status = inb(chip->vendor->base + NSC_STATUS);
+       if (status & NSC_STATUS_OBF)
+               status = inb(chip->vendor->base + NSC_DATA);
+       if (status & NSC_STATUS_RDY)
+               return 0;
+
+       /* wait for status */
+       stop = jiffies + 100;
+       do {
+               msleep(TPM_TIMEOUT);
+               status = inb(chip->vendor->base + NSC_STATUS);
+               if (status & NSC_STATUS_OBF)
+                       status = inb(chip->vendor->base + NSC_DATA);
+               if (status & NSC_STATUS_RDY)
+                       return 0;
+       }
+       while (time_before(jiffies, stop));
+
+       dev_info(chip->dev, "wait for ready failed\n");
+       return -EBUSY;
+}
+
+
+static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+       u8 *buffer = buf;
+       u8 data, *p;
+       u32 size;
+       __be32 *native_size;
+
+       if (count < 6)
+               return -EIO;
+
+       if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
+               dev_err(chip->dev, "F0 timeout\n");
+               return -EIO;
+       }
+       if ((data =
+            inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
+               dev_err(chip->dev, "not in normal mode (0x%x)\n",
+                       data);
+               return -EIO;
+       }
+
+       /* read the whole packet */
+       for (p = buffer; p < &buffer[count]; p++) {
+               if (wait_for_stat
+                   (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
+                       dev_err(chip->dev,
+                               "OBF timeout (while reading data)\n");
+                       return -EIO;
+               }
+               if (data & NSC_STATUS_F0)
+                       break;
+               *p = inb(chip->vendor->base + NSC_DATA);
+       }
+
+       if ((data & NSC_STATUS_F0) == 0 &&
+       (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
+               dev_err(chip->dev, "F0 not set\n");
+               return -EIO;
+       }
+       if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
+               dev_err(chip->dev,
+                       "expected end of command(0x%x)\n", data);
+               return -EIO;
+       }
+
+       native_size = (__force __be32 *) (buf + 2);
+       size = be32_to_cpu(*native_size);
+
+       if (count < size)
+               return -EIO;
+
+       return size;
+}
+
+static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+       u8 data;
+       int i;
+
+       /*
+        * If we hit the chip with back to back commands it locks up
+        * and never set IBF. Hitting it with this "hammer" seems to
+        * fix it. Not sure why this is needed, we followed the flow
+        * chart in the manual to the letter.
+        */
+       outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+
+       if (nsc_wait_for_ready(chip) != 0)
+               return -EIO;
+
+       if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+               dev_err(chip->dev, "IBF timeout\n");
+               return -EIO;
+       }
+
+       outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
+       if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
+               dev_err(chip->dev, "IBR timeout\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+                       dev_err(chip->dev,
+                               "IBF timeout (while writing data)\n");
+                       return -EIO;
+               }
+               outb(buf[i], chip->vendor->base + NSC_DATA);
+       }
+
+       if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+               dev_err(chip->dev, "IBF timeout\n");
+               return -EIO;
+       }
+       outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
+
+       return count;
+}
+
+static void tpm_nsc_cancel(struct tpm_chip *chip)
+{
+       outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+}
+
+static u8 tpm_nsc_status(struct tpm_chip *chip)
+{
+       return inb(chip->vendor->base + NSC_STATUS);
+}
+
+static struct file_operations nsc_ops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .open = tpm_open,
+       .read = tpm_read,
+       .write = tpm_write,
+       .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute * nsc_attrs[] = {
+       &dev_attr_pubek.attr,
+       &dev_attr_pcrs.attr,
+       &dev_attr_caps.attr,
+       &dev_attr_cancel.attr,
+       0,
+};
+
+static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
+static struct tpm_vendor_specific tpm_nsc = {
+       .recv = tpm_nsc_recv,
+       .send = tpm_nsc_send,
+       .cancel = tpm_nsc_cancel,
+       .status = tpm_nsc_status,
+       .req_complete_mask = NSC_STATUS_OBF,
+       .req_complete_val = NSC_STATUS_OBF,
+       .req_canceled = NSC_STATUS_RDY,
+       .attr_group = &nsc_attr_grp,
+       .miscdev = { .fops = &nsc_ops, },
+};
+
+static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
+                                 const struct pci_device_id *pci_id)
+{
+       int rc = 0;
+       int lo, hi;
+       int nscAddrBase = TPM_ADDR;
+
+
+       if (pci_enable_device(pci_dev))
+               return -EIO;
+
+       /* select PM channel 1 */
+       tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
+
+       /* verify that it is a National part (SID) */
+       if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+               nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
+                       (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
+               if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
+                       rc = -ENODEV;
+                       goto out_err;
+               }
+       }
+
+       hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+       lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+       tpm_nsc.base = (hi<<8) | lo;
+
+       dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
+       dev_dbg(&pci_dev->dev,
+               "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
+               tpm_read_index(nscAddrBase,0x07), 
tpm_read_index(nscAddrBase,0x20),
+               tpm_read_index(nscAddrBase,0x27));
+       dev_dbg(&pci_dev->dev,
+               "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
+               tpm_read_index(nscAddrBase,0x21), 
tpm_read_index(nscAddrBase,0x25),
+               tpm_read_index(nscAddrBase,0x26), 
tpm_read_index(nscAddrBase,0x28));
+       dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
+               (tpm_read_index(nscAddrBase,0x60) << 8) | 
tpm_read_index(nscAddrBase,0x61));
+       dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
+               (tpm_read_index(nscAddrBase,0x62) << 8) | 
tpm_read_index(nscAddrBase,0x63));
+       dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
+               tpm_read_index(nscAddrBase,0x70));
+       dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
+               tpm_read_index(nscAddrBase,0x71));
+       dev_dbg(&pci_dev->dev,
+               "NSC DMA channel select0 0x%x, select1 0x%x\n",
+               tpm_read_index(nscAddrBase,0x74), 
tpm_read_index(nscAddrBase,0x75));
+       dev_dbg(&pci_dev->dev,
+               "NSC Config "
+               "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+               tpm_read_index(nscAddrBase,0xF0), 
tpm_read_index(nscAddrBase,0xF1),
+               tpm_read_index(nscAddrBase,0xF2), 
tpm_read_index(nscAddrBase,0xF3),
+               tpm_read_index(nscAddrBase,0xF4), 
tpm_read_index(nscAddrBase,0xF5),
+               tpm_read_index(nscAddrBase,0xF6), 
tpm_read_index(nscAddrBase,0xF7),
+               tpm_read_index(nscAddrBase,0xF8), 
tpm_read_index(nscAddrBase,0xF9));
+
+       dev_info(&pci_dev->dev,
+                "NSC TPM revision %d\n",
+                tpm_read_index(nscAddrBase, 0x27) & 0x1F);
+
+       /* enable the DPM module */
+       tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
+
+       if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_nsc)) < 0)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       pci_disable_device(pci_dev);
+       return rc;
+}
+
+static void __devexit tpm_nsc_remove(struct pci_dev *pci_dev) 
+{
+       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+       if ( chip )
+               tpm_remove_hardware(chip->dev);
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver nsc_pci_driver = {
+       .name = "tpm_nsc",
+       .id_table = tpm_pci_tbl,
+       .probe = tpm_nsc_init,
+       .remove = __devexit_p(tpm_nsc_remove),
+       .suspend = tpm_pm_suspend,
+       .resume = tpm_pm_resume,
+};
+
+static int __init init_nsc(void)
+{
+       return pci_register_driver(&nsc_pci_driver);
+}
+
+static void __exit cleanup_nsc(void)
+{
+       pci_unregister_driver(&nsc_pci_driver);
+}
+
+fs_initcall(init_nsc);
+module_exit(cleanup_nsc);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c Wed Oct  5 12:41:59 2005
+++ /dev/null   Wed Oct  5 12:52:18 2005
@@ -1,751 +0,0 @@
-/*
- * Copyright (C) 2004 IBM Corporation
- *
- * Authors:
- * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
- * Dave Safford <safford@xxxxxxxxxxxxxx>
- * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
- * Kylene Hall <kjhall@xxxxxxxxxx>
- *
- * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
- *
- * Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * Note, the TPM chip is not interrupt driven (only polling)
- * and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include "tpm_nopci.h"
-
-enum {
-       TPM_MINOR = 224,        /* officially assigned */
-       TPM_MIN_BUFSIZE = 2048,
-       TPM_MAX_BUFSIZE = 65536,
-       TPM_NUM_DEVICES = 256,
-       TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
-};
-
-  /* PCI configuration addresses */
-enum {
-       PCI_GEN_PMCON_1 = 0xA0,
-       PCI_GEN1_DEC = 0xE4,
-       PCI_LPC_EN = 0xE6,
-       PCI_GEN2_DEC = 0xEC
-};
-
-enum {
-       TPM_LOCK_REG = 0x0D,
-       TPM_INTERUPT_REG = 0x0A,
-       TPM_BASE_ADDR_LO = 0x08,
-       TPM_BASE_ADDR_HI = 0x09,
-       TPM_UNLOCK_VALUE = 0x55,
-       TPM_LOCK_VALUE = 0xAA,
-       TPM_DISABLE_INTERUPT_VALUE = 0x00
-};
-
-static LIST_HEAD(tpm_chip_list);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
-static int dev_mask[32];
-
-static void user_reader_timeout(unsigned long ptr)
-{
-       struct tpm_chip *chip = (struct tpm_chip *) ptr;
-
-       down(&chip->buffer_mutex);
-       atomic_set(&chip->data_pending, 0);
-       memset(chip->data_buffer, 0, chip->vendor->buffersize);
-       up(&chip->buffer_mutex);
-}
-
-void tpm_time_expired(unsigned long ptr)
-{
-       int *exp = (int *) ptr;
-       *exp = 1;
-}
-
-EXPORT_SYMBOL_GPL(tpm_time_expired);
-
-
-/*
- * This function should be used by other kernel subsystems attempting to use 
the tpm through the tpm_transmit interface.
- * 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.
- * 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.
- */
-struct tpm_chip* tpm_chip_lookup(int chip_num)
-{
-
-       struct tpm_chip *pos;
-       list_for_each_entry(pos, &tpm_chip_list, list)
-               if (pos->dev_num == chip_num ||
-                   chip_num == TPM_ANY_NUM)
-                       return pos;
-
-       return NULL;
-
-}
-
-/*
- * Internal kernel interface to transmit TPM commands
- */
-ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
-                    size_t bufsiz)
-{
-       ssize_t rc;
-       u32 count;
-       unsigned long stop;
-
-       count = be32_to_cpu(*((__be32 *) (buf + 2)));
-
-       if (count == 0)
-               return -ENODATA;
-       if (count > bufsiz) {
-               dev_err(chip->dev,
-                       "invalid count value %x %x \n", count, bufsiz);
-               return -E2BIG;
-       }
-
-       dev_dbg(chip->dev, "TPM Ordinal: %d\n",
-               be32_to_cpu(*((__be32 *) (buf + 6))));
-       dev_dbg(chip->dev, "Chip Status: %x\n",
-               inb(chip->vendor->base + 1));
-
-       down(&chip->tpm_mutex);
-
-       if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
-               dev_err(chip->dev,
-                       "tpm_transmit: tpm_send: error %d\n", rc);
-               goto out;
-       }
-
-       stop = jiffies + 2 * 60 * HZ;
-       do {
-               u8 status = chip->vendor->status(chip);
-               if ((status & chip->vendor->req_complete_mask) ==
-                   chip->vendor->req_complete_val) {
-                       goto out_recv;
-               }
-
-               if ((status == chip->vendor->req_canceled)) {
-                       dev_err(chip->dev, "Operation Canceled\n");
-                       rc = -ECANCELED;
-                       goto out;
-               }
-
-               msleep(TPM_TIMEOUT);    /* CHECK */
-               rmb();
-       }
-       while (time_before(jiffies, stop));
-
-
-       chip->vendor->cancel(chip);
-       dev_err(chip->dev, "Operation Timed out\n");
-       rc = -ETIME;
-       goto out;
-
-out_recv:
-       rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
-       if (rc < 0)
-               dev_err(chip->dev,
-                       "tpm_transmit: tpm_recv: error %d\n", rc);
-       atomic_set(&chip->data_position, 0);
-
-out:
-       up(&chip->tpm_mutex);
-       return rc;
-}
-
-EXPORT_SYMBOL_GPL(tpm_transmit);
-
-#define TPM_DIGEST_SIZE 20
-#define CAP_PCR_RESULT_SIZE 18
-static const u8 cap_pcr[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 22,            /* length */
-       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
-       0, 0, 0, 5,
-       0, 0, 0, 4,
-       0, 0, 1, 1
-};
-
-#define READ_PCR_RESULT_SIZE 30
-static const u8 pcrread[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 14,            /* length */
-       0, 0, 0, 21,            /* TPM_ORD_PcrRead */
-       0, 0, 0, 0              /* PCR index */
-};
-
-ssize_t tpm_show_pcrs(struct device *dev, char *buf)
-{
-       u8 data[READ_PCR_RESULT_SIZE];
-       ssize_t len;
-       int i, j, num_pcrs;
-       __be32 index;
-       char *str = buf;
-
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       memcpy(data, cap_pcr, sizeof(cap_pcr));
-       if ((len = tpm_transmit(chip, data, sizeof(data)))
-           < CAP_PCR_RESULT_SIZE)
-               return len;
-
-       num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
-
-       for (i = 0; i < num_pcrs; i++) {
-               memcpy(data, pcrread, sizeof(pcrread));
-               index = cpu_to_be32(i);
-               memcpy(data + 10, &index, 4);
-               if ((len = tpm_transmit(chip, data, sizeof(data)))
-                   < READ_PCR_RESULT_SIZE)
-                       return len;
-               str += sprintf(str, "PCR-%02d: ", i);
-               for (j = 0; j < TPM_DIGEST_SIZE; j++)
-                       str += sprintf(str, "%02X ", *(data + 10 + j));
-               str += sprintf(str, "\n");
-       }
-       return str - buf;
-}
-
-EXPORT_SYMBOL_GPL(tpm_show_pcrs);
-
-/*
- * Return 0 on success.  On error pass along error code.
- * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
- * Lower 2 bytes equal tpm idx # or AN&
- * res_buf must fit a TPM_PCR (20 bytes) or NULL if you don't care
- */
-int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size )
-{
-       u8 data[READ_PCR_RESULT_SIZE];
-       int rc;
-       __be32 index;
-       int chip_num = chip_id & TPM_CHIP_NUM_MASK;
-       struct tpm_chip* chip;
-
-       if ( res_buf && res_buf_size < TPM_DIGEST_SIZE )
-               return -ENOSPC;
-       if ( (chip = tpm_chip_lookup( chip_num /*,
-                                      chip_id >> TPM_CHIP_TYPE_SHIFT*/ ) ) == 
NULL ) {
-               printk("chip %d not found.\n",chip_num);
-               return -ENODEV;
-       }
-       memcpy(data, pcrread, sizeof(pcrread));
-       index = cpu_to_be32(pcr_idx);
-       memcpy(data + 10, &index, 4);
-       if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
-               rc = be32_to_cpu(*((u32*)(data+6)));
-
-       if ( rc == 0 && res_buf )
-               memcpy(res_buf, data+10, TPM_DIGEST_SIZE);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(tpm_pcr_read);
-
-#define EXTEND_PCR_SIZE 34
-static const u8 pcrextend[] = {
-       0, 193,                                          /* TPM_TAG_RQU_COMMAND 
*/
-       0, 0, 0, 34,                             /* length */
-       0, 0, 0, 20,                             /* TPM_ORD_Extend */
-       0, 0, 0, 0                               /* PCR index */
-};
-
-/*
- * Return 0 on success.  On error pass along error code.
- * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
- * Lower 2 bytes equal tpm idx # or ANY
- */
-int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash)
-{
-       u8 data[EXTEND_PCR_SIZE];
-       int rc;
-       __be32 index;
-       int chip_num = chip_id & TPM_CHIP_NUM_MASK;
-       struct tpm_chip* chip;
-
-       if ( (chip = tpm_chip_lookup( chip_num /*,
-                                     chip_id >> TPM_CHIP_TYPE_SHIFT */)) == 
NULL )
-               return -ENODEV;
-
-       memcpy(data, pcrextend, sizeof(pcrextend));
-       index = cpu_to_be32(pcr_idx);
-       memcpy(data + 10, &index, 4);
-       memcpy( data + 14, hash, TPM_DIGEST_SIZE );
-       if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
-               rc = be32_to_cpu(*((u32*)(data+6)));
-       return rc;
-}
-EXPORT_SYMBOL_GPL(tpm_pcr_extend);
-
-
-
-#define  READ_PUBEK_RESULT_SIZE 314
-static const u8 readpubek[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 30,            /* length */
-       0, 0, 0, 124,           /* TPM_ORD_ReadPubek */
-};
-
-ssize_t tpm_show_pubek(struct device *dev, char *buf)
-{
-       u8 *data;
-       ssize_t len;
-       int i, rc;
-       char *str = buf;
-
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, readpubek, sizeof(readpubek));
-       memset(data + sizeof(readpubek), 0, 20);        /* zero nonce */
-
-       if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
-           READ_PUBEK_RESULT_SIZE) {
-               rc = len;
-               goto out;
-       }
-
-       /*
-          ignore header 10 bytes
-          algorithm 32 bits (1 == RSA )
-          encscheme 16 bits
-          sigscheme 16 bits
-          parameters (RSA 12->bytes: keybit, #primes, expbit)
-          keylenbytes 32 bits
-          256 byte modulus
-          ignore checksum 20 bytes
-        */
-
-       str +=
-           sprintf(str,
-                   "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
-                   "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
-                   " %02X %02X %02X %02X %02X %02X %02X %02X\n"
-                   "Modulus length: %d\nModulus: \n",
-                   data[10], data[11], data[12], data[13], data[14],
-                   data[15], data[16], data[17], data[22], data[23],
-                   data[24], data[25], data[26], data[27], data[28],
-                   data[29], data[30], data[31], data[32], data[33],
-                   be32_to_cpu(*((__be32 *) (data + 32))));
-
-       for (i = 0; i < 256; i++) {
-               str += sprintf(str, "%02X ", data[i + 39]);
-               if ((i + 1) % 16 == 0)
-                       str += sprintf(str, "\n");
-       }
-       rc = str - buf;
-out:
-       kfree(data);
-       return rc;
-}
-
-EXPORT_SYMBOL_GPL(tpm_show_pubek);
-
-#define CAP_VER_RESULT_SIZE 18
-static const u8 cap_version[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 18,            /* length */
-       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
-       0, 0, 0, 6,
-       0, 0, 0, 0
-};
-
-#define CAP_MANUFACTURER_RESULT_SIZE 18
-static const u8 cap_manufacturer[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 22,            /* length */
-       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
-       0, 0, 0, 5,
-       0, 0, 0, 4,
-       0, 0, 1, 3
-};
-
-ssize_t tpm_show_caps(struct device *dev, char *buf)
-{
-       u8 data[sizeof(cap_manufacturer)];
-       ssize_t len;
-       char *str = buf;
-
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
-
-       if ((len = tpm_transmit(chip, data, sizeof(data))) <
-           CAP_MANUFACTURER_RESULT_SIZE)
-               return len;
-
-       str += sprintf(str, "Manufacturer: 0x%x\n",
-                      be32_to_cpu(*((__be32 *)(data + 14))));
-
-       memcpy(data, cap_version, sizeof(cap_version));
-
-       if ((len = tpm_transmit(chip, data, sizeof(data))) <
-           CAP_VER_RESULT_SIZE)
-               return len;
-
-       str +=
-           sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
-                   (int) data[14], (int) data[15], (int) data[16],
-                   (int) data[17]);
-
-       return str - buf;
-}
-
-EXPORT_SYMBOL_GPL(tpm_show_caps);
-
-ssize_t tpm_store_cancel(struct device * dev, const char *buf,
-                        size_t count)
-{
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return 0;
-
-       chip->vendor->cancel(chip);
-       return count;
-}
-
-EXPORT_SYMBOL_GPL(tpm_store_cancel);
-
-/*
- * Device file system interface to the TPM
- */
-int tpm_open(struct inode *inode, struct file *file)
-{
-       int rc = 0, minor = iminor(inode);
-       struct tpm_chip *chip = NULL, *pos;
-
-       spin_lock(&driver_lock);
-
-       list_for_each_entry(pos, &tpm_chip_list, list) {
-               if (pos->vendor->miscdev.minor == minor) {
-                       chip = pos;
-                       break;
-               }
-       }
-
-       if (chip == NULL) {
-               rc = -ENODEV;
-               goto err_out;
-       }
-
-       if (chip->num_opens) {
-               dev_dbg(chip->dev, "Another process owns this TPM\n");
-               rc = -EBUSY;
-               goto err_out;
-       }
-
-       chip->num_opens++;
-       get_device(chip->dev);
-
-       spin_unlock(&driver_lock);
-
-       chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8),
-                                   GFP_KERNEL);
-       if (chip->data_buffer == NULL) {
-               chip->num_opens--;
-               put_device(chip->dev);
-               return -ENOMEM;
-       }
-
-       atomic_set(&chip->data_pending, 0);
-
-       file->private_data = chip;
-       return 0;
-
-err_out:
-       spin_unlock(&driver_lock);
-       return rc;
-}
-
-EXPORT_SYMBOL_GPL(tpm_open);
-
-int tpm_release(struct inode *inode, struct file *file)
-{
-       struct tpm_chip *chip = file->private_data;
-
-       spin_lock(&driver_lock);
-       file->private_data = NULL;
-       chip->num_opens--;
-       del_singleshot_timer_sync(&chip->user_read_timer);
-       atomic_set(&chip->data_pending, 0);
-       put_device(chip->dev);
-       kfree(chip->data_buffer);
-       spin_unlock(&driver_lock);
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_release);
-
-ssize_t tpm_write(struct file * file, const char __user * buf,
-                 size_t size, loff_t * off)
-{
-       struct tpm_chip *chip = file->private_data;
-       int in_size = size, out_size;
-
-       /* cannot perform a write until the read has cleared
-          either via tpm_read or a user_read_timer timeout */
-       while (atomic_read(&chip->data_pending) != 0)
-               msleep(TPM_TIMEOUT);
-
-       down(&chip->buffer_mutex);
-
-       if (in_size > chip->vendor->buffersize)
-               in_size = chip->vendor->buffersize;
-
-       if (copy_from_user
-           (chip->data_buffer, (void __user *) buf, in_size)) {
-               up(&chip->buffer_mutex);
-               return -EFAULT;
-       }
-
-       /* atomic tpm command send and result receive */
-       out_size = tpm_transmit(chip,
-                               chip->data_buffer,
-                               chip->vendor->buffersize);
-
-       atomic_set(&chip->data_pending, out_size);
-       up(&chip->buffer_mutex);
-
-       /* Set a timeout by which the reader must come claim the result */
-       mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
-
-       return in_size;
-}
-
-EXPORT_SYMBOL_GPL(tpm_write);
-
-ssize_t tpm_read(struct file * file, char __user * buf,
-                size_t size, loff_t * off)
-{
-       struct tpm_chip *chip = file->private_data;
-       int ret_size;
-
-       del_singleshot_timer_sync(&chip->user_read_timer);
-       ret_size = atomic_read(&chip->data_pending);
-
-       if (ret_size > 0) {     /* relay data */
-               int position = atomic_read(&chip->data_position);
-
-               if (size < ret_size)
-                       ret_size = size;
-
-               down(&chip->buffer_mutex);
-
-               if (copy_to_user((void __user *) buf,
-                                &chip->data_buffer[position],
-                                ret_size)) {
-                       ret_size = -EFAULT;
-               } else {
-                       int pending = atomic_read(&chip->data_pending) - 
ret_size;
-                       atomic_set(&chip->data_pending,
-                                  pending);
-                       atomic_set(&chip->data_position,
-                                  position + ret_size);
-               }
-               up(&chip->buffer_mutex);
-       }
-
-       return ret_size;
-}
-
-EXPORT_SYMBOL_GPL(tpm_read);
-
-void tpm_remove_hardware(struct device *dev)
-{
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       int i;
-
-       if (chip == NULL) {
-               dev_err(dev, "No device data found\n");
-               return;
-       }
-
-       spin_lock(&driver_lock);
-
-       list_del(&chip->list);
-
-       spin_unlock(&driver_lock);
-
-       dev_set_drvdata(dev, NULL);
-       misc_deregister(&chip->vendor->miscdev);
-
-       for (i = 0; i < TPM_NUM_ATTR; i++)
-               device_remove_file(dev, &chip->vendor->attr[i]);
-
-       dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &=
-           !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
-
-       kfree(chip);
-
-       put_device(dev);
-}
-
-EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-
-static const u8 savestate[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 10,            /* blob length (in bytes) */
-       0, 0, 0, 152            /* TPM_ORD_SaveState */
-};
-
-/*
- * We are about to suspend. Save the TPM state
- * so that it can be restored.
- */
-int tpm_pm_suspend(struct pci_dev *pci_dev, u32 pm_state)
-{
-       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       tpm_transmit(chip, savestate, sizeof(savestate));
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_pm_suspend);
-
-/*
- * Resume from a power safe. The BIOS already restored
- * the TPM state.
- */
-int tpm_pm_resume(struct pci_dev *pci_dev)
-{
-       struct tpm_chip *chip = pci_get_drvdata(pci_dev);
-
-       if (chip == NULL)
-               return -ENODEV;
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_pm_resume);
-
-/*
- * Called from tpm_<specific>.c probe function only for devices
- * the driver has determined it should claim.  Prior to calling
- * this function the specific probe function has called pci_enable_device
- * upon errant exit from this function specific probe function should call
- * pci_disable_device
- */
-int tpm_register_hardware_nopci(struct device *dev,
-                               struct tpm_vendor_specific *entry)
-{
-       char devname[7];
-       struct tpm_chip *chip;
-       int i, j;
-
-       /* Driver specific per-device data */
-       chip = kmalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
-
-       memset(chip, 0, sizeof(struct tpm_chip));
-
-       init_MUTEX(&chip->buffer_mutex);
-       init_MUTEX(&chip->tpm_mutex);
-       INIT_LIST_HEAD(&chip->list);
-
-       init_timer(&chip->user_read_timer);
-       chip->user_read_timer.function = user_reader_timeout;
-       chip->user_read_timer.data = (unsigned long) chip;
-
-       chip->vendor = entry;
-
-       if (entry->buffersize < TPM_MIN_BUFSIZE) {
-               entry->buffersize = TPM_MIN_BUFSIZE;
-       } else if (entry->buffersize > TPM_MAX_BUFSIZE) {
-               entry->buffersize = TPM_MAX_BUFSIZE;
-       }
-
-       chip->dev_num = -1;
-
-       for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
-               for (j = 0; j < 8 * sizeof(int); j++)
-                       if ((dev_mask[i] & (1 << j)) == 0) {
-                               chip->dev_num =
-                                   i * TPM_NUM_MASK_ENTRIES + j;
-                               dev_mask[i] |= 1 << j;
-                               goto dev_num_search_complete;
-                       }
-
-dev_num_search_complete:
-       if (chip->dev_num < 0) {
-               dev_err(dev, "No available tpm device numbers\n");
-               kfree(chip);
-               return -ENODEV;
-       } else if (chip->dev_num == 0)
-               chip->vendor->miscdev.minor = TPM_MINOR;
-       else
-               chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
-
-       snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
-       chip->vendor->miscdev.name = devname;
-
-       chip->vendor->miscdev.dev = dev;
-       chip->dev = get_device(dev);
-
-
-       if (misc_register(&chip->vendor->miscdev)) {
-               dev_err(chip->dev,
-                       "unable to misc_register %s, minor %d\n",
-                       chip->vendor->miscdev.name,
-                       chip->vendor->miscdev.minor);
-               put_device(dev);
-               kfree(chip);
-               dev_mask[i] &= !(1 << j);
-               return -ENODEV;
-       }
-
-       spin_lock(&driver_lock);
-
-       dev_set_drvdata(dev, chip);
-
-       list_add(&chip->list, &tpm_chip_list);
-
-       spin_unlock(&driver_lock);
-
-       for (i = 0; i < TPM_NUM_ATTR; i++)
-               device_create_file(dev, &chip->vendor->attr[i]);
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_register_hardware_nopci);
-
-static int __init init_tpm(void)
-{
-       return 0;
-}
-
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
-
-MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
-MODULE_DESCRIPTION("TPM Driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24 
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h Wed Oct  5 12:41:59 2005
+++ /dev/null   Wed Oct  5 12:52:18 2005
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2004 IBM Corporation
- *
- * Authors:
- * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
- * Dave Safford <safford@xxxxxxxxxxxxxx>
- * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
- * Kylene Hall <kjhall@xxxxxxxxxx>
- *
- * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
- *
- * Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- */
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-
-enum {
-       TPM_TIMEOUT = 5,        /* msecs */
-       TPM_NUM_ATTR = 4
-};
-
-/* TPM addresses */
-enum {
-       TPM_ADDR = 0x4E,
-       TPM_DATA = 0x4F
-};
-
-/*
- * Chip num is this value or a valid tpm idx in lower two bytes of chip_id
- */
-enum tpm_chip_num {
-       TPM_ANY_NUM = 0xFFFF,
-};
-
-#define TPM_CHIP_NUM_MASK      0x0000ffff
-
-extern ssize_t tpm_show_pubek(struct device *, char *);
-extern ssize_t tpm_show_pcrs(struct device *, char *);
-extern ssize_t tpm_show_caps(struct device *, char *);
-extern ssize_t tpm_store_cancel(struct device *, const char *, size_t);
-
-#define TPM_DEVICE_ATTRS { \
-       __ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL), \
-       __ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL), \
-       __ATTR(caps, S_IRUGO, tpm_show_caps, NULL), \
-       __ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel) }
-
-struct tpm_chip;
-
-struct tpm_vendor_specific {
-       u8 req_complete_mask;
-       u8 req_complete_val;
-       u8 req_canceled;
-       u16 base;               /* TPM base address */
-       u32 buffersize;         /* The device's requested buffersize */
-
-       int (*recv) (struct tpm_chip *, u8 *, size_t);
-       int (*send) (struct tpm_chip *, u8 *, size_t);
-       void (*cancel) (struct tpm_chip *);
-        u8(*status) (struct tpm_chip *);
-       struct miscdevice miscdev;
-       struct device_attribute attr[TPM_NUM_ATTR];
-};
-
-struct tpm_chip {
-       struct device *dev;     /* PCI device stuff */
-
-       int dev_num;            /* /dev/tpm# */
-       int num_opens;          /* only one allowed */
-       int time_expired;
-
-       /* Data passed to and from the tpm via the read/write calls */
-       u8 *data_buffer;
-       atomic_t data_pending;
-       atomic_t data_position;
-       struct semaphore buffer_mutex;
-
-       struct timer_list user_read_timer;      /* user needs to claim result */
-       struct semaphore tpm_mutex;     /* tpm is processing */
-
-       struct tpm_vendor_specific *vendor;
-
-       struct list_head list;
-};
-
-static inline int tpm_read_index(int index)
-{
-       outb(index, TPM_ADDR);
-       return inb(TPM_DATA) & 0xFF;
-}
-
-static inline void tpm_write_index(int index, int value)
-{
-       outb(index, TPM_ADDR);
-       outb(value & 0xFF, TPM_DATA);
-}
-
-extern void tpm_time_expired(unsigned long);
-extern int tpm_lpc_bus_init(struct pci_dev *, u16);
-
-extern int tpm_register_hardware_nopci(struct device *,
-                                      struct tpm_vendor_specific *);
-extern void tpm_remove_hardware(struct device *);
-extern int tpm_open(struct inode *, struct file *);
-extern int tpm_release(struct inode *, struct file *);
-extern ssize_t tpm_write(struct file *, const char __user *, size_t,
-                        loff_t *);
-extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
-extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash);
-extern int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int 
res_buf_size );
-
-extern int tpm_pm_suspend(struct pci_dev *, u32);
-extern int tpm_pm_resume(struct pci_dev *);
-
-/* internal kernel interface */
-extern ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-                           size_t bufsiz);
-extern struct tpm_chip *tpm_chip_lookup(int chip_num);
diff -r 303d51d0d578 -r e6ecfb4f4a24 patches/linux-2.6.12/tpm_partial_read.patch
--- a/patches/linux-2.6.12/tpm_partial_read.patch       Wed Oct  5 12:41:59 2005
+++ /dev/null   Wed Oct  5 12:52:18 2005
@@ -1,74 +0,0 @@
---- ref-linux-2.6.12/drivers/char/tpm/tpm.c    2005-06-17 15:48:29.000000000 
-0400
-+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.c        2005-09-15 
14:56:05.000000000 -0400
-@@ -473,6 +401,7 @@ ssize_t tpm_write(struct file * file, co
-       out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
- 
-       atomic_set(&chip->data_pending, out_size);
-+      atomic_set(&chip->data_position, 0);
-       up(&chip->buffer_mutex);
- 
-       /* Set a timeout by which the reader must come claim the result */
-@@ -494,29 +423,34 @@ ssize_t tpm_read(struct file * file, cha
- {
-       struct tpm_chip *chip = file->private_data;
-       int ret_size = -ENODATA;
-+      int pos, pending = 0;
- 
--      if (atomic_read(&chip->data_pending) != 0) {    /* Result available */
-+      down(&chip->buffer_mutex);
-+      ret_size = atomic_read(&chip->data_pending);
-+      if ( ret_size > 0 ) {   /* Result available */
-+              if (size < ret_size)
-+                      ret_size = size;
-+
-+              pos = atomic_read(&chip->data_position);
-+
-+              if (copy_to_user((void __user *) buf,
-+                               &chip->data_buffer[pos], ret_size)) {
-+                      ret_size = -EFAULT;
-+              } else {
-+                      pending = atomic_read(&chip->data_pending) - ret_size;
-+                      if ( pending ) {
-+                              atomic_set( &chip->data_pending, pending );
-+                              atomic_set( &chip->data_position, pos+ret_size 
);
-+                      }
-+              }
-+      }
-+      up(&chip->buffer_mutex);
-+
-+      if ( ret_size <= 0 || pending == 0 ) {
-+              atomic_set( &chip->data_pending, 0 );
-               down(&chip->timer_manipulation_mutex);
-               del_singleshot_timer_sync(&chip->user_read_timer);
-               up(&chip->timer_manipulation_mutex);
--
--              down(&chip->buffer_mutex);
--
--              ret_size = atomic_read(&chip->data_pending);
--              atomic_set(&chip->data_pending, 0);
--
--              if (ret_size == 0)      /* timeout just occurred */
--                      ret_size = -ETIME;
--              else if (ret_size > 0) {        /* relay data */
--                      if (size < ret_size)
--                              ret_size = size;
--
--                      if (copy_to_user((void __user *) buf,
--                                       chip->data_buffer, ret_size)) {
--                              ret_size = -EFAULT;
--                      }
--              }
--              up(&chip->buffer_mutex);
-       }
- 
-       return ret_size;
---- ref-linux-2.6.12/drivers/char/tpm/tpm.h    2005-06-17 15:48:29.000000000 
-0400
-+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.h        2005-09-15 
14:56:05.000000000 -0400
-@@ -54,6 +54,7 @@ struct tpm_chip {
-       /* Data passed to and from the tpm via the read/write calls */
-       u8 *data_buffer;
-       atomic_t data_pending;
-+      atomic_t data_position;
-       struct semaphore buffer_mutex;
- 
-       struct timer_list user_read_timer;      /* user needs to claim result */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.