|
@@ -312,23 +312,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
|
|
|
TPM_MEDIUM,
|
|
|
};
|
|
|
|
|
|
-static void user_reader_timeout(unsigned long ptr)
|
|
|
-{
|
|
|
- struct tpm_chip *chip = (struct tpm_chip *) ptr;
|
|
|
-
|
|
|
- schedule_work(&chip->work);
|
|
|
-}
|
|
|
-
|
|
|
-static void timeout_work(struct work_struct *work)
|
|
|
-{
|
|
|
- struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
|
|
|
-
|
|
|
- mutex_lock(&chip->buffer_mutex);
|
|
|
- atomic_set(&chip->data_pending, 0);
|
|
|
- memset(chip->data_buffer, 0, TPM_BUFSIZE);
|
|
|
- mutex_unlock(&chip->buffer_mutex);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Returns max number of jiffies to wait
|
|
|
*/
|
|
@@ -355,8 +338,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
|
|
/*
|
|
|
* Internal kernel interface to transmit TPM commands
|
|
|
*/
|
|
|
-static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
|
|
- size_t bufsiz)
|
|
|
+ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
|
|
+ size_t bufsiz)
|
|
|
{
|
|
|
ssize_t rc;
|
|
|
u32 count, ordinal;
|
|
@@ -1151,127 +1134,6 @@ again:
|
|
|
return -ETIME;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
|
|
-/*
|
|
|
- * 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)
|
|
|
-{
|
|
|
- struct miscdevice *misc = file->private_data;
|
|
|
- struct tpm_chip *chip = container_of(misc, struct tpm_chip,
|
|
|
- vendor.miscdev);
|
|
|
-
|
|
|
- if (test_and_set_bit(0, &chip->is_open)) {
|
|
|
- dev_dbg(chip->dev, "Another process owns this TPM\n");
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
|
|
|
- if (chip->data_buffer == NULL) {
|
|
|
- clear_bit(0, &chip->is_open);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- atomic_set(&chip->data_pending, 0);
|
|
|
-
|
|
|
- file->private_data = chip;
|
|
|
- get_device(chip->dev);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-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_work(&chip->work);
|
|
|
- file->private_data = NULL;
|
|
|
- atomic_set(&chip->data_pending, 0);
|
|
|
- kzfree(chip->data_buffer);
|
|
|
- clear_bit(0, &chip->is_open);
|
|
|
- put_device(chip->dev);
|
|
|
- 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;
|
|
|
- size_t in_size = size;
|
|
|
- ssize_t out_size;
|
|
|
-
|
|
|
- /* cannot perform a write until the read has cleared
|
|
|
- either via tpm_read or a user_read_timer timeout.
|
|
|
- This also prevents splitted buffered writes from blocking here.
|
|
|
- */
|
|
|
- if (atomic_read(&chip->data_pending) != 0)
|
|
|
- return -EBUSY;
|
|
|
-
|
|
|
- if (in_size > TPM_BUFSIZE)
|
|
|
- return -E2BIG;
|
|
|
-
|
|
|
- mutex_lock(&chip->buffer_mutex);
|
|
|
-
|
|
|
- if (copy_from_user
|
|
|
- (chip->data_buffer, (void __user *) buf, in_size)) {
|
|
|
- mutex_unlock(&chip->buffer_mutex);
|
|
|
- return -EFAULT;
|
|
|
- }
|
|
|
-
|
|
|
- /* atomic tpm command send and result receive */
|
|
|
- out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
|
|
|
- if (out_size < 0) {
|
|
|
- mutex_unlock(&chip->buffer_mutex);
|
|
|
- return out_size;
|
|
|
- }
|
|
|
-
|
|
|
- atomic_set(&chip->data_pending, out_size);
|
|
|
- mutex_unlock(&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;
|
|
|
- ssize_t ret_size;
|
|
|
- int rc;
|
|
|
-
|
|
|
- del_singleshot_timer_sync(&chip->user_read_timer);
|
|
|
- flush_work(&chip->work);
|
|
|
- ret_size = atomic_read(&chip->data_pending);
|
|
|
- if (ret_size > 0) { /* relay data */
|
|
|
- ssize_t orig_ret_size = ret_size;
|
|
|
- if (size < ret_size)
|
|
|
- ret_size = size;
|
|
|
-
|
|
|
- mutex_lock(&chip->buffer_mutex);
|
|
|
- rc = copy_to_user(buf, chip->data_buffer, ret_size);
|
|
|
- memset(chip->data_buffer, 0, orig_ret_size);
|
|
|
- if (rc)
|
|
|
- ret_size = -EFAULT;
|
|
|
-
|
|
|
- mutex_unlock(&chip->buffer_mutex);
|
|
|
- }
|
|
|
-
|
|
|
- atomic_set(&chip->data_pending, 0);
|
|
|
-
|
|
|
- return ret_size;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(tpm_read);
|
|
|
|
|
|
void tpm_remove_hardware(struct device *dev)
|
|
|
{
|
|
@@ -1287,7 +1149,7 @@ void tpm_remove_hardware(struct device *dev)
|
|
|
spin_unlock(&driver_lock);
|
|
|
synchronize_rcu();
|
|
|
|
|
|
- misc_deregister(&chip->vendor.miscdev);
|
|
|
+ tpm_dev_del_device(chip);
|
|
|
sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
|
|
|
tpm_remove_ppi(&dev->kobj);
|
|
|
tpm_bios_log_teardown(chip->bios_dir);
|
|
@@ -1448,7 +1310,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
|
|
|
* Once all references to platform device are down to 0,
|
|
|
* release all allocated structures.
|
|
|
*/
|
|
|
-void tpm_dev_release(struct device *dev)
|
|
|
+static void tpm_dev_release(struct device *dev)
|
|
|
{
|
|
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
|
|
|
@@ -1460,7 +1322,6 @@ void tpm_dev_release(struct device *dev)
|
|
|
chip->release(dev);
|
|
|
kfree(chip);
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(tpm_dev_release);
|
|
|
|
|
|
/*
|
|
|
* Called from tpm_<specific>.c probe function only for devices
|
|
@@ -1480,15 +1341,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
|
|
|
if (chip == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
- mutex_init(&chip->buffer_mutex);
|
|
|
mutex_init(&chip->tpm_mutex);
|
|
|
INIT_LIST_HEAD(&chip->list);
|
|
|
|
|
|
- INIT_WORK(&chip->work, timeout_work);
|
|
|
-
|
|
|
- setup_timer(&chip->user_read_timer, user_reader_timeout,
|
|
|
- (unsigned long)chip);
|
|
|
-
|
|
|
memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
|
|
|
|
|
|
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
|
|
@@ -1496,40 +1351,26 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
|
|
|
if (chip->dev_num >= TPM_NUM_DEVICES) {
|
|
|
dev_err(dev, "No available tpm device numbers\n");
|
|
|
goto out_free;
|
|
|
- } else if (chip->dev_num == 0)
|
|
|
- chip->vendor.miscdev.minor = TPM_MINOR;
|
|
|
- else
|
|
|
- chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
|
+ }
|
|
|
|
|
|
set_bit(chip->dev_num, dev_mask);
|
|
|
|
|
|
scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
|
|
|
chip->dev_num);
|
|
|
- chip->vendor.miscdev.name = chip->devname;
|
|
|
|
|
|
- chip->vendor.miscdev.parent = dev;
|
|
|
chip->dev = get_device(dev);
|
|
|
chip->release = dev->release;
|
|
|
dev->release = tpm_dev_release;
|
|
|
dev_set_drvdata(dev, chip);
|
|
|
|
|
|
- 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);
|
|
|
+ if (tpm_dev_add_device(chip))
|
|
|
goto put_device;
|
|
|
- }
|
|
|
|
|
|
- if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
|
|
|
- misc_deregister(&chip->vendor.miscdev);
|
|
|
- goto put_device;
|
|
|
- }
|
|
|
+ if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group))
|
|
|
+ goto del_misc;
|
|
|
|
|
|
- if (tpm_add_ppi(&dev->kobj)) {
|
|
|
- misc_deregister(&chip->vendor.miscdev);
|
|
|
- goto put_device;
|
|
|
- }
|
|
|
+ if (tpm_add_ppi(&dev->kobj))
|
|
|
+ goto del_misc;
|
|
|
|
|
|
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
|
|
|
|
@@ -1540,6 +1381,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
|
|
|
|
|
|
return chip;
|
|
|
|
|
|
+del_misc:
|
|
|
+ tpm_dev_del_device(chip);
|
|
|
put_device:
|
|
|
put_device(chip->dev);
|
|
|
out_free:
|