18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corporation
48c2ecf20Sopenharmony_ci * Authors:
58c2ecf20Sopenharmony_ci * Leendert van Doorn <leendert@watson.ibm.com>
68c2ecf20Sopenharmony_ci * Dave Safford <safford@watson.ibm.com>
78c2ecf20Sopenharmony_ci * Reiner Sailer <sailer@watson.ibm.com>
88c2ecf20Sopenharmony_ci * Kylene Hall <kjhall@us.ibm.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2013 Obsidian Research Corp
118c2ecf20Sopenharmony_ci * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Device file system interface to the TPM
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include "tpm-dev.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic int tpm_open(struct inode *inode, struct file *file)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct tpm_chip *chip;
218c2ecf20Sopenharmony_ci	struct file_priv *priv;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	chip = container_of(inode->i_cdev, struct tpm_chip, cdev);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	/* It's assured that the chip will be opened just once,
268c2ecf20Sopenharmony_ci	 * by the check of is_open variable, which is protected
278c2ecf20Sopenharmony_ci	 * by driver_lock. */
288c2ecf20Sopenharmony_ci	if (test_and_set_bit(0, &chip->is_open)) {
298c2ecf20Sopenharmony_ci		dev_dbg(&chip->dev, "Another process owns this TPM\n");
308c2ecf20Sopenharmony_ci		return -EBUSY;
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
348c2ecf20Sopenharmony_ci	if (priv == NULL)
358c2ecf20Sopenharmony_ci		goto out;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	tpm_common_open(file, chip, priv, NULL);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return 0;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci out:
428c2ecf20Sopenharmony_ci	clear_bit(0, &chip->is_open);
438c2ecf20Sopenharmony_ci	return -ENOMEM;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * Called on file close
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_cistatic int tpm_release(struct inode *inode, struct file *file)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct file_priv *priv = file->private_data;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	tpm_common_release(file, priv);
548c2ecf20Sopenharmony_ci	clear_bit(0, &priv->chip->is_open);
558c2ecf20Sopenharmony_ci	kfree(priv);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	return 0;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ciconst struct file_operations tpm_fops = {
618c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
628c2ecf20Sopenharmony_ci	.llseek = no_llseek,
638c2ecf20Sopenharmony_ci	.open = tpm_open,
648c2ecf20Sopenharmony_ci	.read = tpm_common_read,
658c2ecf20Sopenharmony_ci	.write = tpm_common_write,
668c2ecf20Sopenharmony_ci	.poll = tpm_common_poll,
678c2ecf20Sopenharmony_ci	.release = tpm_release,
688c2ecf20Sopenharmony_ci};
69