lkml.org 
[lkml]   [2011]   [Jan]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 1/3] TPM: new stm i2c device driver
    Hello Rajiv, James,

    As a new year is here, I'm cleaning up some stuff that were kept on the shelves.
    Please find below in a plain text format, the updated tpm stm st19np18 i2c driver.
    This patch provide in one part the full tpm driver for st19np18 using i2c protocol.
    The updates are:
    - some code/comment cleaning.
    - replace wait_event_interruptible_on_gpio function with wait_for_stat (as found in tpm_tis).
    This move the duration
    (which is different to timeout according TCG PC Client Specific TPM Interface Specification (TIS) spec: http://www.trustedcomputinggroup.org/files/resource_files/87BCE22B-1D09-3519-ADEBA772FBF02CBD/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf) management to the tpm.c to the tpm_transmit function in tpm.c.
    I believe, it makes the driver more similar and easier to understand for everybody (I guess).
    - I have tried to take care of my English spelling in some comments and in the documentation file.
    - I have updated/replaced the ioctl function by unlocked_ioctl to avoid any warning from the Linux TSS trousers (tcsd) and according to the 2.6.35 --> 2.6.36 ioctl mechanism delta.

    I have applied this patch to the last security-next kernel as you mentioned below (2.6.37 rc3) and run it on a beagleboard xM and C4
    http://beagleboard.org/.
    Those devices are already in the market.

    I've tried to take care of all your feedbacks and to be familiar as good as I can
    with all the Linux guidelines for all the patches submission process.
    I'm using Outlook as mail client for company policy rules reasons.

    I would like to know also what is the gap I have to reach to get this driver on the kernel source tree.

    Any feedback or comments are welcome.

    Thanks
    Christophe

    ------------------------------
    Signed-off-by: Christophe RICARD <christophe-h.ricard[at]st.com>
    diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt b/Documentation/tpm/tpm_stm_st19_i2c.txt
    --- a/Documentation/tpm/tpm_stm_st19_i2c.txt 1969-12-31 17:00:00.000000000 -0700
    +++ b/Documentation/tpm/tpm_stm_st19_i2c.txt 2011-01-17 04:54:13.534658985 -0600
    @@ -0,0 +1,169 @@
    +/*
    + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
    + * Copyright (C) 2009, 2010 STMicroelectronics
    + * 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; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License along
    + * with this program; if not, write to the Free Software Foundation, Inc.,
    + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * STMicroelectronics version 1.2.0, Copyright (C) 2010
    + * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
    + * This is free software, and you are welcome to redistribute it
    + * under certain conditions.
    + *
    + * @Author: Christophe RICARD tpmsupport@st.com
    + */
    +
    +PURPOSE OF THE DOCUMENT
    +------------------------
    +This document describe the installation of the TPM driver for
    +TPM ST19NP18 using I2C protocols.
    +
    +
    +PLATFORM USED FOR TESTING
    +--------------------------
    +During the development, several embedded platforms running ARM CPU were
    +used.
    +Listing of validated platforms:
    +- TI Beagleboard
    +- STMicroelectronics Spear 300
    +- STMicroelectronics Spear 600
    +
    +REQUIREMENTS
    +-------------
    +Software
    +=========
    +The TPM driver can be install under a kernel that implements at least the
    +following features:
    +- Linux GENERIC_GPIO programming interfaces.
    +- I2C new style programming interface base (with probe & remove functions).
    +- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO driver for I2C
    +bitbanging.
    +
    +
    +Hardware
    +=========
    +To run a TPM, the platform needs at least:
    +- 2 Power supplies (3.3V).
    +- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang method).
    +- 2 GPIOs for signals accept_command & data_available.
    +
    +TPM I2C speed is 100Khz (Maximum)
    +
    +All TPM signals work at 3.3V
    +
    +HOW TO INSTALL
    +---------------
    +Platform installation file
    +===========================
    +(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
    +
    +
    +1 - Software integration
    +=========================
    +<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv, h8300, ia64,
    +m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um, x86,
    +xtensa...
    +<platform-name> corresponds to your platform
    +
    +In the file where the machine_init() function exists, the developer must
    +declare:
    +- 1 struct st19np18_platform_data to provide which gpio the driver will use.
    + * The accept_pin and data_avail_pin gpio are configured as input only.
    + * This gpio management is under the platform developer's responsability.
    +
    +Finally, in the machine_init() function provided in the same file, the developer
    +should use the well known function i2c_register_board_info() from the I2C Linux
    +API Core.
    +
    +2- Hardware integration
    +========================
    +- ST recommends connecting VPS1 and VPS2 to the board power supply and at least two
    +GNDs (on each side of TSSOP28 package). (See datasheet for further information)
    +
    +- As the ST19NP18 has no internal pull up, ST recommands having:
    + * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with values according
    +to the abacus on page 40 or the "I2C Bus specification, version 2.1 January
    +2000".
    +
    +
    +Platform integration advises
    +=============================
    +
    +For power management purposes, the kernel will send a TPM_SaveState command in the
    +suspend tpm driver function.
    +If the platform generates a TPM Init event on wakeup, the TPM_Startup(ST_STATE) command should
    +be executed before the Linux kernel come up (resume function execution).
    +
    +Here is an example with beagleboard:
    +====================================
    +In the corresponding platform init file, the developer should specify
    +the following information:
    +- The platform gpio's used to managed the tpm's accept_pin/data_avail_pin
    +(in a struct st19np18_platform_data declaration).
    +- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct i2c_board_info).
    +
    +Then the developer should add the TPM slave device to the good i2c adapter with the
    +i2c_register_board_info function (assuming that the gpio and the i2c bus are well configured).
    +
    +Note: For the beagleboard configure your kernel with the following option: CONFIG_OMAP_MUX=y
    +
    +file arch\arm\mach-omap2\board-omap3beagle.c
    +add the following:
    +-----------------------------------------------------------------------
    +
    +static struct st19np18_platform_data tpm_data = {
    + .accept_pin = 135,
    + .data_avail_pin = 143,
    +};
    +
    +static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
    + {
    + I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
    + .platform_data = &tpm_data,
    + },
    +};
    +
    +------------------------------------------------------------------------
    +Then complete the beagleboard init to be like this:
    +------------------------------------------------------------------------
    +static void __init omap3_beagle_init(void)
    +{
    + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
    + omap3_beagle_i2c_init();
    + platform_add_devices(omap3_beagle_devices,
    + ARRAY_SIZE(omap3_beagle_devices));
    + omap_serial_init();
    +
    + omap_mux_init_gpio(170, OMAP_PIN_INPUT);
    + gpio_request(170, "DVI_nPD");
    + /* REVISIT leave DVI powered down until it's needed ... */
    + gpio_direction_output(170, true);
    +
    + usb_musb_init(&musb_board_data);
    + usb_ehci_init(&ehci_pdata);
    + omap3beagle_flash_init();
    +
    + beagle_display_init();
    +
    + /* Ensure SDRC pins are mux'd for self-refresh */
    + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
    + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
    + omap_mux_init_gpio(((struct st19np18_platform_data *)
    + tpm_st19_i2c_board_info[0].platform_data)->data_avail_pin,
    + OMAP_PIN_INPUT);
    + omap_mux_init_gpio(((struct st19np18_platform_data *)
    + tpm_st19_i2c_board_info[0].platform_data)->accept_pin,
    + OMAP_PIN_INPUT);
    +
    + i2c_register_board_info(2, tpm_st19_i2c_board_info, ARRAY_SIZE(tpm_st19_i2c_board_info));
    +}
    diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
    --- a/drivers/char/tpm/Kconfig 2011-01-06 04:44:39.000000000 -0600
    +++ b/drivers/char/tpm/Kconfig 2011-01-13 22:44:42.906408085 -0600
    @@ -60,4 +60,13 @@
    Further information on this driver and the supported hardware
    can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/

    +config TCG_ST19_I2C
    + tristate "STMicroelectronics ST19 I2C TPM"
    + depends on I2C
    + depends on GPIOLIB
    + ---help---
    + If you have a TPM security chip from STMicroelectronics working with
    + an I2C bus, 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_stm_st19_i2c.
    endif # TCG_TPM
    diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
    --- a/drivers/char/tpm/Makefile 2011-01-06 04:44:39.000000000 -0600
    +++ b/drivers/char/tpm/Makefile 2011-01-13 22:44:35.506658670 -0600
    @@ -9,3 +9,4 @@
    obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
    obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
    obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
    +obj-$(CONFIG_TCG_ST19_I2C) += tpm_stm_st19_i2c.o
    diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
    --- a/drivers/char/tpm/tpm_stm_st19_i2c.c 1969-12-31 17:00:00.000000000 -0700
    +++ b/drivers/char/tpm/tpm_stm_st19_i2c.c 2011-01-16 22:44:58.466479759 -0600
    @@ -0,0 +1,602 @@
    +/*
    + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
    + * Copyright (C) 2009, 2010 STMicroelectronics
    + *
    + * 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; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License along
    + * with this program; if not, write to the Free Software Foundation, Inc.,
    + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * STMicroelectronics version 1.2.0, Copyright (C) 2010
    + * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
    + * This is free software, and you are welcome to redistribute it
    + * under certain conditions.
    + *
    + * @Author: Christophe RICARD tpmsupport@st.com
    + *
    + * @File: tpm_stm_st19_i2c.c
    + *
    + * @Synopsis:
    + * ----------------------------------------------------------------------
    + * 02/12/2008
    + * - Stand alone implementation (without any TPM api)
    + * ----------------------------------------------------------------------
    + * 03/02/2010
    + * - Power management (suspend and resume functions)
    + * implementation
    + * ----------------------------------------------------------------------
    + * 03/19/2010
    + * - Use of the linux kernel TPM api --> driver/char/tpm
    + * ----------------------------------------------------------------------
    + * 05/26/2010
    + * - Update code for code submission and bug fixes:
    + * - Comments spelling fixes
    + * - Lindent script execution
    + * - checkpatch.pl script execution
    + * - fix syslog error when loaded as a module:
    + * "release() function missing and must be fixed"
    + * - name files change from
    + * stm_st19_tpm_i2c to tpm_stm_st19_i2c
    + * ----------------------------------------------------------------------
    + * 06/15/2010
    + * - Update for new tpm core device.
    + * num_opens --> is_open
    + * ----------------------------------------------------------------------
    + * 07/08/2010
    + * - Update probe, resume suspend functions
    + * - Fix issue suspend buffer and work around related to the
    + * chip->data_buffer not allocated.
    + * ----------------------------------------------------------------------
    + * 09/03/2010
    + * - Review under LKLM
    + * - Patches from Joe Perches after review which fix some break and
    + * some neatings.
    + * ----------------------------------------------------------------------
    + * 09/16/2010
    + * - Remove unaccurate comment.
    + * ----------------------------------------------------------------------
    + * 01/12/2011
    + * - update ioctl function to unlocked_ioctl for kernel >= 2.6.36
    + * - Some cleaning
    + */
    +
    +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
    +
    +#include <linux/module.h>
    +#include <linux/kernel.h>
    +#include <linux/delay.h>
    +#include <linux/init.h>
    +#include <linux/i2c.h>
    +#include <linux/i2c-id.h>
    +#include <linux/wait.h>
    +#include <linux/string.h>
    +#include <linux/interrupt.h>
    +#include <linux/spinlock.h>
    +#include <linux/sysfs.h>
    +#include <linux/gpio.h>
    +#include <linux/sched.h>
    +#include <linux/uaccess.h>
    +#include <linux/io.h>
    +#include <linux/slab.h>
    +#include <linux/version.h>
    +#include <linux/smp_lock.h>
    +
    +#include <linux/i2c/tpm_stm_st19_i2c.h>
    +
    +#include "tpm.h"
    +
    +#include "tpm_stm_st19_i2c.h"
    +
    +#ifdef DEBUG
    +#define FUNC_ENTER() pr_info("%s\n", __func__)
    +#else
    +#define FUNC_ENTER() do {} while (0)
    +#endif
    +
    +static struct st19np18_platform_data *pin_infos;
    +
    +#define TPM_STS_DATA_AVAIL 0x10
    +#define TPM_STS_ACCEPT_COMMAND 0x01
    +#define TPM_STS_CANCEL (TPM_STS_DATA_AVAIL | TPM_STS_ACCEPT_COMMAND)
    +enum tis_defaults {
    + TIS_SHORT_TIMEOUT = 750, /* ms */
    + TIS_LONG_TIMEOUT = 2000, /* 2 sec */
    +};
    +
    +/*
    + * gpio_readpin is a wrapper to read a gpio value.
    + * Use generic gpio APIs
    + * @param: pin_id, the pin identifier where the value will be read.
    + * @return: the gpio value (should be 0 or 1) or negative errno
    + */
    +static int gpio_readpin(int pin_id)
    +{
    + int ret;
    + ret = gpio_direction_input(pin_id);
    + if (ret == 0)
    + return gpio_get_value(pin_id);
    + return ret;
    +}
    +
    +/*
    + * tpm_stm_i2c_status is not implemented because TIS registers are not
    + * implemented.
    + */
    +static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
    +{
    + u8 state_data, state_command;
    +
    + state_data = gpio_readpin(pin_infos->data_avail_pin);
    + state_command = gpio_readpin(pin_infos->accept_pin);
    + return (state_data << 4) | state_command;
    +}
    +
    +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
    + wait_queue_head_t *queue)
    +{
    + unsigned long stop;
    + u8 status;
    +
    + FUNC_ENTER();
    +
    + /* check current status */
    + status = tpm_stm_i2c_status(chip);
    + if (status == mask)
    + return 0;
    + if (status == TPM_STS_CANCEL)
    + goto end;
    + stop = jiffies + timeout;
    + do {
    + msleep(TPM_TIMEOUT);
    + status = tpm_stm_i2c_status(chip);
    + if ((status & mask) == mask)
    + return 0;
    + } while (time_before(jiffies, stop));
    +end:
    + return -ETIME;
    +}
    +
    +/*
    + * tpm_stm_i2c_send send TPM commands through the I2C bus.
    + * Before sending any TPM commands, tpm_stm_i2c_send poll data_available and
    + * accept_command TPM GPIOs.
    + *
    + * In case the data_available is high (logical value 1), tpm_stm_i2c_send will
    + * empty the TPM FIFO by reading all the datas stored inside the TPM.
    + *
    + * Then, if the accept_command TPM GPIO is high(logical value 1)
    + * tpm_stm_i2c_send will first send the 10 bytes header of the TCG commands and
    + * then send the others bytes by 40 bytes blocks.
    + *
    + * data_available and accept_command TPM GPIOs will goes low when the TPM
    + * compute the command.
    + *
    + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
    + * @param: buf, the buffer to send.
    + * @param: count, the number of bytes to send.
    + * @return: In case of success the number of bytes sent.
    + * In other case, a < 0 value describing the issue.
    + */
    +static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
    + size_t count)
    +{
    + u32 ret = 0, i, size, ordinal;
    + struct i2c_client *client;
    +
    + FUNC_ENTER();
    +
    + if (chip == NULL)
    + return -EBUSY;
    + if (count < TPM_HEADER_SIZE)
    + return -EBUSY;
    + client = (struct i2c_client *)pin_infos->client;
    +
    + ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
    +
    + size = TPM_HEADER_SIZE;
    + i = 0;
    + while (i < size && wait_for_stat(chip, TPM_STS_ACCEPT_COMMAND,
    + TPM_I2C_SHORT,
    + &chip->vendor.int_queue) == 0) {
    + int bytes;
    +
    + if (i == 0)
    + bytes = TPM_HEADER_SIZE;
    + else
    + bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
    +
    + if (i == 0) {
    + size = be32_to_cpu(*(__be32 *) (buf + 2));
    + size = size < count ? size : count;
    + }
    + if (count < TPM_HEADER_SIZE)
    + bytes = count;
    + ret = i2c_master_send(client, buf + i, bytes);
    + if (ret < 0) {
    + pr_info("Failed to send data\n");
    + goto end;
    + }
    +
    + if (i == 0)
    + i += TPM_HEADER_SIZE;
    + else
    + i += TPM_I2C_BLOCK_SIZE;
    + }
    +
    + if (i == 0) {
    + pr_info("Failed to read gpio pin (AcceptCmd)\n");
    + ret = -EIO;
    + }
    +end:
    + return ret ? ret : count;
    +}
    +
    +/*
    + * tpm_stm_i2c_recv received TPM response through the I2C bus.
    + * Before receiving any TPM response, tpm_stm_i2c_recv poll data_available and
    + * accept_command TPM GPIOs.
    + *
    + * In case the accept_command is high (logical value 1), tpm_stm_i2c_recv will
    + * do nothing.
    + *
    + * Then, if the data_available TPM GPIO is high(logical value 1)
    + * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG TPM
    + * response and then receive the others bytes by 40 bytes blocks.
    + *
    + * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
    + *
    + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
    + * @param: buf, the buffer to store datas.
    + * @param: count, the number of bytes to send.
    + * @return: In case of success the number of bytes received.
    + * In other case, a < 0 value describing the issue.
    + */
    +static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
    + size_t count)
    +{
    + int ret = 0;
    + int i, size;
    + struct i2c_client *client;
    +
    + FUNC_ENTER();
    +
    + if (chip == NULL)
    + return -EBUSY;
    + if (count < TPM_HEADER_SIZE)
    + return -EBUSY;
    +
    + client = (struct i2c_client *)pin_infos->client;
    +
    + size = TPM_HEADER_SIZE;
    + i = 0;
    + while (i < size && wait_for_stat(chip, TPM_STS_DATA_AVAIL,
    + TPM_I2C_SHORT,
    + &chip->vendor.read_queue) == 0) {
    + int bytes;
    +
    + if (count < TPM_HEADER_SIZE)
    + bytes = count;
    + else if (i == 0)
    + bytes = TPM_HEADER_SIZE;
    + else
    + bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
    +
    + ret = i2c_master_recv(client, buf + i, bytes);
    + if (ret < 0) {
    + pr_info(" Failed to read gpio pin (DataAvailable)\n");
    + goto end;
    + }
    +
    + if (!buf) {
    + pr_info("read buffer is NULL\n");
    + goto end;
    + }
    +
    + if (i == 0) {
    + size = be32_to_cpu(*(__be32 *) (buf + 2));
    + if (size > count)
    + size = count;
    + i += TPM_HEADER_SIZE;
    + } else
    + i += TPM_I2C_BLOCK_SIZE;
    + }
    +
    + if (i == 0) {
    + pr_info("Failed to read gpio pin (DataAvailable)\n");
    + ret = -EIO;
    + goto end;
    + }
    + return size;
    +end:
    + return ret;
    +}
    +
    +/*
    + * tpm_stm_i2c_cancel, cancel is not implemented.
    + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
    + */
    +static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
    +{
    +}
    +
    +/*
    + * tpm_st19_i2c_ioctl provides 2 handles:
    + * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
    + * See tpm_stm_i2c_cancel description above
    + * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
    + *
    + * @return: In case of success, return TPM response size.
    + * In other case return < 0 value describing the issue.
    + */
    +/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
    +static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file *file,
    + unsigned int cmd, unsigned long arg)
    +#else*/
    +static long tpm_st19_i2c_unlocked_ioctl(struct file *file,
    + unsigned int cmd, unsigned long arg)
    +/*#endif*/
    +{
    + int in_size = 0, out_size = 0, ret = -ENOTTY;
    + struct tpm_chip *chip = file->private_data;
    +
    + lock_kernel();
    + switch (cmd) {
    + case TPMIOC_CANCEL:
    + tpm_stm_i2c_cancel(chip);
    + ret = -ENOSYS;
    + break;
    + case TPMIOC_TRANSMIT:
    + if (copy_from_user(chip->data_buffer,
    + (const char *)arg, TPM_HEADER_SIZE)) {
    + ret = -EFAULT;
    + break;
    + }
    +
    + in_size = be32_to_cpu(*(__be32 *) (chip->data_buffer + 2));
    + if (copy_from_user(chip->data_buffer,
    + (const char *)arg, in_size)) {
    + ret = -EFAULT;
    + break;
    + }
    +
    + tpm_stm_i2c_send(chip, chip->data_buffer, in_size);
    +
    + out_size = tpm_stm_i2c_recv(chip, chip->data_buffer,
    + TPM_BUFSIZE);
    + if (copy_to_user((char *)arg, chip->data_buffer, out_size)) {
    + ret = -EFAULT;
    + break;
    + }
    + ret = out_size;
    + break;
    + }
    + unlock_kernel();
    + return ret;
    +}
    +
    +static const struct file_operations tpm_st19_i2c_fops = {
    + .owner = THIS_MODULE,
    + .llseek = no_llseek,
    + .read = tpm_read,
    +
    + /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
    + .ioctl = tpm_st19_i2c_ioctl,
    + #else */
    + .unlocked_ioctl = tpm_st19_i2c_unlocked_ioctl,
    + /*#endif */
    +
    + .write = tpm_write,
    + .open = tpm_open,
    + .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(enabled, S_IRUGO, tpm_show_enabled, NULL);
    +static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
    +static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
    +static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
    +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
    +static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
    +
    +static struct attribute *stm_tpm_attrs[] = {
    + &dev_attr_pubek.attr,
    + &dev_attr_pcrs.attr,
    + &dev_attr_enabled.attr,
    + &dev_attr_active.attr,
    + &dev_attr_owned.attr,
    + &dev_attr_temp_deactivated.attr,
    + &dev_attr_caps.attr,
    + &dev_attr_cancel.attr, NULL,
    +};
    +
    +static struct attribute_group stm_tpm_attr_grp = {
    + .attrs = stm_tpm_attrs
    +};
    +
    +static struct tpm_vendor_specific st_i2c_tpm = {
    + .send = tpm_stm_i2c_send,
    + .recv = tpm_stm_i2c_recv,
    + .cancel = tpm_stm_i2c_cancel,
    + .status = tpm_stm_i2c_status,
    + .req_complete_mask = TPM_STS_DATA_AVAIL,
    + .req_complete_val = TPM_STS_DATA_AVAIL,
    + .req_canceled = TPM_STS_CANCEL,
    + .attr_group = &stm_tpm_attr_grp,
    + .miscdev = {.fops = &tpm_st19_i2c_fops,},
    +};
    +
    +/*
    + * tpm_st19_i2c_probe initialize the TPM device
    + * @param: client, the i2c_client drescription (TPM I2C description).
    + * @param: id, the i2c_device_id struct.
    + * @return: 0 in case of success.
    + * -1 in other case.
    + */
    +static int
    +tpm_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
    +{
    + int err;
    + struct tpm_chip *chip;
    + struct st19np18_platform_data *platform_data;
    +
    + FUNC_ENTER();
    +
    + err = 0;
    +
    + /* Check I2C platform functionnalities */
    + if (client == NULL) {
    + pr_info("client is NULL. exiting.\n");
    + err = -ENODEV;
    + goto end;
    + }
    +
    + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    + pr_info("client not i2c capable\n");
    + err = -ENODEV;
    + goto end;
    + }
    +
    + chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
    + if (!chip) {
    + err = -ENODEV;
    + goto end;
    + }
    +
    + platform_data = client->dev.platform_data;
    + pin_infos = platform_data;
    + platform_data->client = client;
    + /* 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);
    +
    + /* Register GPIO pin through generic Linux GPIO API */
    + err = gpio_request(platform_data->accept_pin, "accept command");
    + if (err)
    + goto _gpio_init;
    +
    + err = gpio_request(platform_data->data_avail_pin, "data available");
    + if (err)
    + goto _gpio_init;
    +
    + tpm_get_timeouts(chip);
    + tpm_continue_selftest(chip);
    +
    + /* attach chip datas to client */
    + i2c_set_clientdata(client, chip);
    +
    + pr_info("TPM I2C Initialized\n");
    + return 0;
    +_gpio_init:
    + if (platform_data) {
    + gpio_free(platform_data->accept_pin);
    + gpio_free(platform_data->data_avail_pin);
    + }
    + tpm_remove_hardware(chip->dev);
    +end:
    + i2c_set_clientdata(client, NULL);
    + pr_info("TPM I2C initialisation fail\n");
    + return err;
    +}
    +
    +/*
    + * tpm_st19_i2c_remove remove the TPM device
    + * @param: client, the i2c_client drescription (TPM I2C description).
    + clear_bit(0, &chip->is_open);
    + * @return: 0 in case of success.
    + */
    +static __devexit int tpm_st19_i2c_remove(struct i2c_client *client)
    +{
    + struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
    + FUNC_ENTER();
    +
    + if (pin_infos != NULL) {
    + gpio_free(pin_infos->accept_pin);
    + gpio_free(pin_infos->data_avail_pin);
    + }
    +
    + /* Check if chip has been previously clean */
    + if (chip != NULL)
    + tpm_remove_hardware(chip->dev);
    +
    + return 0;
    +}
    +
    +/*
    + * tpm_st19_i2c_pm_suspend suspend the TPM device
    + * @param: client, the i2c_client drescription (TPM I2C description).
    + * @param: mesg, the power management message.
    + * @return: 0 in case of success.
    + */
    +static int tpm_st19_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
    +{
    + return tpm_pm_suspend(&client->dev, mesg);
    +}
    +
    +/*
    + * tpm_st19_i2c_pm_resume resume the TPM device
    + * @param: client, the i2c_client drescription (TPM I2C description).
    + * @return: 0 in case of success.
    + */
    +static int tpm_st19_i2c_pm_resume(struct i2c_client *client)
    +{
    + return tpm_pm_resume(&client->dev);
    +} /* tpm_st19_i2c_pm_resume() */
    +
    +static const struct i2c_device_id tpm_st19_i2c_id[] = {
    + {TPM_DRIVER_NAME, 0},
    + {}
    +};
    +
    +MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
    +
    +static struct i2c_driver tpm_st19_i2c_driver = {
    + .driver = {
    + .owner = THIS_MODULE,
    + .name = TPM_DRIVER_NAME,
    + },
    + .probe = tpm_st19_i2c_probe,
    + .remove = tpm_st19_i2c_remove,
    + .resume = tpm_st19_i2c_pm_resume,
    + .suspend = tpm_st19_i2c_pm_suspend,
    + .id_table = tpm_st19_i2c_id
    +};
    +
    +/*
    + * tpm_st19_i2c_init initialize driver
    + * @return: 0 if successful, else non zero value.
    + */
    +static int __init tpm_st19_i2c_init(void)
    +{
    + FUNC_ENTER();
    + return i2c_add_driver(&tpm_st19_i2c_driver);
    +}
    +
    +/*
    + * tpm_st19_i2c_exit The kernel calls this function during unloading the
    + * module or during shut down process
    + */
    +static void __exit tpm_st19_i2c_exit(void)
    +{
    + FUNC_ENTER();
    + i2c_del_driver(&tpm_st19_i2c_driver);
    +}
    +
    +module_init(tpm_st19_i2c_init);
    +module_exit(tpm_st19_i2c_exit);
    +
    +MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
    +MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
    +MODULE_VERSION("1.2.0");
    +MODULE_LICENSE("GPL");
    diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h b/drivers/char/tpm/tpm_stm_st19_i2c.h
    --- a/drivers/char/tpm/tpm_stm_st19_i2c.h 1969-12-31 17:00:00.000000000 -0700
    +++ b/drivers/char/tpm/tpm_stm_st19_i2c.h 2011-01-16 22:45:08.918407969 -0600
    @@ -0,0 +1,52 @@
    +/*
    + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
    + * Copyright (C) 2009, 2010 STMicroelectronics
    + *
    + * 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; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License along
    + * with this program; if not, write to the Free Software Foundation, Inc.,
    + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * STMicroelectronics version 1.2.0, Copyright (C) 2010
    + * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
    + * This is free software, and you are welcome to redistribute it
    + * under certain conditions.
    + *
    + * @Author: Christophe RICARD tpmsupport@st.com
    + *
    + * @File: stm_st19_tpm_i2c.h
    + *
    + * @Date: 02/12/2008
    + */
    +#ifndef __STM_ST19_TPM_I2C_MAIN_H__
    +#define __STM_ST19_TPM_I2C_MAIN_H__
    +
    +#include <linux/pci.h>
    +#include <linux/module.h>
    +#include <linux/platform_device.h>
    +#include <linux/i2c.h>
    +#include <linux/i2c-id.h>
    +#include <linux/fs.h>
    +#include <linux/miscdevice.h>
    +
    +#define TPM_BUFSIZE 2048
    +#define TPM_HEADER_SIZE 10
    +#define TPM_I2C_BLOCK_SIZE 0x28
    +
    +#define TPM_I2C_SHORT 2000 /* 2s */
    +#define STARTUP_WAIT_INTERVAL 8 /* 8ms */
    +
    +/* ioctl commands */
    +#define TPMIOC_CANCEL _IO('T', 0x00) /* Not supported */
    +#define TPMIOC_TRANSMIT _IO('T', 0x01)
    +
    +#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
    diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h b/include/linux/i2c/tpm_stm_st19_i2c.h
    --- a/include/linux/i2c/tpm_stm_st19_i2c.h 1969-12-31 17:00:00.000000000 -0700
    +++ b/include/linux/i2c/tpm_stm_st19_i2c.h 2011-01-16 22:45:31.758408188 -0600
    @@ -0,0 +1,42 @@
    +/*
    + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
    + * Copyright (C) 2009, 2010 STMicroelectronics
    + * Christophe RICARD tpmsupport@st.com
    + * 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; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License along
    + * with this program; if not, write to the Free Software Foundation, Inc.,
    + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * STMicroelectronics version 1.2.0, Copyright (C) 2010
    + * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
    + * This is free software, and you are welcome to redistribute it
    + * under certain conditions.
    + *
    + * @File: stm_st19_tpm_i2c.h
    + *
    + * @Date: 06/15/2008
    + */
    +#ifndef __STM_ST19_TPM_I2C_H__
    +#define __STM_ST19_TPM_I2C_H__
    +
    +#include <linux/i2c.h>
    +
    +#define TPM_DRIVER_NAME "st19np18"
    +#define TPM_I2C_ST19_ADDR_WR (0x26 >> 1) /*0x13 7 bits address */
    +
    +struct st19np18_platform_data {
    + int accept_pin; /* accept command pin */
    + int data_avail_pin;/* data available pin */
    + struct i2c_client *client;
    +};
    +
    +#endif /* __STM_ST19_TPM_I2C_H__ */

    \
     
     \ /
      Last update: 2011-01-18 00:39    [W:0.078 / U:0.132 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site