From patchwork Wed Jul 9 07:40:14 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Luc BLANC X-Patchwork-Id: 368115 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 17FF5140110 for ; Wed, 9 Jul 2014 17:49:33 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 514B3A7425; Wed, 9 Jul 2014 09:49:31 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id paYCghTvpJoI; Wed, 9 Jul 2014 09:49:31 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A2D3EA7427; Wed, 9 Jul 2014 09:49:27 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E1F5BA7427 for ; Wed, 9 Jul 2014 09:49:23 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rhVMa2F5iJte for ; Wed, 9 Jul 2014 09:49:20 +0200 (CEST) X-Greylist: delayed 382 seconds by postgrey-1.27 at theia; Wed, 09 Jul 2014 09:49:15 CEST X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-wg0-f46.google.com (mail-wg0-f46.google.com [74.125.82.46]) by theia.denx.de (Postfix) with ESMTPS id 32AD5A7425 for ; Wed, 9 Jul 2014 09:49:15 +0200 (CEST) Received: by mail-wg0-f46.google.com with SMTP id m15so1649495wgh.17 for ; Wed, 09 Jul 2014 00:49:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=FvW71LDom/rnCOQ1IhTYec0JSN7j9L4XWJiq+VDxgpg=; b=dkeHy2IJxU6zHN9cIdS0/g3RahaDXqx25amxJ3U/ghjJNLrX2DnbCaoti08OJxePk6 dezNH2bq2+umeYJZRG/Ltn2oJuX6o6wMn9QrYFqhuAZOo2kXhT4czgQ1QXNbHAssDc67 xkavvtr1ZzbxLJJaKkEEoL66ZTp4gvtA9DuHiAB9lm1po8mg0KDwDXRyLF8QYSgjbOhc xblPOEEb2aglbWSVz4AY8Ehzl3wftkeXCti0qaaAUUqWIXB/hb+oB+NY3jUYicVsw0Ol aYg11xbYQOljxKj7bwwkf4Tewp+YX82SKziEbkGoXPqjnJHhDkJfP2ok6Eu577HRyh3A F5zw== X-Received: by 10.194.185.238 with SMTP id ff14mr46750180wjc.9.1404891772737; Wed, 09 Jul 2014 00:42:52 -0700 (PDT) Received: from localhost.localdomain (99.20.90.92.rev.sfr.net. [92.90.20.99]) by mx.google.com with ESMTPSA id lk5sm16246813wic.18.2014.07.09.00.42.51 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 09 Jul 2014 00:42:52 -0700 (PDT) From: Jean-Luc BLANC X-Google-Original-From: Jean-Luc BLANC To: sjg@chromium.org, U-Boot@lists.denx.de, shawnn@chromium.org, trini@ti.com, clchiou@chromium.org, thutt@chromium.org Date: Wed, 9 Jul 2014 09:40:14 +0200 Message-Id: <1404891614-3794-2-git-send-email-jean-luc.blanc@st.com> X-Mailer: git-send-email 1.7.9.5 Cc: benoit.houyere@st.com Subject: [U-Boot] [PATCH 2/2] i2c: ST33ZP24 I2C TPM driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This driver add support for STMicroelectronics ST33ZP24 I2C TPM. --- README | 6 + drivers/tpm/Makefile | 1 + drivers/tpm/tpm_i2c_stm_st33.c | 633 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 640 insertions(+) create mode 100644 drivers/tpm/tpm_i2c_stm_st33.c diff --git a/README b/README index a4aa28a..c4463d8 100644 --- a/README +++ b/README @@ -1426,6 +1426,12 @@ The following options need to be configured: TPM1_SPI_CS Define SPI Chip Select ID connected to TPM + CONFIG_TPM_ST_I2C + Support I2C STMicroelectronics TPM. Require I2C support + + CONFIG_TPM_I2C_BUS + Define the i2c bus number for the TPM device + - USB Support: At the moment only the UHCI host controller is supported (PIP405, MIP405, MPC5200); define diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 1ee707e..29e1f80 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o obj-$(CONFIG_TPM_ST_SPI) += tpm_spi_stm_st33.o +obj-$(CONFIG_TPM_ST_I2C) += tpm_i2c_stm_st33.o diff --git a/drivers/tpm/tpm_i2c_stm_st33.c b/drivers/tpm/tpm_i2c_stm_st33.c new file mode 100644 index 0000000..6e20f8c --- /dev/null +++ b/drivers/tpm/tpm_i2c_stm_st33.c @@ -0,0 +1,633 @@ +/* + * STMicroelectronics TPM I2C UBOOT Linux driver for TPM ST33ZP24 + * Copyright (C) 2014 STMicroelectronics + * + * Description: Device driver for ST33ZP24 I2C TPM TCG. + * + * This device driver implements the TPM interface as defined in + * the TCG TPM Interface Spec version 1.21, revision 1.0 and the + * STMicroelectronics I2C Protocol Stack Specification version 1.2.0. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * @Author: Jean-Luc BLANC + * + * @File: tpm_i2c_stm_st33.c + */ + +#include +#include +#include +#include +#include +#include + +#define MINOR_NUM_I2C 224 + +#define TPM_ACCESS 0x0 +#define TPM_STS 0x18 +#define TPM_HASH_END 0x20 +#define TPM_DATA_FIFO 0x24 +#define TPM_HASH_DATA 0x24 +#define TPM_HASH_START 0x28 +#define TPM_INTF_CAPABILITY 0x14 +#define TPM_INT_STATUS 0x10 +#define TPM_INT_ENABLE 0x08 + +#define TPM_DUMMY_BYTE 0xAA +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_HEADER_SIZE 10 +#define TPM_BUFSIZE 2048 + +#define LOCALITY0 0 +#define LOCALITY4 4 +#define LOCALITY0_I2C_ADDR 0x13 +#define LOCALITY4_I2C_ADDR 0x1B + +/* Index of Count field in TPM response buffer */ +#define TPM_RSP_SIZE_BYTE 2 + +/* Maximum command duration */ +#define TPM_MAX_COMMAND_DURATION_MS 120000 + +enum stm33zp24_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum stm33zp24_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum stm33zp24_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, + TPM_INTF_WAKE_UP_READY_INT = 0x020, + TPM_INTF_LOCTPM_BUFSIZE4SOFTRELEASE_INT = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +enum tis_defaults { + TIS_SHORT_TIMEOUT_MS = 750, /* ms */ + TIS_LONG_TIMEOUT_MS = 2000, /* 2 sec */ +}; + +/** + * @addr: TPM I2C address + * @i2c_bus: I2C bus ID the TPM is connected to + * @is_open: TPM connection establishment information + * @locality: active locality of the TPM (0 OR 4) + * @buf: command/response buffer + * @timeout_*: timeouts for TPM states changes + * @duration: maximum time for a TPM command processing + */ +struct tpm_chip { + uint addr; + uint i2c_bus; + int is_open; + u8 buf[TPM_BUFSIZE]; + int locality; + unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ + unsigned long duration; /* msec */ +}; + +static struct tpm_chip tpm_dev; + +/* + * write8_reg(): Send byte to the TIS register according to I2C TPM protocol. + * @tpm_register, the tpm tis register where the data should be written + * @tpm_data, the tpm_data to write inside the tpm_register + * @tpm_size, The length of the data + * @return: Returns zero in case of success else the negative error code. + */ +static int write8_reg(u8 addr, u8 tpm_register, + const u8 *tpm_data, u16 tpm_size) +{ + u8 data; + + data = tpm_register; + memcpy(&(tpm_dev.buf[0]), &data, sizeof(data)); + memcpy(&(tpm_dev.buf[0])+1, tpm_data, tpm_size); + return i2c_write(addr, 0, 0, &tpm_dev.buf[0], tpm_size + 1); +} + +/* +* read8_reg(): Recv byte from the TIS register according to I2C TPM protocol. +* @tpm_register, the tpm tis register where the data should be read +* @tpm_data, the TPM response +* @tpm_size, TPM response size to read. +* @return: Returns zero in case of success else the negative error code. +*/ +static int read8_reg(u8 addr, u8 tpm_register, u8 *tpm_data, int tpm_size) +{ + u8 status = 0; + u8 data; + + data = TPM_DUMMY_BYTE; + status = write8_reg(addr, tpm_register, &data, 1); + if (status == 0) + status = i2c_read(addr, 0, 0, tpm_data, tpm_size); +return status; +} + +/* + * I2C_WRITE_DATA(): Send byte to TIS register according to I2C TPM protocol. + * @client, the chip description + * @tpm_register, TPM tis register where the data should be written + * @tpm_data, the tpm_data to write inside the tpm_register + * @tpm_size, The length of the data + * @return: Returns zero in case of success else the negative error code. + */ +#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size)\ + (write8_reg(client, tpm_register | \ + TPM_WRITE_DIRECTION, tpm_data, tpm_size)) + +/* + * I2C_READ_DATA(): Recv byte from TIS register according I2C TPM protocol. + * @tpm, the chip description + * @tpm_register, the tpm tis register where the data should be read + * @tpm_data, the TPM response + * @tpm_size, tpm TPM response size to read. + * @return: Returns zero in case of success else the negative error code. + */ +#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size)\ + (read8_reg(client, tpm_register, tpm_data, tpm_size)) + +/* + * release_locality(): release the active locality + * @chip, TPM chip descriptor. + * @return: Returns zero in case of success else the negative error code. + */ +static int release_locality(struct tpm_chip *chip) +{ + u8 data = TPM_ACCESS_ACTIVE_LOCALITY; + + return I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); +} + +/* + * check_locality(): check if the locality is active + * @chip, TPM chip descriptor. + * @return: the active locality or -EIO. + */ +static int check_locality(struct tpm_chip *chip) +{ + u8 data; + u8 status; + + status = I2C_READ_DATA(chip->addr, TPM_ACCESS, &data, 1); + if ((status == 0) && (data & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) + return chip->locality; + return -EIO; +} + +/* + * request_locality(): request the TPM locality + * @chip: TPM chip descriptor. + * @return: the active locality or -ETIME. + */ +static int request_locality(struct tpm_chip *chip) +{ + unsigned long start, stop; + long rc; + u8 data; + + if (check_locality(chip) == chip->locality) + return chip->locality; + + data = TPM_ACCESS_REQUEST_USE; + rc = I2C_WRITE_DATA(chip->addr, TPM_ACCESS, &data, 1); + if (rc < 0) + goto end; + + /* wait for locality activated */ + start = get_timer(0); + stop = chip->timeout_a; + do { + if (check_locality(chip) >= 0) + return chip->locality; + } while (get_timer(start) < stop); + rc = -ETIME; +end: + return rc; +} + +/* + * tpm_stm_spi_status(): return the TPM_STS register + * @chip: TPM chip descriptor. + * @return: the TPM_STS register value. + */ +static u8 tpm_stm_i2c_status(struct tpm_chip *chip) +{ + u8 data; + + I2C_READ_DATA(chip->addr, TPM_STS, &data, 1); + return data; +} + +/* + * get_burstcount(): return burstcount value from address 0x19 0x1A + * @chip: TPM chip descriptor. + * return: the burstcount or negative value in case of error. + */ +static int get_burstcount(struct tpm_chip *chip) +{ + unsigned long start, stop; + int burstcnt, status, ret; + u8 tpm_reg, temp; + + /* wait for burstcount */ + start = get_timer(0); + stop = chip->timeout_d; + do { + tpm_reg = TPM_STS + 1; + status = I2C_READ_DATA(chip->addr, tpm_reg, &temp, 1); + if (status < 0) + break; + tpm_reg = tpm_reg + 1; + burstcnt = temp; + status = I2C_READ_DATA(chip->addr, tpm_reg, &temp, 1); + if (status < 0) + break; + burstcnt |= temp << 8; + if (burstcnt) { + ret = burstcnt; + goto end; + } + udelay(TIS_SHORT_TIMEOUT_MS*1000); + } while (get_timer(start) < stop); + ret = -ETIME; +end: + return ret; +} + +/* + * tpm_stm_i2c_command_ready(): move TPM state to Command Ready state. + * @chip: TPM descriptor. + * return: 0 on success or negative value in case of error. + */ +static int tpm_stm_i2c_command_ready(struct tpm_chip *chip) +{ + unsigned long start, stop; + int ret; + u8 status; + u8 data; + + data = TPM_STS_COMMAND_READY; + I2C_WRITE_DATA(chip->addr, TPM_STS, &data, 1); + start = get_timer(0); + stop = tpm_dev.timeout_b; + do { + status = tpm_stm_i2c_status(chip); + debug("%s:%d - status = %d\n", __FILE__, __LINE__, status); + if ((status & data) == data) + return 0; + } while (get_timer(start) < stop); + ret = -ETIME; +return ret; +} + +/* + * recv_data(): receive data + * @chip: TPM chip descriptor. + * @buf, the buffer where the data are received + * @count, the number of data to receive + * @return: the number of bytes read from TPM FIFO. + */ +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) +{ + int size = 0, burstcnt, len; + + while (size < count) { + burstcnt = get_burstcount(chip); + len = count - size; + if ((len) > burstcnt) + len = burstcnt; + if (I2C_READ_DATA(chip->addr, TPM_DATA_FIFO, buf + size, len) + == 0) + size += len; + else + break; + } + return size; +} + +/* + * tpm_stm_i2c_pool_command_completion(): pool the TPM_STS register until + * command execution complete + * @chip:TPM chip descriptor. + * @return: O when TPM complete command execution or negative error code. + */ +static int tpm_stm_i2c_pool_command_completion(struct tpm_chip *chip) +{ + unsigned long start, stop; + long rc; + u8 status; + + start = get_timer(0); + stop = tpm_dev.duration; + do { + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_DATA_AVAIL) == + TPM_STS_DATA_AVAIL) + return 0; + } while (get_timer(start) < stop); + rc = -ETIME; + return rc; +} + +/* + * tpm_stm_i2c_recv(): received TPM response through the I2C bus. + * @chip: TPM chip descriptor. + * @buf: the buffer to store data. + * @count: the number of bytes that can be received max (sizeof buf). + * @return: Returns zero in case of success else negative error code. + */ +static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, + size_t count) +{ + int size = 0; + int expected; + + if (chip == NULL) + return -ENODEV; + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + size = recv_data(chip, buf, TPM_HEADER_SIZE); + if (size < TPM_HEADER_SIZE) { + error("%s:%d - Unable to read header\n", + __FILE__, __LINE__); + goto out; + } + expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); + if (expected > count) { + size = -EIO; + goto out; + } + size += recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); + if (size < expected) { + error("%s:%d - Unable to read remaining bytes of result\n", + __FILE__, __LINE__); + size = -EIO; + goto out; + } +out: + tpm_stm_i2c_command_ready(chip); + release_locality(chip); + return size; +} + +/* + * tpm_stm_i2c_send(): send TPM commands through the I2C bus. + * @chip: TPM descriptor. + * @buf: the buffer to send. + * @len: the number of bytes to send. + * @return: Returns zero in case of success else the negative error code. + */ +static int tpm_stm_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + u32 ret = 0, + status, + burstcnt = 0, i, size; + u8 data; + + if (chip == NULL) + return -ENODEV; + if (len < TPM_HEADER_SIZE) + return -EIO; + ret = request_locality(chip); + if (ret < 0) + return ret; + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) + ret = tpm_stm_i2c_command_ready(chip); + if (ret < 0) + goto out_err; + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); + size = len - i - 1; + if ((size) > burstcnt) + size = burstcnt; + ret = I2C_WRITE_DATA(chip->addr, TPM_DATA_FIFO, buf, size); + if (ret < 0) + goto out_err; + i += size; + } + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_DATA_EXPECT) == 0) { + ret = -EIO; + goto out_err; + } + ret = I2C_WRITE_DATA(chip->addr, TPM_DATA_FIFO, buf + len - 1, 1); + if (ret < 0) + goto out_err; + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + ret = -EIO; + goto out_err; + } + data = TPM_STS_GO; + ret = I2C_WRITE_DATA(chip->addr, TPM_STS, &data, 1); + if (ret < 0) + goto out_err; + return len; + +out_err: + ret = tpm_stm_i2c_command_ready(chip); + release_locality(chip); + return ret; +} + +/* + * tpm_stm_i2c_send_hash(): send TPM locality 4 hash datas through the I2C bus + * to update the PCR[17]. + * @chip: TPM chip descriptor. + * @buf: the data buffer to send. + * @len: the number of bytes to send. + * @return: Returns zero in case of success else a negative error code. + */ +static int tpm_stm_i2c_send_hash(struct tpm_chip *chip, const uint8_t *buf, + size_t len) +{ + int ret = 0; + u8 data; + + if (chip == NULL) + return -EBUSY; + release_locality(chip); + chip->addr = LOCALITY4_I2C_ADDR; + chip->locality = LOCALITY4; + data = TPM_DUMMY_BYTE; + ret = I2C_WRITE_DATA(chip->addr, TPM_HASH_START, &data, 1); + if (ret != 0) + goto end; + ret = I2C_WRITE_DATA(chip->addr, TPM_DATA_FIFO, buf, len); + if (ret != 0) + goto end; + ret = I2C_WRITE_DATA(chip->addr, TPM_HASH_END, &data, 1); + if (ret != 0) + goto end; + +end: + release_locality(chip); + chip->locality = LOCALITY0; + chip->addr = LOCALITY0_I2C_ADDR; + ret |= request_locality(chip); + return ret; +} + +/* + * tpm_vendor_init(): initialize the TPM device + * @dev_addr: the i2c address of TPM. + * @return: 0 in case of success, negative value in case of error. + */ +int tpm_vendor_init(uint32_t dev_addr, uint32_t dev_bus) +{ + int rc = 0; + + tpm_dev.addr = dev_addr; + tpm_dev.i2c_bus = dev_bus; + if (i2c_set_bus_num(tpm_dev.i2c_bus) != 0) { + rc = -ENODEV; + goto out_err; + } + /* Default timeouts */ + tpm_dev.timeout_a = TIS_SHORT_TIMEOUT_MS; + tpm_dev.timeout_b = TIS_LONG_TIMEOUT_MS; + tpm_dev.timeout_c = TIS_SHORT_TIMEOUT_MS; + tpm_dev.timeout_d = TIS_SHORT_TIMEOUT_MS; + tpm_dev.locality = LOCALITY0; + tpm_dev.duration = TPM_MAX_COMMAND_DURATION_MS; + if (request_locality(&tpm_dev) != 0) { + rc = -EIO; + goto out_err; + } + tpm_dev.is_open = 1; + debug("%s:%d - ST33ZP24 I2C TPM from STMicroelectronics found\n", + __FILE__, __LINE__); + return 0; + +out_err: + tpm_dev.is_open = 0; + return rc; +} + + +/* + * tis_init() verify presence of ST33ZP24 I2C TPM device and configure driver + * for it. + * @return: 0 on success (the device is found or was found during an earlier + * invocation) or negative value if the device is not found. + */ +int tis_init(void) +{ + int rc; + uint32_t dev_addr, dev_bus; + + dev_addr = LOCALITY0_I2C_ADDR; + dev_bus = CONFIG_TPM_I2C_BUS; + rc = tpm_vendor_init(dev_addr, dev_bus); + return rc; +} + +/* + * tis_sendrecv() send the requested data to the TPM and then try to get + * its response + * @sendbuf: buffer of the data to send + * @sbuf_size: size of the data to send + * @recvbuf: buffer to save the response to + * @recv_len: pointer to the size of the response buffer + * @return: 0 on success (and places the number of response bytes at recv_len) + * or negative value on failure. + */ +int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, + uint8_t *recvbuf, size_t *rbuf_len) +{ + int len, i; + uint8_t buf[TPM_BUFSIZE]; + + if (tpm_dev.is_open == 0) + return -ENXIO; + if (sizeof(buf) < sbuf_size) + return -EIO; + memcpy(buf, sendbuf, sbuf_size); + len = tpm_stm_i2c_send(&tpm_dev, buf, sbuf_size); + if (len != sbuf_size) { + error(" %s:%d - Command not fully transmitted\n", + __FILE__, __LINE__); + return -EIO; + } + if (tpm_stm_i2c_pool_command_completion(&tpm_dev) != 0) + return -ETIME; + len = tpm_stm_i2c_recv(&tpm_dev, buf, sizeof(buf)); + if (len < 10) { + *rbuf_len = 0; + return -EIO; + } + memcpy(recvbuf, buf, len); + *rbuf_len = len; + return 0; +} + +/* + * tis_sendhashloc4() perform a hash in locality 4 in order to extend PCR17 + * @sendbuf: buffer of the data to send + * @send_size: size of the data to send + * @return: 0 on success or negative value on failure. + */ +int tis_sendhashloc4(const uint8_t *sendbuf, size_t sbuf_size) +{ + int ret; + + if (tpm_dev.is_open == 0) { + error("%s:%d - TPM not yet initialized\n", + __FILE__, __LINE__); + error("Perform \"tpm init\" first\n"); + return -EIO; + } + ret = tpm_stm_i2c_send_hash(&tpm_dev, sendbuf, sbuf_size); + return ret; +} + +/* + * tis_open(): requests access to locality 0 for the caller. After all + * commands have been completed the caller is supposed to call tis_close(). + * @return: 0 on success, negative value on failure. + */ +int tis_open(void) +{ + if (tis_close()) + return -EIO; + + /* now request access to locality. */ + if (request_locality(&tpm_dev) != 0) { + error("%s:%d - failed to lock locality 0\n", + __FILE__, __LINE__); + return -EIO; + } + return 0; +} + +/* + * tis_close() terminate the current session with the TPM by releasing + * the locked locality. + * @return: 0 on success or negative value on failure. + */ +int tis_close(void) +{ + return release_locality(&tpm_dev); +}