static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; int expected, status; if (count < TPM_HEADER_SIZE) { size = -EIO; goto out; } /* read first 10 bytes, including tag, paramsize, and result */ size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { dev_err(chip->dev, "Unable to read header\n"); goto out; } expected = be32_to_cpu(*(__be32 *)(buf + 2)); if ((size_t) expected > count) { size = -EIO; goto out; } size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { dev_err(chip->dev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ dev_err(chip->dev, "Error left over data\n"); size = -EIO; goto out; } out: tpm_tis_i2c_ready(chip); /* The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); release_locality(chip, chip->vendor.locality, 0); return size; }
static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = tpm_dev.chip; release_locality(chip, chip->vendor.locality, 1); /* close file handles */ tpm_dev_vendor_release(chip); /* remove hardware */ tpm_remove_hardware(chip->dev); /* reset these pointers, otherwise we oops */ chip->dev->release = NULL; chip->release = NULL; tpm_dev.client = NULL; dev_set_drvdata(chip->dev, chip); return 0; }
int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) { int size = 0; int expected, status; if (count < TPM_HEADER_SIZE) { size = -EIO; goto out; } /* read first 10 bytes, including tag, paramsize, and result */ if((size = recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { printk("Error reading tpm cmd header\n"); goto out; } expected = be32_to_cpu(*((uint32_t*)(buf + 2))); if(expected > count) { size = -EIO; goto out; } if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE)) < expected) { printk("Unable to read rest of tpm command size=%d expected=%d\n", size, expected); size = -ETIME; goto out; } wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); status = tpm_tis_status(tpm); if(status & TPM_STS_DATA_AVAIL) { printk("Error: left over data\n"); size = -EIO; goto out; } out: tpm_tis_ready(tpm); release_locality(tpm, tpm->locality, 0); return size; }
/* * tpm_stm_i2c_recv received TPM response through the I2C bus. * @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 size = 0; int expected; if (chip == NULL) return -EBUSY; if (count < TPM_HEADER_SIZE) { size = -EIO; goto out; } size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { dev_err(chip->dev, "Unable to read header\n"); goto out; } expected = be32_to_cpu(*(__be32 *) (buf + 2)); if (expected > count) { size = -EIO; goto out; } size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { dev_err(chip->dev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } out: chip->vendor.cancel(chip); release_locality(chip); return size; }
static int __devinit tpm_tis_i2c_init(struct device *dev) { u32 vendor; int rc = 0; struct tpm_chip *chip; chip = tpm_register_hardware(dev, &tpm_tis_i2c); if (!chip) { rc = -ENODEV; goto out_err; } /* Disable interrupts */ chip->vendor.irq = 0; /* 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); if (request_locality(chip, 0) != 0) { rc = -ENODEV; goto out_vendor; } /* read four bytes from DID_VID register */ if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { rc = -EIO; goto out_release; } /* create DID_VID register value, after swapping to little-endian */ vendor = be32_to_cpu((__be32) vendor); if (vendor != TPM_TIS_I2C_DID_VID) { rc = -ENODEV; goto out_release; } dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16); INIT_LIST_HEAD(&chip->vendor.list); tpm_dev.chip = chip; tpm_get_timeouts(chip); tpm_do_selftest(chip); return 0; out_release: release_locality(chip, chip->vendor.locality, 1); out_vendor: /* close file handles */ tpm_dev_vendor_release(chip); /* remove hardware */ tpm_remove_hardware(chip->dev); /* reset these pointers, otherwise we oops */ chip->dev->release = NULL; chip->release = NULL; tpm_dev.client = NULL; dev_set_drvdata(chip->dev, chip); out_err: return rc; }
static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) { int rc, status; ssize_t burstcnt; size_t count = 0; u8 retries = 0; u8 sts = TPM_STS_GO; if (len > TPM_BUFSIZE) return -E2BIG; /* command is too long for our tpm, sorry */ if (request_locality(chip, 0) < 0) return -EBUSY; status = tpm_tis_i2c_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_i2c_ready(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, &status) < 0) { rc = -ETIME; goto out_err; } } while (count < len - 1) { burstcnt = get_burstcount(chip); /* burstcnt < 0 = TPM is busy */ if (burstcnt < 0) return burstcnt; if (burstcnt > (len - 1 - count)) burstcnt = len - 1 - count; rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; else if (rc < 0) retries++; /* avoid endless loop in case of broken HW */ if (retries > MAX_COUNT_LONG) { rc = -EIO; goto out_err; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if ((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } } /* write last byte */ iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if ((status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; goto out_err; } /* go and do it */ iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); return len; out_err: tpm_tis_i2c_ready(chip); /* The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); release_locality(chip, chip->vendor.locality, 0); return rc; }
/* * tpm_stm_i2c_send send TPM commands through the I2C bus. * * @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 len) { u32 status, burstcnt = 0, i, size; int ret; u8 data; struct i2c_client *client; if (chip == NULL) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; client = (struct i2c_client *)TPM_VPRIV(chip); client->flags = 0; ret = request_locality(chip); if (ret < 0) return ret; status = tpm_stm_i2c_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { tpm_stm_i2c_cancel(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, &chip->vendor.int_queue) < 0) { ret = -ETIME; goto out_err; } } for (i = 0 ; i < len - 1 ;) { burstcnt = get_burstcount(chip); size = min_t(int, len - i - 1, burstcnt); ret = I2C_WRITE_DATA(client, 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(client, 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; I2C_WRITE_DATA(client, TPM_STS, &data, 1); return len; out_err: tpm_stm_i2c_cancel(chip); release_locality(chip); return ret; }
/* * st33zp24_send send TPM commands through the I2C bus. * * @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 st33zp24_send(struct tpm_chip *chip, unsigned char *buf, size_t len) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); u32 status, i, size, ordinal; int burstcnt = 0; int ret; u8 data; if (!chip) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; ret = request_locality(chip); if (ret < 0) return ret; status = st33zp24_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { st33zp24_cancel(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->timeout_b, &tpm_dev->read_queue, false) < 0) { ret = -ETIME; goto out_err; } } for (i = 0; i < len - 1;) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; i += size; } status = st33zp24_status(chip); if ((status & TPM_STS_DATA_EXPECT) == 0) { ret = -EIO; goto out_err; } ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, buf + len - 1, 1); if (ret < 0) goto out_err; status = st33zp24_status(chip); if ((status & TPM_STS_DATA_EXPECT) != 0) { ret = -EIO; goto out_err; } data = TPM_STS_GO; ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); if (ret < 0) goto out_err; if (chip->flags & TPM_CHIP_FLAG_IRQ) { ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ret = wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, tpm_calc_ordinal_duration(chip, ordinal), &tpm_dev->read_queue, false); if (ret < 0) goto out_err; } return len; out_err: st33zp24_cancel(chip); release_locality(chip); return ret; }
int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) { int rc; int status, burstcnt = 0; int count = 0; uint32_t ordinal; if(tpm_tis_request_locality(tpm, tpm->locality) < 0) { return -EBUSY; } status = tpm_tis_status(tpm); if((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_ready(tpm); if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, &tpm->int_queue) < 0) { rc = -ETIME; goto out_err; } } while(count < len - 1) { burstcnt = get_burstcount(tpm); for(;burstcnt > 0 && count < len -1; --burstcnt) { iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]); } wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } } /*Write last byte*/ iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]); wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; goto out_err; } /*go and do it*/ iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO); if(tpm->irq) { /*Wait for interrupt */ ordinal = be32_to_cpu(*(buf + 6)); if(wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID, tpm_calc_ordinal_duration(tpm, ordinal), &tpm->read_queue) < 0) { rc = -ETIME; goto out_err; } } #ifdef HAVE_LIBC if(tpm->fd >= 0) { files[tpm->fd].read = 0; files[tpm->fd].tpm_tis.respgot = 0; files[tpm->fd].tpm_tis.offset = 0; } #endif return len; out_err: tpm_tis_ready(tpm); release_locality(tpm, tpm->locality, 0); return rc; }