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 + -
显示快捷键?