tpm_infineon.c
来自「linux 内核源代码」· C语言 代码 · 共 643 行 · 第 1/2 页
C
643 行
if (ret) { dev_err(chip->dev, "Timeout while clearing FIFO\n"); return -EIO; } ret = wait(chip, STAT_XFE); if (ret) return -EIO; count_4 = (count & 0xff000000) >> 24; count_3 = (count & 0x00ff0000) >> 16; count_2 = (count & 0x0000ff00) >> 8; count_1 = (count & 0x000000ff); count_high = ((count + 6) & 0xffffff00) >> 8; count_low = ((count + 6) & 0x000000ff); /* Sending Header */ wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_DATA); wait_and_send(chip, count_high); wait_and_send(chip, count_low); /* Sending Data Header */ wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_VL_CHANNEL_TPM); wait_and_send(chip, count_4); wait_and_send(chip, count_3); wait_and_send(chip, count_2); wait_and_send(chip, count_1); /* Sending Data */ for (i = 0; i < count; i++) { wait_and_send(chip, buf[i]); } return count;}static void tpm_inf_cancel(struct tpm_chip *chip){ /* Since we are using the legacy mode to communicate with the TPM, we have no cancel functions, but have a workaround for interrupting the TPM through WTX. */}static u8 tpm_inf_status(struct tpm_chip *chip){ return tpm_data_in(STAT);}static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);static struct attribute *inf_attrs[] = { &dev_attr_pubek.attr, &dev_attr_pcrs.attr, &dev_attr_caps.attr, &dev_attr_cancel.attr, NULL,};static struct attribute_group inf_attr_grp = {.attrs = inf_attrs };static const struct file_operations inf_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = tpm_open, .read = tpm_read, .write = tpm_write, .release = tpm_release,};static const struct tpm_vendor_specific tpm_inf = { .recv = tpm_inf_recv, .send = tpm_inf_send, .cancel = tpm_inf_cancel, .status = tpm_inf_status, .req_complete_mask = 0, .req_complete_val = 0, .attr_group = &inf_attr_grp, .miscdev = {.fops = &inf_ops,},};static const struct pnp_device_id tpm_pnp_tbl[] = { /* Infineon TPMs */ {"IFX0101", 0}, {"IFX0102", 0}, {"", 0}};MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id){ int rc = 0; u8 iol, ioh; int vendorid[2]; int version[2]; int productid[2]; char chipname[20]; struct tpm_chip *chip; /* read IO-ports through PnP */ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { tpm_dev.iotype = TPM_INF_IO_PORT; tpm_dev.config_port = pnp_port_start(dev, 0); tpm_dev.config_size = pnp_port_len(dev, 0); tpm_dev.data_regs = pnp_port_start(dev, 1); tpm_dev.data_size = pnp_port_len(dev, 1); if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) { rc = -EINVAL; goto err_last; } dev_info(&dev->dev, "Found %s with ID %s\n", dev->name, dev_id->id); if (!((tpm_dev.data_regs >> 8) & 0xff)) { rc = -EINVAL; goto err_last; } /* publish my base address and request region */ if (request_region(tpm_dev.data_regs, tpm_dev.data_size, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } if (request_region(tpm_dev.config_port, tpm_dev.config_size, "tpm_infineon0") == NULL) { release_region(tpm_dev.data_regs, tpm_dev.data_size); rc = -EINVAL; goto err_last; } } else if (pnp_mem_valid(dev, 0) && !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) { tpm_dev.iotype = TPM_INF_IO_MEM; tpm_dev.map_base = pnp_mem_start(dev, 0); tpm_dev.map_size = pnp_mem_len(dev, 0); dev_info(&dev->dev, "Found %s with ID %s\n", dev->name, dev_id->id); /* publish my base address and request region */ if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size); if (tpm_dev.mem_base == NULL) { release_mem_region(tpm_dev.map_base, tpm_dev.map_size); rc = -EINVAL; goto err_last; } /* * The only known MMIO based Infineon TPM system provides * a single large mem region with the device config * registers at the default TPM_ADDR. The data registers * seem like they could be placed anywhere within the MMIO * region, but lets just put them at zero offset. */ tpm_dev.index_off = TPM_ADDR; tpm_dev.data_regs = 0x0; } else { rc = -EINVAL; goto err_last; } /* query chip for its vendor, its version number a.s.o. */ tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); tpm_config_out(IDVENL, TPM_INF_ADDR); vendorid[1] = tpm_config_in(TPM_INF_DATA); tpm_config_out(IDVENH, TPM_INF_ADDR); vendorid[0] = tpm_config_in(TPM_INF_DATA); tpm_config_out(IDPDL, TPM_INF_ADDR); productid[1] = tpm_config_in(TPM_INF_DATA); tpm_config_out(IDPDH, TPM_INF_ADDR); productid[0] = tpm_config_in(TPM_INF_DATA); tpm_config_out(CHIP_ID1, TPM_INF_ADDR); version[1] = tpm_config_in(TPM_INF_DATA); tpm_config_out(CHIP_ID2, TPM_INF_ADDR); version[0] = tpm_config_in(TPM_INF_DATA); switch ((productid[0] << 8) | productid[1]) { case 6: snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)"); break; case 11: snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)"); break; default: snprintf(chipname, sizeof(chipname), " (unknown chip)"); break; } if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { /* configure TPM with IO-ports */ tpm_config_out(IOLIMH, TPM_INF_ADDR); tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA); tpm_config_out(IOLIML, TPM_INF_ADDR); tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA); /* control if IO-ports are set correctly */ tpm_config_out(IOLIMH, TPM_INF_ADDR); ioh = tpm_config_in(TPM_INF_DATA); tpm_config_out(IOLIML, TPM_INF_ADDR); iol = tpm_config_in(TPM_INF_DATA); if ((ioh << 8 | iol) != tpm_dev.data_regs) { dev_err(&dev->dev, "Could not set IO-data registers to 0x%x\n", tpm_dev.data_regs); rc = -EIO; goto err_release_region; } /* activate register */ tpm_config_out(TPM_DAR, TPM_INF_ADDR); tpm_config_out(0x01, TPM_INF_DATA); tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); /* disable RESET, LP and IRQC */ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); /* Finally, we're done, print some infos */ dev_info(&dev->dev, "TPM found: " "config base 0x%lx, " "data base 0x%lx, " "chip version 0x%02x%02x, " "vendor id 0x%x%x (Infineon), " "product id 0x%02x%02x" "%s\n", tpm_dev.iotype == TPM_INF_IO_PORT ? tpm_dev.config_port : tpm_dev.map_base + tpm_dev.index_off, tpm_dev.iotype == TPM_INF_IO_PORT ? tpm_dev.data_regs : tpm_dev.map_base + tpm_dev.data_regs, version[0], version[1], vendorid[0], vendorid[1], productid[0], productid[1], chipname); if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) goto err_release_region; return 0; } else { rc = -ENODEV; goto err_release_region; }err_release_region: if (tpm_dev.iotype == TPM_INF_IO_PORT) { release_region(tpm_dev.data_regs, tpm_dev.data_size); release_region(tpm_dev.config_port, tpm_dev.config_size); } else { iounmap(tpm_dev.mem_base); release_mem_region(tpm_dev.map_base, tpm_dev.map_size); }err_last: return rc;}static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev){ struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { if (tpm_dev.iotype == TPM_INF_IO_PORT) { release_region(tpm_dev.data_regs, tpm_dev.data_size); release_region(tpm_dev.config_port, tpm_dev.config_size); } else { iounmap(tpm_dev.mem_base); release_mem_region(tpm_dev.map_base, tpm_dev.map_size); } tpm_remove_hardware(chip->dev); }}static struct pnp_driver tpm_inf_pnp = { .name = "tpm_inf_pnp", .driver = { .owner = THIS_MODULE, .suspend = tpm_pm_suspend, .resume = tpm_pm_resume, }, .id_table = tpm_pnp_tbl, .probe = tpm_inf_pnp_probe, .remove = __devexit_p(tpm_inf_pnp_remove),};static int __init init_inf(void){ return pnp_register_driver(&tpm_inf_pnp);}static void __exit cleanup_inf(void){ pnp_unregister_driver(&tpm_inf_pnp);}module_init(init_inf);module_exit(cleanup_inf);MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");MODULE_VERSION("1.9");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?