]> xenbits.xen.org Git - xenclient/linux-2.6.27-pq.git/commitdiff
Backport of tpm from 2.6.30.1, together with a set of patches
authorroot <root@taoand.(none)>
Sun, 4 Oct 2009 00:19:30 +0000 (01:19 +0100)
committerroot <root@taoand.(none)>
Sun, 4 Oct 2009 00:19:30 +0000 (01:19 +0100)
from the linux kernel mailing list to support itpm

master/itpm

index 82014aab827dbc3457f09b077a18f1a200bd916b..864c17fc8d021030cbdd1770114bbf512a4e71da 100644 (file)
+diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
+index 692573e..da96c8e 100644
+--- a/drivers/char/tpm/Kconfig
++++ b/drivers/char/tpm/Kconfig
+@@ -23,7 +23,7 @@ if TCG_TPM
+ config TCG_TIS
+       tristate "TPM Interface Specification 1.2 Interface"
+-      depends on PNP
++      depends on ACPI
+       ---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
+diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
+index 3244389..ccdd828 100644
+--- a/drivers/char/tpm/tpm.c
++++ b/drivers/char/tpm/tpm.c
+@@ -429,134 +429,148 @@ out:
+ #define TPM_DIGEST_SIZE 20
+ #define TPM_ERROR_SIZE 10
+ #define TPM_RET_CODE_IDX 6
+-#define TPM_GET_CAP_RET_SIZE_IDX 10
+-#define TPM_GET_CAP_RET_UINT32_1_IDX 14
+-#define TPM_GET_CAP_RET_UINT32_2_IDX 18
+-#define TPM_GET_CAP_RET_UINT32_3_IDX 22
+-#define TPM_GET_CAP_RET_UINT32_4_IDX 26
+-#define TPM_GET_CAP_PERM_DISABLE_IDX 16
+-#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
+-#define TPM_GET_CAP_RET_BOOL_1_IDX 14
+-#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16
+-
+-#define TPM_CAP_IDX 13
+-#define TPM_CAP_SUBCAP_IDX 21
+ enum tpm_capabilities {
+-      TPM_CAP_FLAG = 4,
+-      TPM_CAP_PROP = 5,
++      TPM_CAP_FLAG = cpu_to_be32(4),
++      TPM_CAP_PROP = cpu_to_be32(5),
++      CAP_VERSION_1_1 = cpu_to_be32(0x06),
++      CAP_VERSION_1_2 = cpu_to_be32(0x1A)
+ };
+ enum tpm_sub_capabilities {
+-      TPM_CAP_PROP_PCR = 0x1,
+-      TPM_CAP_PROP_MANUFACTURER = 0x3,
+-      TPM_CAP_FLAG_PERM = 0x8,
+-      TPM_CAP_FLAG_VOL = 0x9,
+-      TPM_CAP_PROP_OWNER = 0x11,
+-      TPM_CAP_PROP_TIS_TIMEOUT = 0x15,
+-      TPM_CAP_PROP_TIS_DURATION = 0x20,
+-};
+-
+-/*
+- * This is a semi generic GetCapability command for use
+- * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
+- * and their associated sub_capabilities.
+- */
++      TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
++      TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
++      TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
++      TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
++      TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
++      TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
++      TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
+-static const u8 tpm_cap[] = {
+-      0, 193,                 /* TPM_TAG_RQU_COMMAND */
+-      0, 0, 0, 22,            /* length */
+-      0, 0, 0, 101,           /* TPM_ORD_GetCapability */
+-      0, 0, 0, 0,             /* TPM_CAP_<TYPE> */
+-      0, 0, 0, 4,             /* TPM_CAP_SUB_<TYPE> size */
+-      0, 0, 1, 0              /* TPM_CAP_SUB_<TYPE> */
+ };
+-static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len,
+-                          char *desc)
++static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
++                          int len, const char *desc)
+ {
+       int err;
+-      len = tpm_transmit(chip, data, len);
++      len = tpm_transmit(chip,(u8 *) cmd, len);
+       if (len <  0)
+               return len;
+       if (len == TPM_ERROR_SIZE) {
+-              err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
++              err = be32_to_cpu(cmd->header.out.return_code);
+               dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+               return err;
+       }
+       return 0;
+ }
++#define TPM_INTERNAL_RESULT_SIZE 200
++#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
++#define TPM_ORD_GET_CAP cpu_to_be32(101)
++
++static const struct tpm_input_header tpm_getcap_header = {
++      .tag = TPM_TAG_RQU_COMMAND,
++      .length = cpu_to_be32(22),
++      .ordinal = TPM_ORD_GET_CAP
++};
++
++ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
++                 const char *desc)
++{
++      struct tpm_cmd_t tpm_cmd;
++      int rc;
++      struct tpm_chip *chip = dev_get_drvdata(dev);
++
++      tpm_cmd.header.in = tpm_getcap_header;
++      if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
++              tpm_cmd.params.getcap_in.cap = subcap_id;
++              /*subcap field not necessary */
++              tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
++              tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
++      } else {
++              if (subcap_id == TPM_CAP_FLAG_PERM ||
++                  subcap_id == TPM_CAP_FLAG_VOL)
++                      tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
++              else
++                      tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
++              tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
++              tpm_cmd.params.getcap_in.subcap = subcap_id;
++      }
++      rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
++      if (!rc)
++              *cap = tpm_cmd.params.getcap_out.cap;
++      return rc;
++}
++
+ void tpm_gen_interrupt(struct tpm_chip *chip)
+ {
+-      u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
++      struct  tpm_cmd_t tpm_cmd;
+       ssize_t rc;
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
++      tpm_cmd.header.in = tpm_getcap_header;
++      tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
++      tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
++      tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+-      rc = transmit_cmd(chip, data, sizeof(data),
++      rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+                       "attempting to determine the timeouts");
+ }
+ EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
+ void tpm_get_timeouts(struct tpm_chip *chip)
+ {
+-      u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
++      struct tpm_cmd_t tpm_cmd;
++      struct timeout_t *timeout_cap;
++      struct duration_t *duration_cap;
+       ssize_t rc;
+       u32 timeout;
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
++      tpm_cmd.header.in = tpm_getcap_header;
++      tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
++      tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
++      tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+-      rc = transmit_cmd(chip, data, sizeof(data),
++      rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+                       "attempting to determine the timeouts");
+       if (rc)
+               goto duration;
+-      if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
++      if (be32_to_cpu(tpm_cmd.header.out.length)
+           != 4 * sizeof(u32))
+               goto duration;
++      timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
+       /* Don't overwrite default if value is 0 */
+-      timeout =
+-          be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
++      timeout = be32_to_cpu(timeout_cap->a);
+       if (timeout)
+               chip->vendor.timeout_a = usecs_to_jiffies(timeout);
+-      timeout =
+-          be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
++      timeout = be32_to_cpu(timeout_cap->b);
+       if (timeout)
+               chip->vendor.timeout_b = usecs_to_jiffies(timeout);
+-      timeout =
+-          be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
++      timeout = be32_to_cpu(timeout_cap->c);
+       if (timeout)
+               chip->vendor.timeout_c = usecs_to_jiffies(timeout);
+-      timeout =
+-          be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
++      timeout = be32_to_cpu(timeout_cap->d);
+       if (timeout)
+               chip->vendor.timeout_d = usecs_to_jiffies(timeout);
+ duration:
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
++      tpm_cmd.header.in = tpm_getcap_header;
++      tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
++      tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
++      tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
+-      rc = transmit_cmd(chip, data, sizeof(data),
++      rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+                       "attempting to determine the durations");
+       if (rc)
+               return;
+-      if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
++      if (be32_to_cpu(tpm_cmd.header.out.return_code)
+           != 3 * sizeof(u32))
+               return;
+-
++      duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
+       chip->vendor.duration[TPM_SHORT] =
+-          usecs_to_jiffies(be32_to_cpu
+-                           (*((__be32 *) (data +
+-                                          TPM_GET_CAP_RET_UINT32_1_IDX))));
++          usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
+       /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
+        * value wrong and apparently reports msecs rather than usecs. So we
+        * fix up the resulting too-small TPM_SHORT value to make things work.
+@@ -565,13 +579,9 @@ duration:
+               chip->vendor.duration[TPM_SHORT] = HZ;
+       chip->vendor.duration[TPM_MEDIUM] =
+-          usecs_to_jiffies(be32_to_cpu
+-                           (*((__be32 *) (data +
+-                                          TPM_GET_CAP_RET_UINT32_2_IDX))));
++          usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
+       chip->vendor.duration[TPM_LONG] =
+-          usecs_to_jiffies(be32_to_cpu
+-                           (*((__be32 *) (data +
+-                                          TPM_GET_CAP_RET_UINT32_3_IDX))));
++          usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
+ }
+ EXPORT_SYMBOL_GPL(tpm_get_timeouts);
+@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip)
+ }
+ EXPORT_SYMBOL_GPL(tpm_continue_selftest);
+-#define  TPM_INTERNAL_RESULT_SIZE 200
+-
+ ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
+                       char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
+       ssize_t rc;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
+-
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                      "attemtping to determine the permanent enabled state");
+-      if (rc) {
+-              kfree(data);
++      rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
++                       "attempting to determine the permanent enabled state");
++      if (rc)
+               return 0;
+-      }
+-      rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
+-
+-      kfree(data);
++      rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
+       return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_enabled);
+@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled);
+ ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
+                       char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
+       ssize_t rc;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
+-
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                      "attemtping to determine the permanent active state");
+-      if (rc) {
+-              kfree(data);
++      rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
++                       "attempting to determine the permanent active state");
++      if (rc)
+               return 0;
+-      }
+-
+-      rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);
+-      kfree(data);
++      rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
+       return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_active);
+@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active);
+ ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
+                       char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
+       ssize_t rc;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
+-
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                      "attempting to determine the owner state");
+-      if (rc) {
+-              kfree(data);
++      rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
++                       "attempting to determine the owner state");
++      if (rc)
+               return 0;
+-      }
+-      rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
+-
+-      kfree(data);
++      rc = sprintf(buf, "%d\n", cap.owned);
+       return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_owned);
+@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned);
+ ssize_t tpm_show_temp_deactivated(struct device * dev,
+                               struct device_attribute * attr, char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
+       ssize_t rc;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
++      rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
++                       "attempting to determine the temporary state");
++      if (rc)
++              return 0;
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
++      rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
++
++/*
++ * tpm_chip_find_get - return tpm_chip for given chip number
++ */
++static struct tpm_chip *tpm_chip_find_get(int chip_num)
++{
++      struct tpm_chip *pos, *chip = NULL;
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
++      rcu_read_lock();
++      list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
++              if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
++                      continue;
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                      "attempting to determine the temporary state");
+-      if (rc) {
+-              kfree(data);
+-              return 0;
++              if (try_module_get(pos->dev->driver->owner)) {
++                      chip = pos;
++                      break;
++              }
+       }
++      rcu_read_unlock();
++      return chip;
++}
+-      rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
++#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
++#define READ_PCR_RESULT_SIZE 30
++static struct tpm_input_header pcrread_header = {
++      .tag = TPM_TAG_RQU_COMMAND,
++      .length = cpu_to_be32(14),
++      .ordinal = TPM_ORDINAL_PCRREAD
++};
+-      kfree(data);
++int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
++{
++      int rc;
++      struct tpm_cmd_t cmd;
++
++      cmd.header.in = pcrread_header;
++      cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
++      BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
++      rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
++                        "attempting to read a pcr value");
++
++      if (rc == 0)
++              memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
++                     TPM_DIGEST_SIZE);
+       return rc;
+ }
+-EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
+-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 */
++/**
++ * tpm_pcr_read - read a pcr value
++ * @chip_num:         tpm idx # or ANY
++ * @pcr_idx:  pcr idx to retrieve
++ * @res_buf:  TPM_PCR value
++ *            size of res_buf is 20 bytes (or NULL if you don't care)
++ *
++ * The TPM driver should be built-in, but for whatever reason it
++ * isn't, protect against the chip disappearing, by incrementing
++ * the module usage count.
++ */
++int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
++{
++      struct tpm_chip *chip;
++      int rc;
++
++      chip = tpm_chip_find_get(chip_num);
++      if (chip == NULL)
++              return -ENODEV;
++      rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
++      module_put(chip->dev->driver->owner);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(tpm_pcr_read);
++
++/**
++ * tpm_pcr_extend - extend pcr value with hash
++ * @chip_num:         tpm idx # or AN&
++ * @pcr_idx:  pcr idx to extend
++ * @hash:     hash value used to extend pcr value
++ *
++ * The TPM driver should be built-in, but for whatever reason it
++ * isn't, protect against the chip disappearing, by incrementing
++ * the module usage count.
++ */
++#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
++#define EXTEND_PCR_SIZE 34
++static struct tpm_input_header pcrextend_header = {
++      .tag = TPM_TAG_RQU_COMMAND,
++      .length = cpu_to_be32(34),
++      .ordinal = TPM_ORD_PCR_EXTEND
+ };
++int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
++{
++      struct tpm_cmd_t cmd;
++      int rc;
++      struct tpm_chip *chip;
++
++      chip = tpm_chip_find_get(chip_num);
++      if (chip == NULL)
++              return -ENODEV;
++
++      cmd.header.in = pcrextend_header;
++      BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE);
++      cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
++      memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
++      rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
++                        "attempting extend a PCR value");
++
++      module_put(chip->dev->driver->owner);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(tpm_pcr_extend);
++
+ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+                     char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
++      u8 digest[TPM_DIGEST_SIZE];
+       ssize_t rc;
+       int i, j, num_pcrs;
+-      __be32 index;
+       char *str = buf;
+-
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
++      rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
+                       "attempting to determine the number of PCRS");
+-      if (rc) {
+-              kfree(data);
++      if (rc)
+               return 0;
+-      }
+-      num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
++      num_pcrs = be32_to_cpu(cap.num_pcrs);
+       for (i = 0; i < num_pcrs; i++) {
+-              memcpy(data, pcrread, sizeof(pcrread));
+-              index = cpu_to_be32(i);
+-              memcpy(data + 10, &index, 4);
+-              rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                              "attempting to read a PCR");
++              rc = __tpm_pcr_read(chip, i, digest);
+               if (rc)
+-                      goto out;
++                      break;
+               str += sprintf(str, "PCR-%02d: ", i);
+               for (j = 0; j < TPM_DIGEST_SIZE; j++)
+-                      str += sprintf(str, "%02X ", *(data + 10 + j));
++                      str += sprintf(str, "%02X ", digest[j]);
+               str += sprintf(str, "\n");
+       }
+-out:
+-      kfree(data);
+       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 */
++#define TPM_ORD_READPUBEK cpu_to_be32(124)
++struct tpm_input_header tpm_readpubek_header = {
++      .tag = TPM_TAG_RQU_COMMAND,
++      .length = cpu_to_be32(30),
++      .ordinal = TPM_ORD_READPUBEK
+ };
+ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+ {
+       u8 *data;
++      struct tpm_cmd_t tpm_cmd;
+       ssize_t err;
+       int i, rc;
+       char *str = buf;
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-      data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, readpubek, sizeof(readpubek));
+-
+-      err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
++      tpm_cmd.header.in = tpm_readpubek_header;
++      err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+                       "attempting to read the PUBEK");
+       if (err)
+               goto out;
+@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+          256 byte modulus
+          ignore checksum 20 bytes
+        */
+-
++      data = tpm_cmd.params.readpubek_out_buffer;
+       str +=
+           sprintf(str,
+                   "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+       }
+ out:
+       rc = str - buf;
+-      kfree(data);
+       return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_pubek);
+-#define CAP_VERSION_1_1 6
+-#define CAP_VERSION_1_2 0x1A
+-#define CAP_VERSION_IDX 13
+-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, 0,
+-      0, 0, 0, 0
+-};
+ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+                     char *buf)
+ {
+-      u8 *data;
++      cap_t cap;
+       ssize_t rc;
+       char *str = buf;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
+-
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
++      rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
+                       "attempting to determine the manufacturer");
+-      if (rc) {
+-              kfree(data);
++      if (rc)
+               return 0;
+-      }
+-
+       str += sprintf(str, "Manufacturer: 0x%x\n",
+-                     be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
++                     be32_to_cpu(cap.manufacturer_id));
+-      memcpy(data, cap_version, sizeof(cap_version));
+-      data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
+-      rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+-                      "attempting to determine the 1.1 version");
++      rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
++                      "attempting to determine the 1.1 version");
+       if (rc)
+-              goto out;
+-
++              return 0;
+       str += sprintf(str,
+                      "TCG version: %d.%d\nFirmware version: %d.%d\n",
+-                     (int) data[14], (int) data[15], (int) data[16],
+-                     (int) data[17]);
+-
+-out:
+-      kfree(data);
++                     cap.tpm_version.Major, cap.tpm_version.Minor,
++                     cap.tpm_version.revMajor, cap.tpm_version.revMinor);
+       return str - buf;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_caps);
+@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps);
+ ssize_t tpm_show_caps_1_2(struct device * dev,
+                         struct device_attribute * attr, char *buf)
+ {
+-      u8 *data;
+-      ssize_t len;
++      cap_t cap;
++      ssize_t rc;
+       char *str = buf;
+-      struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip == NULL)
+-              return -ENODEV;
+-
+-      data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      memcpy(data, tpm_cap, sizeof(tpm_cap));
+-      data[TPM_CAP_IDX] = TPM_CAP_PROP;
+-      data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
+-
+-      len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
+-      if (len <= TPM_ERROR_SIZE) {
+-              dev_dbg(chip->dev, "A TPM error (%d) occurred "
+-                      "attempting to determine the manufacturer\n",
+-                      be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+-              kfree(data);
++      rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
++                      "attempting to determine the manufacturer");
++      if (rc)
+               return 0;
+-      }
+-
+       str += sprintf(str, "Manufacturer: 0x%x\n",
+-                     be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+-
+-      memcpy(data, cap_version, sizeof(cap_version));
+-      data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
+-
+-      len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
+-      if (len <= TPM_ERROR_SIZE) {
+-              dev_err(chip->dev, "A TPM error (%d) occurred "
+-                      "attempting to determine the 1.2 version\n",
+-                      be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+-              goto out;
+-      }
++                     be32_to_cpu(cap.manufacturer_id));
++      rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
++                       "attempting to determine the 1.2 version");
++      if (rc)
++              return 0;
+       str += sprintf(str,
+                      "TCG version: %d.%d\nFirmware version: %d.%d\n",
+-                     (int) data[16], (int) data[17], (int) data[18],
+-                     (int) data[19]);
+-
+-out:
+-      kfree(data);
++                     cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
++                     cap.tpm_version_1_2.revMajor,
++                     cap.tpm_version_1_2.revMinor);
+       return str - buf;
+ }
+ EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
+@@ -961,72 +927,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel);
+ /*
+  * Device file system interface to the TPM
++ *
++ * It's assured that the chip will be opened just once,
++ * by the check of is_open variable, which is protected
++ * by driver_lock.
+  */
+ int tpm_open(struct inode *inode, struct file *file)
+ {
+-      int rc = 0, minor = iminor(inode);
++      int minor = iminor(inode);
+       struct tpm_chip *chip = NULL, *pos;
+-      lock_kernel();
+-      spin_lock(&driver_lock);
+-
+-      list_for_each_entry(pos, &tpm_chip_list, list) {
++      rcu_read_lock();
++      list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+               if (pos->vendor.miscdev.minor == minor) {
+                       chip = pos;
++                      get_device(chip->dev);
+                       break;
+               }
+       }
++      rcu_read_unlock();
+-      if (chip == NULL) {
+-              rc = -ENODEV;
+-              goto err_out;
+-      }
++      if (!chip)
++              return -ENODEV;
+-      if (chip->num_opens) {
++      if (test_and_set_bit(0, &chip->is_open)) {
+               dev_dbg(chip->dev, "Another process owns this TPM\n");
+-              rc = -EBUSY;
+-              goto err_out;
++              put_device(chip->dev);
++              return -EBUSY;
+       }
+-      chip->num_opens++;
+-      get_device(chip->dev);
+-
+-      spin_unlock(&driver_lock);
+-
+       chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+       if (chip->data_buffer == NULL) {
+-              chip->num_opens--;
++              clear_bit(0, &chip->is_open);
+               put_device(chip->dev);
+-              unlock_kernel();
+               return -ENOMEM;
+       }
+       atomic_set(&chip->data_pending, 0);
+       file->private_data = chip;
+-      unlock_kernel();
+       return 0;
+-
+-err_out:
+-      spin_unlock(&driver_lock);
+-      unlock_kernel();
+-      return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_open);
++/*
++ * Called on file close
++ */
+ int tpm_release(struct inode *inode, struct file *file)
+ {
+       struct tpm_chip *chip = file->private_data;
++      del_singleshot_timer_sync(&chip->user_read_timer);
+       flush_scheduled_work();
+-      spin_lock(&driver_lock);
+       file->private_data = NULL;
+-      del_singleshot_timer_sync(&chip->user_read_timer);
+       atomic_set(&chip->data_pending, 0);
+-      chip->num_opens--;
+-      put_device(chip->dev);
+       kfree(chip->data_buffer);
+-      spin_unlock(&driver_lock);
++      clear_bit(0, &chip->is_open);
++      put_device(chip->dev);
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(tpm_release);
+@@ -1100,13 +1057,11 @@ void tpm_remove_hardware(struct device *dev)
+       }
+       spin_lock(&driver_lock);
+-
+-      list_del(&chip->list);
+-
++      list_del_rcu(&chip->list);
+       spin_unlock(&driver_lock);
++      synchronize_rcu();
+       misc_deregister(&chip->vendor.miscdev);
+-
+       sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
+       tpm_bios_log_teardown(chip->bios_dir);
+@@ -1151,25 +1106,33 @@ int tpm_pm_resume(struct device *dev)
+ }
+ EXPORT_SYMBOL_GPL(tpm_pm_resume);
++/* In case vendor provided release function, call it too.*/
++
++void tpm_dev_vendor_release(struct tpm_chip *chip)
++{
++      if (chip->vendor.release)
++              chip->vendor.release(chip->dev);
++
++      clear_bit(chip->dev_num, dev_mask);
++      kfree(chip->vendor.miscdev.name);
++}
++EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
++
++
+ /*
+  * Once all references to platform device are down to 0,
+  * release all allocated structures.
+- * In case vendor provided release function,
+- * call it too.
+  */
+-static void tpm_dev_release(struct device *dev)
++void tpm_dev_release(struct device *dev)
+ {
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+-      if (chip->vendor.release)
+-              chip->vendor.release(dev);
++      tpm_dev_vendor_release(chip);
+       chip->release(dev);
+-
+-      clear_bit(chip->dev_num, dev_mask);
+-      kfree(chip->vendor.miscdev.name);
+       kfree(chip);
+ }
++EXPORT_SYMBOL_GPL(tpm_dev_release);
+ /*
+  * Called from tpm_<specific>.c probe function only for devices 
+@@ -1178,8 +1141,8 @@ static void tpm_dev_release(struct device *dev)
+  * upon errant exit from this function specific probe function should call
+  * pci_disable_device
+  */
+-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
+-                                     *entry)
++struct tpm_chip *tpm_register_hardware(struct device *dev,
++                                      const struct tpm_vendor_specific *entry)
+ {
+ #define DEVNAME_SIZE 7
+@@ -1190,11 +1153,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+-      if (chip == NULL || devname == NULL) {
+-              kfree(chip);
+-              kfree(devname);
+-              return NULL;
+-      }
++      if (chip == NULL || devname == NULL)
++              goto out_free;
+       mutex_init(&chip->buffer_mutex);
+       mutex_init(&chip->tpm_mutex);
+@@ -1211,8 +1171,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
+       if (chip->dev_num >= TPM_NUM_DEVICES) {
+               dev_err(dev, "No available tpm device numbers\n");
+-              kfree(chip);
+-              return NULL;
++              goto out_free;
+       } else if (chip->dev_num == 0)
+               chip->vendor.miscdev.minor = TPM_MINOR;
+       else
+@@ -1238,22 +1197,26 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
+               return NULL;
+       }
+-      spin_lock(&driver_lock);
+-
+-      list_add(&chip->list, &tpm_chip_list);
+-
+-      spin_unlock(&driver_lock);
+-
+       if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
+-              list_del(&chip->list);
+               misc_deregister(&chip->vendor.miscdev);
+               put_device(chip->dev);
++
+               return NULL;
+       }
+       chip->bios_dir = tpm_bios_log_setup(devname);
++      /* Make chip available */
++      spin_lock(&driver_lock);
++      list_add_rcu(&chip->list, &tpm_chip_list);
++      spin_unlock(&driver_lock);
++
+       return chip;
++
++out_free:
++      kfree(chip);
++      kfree(devname);
++      return NULL;
+ }
+ EXPORT_SYMBOL_GPL(tpm_register_hardware);
+diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
+index 557550a..8e00b4d 100644
+--- a/drivers/char/tpm/tpm.h
++++ b/drivers/char/tpm/tpm.h
+@@ -26,6 +26,7 @@
+ #include <linux/miscdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
++#include <linux/tpm.h>
+ enum tpm_timeout {
+       TPM_TIMEOUT = 5,        /* msecs */
+@@ -90,7 +91,7 @@ struct tpm_chip {
+       struct device *dev;     /* Device stuff */
+       int dev_num;            /* /dev/tpm# */
+-      int num_opens;          /* only one allowed */
++      unsigned long is_open;  /* only one allowed */
+       int time_expired;
+       /* Data passed to and from the tpm via the read/write calls */
+@@ -107,9 +108,6 @@ struct tpm_chip {
+       struct dentry **bios_dir;
+       struct list_head list;
+-#ifdef CONFIG_XEN
+-      void *priv;
+-#endif
+       void (*release) (struct device *);
+ };
+@@ -126,18 +124,147 @@ static inline void tpm_write_index(int base, int index, int value)
+       outb(index, base);
+       outb(value & 0xFF, base+1);
+ }
++struct tpm_input_header {
++      __be16  tag;
++      __be32  length;
++      __be32  ordinal;
++}__attribute__((packed));
+-#ifdef CONFIG_XEN
+-static inline void *chip_get_private(const struct tpm_chip *chip)
+-{
+-      return chip->priv;
+-}
++struct tpm_output_header {
++      __be16  tag;
++      __be32  length;
++      __be32  return_code;
++}__attribute__((packed));
+-static inline void chip_set_private(struct tpm_chip *chip, void *priv)
+-{
+-      chip->priv = priv;
+-}
+-#endif
++struct        stclear_flags_t {
++      __be16  tag;
++      u8      deactivated;
++      u8      disableForceClear;
++      u8      physicalPresence;
++      u8      physicalPresenceLock;
++      u8      bGlobalLock;
++}__attribute__((packed));
++
++struct        tpm_version_t {
++      u8      Major;
++      u8      Minor;
++      u8      revMajor;
++      u8      revMinor;
++}__attribute__((packed));
++
++struct        tpm_version_1_2_t {
++      __be16  tag;
++      u8      Major;
++      u8      Minor;
++      u8      revMajor;
++      u8      revMinor;
++}__attribute__((packed));
++
++struct        timeout_t {
++      __be32  a;
++      __be32  b;
++      __be32  c;
++      __be32  d;
++}__attribute__((packed));
++
++struct duration_t {
++      __be32  tpm_short;
++      __be32  tpm_medium;
++      __be32  tpm_long;
++}__attribute__((packed));
++
++struct permanent_flags_t {
++      __be16  tag;
++      u8      disable;
++      u8      ownership;
++      u8      deactivated;
++      u8      readPubek;
++      u8      disableOwnerClear;
++      u8      allowMaintenance;
++      u8      physicalPresenceLifetimeLock;
++      u8      physicalPresenceHWEnable;
++      u8      physicalPresenceCMDEnable;
++      u8      CEKPUsed;
++      u8      TPMpost;
++      u8      TPMpostLock;
++      u8      FIPS;
++      u8      operator;
++      u8      enableRevokeEK;
++      u8      nvLocked;
++      u8      readSRKPub;
++      u8      tpmEstablished;
++      u8      maintenanceDone;
++      u8      disableFullDALogicInfo;
++}__attribute__((packed));
++
++typedef union {
++      struct  permanent_flags_t perm_flags;
++      struct  stclear_flags_t stclear_flags;
++      bool    owned;
++      __be32  num_pcrs;
++      struct  tpm_version_t   tpm_version;
++      struct  tpm_version_1_2_t tpm_version_1_2;
++      __be32  manufacturer_id;
++      struct timeout_t  timeout;
++      struct duration_t duration;
++} cap_t;
++
++struct        tpm_getcap_params_in {
++      __be32  cap;
++      __be32  subcap_size;
++      __be32  subcap;
++}__attribute__((packed));
++
++struct        tpm_getcap_params_out {
++      __be32  cap_size;
++      cap_t   cap;
++}__attribute__((packed));
++
++struct        tpm_readpubek_params_out {
++      u8      algorithm[4];
++      u8      encscheme[2];
++      u8      sigscheme[2];
++      u8      parameters[12]; /*assuming RSA*/
++      __be32  keysize;
++      u8      modulus[256];
++      u8      checksum[20];
++}__attribute__((packed));
++
++typedef union {
++      struct  tpm_input_header in;
++      struct  tpm_output_header out;
++} tpm_cmd_header;
++
++#define TPM_DIGEST_SIZE 20
++struct tpm_pcrread_out {
++      u8      pcr_result[TPM_DIGEST_SIZE];
++}__attribute__((packed));
++
++struct tpm_pcrread_in {
++      __be32  pcr_idx;
++}__attribute__((packed));
++
++struct tpm_pcrextend_in {
++      __be32  pcr_idx;
++      u8      hash[TPM_DIGEST_SIZE];
++}__attribute__((packed));
++
++typedef union {
++      struct  tpm_getcap_params_out getcap_out;
++      struct  tpm_readpubek_params_out readpubek_out;
++      u8      readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
++      struct  tpm_getcap_params_in getcap_in;
++      struct  tpm_pcrread_in  pcrread_in;
++      struct  tpm_pcrread_out pcrread_out;
++      struct  tpm_pcrextend_in pcrextend_in;
++} tpm_cmd_params;
++
++struct tpm_cmd_t {
++      tpm_cmd_header  header;
++      tpm_cmd_params  params;
++}__attribute__((packed));
++
++ssize_t       tpm_getcap(struct device *, __be32, cap_t *, const char *);
+ extern void tpm_get_timeouts(struct tpm_chip *);
+ extern void tpm_gen_interrupt(struct tpm_chip *);
+@@ -147,6 +274,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
+                                const struct tpm_vendor_specific *);
+ extern int tpm_open(struct inode *, struct file *);
+ extern int tpm_release(struct inode *, struct file *);
++extern void tpm_dev_vendor_release(struct tpm_chip *);
+ 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 *);
+diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
+index d0e7926..c64a1bc 100644
+--- a/drivers/char/tpm/tpm_atmel.c
++++ b/drivers/char/tpm/tpm_atmel.c
+@@ -168,12 +168,22 @@ static void atml_plat_remove(void)
+       }
+ }
+-static struct device_driver atml_drv = {
+-      .name = "tpm_atmel",
+-      .bus = &platform_bus_type,
+-      .owner = THIS_MODULE,
+-      .suspend = tpm_pm_suspend,
+-      .resume = tpm_pm_resume,
++static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg)
++{
++      return tpm_pm_suspend(&dev->dev, msg);
++}
++
++static int tpm_atml_resume(struct platform_device *dev)
++{
++      return tpm_pm_resume(&dev->dev);
++}
++static struct platform_driver atml_drv = {
++      .driver = {
++              .name = "tpm_atmel",
++              .owner          = THIS_MODULE,
++      },
++      .suspend = tpm_atml_suspend,
++      .resume = tpm_atml_resume,
+ };
+ static int __init init_atmel(void)
+@@ -184,7 +194,7 @@ static int __init init_atmel(void)
+       unsigned long base;
+       struct  tpm_chip *chip;
+-      rc = driver_register(&atml_drv);
++      rc = platform_driver_register(&atml_drv);
+       if (rc)
+               return rc;
+@@ -223,13 +233,13 @@ err_rel_reg:
+               atmel_release_region(base,
+                                    region_size);
+ err_unreg_drv:
+-      driver_unregister(&atml_drv);
++      platform_driver_unregister(&atml_drv);
+       return rc;
+ }
+ static void __exit cleanup_atmel(void)
+ {
+-      driver_unregister(&atml_drv);
++      platform_driver_unregister(&atml_drv);
+       atml_plat_remove();
+ }
+diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
+index 68f052b..0c2f55a 100644
+--- a/drivers/char/tpm/tpm_bios.c
++++ b/drivers/char/tpm/tpm_bios.c
+@@ -23,8 +23,6 @@
+ #include <linux/security.h>
+ #include <linux/module.h>
+ #include <acpi/acpi.h>
+-#include <acpi/actypes.h>
+-#include <acpi/actbl.h>
+ #include "tpm.h"
+ #define TCG_EVENT_NAME_LEN_MAX        255
+@@ -214,7 +212,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
+                       unsigned char * event_entry)
+ {
+       const char *name = "";
+-      char data[40] = "";
++      /* 41 so there is room for 40 data and 1 nul */
++      char data[41] = "";
+       int i, n_len = 0, d_len = 0;
+       struct tcpa_pc_event *pc_event;
+diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
+index 726ee8a..ecba494 100644
+--- a/drivers/char/tpm/tpm_infineon.c
++++ b/drivers/char/tpm/tpm_infineon.c
+@@ -4,7 +4,7 @@
+  * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
+  * Specifications at www.trustedcomputinggroup.org
+  *
+- * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de>
++ * Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com>
+  * Sirrix AG - security technologies, http://www.sirrix.com and
+  * Applied Data Security Group, Ruhr-University Bochum, Germany
+  * Project-Homepage: http://www.prosec.rub.de/tpm
+@@ -636,7 +636,7 @@ static void __exit cleanup_inf(void)
+ module_init(init_inf);
+ module_exit(cleanup_inf);
+-MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
++MODULE_AUTHOR("Marcel Selhorst <m.selhorst@sirrix.com>");
+ MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
+ MODULE_VERSION("1.9");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
+index ab18c1e..70efba2 100644
+--- a/drivers/char/tpm/tpm_nsc.c
++++ b/drivers/char/tpm/tpm_nsc.c
+@@ -273,12 +273,23 @@ static void tpm_nsc_remove(struct device *dev)
+       }
+ }
+-static struct device_driver nsc_drv = {
+-      .name = "tpm_nsc",
+-      .bus = &platform_bus_type,
+-      .owner = THIS_MODULE,
+-      .suspend = tpm_pm_suspend,
+-      .resume = tpm_pm_resume,
++static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg)
++{
++      return tpm_pm_suspend(&dev->dev, msg);
++}
++
++static int tpm_nsc_resume(struct platform_device *dev)
++{
++      return tpm_pm_resume(&dev->dev);
++}
++
++static struct platform_driver nsc_drv = {
++      .suspend         = tpm_nsc_suspend,
++      .resume          = tpm_nsc_resume,
++      .driver          = {
++              .name    = "tpm_nsc",
++              .owner   = THIS_MODULE,
++      },
+ };
+ static int __init init_nsc(void)
+@@ -297,7 +308,7 @@ static int __init init_nsc(void)
+                       return -ENODEV;
+       }
+-      err = driver_register(&nsc_drv);
++      err = platform_driver_register(&nsc_drv);
+       if (err)
+               return err;
+@@ -308,17 +319,15 @@ static int __init init_nsc(void)
+       /* enable the DPM module */
+       tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
+-      pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
++      pdev = platform_device_alloc("tpm_nscl0", -1);
+       if (!pdev) {
+               rc = -ENOMEM;
+               goto err_unreg_drv;
+       }
+-      pdev->name = "tpm_nscl0";
+-      pdev->id = -1;
+       pdev->num_resources = 0;
++      pdev->dev.driver = &nsc_drv.driver;
+       pdev->dev.release = tpm_nsc_remove;
+-      pdev->dev.driver = &nsc_drv;
+       if ((rc = platform_device_register(pdev)) < 0)
+               goto err_free_dev;
+@@ -377,7 +386,7 @@ err_unreg_dev:
+ err_free_dev:
+       kfree(pdev);
+ err_unreg_drv:
+-      driver_unregister(&nsc_drv);
++      platform_driver_unregister(&nsc_drv);
+       return rc;
+ }
+@@ -390,7 +399,7 @@ static void __exit cleanup_nsc(void)
+               pdev = NULL;
+       }
+-      driver_unregister(&nsc_drv);
++      platform_driver_unregister(&nsc_drv);
+ }
+ module_init(init_nsc);
 diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
-index ed1879c..b83b305 100644
+index ed1879c..22b2a69 100644
 --- a/drivers/char/tpm/tpm_tis.c
 +++ b/drivers/char/tpm/tpm_tis.c
-@@ -293,7 +293,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+@@ -21,9 +21,12 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <linux/pnp.h>
+ #include <linux/interrupt.h>
+ #include <linux/wait.h>
++
++#include <linux/acpi.h>
++#include <acpi/acpi_bus.h>
++
+ #include "tpm.h"
+ #define TPM_HEADER_SIZE 10
+@@ -77,6 +80,14 @@ enum tis_defaults {
+ static LIST_HEAD(tis_chips);
+ static DEFINE_SPINLOCK(tis_lock);
++struct tpm_data {
++      unsigned long tpm_phys_address;
++      void __iomem *tpm_address;
++      int tpm_size;
++      int tpm_irq;
++      int itpm;
++};
++
+ static int check_locality(struct tpm_chip *chip, int l)
+ {
+       if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
+@@ -267,6 +278,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+       int rc, status, burstcnt;
+       size_t count = 0;
+       u32 ordinal;
++      struct tpm_data *tpm = to_acpi_device(chip->dev)->driver_data;
+       if (request_locality(chip, 0) < 0)
+               return -EBUSY;
+@@ -293,7 +305,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
                wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
                              &chip->vendor.int_queue);
                status = tpm_tis_status(chip);
 -              if ((status & TPM_STS_DATA_EXPECT) == 0) {
-+              if ((status & TPM_STS_VALID) == 0) {
++              if (!tpm->itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
                        rc = -EIO;
                        goto out_err;
                }
-@@ -430,7 +430,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
-       return IRQ_HANDLED;
- }
--static int interrupts = 1;
-+static int interrupts = 0;
+@@ -434,12 +446,17 @@ static int interrupts = 1;
  module_param(interrupts, bool, 0444);
  MODULE_PARM_DESC(interrupts, "Enable interrupts");
  
-@@ -450,19 +450,19 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
++static int itpm;
++module_param(itpm, bool, 0444);
++MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
++
+ static int tpm_tis_init(struct device *dev, resource_size_t start,
+                       resource_size_t len, unsigned int irq)
+ {
+       u32 vendor, intfcaps, intmask;
+       int rc, i;
+       struct tpm_chip *chip;
++      struct tpm_data *tpm = to_acpi_device(dev)->driver_data;
+       if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
+               return -ENODEV;
+@@ -450,6 +467,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                goto out_err;
        }
  
--      if (request_locality(chip, 0) != 0) {
--              rc = -ENODEV;
--              goto out_err;
--      }
--
--      vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
++      /* Default timeouts */
++      chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++      chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
++      chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++      chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++
+       if (request_locality(chip, 0) != 0) {
+               rc = -ENODEV;
+               goto out_err;
+@@ -457,16 +480,15 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
+       vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+-      /* Default timeouts */
+-      chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+-      chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
+-      chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+-      chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 -
-       /* Default timeouts */
-       chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-       chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
-       chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-       chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+       dev_info(dev,
+-               "1.2 TPM (device-id 0x%X, rev-id %d)\n",
++               "1.2 TPM (%04X:%04X rev %d)\n", vendor & 0xffff,
+                vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
  
-+      if (request_locality(chip, 0) != 0) { 
-+              rc = -ENODEV;
-+              goto out_err;
++      if (itpm || vendor == 0x10208086) {
++              dev_info(dev, "Intel iTPM workaround enabled\n");
++              tpm->itpm = 1;
 +      }
 +
-+      vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+       /* Figure out the capabilities */
+       intfcaps =
+           ioread32(chip->vendor.iobase +
+@@ -474,23 +496,23 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
+       dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
+               intfcaps);
+       if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
+-              dev_dbg(dev, "\tBurst Count Static\n");
++              dev_dbg(dev, "    Burst Count Static\n");
+       if (intfcaps & TPM_INTF_CMD_READY_INT)
+-              dev_dbg(dev, "\tCommand Ready Int Support\n");
++              dev_dbg(dev, "    Command Ready Int Support\n");
+       if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
+-              dev_dbg(dev, "\tInterrupt Edge Falling\n");
++              dev_dbg(dev, "    Interrupt Edge Falling\n");
+       if (intfcaps & TPM_INTF_INT_EDGE_RISING)
+-              dev_dbg(dev, "\tInterrupt Edge Rising\n");
++              dev_dbg(dev, "    Interrupt Edge Rising\n");
+       if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
+-              dev_dbg(dev, "\tInterrupt Level Low\n");
++              dev_dbg(dev, "    Interrupt Level Low\n");
+       if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
+-              dev_dbg(dev, "\tInterrupt Level High\n");
++              dev_dbg(dev, "    Interrupt Level High\n");
+       if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
+-              dev_dbg(dev, "\tLocality Change Int Support\n");
++              dev_dbg(dev, "    Locality Change Int Support\n");
+       if (intfcaps & TPM_INTF_STS_VALID_INT)
+-              dev_dbg(dev, "\tSts Valid Int Support\n");
++              dev_dbg(dev, "    Sts Valid Int Support\n");
+       if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
+-              dev_dbg(dev, "\tData Avail Int Support\n");
++              dev_dbg(dev, "    Data Avail Int Support\n");
+       /* INTERRUPT Setup */
+       init_waitqueue_head(&chip->vendor.read_queue);
+@@ -590,34 +612,114 @@ out_err:
+       return rc;
+ }
+-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+-                                    const struct pnp_device_id *pnp_id)
++static acpi_status tpm_resources(struct acpi_resource *res, void *data)
+ {
+-      resource_size_t start, len;
+-      unsigned int irq = 0;
++      struct acpi_device *device = data;
++      struct device *dev = &device->dev;
++      struct tpm_data *tpm = device->driver_data;
++      acpi_status status;
++      struct acpi_resource_address64 addr;
 +
-       dev_info(dev,
-                "1.2 TPM (device-id 0x%X, rev-id %d)\n",
-                vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
-@@ -653,7 +653,7 @@ static struct device_driver tis_drv = {
++      status = acpi_resource_to_address64(res, &addr);
++
++      if (ACPI_SUCCESS(status)) {
++              dev_info(dev, "found 0x%llx(0x%llx)\n",
++                              (long long)addr.minimum,
++                              (long long)addr.address_length);
++              tpm->tpm_phys_address = addr.minimum;
++              tpm->tpm_address = ioremap(addr.minimum, addr.address_length);
++              tpm->tpm_size = addr.address_length;
++      } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
++              struct acpi_resource_fixed_memory32 *fixmem32;
++
++              fixmem32 = &res->data.fixed_memory32;
++              if (!fixmem32)
++                      return AE_NO_MEMORY;
++
++              dev_info(dev, "found 0x%llx(0x%llx)\n",
++                              (long long)fixmem32->address,
++                              (long long)TIS_MEM_LEN);
++              tpm->tpm_phys_address = fixmem32->address;
++              tpm->tpm_address = ioremap(fixmem32->address, TIS_MEM_LEN);
++              tpm->tpm_size = fixmem32->address_length;
++      } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
++              struct acpi_resource_extended_irq *irq;
++
++              irq = &res->data.extended_irq;
++              if (irq->interrupt_count > 0 && irq->interrupts[0] > 0) {
++                      dev_info(dev, "IRQ %d (%d, %d)\n",
++                                      irq->interrupts[0],
++                                      irq->triggering, irq->polarity);
++                      tpm->tpm_irq = irq->interrupts[0];
++              }
++      }
++
++      return AE_OK;
++}
++
++static int tpm_tis_acpi_add(struct acpi_device *device)
++{
++      acpi_status result;
++      struct tpm_data *tpm = kzalloc(sizeof(*tpm), GFP_KERNEL);
++      int rc = -ENOMEM;
++
++      if (!tpm)
++              goto out;
+-      start = pnp_mem_start(pnp_dev, 0);
+-      len = pnp_mem_len(pnp_dev, 0);
++      device->driver_data = tpm;
+-      if (pnp_irq_valid(pnp_dev, 0))
+-              irq = pnp_irq(pnp_dev, 0);
+-      else
++      result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
++                      tpm_resources, device);
++
++      rc = -ENODEV;
++      if (ACPI_FAILURE(result))
++              goto out_free;
++
++      if (!tpm->tpm_address) {
++              dev_err(&device->dev, "no address found in _CRS\n");
++              goto out_free;
++      }
++
++      if (!tpm->tpm_irq) {
++              dev_err(&device->dev, "no IRQ found in _CRS, polling mode\n");
+               interrupts = 0;
++      }
+-      return tpm_tis_init(&pnp_dev->dev, start, len, irq);
++      return tpm_tis_init(&device->dev, tpm->tpm_phys_address, tpm->tpm_size,
++                      tpm->tpm_irq);
++out_free:
++      kfree(tpm);
++out:
++      return rc;
+ }
+-static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
++static int tpm_tis_acpi_remove(struct acpi_device *device, int type)
+ {
+-      return tpm_pm_suspend(&dev->dev, msg);
++      struct tpm_chip *chip = dev_get_drvdata(&device->dev);
++      tpm_remove_hardware(&device->dev);
++      iowrite32(~TPM_GLOBAL_INT_ENABLE & ioread32(chip->vendor.iobase +
++                              TPM_INT_ENABLE(chip->vendor.locality)),
++                chip->vendor.iobase +
++                TPM_INT_ENABLE(chip->vendor.locality));
++      release_locality(chip, chip->vendor.locality, 1);
++      if (chip->vendor.irq)
++              free_irq(chip->vendor.irq, chip);
++      iounmap(chip->vendor.iobase);
++      kfree(device->driver_data);
++      return 0;
++}
++
++static int tpm_tis_acpi_suspend(struct acpi_device *dev, pm_message_t state)
++{
++      return tpm_pm_suspend(&dev->dev, state);
+ }
+-static int tpm_tis_pnp_resume(struct pnp_dev *dev)
++static int tpm_tis_acpi_resume(struct acpi_device *dev)
+ {
+       return tpm_pm_resume(&dev->dev);
+ }
+-static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
++static struct acpi_device_id tpm_tis_acpi_tbl[] __devinitdata = {
+       {"PNP0C31", 0},         /* TPM */
+       {"ATM1200", 0},         /* Atmel */
+       {"IFX0102", 0},         /* Infineon */
+@@ -625,30 +727,45 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
+       {"BCM0102", 0},         /* Broadcom */
+       {"NSC1200", 0},         /* National */
+       {"ICO0102", 0},         /* Intel */
++      {"INTC0102", 0},        /* TPM spec says to look for this in _CID */
+       /* Add new here */
+       {"", 0},                /* User Specified */
+       {"", 0}                 /* Terminator */
+ };
++MODULE_DEVICE_TABLE(acpi, tpm_tis_acpi_tbl);
+-static struct pnp_driver tis_pnp_driver = {
++static struct acpi_driver tis_acpi_driver = {
+       .name = "tpm_tis",
+-      .id_table = tpm_pnp_tbl,
+-      .probe = tpm_tis_pnp_init,
+-      .suspend = tpm_tis_pnp_suspend,
+-      .resume = tpm_tis_pnp_resume,
++      .ids = tpm_tis_acpi_tbl,
++      .ops = {
++              .add = tpm_tis_acpi_add,
++              .remove = tpm_tis_acpi_remove,
++              .suspend = tpm_tis_acpi_suspend,
++              .resume = tpm_tis_acpi_resume,
++      },
+ };
+-#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
+-module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
+-                  sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
++#define TIS_HID_USR_IDX (ARRAY_SIZE(tpm_tis_acpi_tbl) - 2)
++module_param_string(hid, tpm_tis_acpi_tbl[TIS_HID_USR_IDX].id,
++                  sizeof(tpm_tis_acpi_tbl[TIS_HID_USR_IDX].id), 0444);
+ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+-static struct device_driver tis_drv = {
+-      .name = "tpm_tis",
+-      .bus = &platform_bus_type,
+-      .owner = THIS_MODULE,
+-      .suspend = tpm_pm_suspend,
+-      .resume = tpm_pm_resume,
++static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
++{
++      return tpm_pm_suspend(&dev->dev, msg);
++}
++
++static int tpm_tis_resume(struct platform_device *dev)
++{
++      return tpm_pm_resume(&dev->dev);
++}
++static struct platform_driver tis_drv = {
++      .driver = {
++              .name = "tpm_tis",
++              .owner          = THIS_MODULE,
++      },
++      .suspend = tpm_tis_suspend,
++      .resume = tpm_tis_resume,
+ };
  
  static struct platform_device *pdev;
+@@ -661,19 +778,19 @@ static int __init init_tis(void)
+       int rc;
+       if (force) {
+-              rc = driver_register(&tis_drv);
++              rc = platform_driver_register(&tis_drv);
+               if (rc < 0)
+                       return rc;
+               if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+                       return PTR_ERR(pdev);
+               if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
+                       platform_device_unregister(pdev);
+-                      driver_unregister(&tis_drv);
++                      platform_driver_unregister(&tis_drv);
+               }
+               return rc;
+       }
+-      return pnp_register_driver(&tis_pnp_driver);
++      return acpi_bus_register_driver(&tis_acpi_driver);
+ }
+ static void __exit cleanup_tis(void)
+@@ -683,6 +800,7 @@ static void __exit cleanup_tis(void)
+       spin_lock(&tis_lock);
+       list_for_each_entry_safe(i, j, &tis_chips, list) {
+               chip = to_tpm_chip(i);
++              tpm_remove_hardware(chip->dev);
+               iowrite32(~TPM_GLOBAL_INT_ENABLE &
+                         ioread32(chip->vendor.iobase +
+                                  TPM_INT_ENABLE(chip->vendor.
+@@ -694,14 +812,14 @@ static void __exit cleanup_tis(void)
+                       free_irq(chip->vendor.irq, chip);
+               iounmap(i->iobase);
+               list_del(&i->list);
+-              tpm_remove_hardware(chip->dev);
+       }
+       spin_unlock(&tis_lock);
++
+       if (force) {
+               platform_device_unregister(pdev);
+-              driver_unregister(&tis_drv);
++              platform_driver_unregister(&tis_drv);
+       } else
+-              pnp_unregister_driver(&tis_pnp_driver);
++              acpi_bus_unregister_driver(&tis_acpi_driver);
+ }
  
--static int force;
-+static int force = 1;
- module_param(force, bool, 0444);
- MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
- static int __init init_tis(void)
+ module_init(init_tis);