|
@@ -33,6 +33,7 @@ DEFINE_IDR(dev_nums_idr);
|
|
|
static DEFINE_MUTEX(idr_lock);
|
|
|
|
|
|
struct class *tpm_class;
|
|
|
+struct class *tpmrm_class;
|
|
|
dev_t tpm_devt;
|
|
|
|
|
|
/**
|
|
@@ -132,6 +133,14 @@ static void tpm_dev_release(struct device *dev)
|
|
|
kfree(chip);
|
|
|
}
|
|
|
|
|
|
+static void tpm_devs_release(struct device *dev)
|
|
|
+{
|
|
|
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
|
|
|
+
|
|
|
+ /* release the master device reference */
|
|
|
+ put_device(&chip->dev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
|
|
|
* @pdev: device to which the chip is associated
|
|
@@ -168,18 +177,35 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
|
|
|
chip->dev_num = rc;
|
|
|
|
|
|
device_initialize(&chip->dev);
|
|
|
+ device_initialize(&chip->devs);
|
|
|
|
|
|
chip->dev.class = tpm_class;
|
|
|
chip->dev.release = tpm_dev_release;
|
|
|
chip->dev.parent = pdev;
|
|
|
chip->dev.groups = chip->groups;
|
|
|
|
|
|
+ chip->devs.parent = pdev;
|
|
|
+ chip->devs.class = tpmrm_class;
|
|
|
+ chip->devs.release = tpm_devs_release;
|
|
|
+ /* get extra reference on main device to hold on
|
|
|
+ * behalf of devs. This holds the chip structure
|
|
|
+ * while cdevs is in use. The corresponding put
|
|
|
+ * is in the tpm_devs_release
|
|
|
+ */
|
|
|
+ get_device(&chip->dev);
|
|
|
+
|
|
|
if (chip->dev_num == 0)
|
|
|
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
|
|
|
else
|
|
|
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
|
|
|
|
|
|
+ chip->devs.devt =
|
|
|
+ MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
|
|
|
+
|
|
|
rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+ rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
|
|
@@ -187,8 +213,11 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
|
|
|
chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
|
|
|
|
|
|
cdev_init(&chip->cdev, &tpm_fops);
|
|
|
+ cdev_init(&chip->cdevs, &tpmrm_fops);
|
|
|
chip->cdev.owner = THIS_MODULE;
|
|
|
+ chip->cdevs.owner = THIS_MODULE;
|
|
|
chip->cdev.kobj.parent = &chip->dev.kobj;
|
|
|
+ chip->cdevs.kobj.parent = &chip->devs.kobj;
|
|
|
|
|
|
chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
|
|
if (!chip->work_space.context_buf) {
|
|
@@ -199,6 +228,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
|
|
|
return chip;
|
|
|
|
|
|
out:
|
|
|
+ put_device(&chip->devs);
|
|
|
put_device(&chip->dev);
|
|
|
return ERR_PTR(rc);
|
|
|
}
|
|
@@ -243,7 +273,6 @@ static int tpm_add_char_device(struct tpm_chip *chip)
|
|
|
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
|
|
|
dev_name(&chip->dev), MAJOR(chip->dev.devt),
|
|
|
MINOR(chip->dev.devt), rc);
|
|
|
-
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -258,6 +287,29 @@ static int tpm_add_char_device(struct tpm_chip *chip)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
|
|
+ rc = cdev_add(&chip->cdevs, chip->devs.devt, 1);
|
|
|
+ if (rc) {
|
|
|
+ dev_err(&chip->dev,
|
|
|
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
|
|
|
+ dev_name(&chip->devs), MAJOR(chip->devs.devt),
|
|
|
+ MINOR(chip->devs.devt), rc);
|
|
|
+ tpm_del_char_device(chip, true);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
|
|
+ rc = device_add(&chip->devs);
|
|
|
+ if (rc) {
|
|
|
+ dev_err(&chip->dev,
|
|
|
+ "unable to device_register() %s, major %d, minor %d, err=%d\n",
|
|
|
+ dev_name(&chip->devs), MAJOR(chip->devs.devt),
|
|
|
+ MINOR(chip->devs.devt), rc);
|
|
|
+ cdev_del(&chip->cdevs);
|
|
|
+ tpm_del_char_device(chip, true);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
/* Make the chip available. */
|
|
|
mutex_lock(&idr_lock);
|
|
|
idr_replace(&dev_nums_idr, chip, chip->dev_num);
|
|
@@ -391,6 +443,10 @@ void tpm_chip_unregister(struct tpm_chip *chip)
|
|
|
{
|
|
|
tpm_del_legacy_sysfs(chip);
|
|
|
tpm_bios_log_teardown(chip);
|
|
|
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
|
|
+ cdev_del(&chip->cdevs);
|
|
|
+ device_del(&chip->devs);
|
|
|
+ }
|
|
|
tpm_del_char_device(chip);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
|