xref: /freebsd/sys/dev/tpm/tpm.c (revision 453130d9bfc1c6d68b366dfcb041689d69f81295)
197f24f66STakanori Watanabe /*
297f24f66STakanori Watanabe  * Copyright (c) 2008, 2009 Michael Shalayeff
397f24f66STakanori Watanabe  * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
497f24f66STakanori Watanabe  * All rights reserved.
597f24f66STakanori Watanabe  *
697f24f66STakanori Watanabe  * Permission to use, copy, modify, and distribute this software for any
797f24f66STakanori Watanabe  * purpose with or without fee is hereby granted, provided that the above
897f24f66STakanori Watanabe  * copyright notice and this permission notice appear in all copies.
997f24f66STakanori Watanabe  *
1097f24f66STakanori Watanabe  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1197f24f66STakanori Watanabe  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1297f24f66STakanori Watanabe  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1397f24f66STakanori Watanabe  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1497f24f66STakanori Watanabe  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
1597f24f66STakanori Watanabe  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1697f24f66STakanori Watanabe  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1797f24f66STakanori Watanabe  */
1897f24f66STakanori Watanabe 
1997f24f66STakanori Watanabe /* #define	TPM_DEBUG */
2097f24f66STakanori Watanabe 
2197f24f66STakanori Watanabe #include <sys/cdefs.h>
2297f24f66STakanori Watanabe __FBSDID("$FreeBSD$");
2397f24f66STakanori Watanabe 
2497f24f66STakanori Watanabe #include <sys/param.h>
2597f24f66STakanori Watanabe #include <sys/systm.h>
2697f24f66STakanori Watanabe #include <sys/kernel.h>
2797f24f66STakanori Watanabe #include <sys/malloc.h>
2897f24f66STakanori Watanabe #include <sys/proc.h>
2997f24f66STakanori Watanabe 
3097f24f66STakanori Watanabe #ifdef __FreeBSD__
3197f24f66STakanori Watanabe #include <sys/module.h>
3297f24f66STakanori Watanabe #include <sys/conf.h>
3397f24f66STakanori Watanabe #include <sys/uio.h>
3497f24f66STakanori Watanabe #include <sys/bus.h>
3597f24f66STakanori Watanabe 
3697f24f66STakanori Watanabe #include <machine/bus.h>
3797f24f66STakanori Watanabe #include <sys/rman.h>
3897f24f66STakanori Watanabe #include <machine/resource.h>
3997f24f66STakanori Watanabe 
4097f24f66STakanori Watanabe #include <machine/md_var.h>
4197f24f66STakanori Watanabe 
4297f24f66STakanori Watanabe #include <isa/isareg.h>
4397f24f66STakanori Watanabe #include <isa/isavar.h>
4497f24f66STakanori Watanabe #else
4597f24f66STakanori Watanabe #include <sys/device.h>
4697f24f66STakanori Watanabe 
4797f24f66STakanori Watanabe #include <machine/cpu.h>
4897f24f66STakanori Watanabe #include <machine/bus.h>
4997f24f66STakanori Watanabe #include <machine/intr.h>
5097f24f66STakanori Watanabe #include <machine/conf.h>
5197f24f66STakanori Watanabe 
5297f24f66STakanori Watanabe #include <dev/isa/isareg.h>
5397f24f66STakanori Watanabe #include <dev/isa/isavar.h>
5497f24f66STakanori Watanabe #endif
5597f24f66STakanori Watanabe #include <dev/tpm/tpmvar.h>
5697f24f66STakanori Watanabe 
5797f24f66STakanori Watanabe #ifndef __FreeBSD__
5897f24f66STakanori Watanabe /* XXX horrible hack for tcsd (-lpthread) workaround on OpenBSD */
5997f24f66STakanori Watanabe #undef PCATCH
6097f24f66STakanori Watanabe #define PCATCH	0
6197f24f66STakanori Watanabe #endif
6297f24f66STakanori Watanabe 
6397f24f66STakanori Watanabe #define	TPM_BUFSIZ	1024
6497f24f66STakanori Watanabe 
6597f24f66STakanori Watanabe #define TPM_HDRSIZE	10
6697f24f66STakanori Watanabe 
6797f24f66STakanori Watanabe #define TPM_PARAM_SIZE	0x0001
6897f24f66STakanori Watanabe 
6997f24f66STakanori Watanabe #ifdef __FreeBSD__
7097f24f66STakanori Watanabe #define IRQUNK	-1
7197f24f66STakanori Watanabe #endif
7297f24f66STakanori Watanabe 
73*453130d9SPedro F. Giffuni #define	TPM_ACCESS			0x0000	/* access register */
7497f24f66STakanori Watanabe #define	TPM_ACCESS_ESTABLISHMENT	0x01	/* establishment */
7597f24f66STakanori Watanabe #define	TPM_ACCESS_REQUEST_USE		0x02	/* request using locality */
7697f24f66STakanori Watanabe #define	TPM_ACCESS_REQUEST_PENDING	0x04	/* pending request */
7797f24f66STakanori Watanabe #define	TPM_ACCESS_SEIZE		0x08	/* request locality seize */
7897f24f66STakanori Watanabe #define	TPM_ACCESS_SEIZED		0x10	/* locality has been seized */
7997f24f66STakanori Watanabe #define	TPM_ACCESS_ACTIVE_LOCALITY	0x20	/* locality is active */
8097f24f66STakanori Watanabe #define	TPM_ACCESS_VALID		0x80	/* bits are valid */
8197f24f66STakanori Watanabe #define	TPM_ACCESS_BITS	\
8297f24f66STakanori Watanabe     "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
8397f24f66STakanori Watanabe 
8497f24f66STakanori Watanabe #define	TPM_INTERRUPT_ENABLE	0x0008
8597f24f66STakanori Watanabe #define	TPM_GLOBAL_INT_ENABLE	0x80000000	/* enable ints */
8697f24f66STakanori Watanabe #define	TPM_CMD_READY_INT	0x00000080	/* cmd ready enable */
8797f24f66STakanori Watanabe #define	TPM_INT_EDGE_FALLING	0x00000018
8897f24f66STakanori Watanabe #define	TPM_INT_EDGE_RISING	0x00000010
8997f24f66STakanori Watanabe #define	TPM_INT_LEVEL_LOW	0x00000008
9097f24f66STakanori Watanabe #define	TPM_INT_LEVEL_HIGH	0x00000000
9197f24f66STakanori Watanabe #define	TPM_LOCALITY_CHANGE_INT	0x00000004	/* locality change enable */
9297f24f66STakanori Watanabe #define	TPM_STS_VALID_INT	0x00000002	/* int on TPM_STS_VALID is set */
9397f24f66STakanori Watanabe #define	TPM_DATA_AVAIL_INT	0x00000001	/* int on TPM_STS_DATA_AVAIL is set */
9497f24f66STakanori Watanabe #define	TPM_INTERRUPT_ENABLE_BITS \
9597f24f66STakanori Watanabe     "\020\040ENA\010RDY\03LOCH\02STSV\01DRDY"
9697f24f66STakanori Watanabe 
9797f24f66STakanori Watanabe #define	TPM_INT_VECTOR		0x000c	/* 8 bit reg for 4 bit irq vector */
9897f24f66STakanori Watanabe #define	TPM_INT_STATUS		0x0010	/* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
9997f24f66STakanori Watanabe 
10097f24f66STakanori Watanabe #define	TPM_INTF_CAPABILITIES		0x0014	/* capability register */
10197f24f66STakanori Watanabe #define	TPM_INTF_BURST_COUNT_STATIC	0x0100	/* TPM_STS_BMASK static */
10297f24f66STakanori Watanabe #define	TPM_INTF_CMD_READY_INT		0x0080	/* int on ready supported */
10397f24f66STakanori Watanabe #define	TPM_INTF_INT_EDGE_FALLING	0x0040	/* falling edge ints supported */
10497f24f66STakanori Watanabe #define	TPM_INTF_INT_EDGE_RISING	0x0020	/* rising edge ints supported */
10597f24f66STakanori Watanabe #define	TPM_INTF_INT_LEVEL_LOW		0x0010	/* level-low ints supported */
10697f24f66STakanori Watanabe #define	TPM_INTF_INT_LEVEL_HIGH		0x0008	/* level-high ints supported */
10797f24f66STakanori Watanabe #define	TPM_INTF_LOCALITY_CHANGE_INT	0x0004	/* locality-change int (mb 1) */
10897f24f66STakanori Watanabe #define	TPM_INTF_STS_VALID_INT		0x0002	/* TPM_STS_VALID int supported */
10997f24f66STakanori Watanabe #define	TPM_INTF_DATA_AVAIL_INT		0x0001	/* TPM_STS_DATA_AVAIL int supported (mb 1) */
11097f24f66STakanori Watanabe #define	TPM_CAPSREQ \
11197f24f66STakanori Watanabe   (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
11297f24f66STakanori Watanabe #define	TPM_CAPBITS \
11397f24f66STakanori Watanabe   "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IEDGE\07IFALL\010IRDY\011BCST"
11497f24f66STakanori Watanabe 
11597f24f66STakanori Watanabe #define	TPM_STS			0x0018		/* status register */
11697f24f66STakanori Watanabe #define TPM_STS_MASK		0x000000ff	/* status bits */
11797f24f66STakanori Watanabe #define	TPM_STS_BMASK		0x00ffff00	/* ro io burst size */
11897f24f66STakanori Watanabe #define	TPM_STS_VALID		0x00000080	/* ro other bits are valid */
11997f24f66STakanori Watanabe #define	TPM_STS_CMD_READY	0x00000040	/* rw chip/signal ready */
12097f24f66STakanori Watanabe #define	TPM_STS_GO		0x00000020	/* wo start the command */
12197f24f66STakanori Watanabe #define	TPM_STS_DATA_AVAIL	0x00000010	/* ro data available */
12297f24f66STakanori Watanabe #define	TPM_STS_DATA_EXPECT	0x00000008	/* ro more data to be written */
12397f24f66STakanori Watanabe #define	TPM_STS_RESP_RETRY	0x00000002	/* wo resend the response */
12497f24f66STakanori Watanabe #define	TPM_STS_BITS	"\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
12597f24f66STakanori Watanabe 
12697f24f66STakanori Watanabe #define	TPM_DATA	0x0024
12797f24f66STakanori Watanabe #define	TPM_ID		0x0f00
12897f24f66STakanori Watanabe #define	TPM_REV		0x0f04
12997f24f66STakanori Watanabe #define	TPM_SIZE	0x5000		/* five pages of the above */
13097f24f66STakanori Watanabe 
13197f24f66STakanori Watanabe #define	TPM_ACCESS_TMO	2000		/* 2sec */
13297f24f66STakanori Watanabe #define	TPM_READY_TMO	2000		/* 2sec */
13397f24f66STakanori Watanabe #define	TPM_READ_TMO	120000		/* 2 minutes */
13497f24f66STakanori Watanabe #define TPM_BURST_TMO	2000		/* 2sec */
13597f24f66STakanori Watanabe 
13697f24f66STakanori Watanabe #define	TPM_LEGACY_BUSY	0x01
13797f24f66STakanori Watanabe #define	TPM_LEGACY_ABRT	0x01
13897f24f66STakanori Watanabe #define	TPM_LEGACY_DA	0x02
13997f24f66STakanori Watanabe #define	TPM_LEGACY_RE	0x04
14097f24f66STakanori Watanabe #define	TPM_LEGACY_LAST	0x04
14197f24f66STakanori Watanabe #define	TPM_LEGACY_BITS	"\020\01BUSY\2DA\3RE\4LAST"
14297f24f66STakanori Watanabe #define	TPM_LEGACY_TMO		(2*60)	/* sec */
14397f24f66STakanori Watanabe #define	TPM_LEGACY_SLEEP	5	/* ticks */
14497f24f66STakanori Watanabe #define	TPM_LEGACY_DELAY	100
14597f24f66STakanori Watanabe 
14697f24f66STakanori Watanabe /* Set when enabling legacy interface in host bridge. */
14797f24f66STakanori Watanabe int tpm_enabled;
14897f24f66STakanori Watanabe 
14997f24f66STakanori Watanabe 
15097f24f66STakanori Watanabe #ifdef __FreeBSD__
15197f24f66STakanori Watanabe #define	TPMSOFTC(dev) \
15297f24f66STakanori Watanabe 	((struct tpm_softc *)dev->si_drv1)
15397f24f66STakanori Watanabe 
15497f24f66STakanori Watanabe d_open_t	tpmopen;
15597f24f66STakanori Watanabe d_close_t	tpmclose;
15697f24f66STakanori Watanabe d_read_t	tpmread;
15797f24f66STakanori Watanabe d_write_t	tpmwrite;
15897f24f66STakanori Watanabe d_ioctl_t	tpmioctl;
15997f24f66STakanori Watanabe 
16097f24f66STakanori Watanabe static struct cdevsw tpm_cdevsw = {
16197f24f66STakanori Watanabe 	.d_version =	D_VERSION,
16297f24f66STakanori Watanabe 	.d_flags =	D_NEEDGIANT,
16397f24f66STakanori Watanabe 	.d_open =	tpmopen,
16497f24f66STakanori Watanabe 	.d_close =	tpmclose,
16597f24f66STakanori Watanabe 	.d_read =	tpmread,
16697f24f66STakanori Watanabe 	.d_write =	tpmwrite,
16797f24f66STakanori Watanabe 	.d_ioctl =	tpmioctl,
16897f24f66STakanori Watanabe 	.d_name =	"tpm",
16997f24f66STakanori Watanabe };
17097f24f66STakanori Watanabe #else
17197f24f66STakanori Watanabe #define	TPMSOFTC(dev) \
17297f24f66STakanori Watanabe     (struct tpm_softc *)device_lookup(&tpm_cd, minor(dev))
17397f24f66STakanori Watanabe 
17497f24f66STakanori Watanabe struct cfdriver tpm_cd = {
17597f24f66STakanori Watanabe 	NULL, "tpm", DV_DULL
17697f24f66STakanori Watanabe };
17797f24f66STakanori Watanabe 
17897f24f66STakanori Watanabe int	tpm_match(struct device *, void *, void *);
17997f24f66STakanori Watanabe void	tpm_attach(struct device *, struct device *, void *);
18097f24f66STakanori Watanabe 
18197f24f66STakanori Watanabe struct cfattach tpm_ca = {
18297f24f66STakanori Watanabe 	sizeof(struct tpm_softc), tpm_match, tpm_attach
18397f24f66STakanori Watanabe };
18497f24f66STakanori Watanabe #endif
18597f24f66STakanori Watanabe 
18697f24f66STakanori Watanabe const struct {
18797f24f66STakanori Watanabe 	u_int32_t devid;
18897f24f66STakanori Watanabe 	char name[32];
18997f24f66STakanori Watanabe 	int flags;
19097f24f66STakanori Watanabe #define TPM_DEV_NOINTS	0x0001
19197f24f66STakanori Watanabe } tpm_devs[] = {
19297f24f66STakanori Watanabe 	{ 0x000615d1, "IFX SLD 9630 TT 1.1", 0 },
19397f24f66STakanori Watanabe 	{ 0x000b15d1, "IFX SLB 9635 TT 1.2", 0 },
19497f24f66STakanori Watanabe 	{ 0x100214e4, "Broadcom BCM0102", TPM_DEV_NOINTS },
19597f24f66STakanori Watanabe 	{ 0x00fe1050, "WEC WPCT200", 0 },
19697f24f66STakanori Watanabe 	{ 0x687119fa, "SNS SSX35", 0 },
19797f24f66STakanori Watanabe 	{ 0x2e4d5453, "STM ST19WP18", 0 },
19897f24f66STakanori Watanabe 	{ 0x32021114, "ATML 97SC3203", TPM_DEV_NOINTS },
19997f24f66STakanori Watanabe 	{ 0x10408086, "INTEL INTC0102", 0 },
20097f24f66STakanori Watanabe 	{ 0, "", TPM_DEV_NOINTS },
20197f24f66STakanori Watanabe };
20297f24f66STakanori Watanabe 
20397f24f66STakanori Watanabe int tpm_tis12_irqinit(struct tpm_softc *, int, int);
20497f24f66STakanori Watanabe int tpm_tis12_init(struct tpm_softc *, int, const char *);
20597f24f66STakanori Watanabe int tpm_tis12_start(struct tpm_softc *, int);
20697f24f66STakanori Watanabe int tpm_tis12_read(struct tpm_softc *, void *, int, size_t *, int);
20797f24f66STakanori Watanabe int tpm_tis12_write(struct tpm_softc *, void *, int);
20897f24f66STakanori Watanabe int tpm_tis12_end(struct tpm_softc *, int, int);
20997f24f66STakanori Watanabe 
21097f24f66STakanori Watanabe #ifdef __FreeBSD__
21197f24f66STakanori Watanabe void tpm_intr(void *);
21297f24f66STakanori Watanabe #else
21397f24f66STakanori Watanabe int tpm_intr(void *);
21497f24f66STakanori Watanabe void tpm_powerhook(int, void *);
21597f24f66STakanori Watanabe int tpm_suspend(struct tpm_softc *, int);
21697f24f66STakanori Watanabe int tpm_resume(struct tpm_softc *, int);
21797f24f66STakanori Watanabe #endif
21897f24f66STakanori Watanabe 
21997f24f66STakanori Watanabe int tpm_waitfor_poll(struct tpm_softc *, u_int8_t, int, void *);
22097f24f66STakanori Watanabe int tpm_waitfor_int(struct tpm_softc *, u_int8_t, int, void *, int);
22197f24f66STakanori Watanabe int tpm_waitfor(struct tpm_softc *, u_int8_t, int, void *);
22297f24f66STakanori Watanabe int tpm_request_locality(struct tpm_softc *, int);
22397f24f66STakanori Watanabe int tpm_getburst(struct tpm_softc *);
22497f24f66STakanori Watanabe u_int8_t tpm_status(struct tpm_softc *);
22597f24f66STakanori Watanabe int tpm_tmotohz(int);
22697f24f66STakanori Watanabe 
22797f24f66STakanori Watanabe int tpm_legacy_probe(bus_space_tag_t, bus_addr_t);
22897f24f66STakanori Watanabe int tpm_legacy_init(struct tpm_softc *, int, const char *);
22997f24f66STakanori Watanabe int tpm_legacy_start(struct tpm_softc *, int);
23097f24f66STakanori Watanabe int tpm_legacy_read(struct tpm_softc *, void *, int, size_t *, int);
23197f24f66STakanori Watanabe int tpm_legacy_write(struct tpm_softc *, void *, int);
23297f24f66STakanori Watanabe int tpm_legacy_end(struct tpm_softc *, int, int);
23397f24f66STakanori Watanabe 
23497f24f66STakanori Watanabe #ifdef __FreeBSD__
23597f24f66STakanori Watanabe 
23697f24f66STakanori Watanabe /*
23797f24f66STakanori Watanabe  * FreeBSD specific code for probing and attaching TPM to device tree.
23897f24f66STakanori Watanabe  */
23997f24f66STakanori Watanabe #if 0
24097f24f66STakanori Watanabe static void
24197f24f66STakanori Watanabe tpm_identify(driver_t *driver, device_t parent)
24297f24f66STakanori Watanabe {
24397f24f66STakanori Watanabe 	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "tpm", 0);
24497f24f66STakanori Watanabe }
24597f24f66STakanori Watanabe #endif
24697f24f66STakanori Watanabe 
24797f24f66STakanori Watanabe 
24897f24f66STakanori Watanabe int
24997f24f66STakanori Watanabe tpm_attach(device_t dev)
25097f24f66STakanori Watanabe {
25197f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
25297f24f66STakanori Watanabe 	int irq;
25397f24f66STakanori Watanabe 
25497f24f66STakanori Watanabe 	sc->mem_rid = 0;
25597f24f66STakanori Watanabe 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
25697f24f66STakanori Watanabe 	    RF_ACTIVE);
25797f24f66STakanori Watanabe 	if (sc->mem_res == NULL)
25897f24f66STakanori Watanabe 		return ENXIO;
25997f24f66STakanori Watanabe 
26097f24f66STakanori Watanabe 	sc->sc_bt = rman_get_bustag(sc->mem_res);
26197f24f66STakanori Watanabe 	sc->sc_bh = rman_get_bushandle(sc->mem_res);
26297f24f66STakanori Watanabe 
26397f24f66STakanori Watanabe 	sc->irq_rid = 0;
26497f24f66STakanori Watanabe 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
26597f24f66STakanori Watanabe 	    RF_ACTIVE | RF_SHAREABLE);
26697f24f66STakanori Watanabe 	if (sc->irq_res != NULL)
26797f24f66STakanori Watanabe 		irq = rman_get_start(sc->irq_res);
26897f24f66STakanori Watanabe 	else
26997f24f66STakanori Watanabe 		irq = IRQUNK;
27097f24f66STakanori Watanabe 
27197f24f66STakanori Watanabe 	/* In case PnP probe this may contain some initialization. */
27297f24f66STakanori Watanabe 	tpm_tis12_probe(sc->sc_bt, sc->sc_bh);
27397f24f66STakanori Watanabe 
27497f24f66STakanori Watanabe 	if (tpm_legacy_probe(sc->sc_bt, sc->sc_bh)) {
27597f24f66STakanori Watanabe 		sc->sc_init = tpm_legacy_init;
27697f24f66STakanori Watanabe 		sc->sc_start = tpm_legacy_start;
27797f24f66STakanori Watanabe 		sc->sc_read = tpm_legacy_read;
27897f24f66STakanori Watanabe 		sc->sc_write = tpm_legacy_write;
27997f24f66STakanori Watanabe 		sc->sc_end = tpm_legacy_end;
28097f24f66STakanori Watanabe 	} else {
28197f24f66STakanori Watanabe 		sc->sc_init = tpm_tis12_init;
28297f24f66STakanori Watanabe 		sc->sc_start = tpm_tis12_start;
28397f24f66STakanori Watanabe 		sc->sc_read = tpm_tis12_read;
28497f24f66STakanori Watanabe 		sc->sc_write = tpm_tis12_write;
28597f24f66STakanori Watanabe 		sc->sc_end = tpm_tis12_end;
28697f24f66STakanori Watanabe 	}
28797f24f66STakanori Watanabe 
28897f24f66STakanori Watanabe 	printf("%s", device_get_name(dev));
28997f24f66STakanori Watanabe 	if ((sc->sc_init)(sc, irq, "tpm")) {
29097f24f66STakanori Watanabe 		tpm_detach(dev);
29197f24f66STakanori Watanabe 		return ENXIO;
29297f24f66STakanori Watanabe 	}
29397f24f66STakanori Watanabe 
29497f24f66STakanori Watanabe 	if (sc->sc_init == tpm_tis12_init && sc->irq_res != NULL &&
29597f24f66STakanori Watanabe 	    bus_setup_intr(dev, sc->irq_res, INTR_TYPE_TTY, NULL,
29697f24f66STakanori Watanabe 	    tpm_intr, sc, &sc->intr_cookie) != 0) {
29797f24f66STakanori Watanabe 		tpm_detach(dev);
29897f24f66STakanori Watanabe 		printf(": cannot establish interrupt\n");
29997f24f66STakanori Watanabe 		return 1;
30097f24f66STakanori Watanabe 	}
30197f24f66STakanori Watanabe 
30297f24f66STakanori Watanabe 	sc->sc_cdev = make_dev(&tpm_cdevsw, device_get_unit(dev),
30397f24f66STakanori Watanabe 			    UID_ROOT, GID_WHEEL, 0600, "tpm");
30497f24f66STakanori Watanabe 	sc->sc_cdev->si_drv1 = sc;
30597f24f66STakanori Watanabe 
30697f24f66STakanori Watanabe 	return 0;
30797f24f66STakanori Watanabe }
30897f24f66STakanori Watanabe 
30997f24f66STakanori Watanabe int
31097f24f66STakanori Watanabe tpm_detach(device_t dev)
31197f24f66STakanori Watanabe {
31297f24f66STakanori Watanabe 	struct tpm_softc * sc = device_get_softc(dev);
31397f24f66STakanori Watanabe 
31497f24f66STakanori Watanabe 	if(sc->intr_cookie){
31597f24f66STakanori Watanabe 		bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
31697f24f66STakanori Watanabe 	}
31797f24f66STakanori Watanabe 
31897f24f66STakanori Watanabe 	if(sc->mem_res){
31997f24f66STakanori Watanabe 		bus_release_resource(dev, SYS_RES_MEMORY,
32097f24f66STakanori Watanabe 				     sc->mem_rid, sc->mem_res);
32197f24f66STakanori Watanabe 	}
32297f24f66STakanori Watanabe 
32397f24f66STakanori Watanabe 	if(sc->irq_res){
32497f24f66STakanori Watanabe 		bus_release_resource(dev, SYS_RES_IRQ,
32597f24f66STakanori Watanabe 				     sc->irq_rid, sc->irq_res);
32697f24f66STakanori Watanabe 	}
32797f24f66STakanori Watanabe 	if(sc->sc_cdev){
32897f24f66STakanori Watanabe 		destroy_dev(sc->sc_cdev);
32997f24f66STakanori Watanabe 	}
33097f24f66STakanori Watanabe 
33197f24f66STakanori Watanabe 	return 0;
33297f24f66STakanori Watanabe }
33397f24f66STakanori Watanabe 
33497f24f66STakanori Watanabe 
33597f24f66STakanori Watanabe #else
33697f24f66STakanori Watanabe /*
33797f24f66STakanori Watanabe  * OpenBSD specific code for probing and attaching TPM to device tree.
33897f24f66STakanori Watanabe  */
33997f24f66STakanori Watanabe int
34097f24f66STakanori Watanabe tpm_match(struct device *parent, void *match, void *aux)
34197f24f66STakanori Watanabe {
34297f24f66STakanori Watanabe 	struct isa_attach_args *ia = aux;
34397f24f66STakanori Watanabe 	struct cfdata *cf = match;
34497f24f66STakanori Watanabe 	bus_space_tag_t bt = ia->ia_memt;
34597f24f66STakanori Watanabe 	bus_space_handle_t bh;
34697f24f66STakanori Watanabe 	int rv;
34797f24f66STakanori Watanabe 
34897f24f66STakanori Watanabe 	/* There can be only one. */
34997f24f66STakanori Watanabe 	if (cf->cf_unit)
35097f24f66STakanori Watanabe 		return 0;
35197f24f66STakanori Watanabe 
35297f24f66STakanori Watanabe 	if (tpm_legacy_probe(ia->ia_iot, ia->ia_iobase)) {
35397f24f66STakanori Watanabe 		ia->ia_iosize = 2;
35497f24f66STakanori Watanabe 		return 1;
35597f24f66STakanori Watanabe 	}
35697f24f66STakanori Watanabe 
35797f24f66STakanori Watanabe 	if (ia->ia_maddr == -1)
35897f24f66STakanori Watanabe 		return 0;
35997f24f66STakanori Watanabe 
36097f24f66STakanori Watanabe 	if (bus_space_map(bt, ia->ia_maddr, TPM_SIZE, 0, &bh))
36197f24f66STakanori Watanabe 		return 0;
36297f24f66STakanori Watanabe 
36397f24f66STakanori Watanabe 	if ((rv = tpm_tis12_probe(bt, bh))) {
36497f24f66STakanori Watanabe 		ia->ia_iosize = 0;
36597f24f66STakanori Watanabe 		ia->ia_msize = TPM_SIZE;
36697f24f66STakanori Watanabe 	}
36797f24f66STakanori Watanabe 
36897f24f66STakanori Watanabe 	bus_space_unmap(bt, bh, TPM_SIZE);
36997f24f66STakanori Watanabe 	return rv;
37097f24f66STakanori Watanabe }
37197f24f66STakanori Watanabe 
37297f24f66STakanori Watanabe void
37397f24f66STakanori Watanabe tpm_attach(struct device *parent, struct device *self, void *aux)
37497f24f66STakanori Watanabe {
37597f24f66STakanori Watanabe 	struct tpm_softc *sc = (struct tpm_softc *)self;
37697f24f66STakanori Watanabe 	struct isa_attach_args *ia = aux;
37797f24f66STakanori Watanabe 	bus_addr_t iobase;
37897f24f66STakanori Watanabe 	bus_size_t size;
37997f24f66STakanori Watanabe 	int rv;
38097f24f66STakanori Watanabe 
38197f24f66STakanori Watanabe 	if (tpm_legacy_probe(ia->ia_iot, ia->ia_iobase)) {
38297f24f66STakanori Watanabe 		sc->sc_bt = ia->ia_iot;
38397f24f66STakanori Watanabe 		iobase = ia->ia_iobase;
38497f24f66STakanori Watanabe 		size = ia->ia_iosize;
38597f24f66STakanori Watanabe 		sc->sc_batm = ia->ia_iot;
38697f24f66STakanori Watanabe 		sc->sc_init = tpm_legacy_init;
38797f24f66STakanori Watanabe 		sc->sc_start = tpm_legacy_start;
38897f24f66STakanori Watanabe 		sc->sc_read = tpm_legacy_read;
38997f24f66STakanori Watanabe 		sc->sc_write = tpm_legacy_write;
39097f24f66STakanori Watanabe 		sc->sc_end = tpm_legacy_end;
39197f24f66STakanori Watanabe 	} else {
39297f24f66STakanori Watanabe 		sc->sc_bt = ia->ia_memt;
39397f24f66STakanori Watanabe 		iobase = ia->ia_maddr;
39497f24f66STakanori Watanabe 		size = TPM_SIZE;
39597f24f66STakanori Watanabe 		sc->sc_init = tpm_tis12_init;
39697f24f66STakanori Watanabe 		sc->sc_start = tpm_tis12_start;
39797f24f66STakanori Watanabe 		sc->sc_read = tpm_tis12_read;
39897f24f66STakanori Watanabe 		sc->sc_write = tpm_tis12_write;
39997f24f66STakanori Watanabe 		sc->sc_end = tpm_tis12_end;
40097f24f66STakanori Watanabe 	}
40197f24f66STakanori Watanabe 
40297f24f66STakanori Watanabe 	if (bus_space_map(sc->sc_bt, iobase, size, 0, &sc->sc_bh)) {
40397f24f66STakanori Watanabe 		printf(": cannot map registers\n");
40497f24f66STakanori Watanabe 		return;
40597f24f66STakanori Watanabe 	}
40697f24f66STakanori Watanabe 
40797f24f66STakanori Watanabe 	if ((rv = (sc->sc_init)(sc, ia->ia_irq, sc->sc_dev.dv_xname))) {
40897f24f66STakanori Watanabe 		bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
40997f24f66STakanori Watanabe 		return;
41097f24f66STakanori Watanabe 	}
41197f24f66STakanori Watanabe 
41297f24f66STakanori Watanabe 	/*
41397f24f66STakanori Watanabe 	 * Only setup interrupt handler when we have a vector and the
41497f24f66STakanori Watanabe 	 * chip is TIS 1.2 compliant.
41597f24f66STakanori Watanabe 	 */
41697f24f66STakanori Watanabe 	if (sc->sc_init == tpm_tis12_init && ia->ia_irq != IRQUNK &&
41797f24f66STakanori Watanabe 	    (sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
41897f24f66STakanori Watanabe 	    IPL_TTY, tpm_intr, sc, sc->sc_dev.dv_xname)) == NULL) {
41997f24f66STakanori Watanabe 		bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SIZE);
42097f24f66STakanori Watanabe 		printf("%s: cannot establish interrupt\n",
42197f24f66STakanori Watanabe 		    sc->sc_dev.dv_xname);
42297f24f66STakanori Watanabe 		return;
42397f24f66STakanori Watanabe 	}
42497f24f66STakanori Watanabe 
42597f24f66STakanori Watanabe #ifdef __FreeBSD__
42697f24f66STakanori Watanabe 	sc->sc_suspend = 0;
42797f24f66STakanori Watanabe #else
42897f24f66STakanori Watanabe 	sc->sc_suspend = PWR_RESUME;
42997f24f66STakanori Watanabe 	sc->sc_powerhook = powerhook_establish(tpm_powerhook, sc);
43097f24f66STakanori Watanabe #endif
43197f24f66STakanori Watanabe }
43297f24f66STakanori Watanabe #endif
43397f24f66STakanori Watanabe 
43497f24f66STakanori Watanabe /* Probe TPM using TIS 1.2 interface. */
43597f24f66STakanori Watanabe int
43697f24f66STakanori Watanabe tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
43797f24f66STakanori Watanabe {
43897f24f66STakanori Watanabe 	u_int32_t r;
43997f24f66STakanori Watanabe 	u_int8_t save, reg;
44097f24f66STakanori Watanabe 
44197f24f66STakanori Watanabe 	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
44297f24f66STakanori Watanabe 	if (r == 0xffffffff)
44397f24f66STakanori Watanabe 		return 0;
44497f24f66STakanori Watanabe 
44597f24f66STakanori Watanabe #ifdef TPM_DEBUG
44697f24f66STakanori Watanabe 	printf("tpm: caps=%b\n", r, TPM_CAPBITS);
44797f24f66STakanori Watanabe #endif
44897f24f66STakanori Watanabe 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
44997f24f66STakanori Watanabe 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
45097f24f66STakanori Watanabe #ifdef TPM_DEBUG
45197f24f66STakanori Watanabe 		printf("tpm: caps too low (caps=%b)\n", r, TPM_CAPBITS);
45297f24f66STakanori Watanabe #endif
45397f24f66STakanori Watanabe 		return 0;
45497f24f66STakanori Watanabe 	}
45597f24f66STakanori Watanabe 
45697f24f66STakanori Watanabe 	save = bus_space_read_1(bt, bh, TPM_ACCESS);
45797f24f66STakanori Watanabe 	bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
45897f24f66STakanori Watanabe 	reg = bus_space_read_1(bt, bh, TPM_ACCESS);
45997f24f66STakanori Watanabe 	if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) &&
46097f24f66STakanori Watanabe 	    bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff)
46197f24f66STakanori Watanabe 		return 1;
46297f24f66STakanori Watanabe 
46397f24f66STakanori Watanabe 	bus_space_write_1(bt, bh, TPM_ACCESS, save);
46497f24f66STakanori Watanabe 	return 0;
46597f24f66STakanori Watanabe }
46697f24f66STakanori Watanabe 
46797f24f66STakanori Watanabe /*
46897f24f66STakanori Watanabe  * Setup interrupt vector if one is provided and interrupts are know to
46997f24f66STakanori Watanabe  * work on that particular chip.
47097f24f66STakanori Watanabe  */
47197f24f66STakanori Watanabe int
47297f24f66STakanori Watanabe tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
47397f24f66STakanori Watanabe {
47497f24f66STakanori Watanabe 	u_int32_t r;
47597f24f66STakanori Watanabe 
47697f24f66STakanori Watanabe 	if ((irq == IRQUNK) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
47797f24f66STakanori Watanabe 		sc->sc_vector = IRQUNK;
47897f24f66STakanori Watanabe 		return 0;
47997f24f66STakanori Watanabe 	}
48097f24f66STakanori Watanabe 
48197f24f66STakanori Watanabe 	/* Ack and disable all interrupts. */
48297f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
48397f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
48497f24f66STakanori Watanabe 	    ~TPM_GLOBAL_INT_ENABLE);
48597f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
48697f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
48797f24f66STakanori Watanabe 
48897f24f66STakanori Watanabe 	/* Program interrupt vector. */
48997f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
49097f24f66STakanori Watanabe 	sc->sc_vector = irq;
49197f24f66STakanori Watanabe 
49297f24f66STakanori Watanabe 	/* Program interrupt type. */
49397f24f66STakanori Watanabe 	if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
49497f24f66STakanori Watanabe 		r = TPM_INT_EDGE_RISING;
49597f24f66STakanori Watanabe 	else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
49697f24f66STakanori Watanabe 		r = TPM_INT_LEVEL_HIGH;
49797f24f66STakanori Watanabe 	else
49897f24f66STakanori Watanabe 		r = TPM_INT_LEVEL_LOW;
49997f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r);
50097f24f66STakanori Watanabe 
50197f24f66STakanori Watanabe 	return 0;
50297f24f66STakanori Watanabe }
50397f24f66STakanori Watanabe 
50497f24f66STakanori Watanabe /* Setup TPM using TIS 1.2 interface. */
50597f24f66STakanori Watanabe int
50697f24f66STakanori Watanabe tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name)
50797f24f66STakanori Watanabe {
50897f24f66STakanori Watanabe 	u_int32_t r;
50997f24f66STakanori Watanabe 	int i;
51097f24f66STakanori Watanabe 
51197f24f66STakanori Watanabe 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
51297f24f66STakanori Watanabe #ifdef TPM_DEBUG
51397f24f66STakanori Watanabe 	printf(" caps=%b ", r, TPM_CAPBITS);
51497f24f66STakanori Watanabe #endif
51597f24f66STakanori Watanabe 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
51697f24f66STakanori Watanabe 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
51797f24f66STakanori Watanabe 		printf(": capabilities too low (caps=%b)\n", r, TPM_CAPBITS);
51897f24f66STakanori Watanabe 		return 1;
51997f24f66STakanori Watanabe 	}
52097f24f66STakanori Watanabe 	sc->sc_capabilities = r;
52197f24f66STakanori Watanabe 
52297f24f66STakanori Watanabe 	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
52397f24f66STakanori Watanabe 	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
52497f24f66STakanori Watanabe 
52597f24f66STakanori Watanabe 	for (i = 0; tpm_devs[i].devid; i++)
52697f24f66STakanori Watanabe 		if (tpm_devs[i].devid == sc->sc_devid)
52797f24f66STakanori Watanabe 			break;
52897f24f66STakanori Watanabe 
52997f24f66STakanori Watanabe 	if (tpm_devs[i].devid)
53097f24f66STakanori Watanabe 		printf(": %s rev 0x%x\n", tpm_devs[i].name, sc->sc_rev);
53197f24f66STakanori Watanabe 	else
53297f24f66STakanori Watanabe 		printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
53397f24f66STakanori Watanabe 
53497f24f66STakanori Watanabe 	if (tpm_tis12_irqinit(sc, irq, i))
53597f24f66STakanori Watanabe 		return 1;
53697f24f66STakanori Watanabe 
53797f24f66STakanori Watanabe 	if (tpm_request_locality(sc, 0))
53897f24f66STakanori Watanabe 		return 1;
53997f24f66STakanori Watanabe 
54097f24f66STakanori Watanabe 	/* Abort whatever it thought it was doing. */
54197f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
54297f24f66STakanori Watanabe 
54397f24f66STakanori Watanabe 	return 0;
54497f24f66STakanori Watanabe }
54597f24f66STakanori Watanabe 
54697f24f66STakanori Watanabe int
54797f24f66STakanori Watanabe tpm_request_locality(struct tpm_softc *sc, int l)
54897f24f66STakanori Watanabe {
54997f24f66STakanori Watanabe 	u_int32_t r;
55097f24f66STakanori Watanabe 	int to, rv;
55197f24f66STakanori Watanabe 
55297f24f66STakanori Watanabe 	if (l != 0)
55397f24f66STakanori Watanabe 		return EINVAL;
55497f24f66STakanori Watanabe 
55597f24f66STakanori Watanabe 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
55697f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
55797f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
55897f24f66STakanori Watanabe 		return 0;
55997f24f66STakanori Watanabe 
56097f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
56197f24f66STakanori Watanabe 	    TPM_ACCESS_REQUEST_USE);
56297f24f66STakanori Watanabe 
56397f24f66STakanori Watanabe 	to = tpm_tmotohz(TPM_ACCESS_TMO);
56497f24f66STakanori Watanabe 
56597f24f66STakanori Watanabe 	while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
56697f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
56797f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
56897f24f66STakanori Watanabe 		rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
56997f24f66STakanori Watanabe 		if (rv &&  rv != EWOULDBLOCK) {
57097f24f66STakanori Watanabe #ifdef TPM_DEBUG
57197f24f66STakanori Watanabe 			printf("tpm_request_locality: interrupted %d\n", rv);
57297f24f66STakanori Watanabe #endif
57397f24f66STakanori Watanabe 			return rv;
57497f24f66STakanori Watanabe 		}
57597f24f66STakanori Watanabe 	}
57697f24f66STakanori Watanabe 
57797f24f66STakanori Watanabe 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
57897f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
57997f24f66STakanori Watanabe #ifdef TPM_DEBUG
58097f24f66STakanori Watanabe 		printf("tpm_request_locality: access %b\n", r, TPM_ACCESS_BITS);
58197f24f66STakanori Watanabe #endif
58297f24f66STakanori Watanabe 		return EBUSY;
58397f24f66STakanori Watanabe 	}
58497f24f66STakanori Watanabe 
58597f24f66STakanori Watanabe 	return 0;
58697f24f66STakanori Watanabe }
58797f24f66STakanori Watanabe 
58897f24f66STakanori Watanabe int
58997f24f66STakanori Watanabe tpm_getburst(struct tpm_softc *sc)
59097f24f66STakanori Watanabe {
59197f24f66STakanori Watanabe 	int burst, to, rv;
59297f24f66STakanori Watanabe 
59397f24f66STakanori Watanabe 	to = tpm_tmotohz(TPM_BURST_TMO);
59497f24f66STakanori Watanabe 
59597f24f66STakanori Watanabe 	burst = 0;
59697f24f66STakanori Watanabe 	while (burst == 0 && to--) {
59797f24f66STakanori Watanabe 		/*
59897f24f66STakanori Watanabe 		 * Burst count has to be read from bits 8 to 23 without
59997f24f66STakanori Watanabe 		 * touching any other bits, eg. the actual status bits 0
60097f24f66STakanori Watanabe 		 * to 7.
60197f24f66STakanori Watanabe 		 */
60297f24f66STakanori Watanabe 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
60397f24f66STakanori Watanabe 		burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
60497f24f66STakanori Watanabe 		    << 8;
60597f24f66STakanori Watanabe #ifdef TPM_DEBUG
60697f24f66STakanori Watanabe 		printf("tpm_getburst: read %d\n", burst);
60797f24f66STakanori Watanabe #endif
60897f24f66STakanori Watanabe 		if (burst)
60997f24f66STakanori Watanabe 			return burst;
61097f24f66STakanori Watanabe 
61197f24f66STakanori Watanabe 		rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1);
61297f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK) {
61397f24f66STakanori Watanabe 			return 0;
61497f24f66STakanori Watanabe 		}
61597f24f66STakanori Watanabe 	}
61697f24f66STakanori Watanabe 
61797f24f66STakanori Watanabe 	return 0;
61897f24f66STakanori Watanabe }
61997f24f66STakanori Watanabe 
62097f24f66STakanori Watanabe u_int8_t
62197f24f66STakanori Watanabe tpm_status(struct tpm_softc *sc)
62297f24f66STakanori Watanabe {
62397f24f66STakanori Watanabe 	u_int8_t status;
62497f24f66STakanori Watanabe 
62597f24f66STakanori Watanabe 	status = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) &
62697f24f66STakanori Watanabe 	    TPM_STS_MASK;
62797f24f66STakanori Watanabe 
62897f24f66STakanori Watanabe 	return status;
62997f24f66STakanori Watanabe }
63097f24f66STakanori Watanabe 
63197f24f66STakanori Watanabe int
63297f24f66STakanori Watanabe tpm_tmotohz(int tmo)
63397f24f66STakanori Watanabe {
63497f24f66STakanori Watanabe 	struct timeval tv;
63597f24f66STakanori Watanabe 
63697f24f66STakanori Watanabe 	tv.tv_sec = tmo / 1000;
63797f24f66STakanori Watanabe 	tv.tv_usec = 1000 * (tmo % 1000);
63897f24f66STakanori Watanabe 
63997f24f66STakanori Watanabe 	return tvtohz(&tv);
64097f24f66STakanori Watanabe }
64197f24f66STakanori Watanabe 
64297f24f66STakanori Watanabe /* Save TPM state on suspend. */
64397f24f66STakanori Watanabe int
64497f24f66STakanori Watanabe #ifdef __FreeBSD__
64597f24f66STakanori Watanabe tpm_suspend(device_t dev)
64697f24f66STakanori Watanabe #else
64797f24f66STakanori Watanabe tpm_suspend(struct tpm_softc *sc, int why)
64897f24f66STakanori Watanabe #endif
64997f24f66STakanori Watanabe {
65097f24f66STakanori Watanabe #ifdef __FreeBSD__
65197f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
65297f24f66STakanori Watanabe 	int why = 1;
65397f24f66STakanori Watanabe #endif
65497f24f66STakanori Watanabe 	u_int8_t command[] = {
65597f24f66STakanori Watanabe 	    0, 193,		/* TPM_TAG_RQU_COMMAND */
65697f24f66STakanori Watanabe 	    0, 0, 0, 10,	/* Length in bytes */
65797f24f66STakanori Watanabe 	    0, 0, 0, 156	/* TPM_ORD_SaveStates */
65897f24f66STakanori Watanabe 	};
65997f24f66STakanori Watanabe 
66097f24f66STakanori Watanabe 	/*
66197f24f66STakanori Watanabe 	 * Power down:  We have to issue the SaveStates command.
66297f24f66STakanori Watanabe 	 */
66397f24f66STakanori Watanabe 	sc->sc_write(sc, &command, sizeof(command));
66497f24f66STakanori Watanabe 	sc->sc_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
66597f24f66STakanori Watanabe #ifdef TPM_DEBUG
66697f24f66STakanori Watanabe 	printf("tpm_suspend: power down: %d -> %d\n", sc->sc_suspend, why);
66797f24f66STakanori Watanabe #endif
66897f24f66STakanori Watanabe 	sc->sc_suspend = why;
66997f24f66STakanori Watanabe 
67097f24f66STakanori Watanabe 	return 0;
67197f24f66STakanori Watanabe }
67297f24f66STakanori Watanabe 
67397f24f66STakanori Watanabe /*
67497f24f66STakanori Watanabe  * Handle resume event.  Actually nothing to do as the BIOS is supposed
67597f24f66STakanori Watanabe  * to restore the previously saved state.
67697f24f66STakanori Watanabe  */
67797f24f66STakanori Watanabe int
67897f24f66STakanori Watanabe #ifdef __FreeBSD__
67997f24f66STakanori Watanabe tpm_resume(device_t dev)
68097f24f66STakanori Watanabe #else
68197f24f66STakanori Watanabe tpm_resume(struct tpm_softc *sc, int why)
68297f24f66STakanori Watanabe #endif
68397f24f66STakanori Watanabe {
68497f24f66STakanori Watanabe #ifdef __FreeBSD__
68597f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
68697f24f66STakanori Watanabe 	int why = 0;
68797f24f66STakanori Watanabe #endif
68897f24f66STakanori Watanabe #ifdef TPM_DEBUG
68997f24f66STakanori Watanabe 	printf("tpm_resume: resume: %d -> %d\n", sc->sc_suspend, why);
69097f24f66STakanori Watanabe #endif
69197f24f66STakanori Watanabe 	sc->sc_suspend = why;
69297f24f66STakanori Watanabe 
69397f24f66STakanori Watanabe 	return 0;
69497f24f66STakanori Watanabe }
69597f24f66STakanori Watanabe 
69697f24f66STakanori Watanabe /* Dispatch suspend and resume events. */
69797f24f66STakanori Watanabe #ifndef __FreeBSD__
69897f24f66STakanori Watanabe void
69997f24f66STakanori Watanabe tpm_powerhook(int why, void *self)
70097f24f66STakanori Watanabe {
70197f24f66STakanori Watanabe 	struct tpm_softc *sc = (struct tpm_softc *)self;
70297f24f66STakanori Watanabe 
70397f24f66STakanori Watanabe 	if (why != PWR_RESUME)
70497f24f66STakanori Watanabe 		tpm_suspend(sc, why);
70597f24f66STakanori Watanabe 	else
70697f24f66STakanori Watanabe 		tpm_resume(sc, why);
70797f24f66STakanori Watanabe }
70897f24f66STakanori Watanabe #endif	/* !__FreeBSD__ */
70997f24f66STakanori Watanabe 
71097f24f66STakanori Watanabe /* Wait for given status bits using polling. */
71197f24f66STakanori Watanabe int
71297f24f66STakanori Watanabe tpm_waitfor_poll(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c)
71397f24f66STakanori Watanabe {
71497f24f66STakanori Watanabe 	int rv;
71597f24f66STakanori Watanabe 
71697f24f66STakanori Watanabe 	/*
71797f24f66STakanori Watanabe 	 * Poll until either the requested condition or a time out is
71897f24f66STakanori Watanabe 	 * met.
71997f24f66STakanori Watanabe 	 */
72097f24f66STakanori Watanabe 	while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) {
72197f24f66STakanori Watanabe 		rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1);
72297f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK) {
72397f24f66STakanori Watanabe #ifdef TPM_DEBUG
72497f24f66STakanori Watanabe 			printf("tpm_waitfor_poll: interrupted %d\n", rv);
72597f24f66STakanori Watanabe #endif
72697f24f66STakanori Watanabe 			return rv;
72797f24f66STakanori Watanabe 		}
72897f24f66STakanori Watanabe 	}
72997f24f66STakanori Watanabe 
73097f24f66STakanori Watanabe 	return 0;
73197f24f66STakanori Watanabe }
73297f24f66STakanori Watanabe 
73397f24f66STakanori Watanabe /* Wait for given status bits using interrupts. */
73497f24f66STakanori Watanabe int
73597f24f66STakanori Watanabe tpm_waitfor_int(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c,
73697f24f66STakanori Watanabe     int inttype)
73797f24f66STakanori Watanabe {
73897f24f66STakanori Watanabe 	int rv, to;
73997f24f66STakanori Watanabe 
74097f24f66STakanori Watanabe 	/* Poll and return when condition is already met. */
74197f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
74297f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask)
74397f24f66STakanori Watanabe 		return 0;
74497f24f66STakanori Watanabe 
74597f24f66STakanori Watanabe 	/*
74697f24f66STakanori Watanabe 	 * Enable interrupt on tpm chip.  Note that interrupts on our
74797f24f66STakanori Watanabe 	 * level (SPL_TTY) are disabled (see tpm{read,write} et al) and
74897f24f66STakanori Watanabe 	 * will not be delivered to the cpu until we call tsleep(9) below.
74997f24f66STakanori Watanabe 	 */
75097f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
75197f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
75297f24f66STakanori Watanabe 	    inttype);
75397f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
75497f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
75597f24f66STakanori Watanabe 	    TPM_GLOBAL_INT_ENABLE);
75697f24f66STakanori Watanabe 
75797f24f66STakanori Watanabe 	/*
75897f24f66STakanori Watanabe 	 * Poll once more to remedy the race between previous polling
75997f24f66STakanori Watanabe 	 * and enabling interrupts on the tpm chip.
76097f24f66STakanori Watanabe 	 */
76197f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
76297f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask) {
76397f24f66STakanori Watanabe 		rv = 0;
76497f24f66STakanori Watanabe 		goto out;
76597f24f66STakanori Watanabe 	}
76697f24f66STakanori Watanabe 
76797f24f66STakanori Watanabe 	to = tpm_tmotohz(tmo);
76897f24f66STakanori Watanabe #ifdef TPM_DEBUG
76997f24f66STakanori Watanabe 	printf("tpm_waitfor_int: sleeping for %d ticks on %p\n", to, c);
77097f24f66STakanori Watanabe #endif
77197f24f66STakanori Watanabe 	/*
77297f24f66STakanori Watanabe 	 * tsleep(9) enables interrupts on the cpu and returns after
77397f24f66STakanori Watanabe 	 * wake up with interrupts disabled again.  Note that interrupts
77497f24f66STakanori Watanabe 	 * generated by the tpm chip while being at SPL_TTY are not lost
77597f24f66STakanori Watanabe 	 * but held and delivered as soon as the cpu goes below SPL_TTY.
77697f24f66STakanori Watanabe 	 */
77797f24f66STakanori Watanabe 	rv = tsleep(c, PRIBIO | PCATCH, "tpm_intr", to);
77897f24f66STakanori Watanabe 
77997f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
78097f24f66STakanori Watanabe #ifdef TPM_DEBUG
78197f24f66STakanori Watanabe 	printf("tpm_waitfor_int: woke up with rv %d stat %b\n", rv,
78297f24f66STakanori Watanabe 	    sc->sc_stat, TPM_STS_BITS);
78397f24f66STakanori Watanabe #endif
78497f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask)
78597f24f66STakanori Watanabe 		rv = 0;
78697f24f66STakanori Watanabe 
78797f24f66STakanori Watanabe 	/* Disable interrupts on tpm chip again. */
78897f24f66STakanori Watanabe out:	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
78997f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
79097f24f66STakanori Watanabe 	    ~TPM_GLOBAL_INT_ENABLE);
79197f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
79297f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
79397f24f66STakanori Watanabe 	    ~inttype);
79497f24f66STakanori Watanabe 
79597f24f66STakanori Watanabe 	return rv;
79697f24f66STakanori Watanabe }
79797f24f66STakanori Watanabe 
79897f24f66STakanori Watanabe /*
79997f24f66STakanori Watanabe  * Wait on given status bits, uses interrupts where possible, otherwise polls.
80097f24f66STakanori Watanabe  */
80197f24f66STakanori Watanabe int
80297f24f66STakanori Watanabe tpm_waitfor(struct tpm_softc *sc, u_int8_t b0, int tmo, void *c)
80397f24f66STakanori Watanabe {
80497f24f66STakanori Watanabe 	u_int8_t b;
80597f24f66STakanori Watanabe 	int re, to, rv;
80697f24f66STakanori Watanabe 
80797f24f66STakanori Watanabe #ifdef TPM_DEBUG
80897f24f66STakanori Watanabe 	printf("tpm_waitfor: b0 %b\n", b0, TPM_STS_BITS);
80997f24f66STakanori Watanabe #endif
81097f24f66STakanori Watanabe 
81197f24f66STakanori Watanabe 	/*
81297f24f66STakanori Watanabe 	 * If possible, use interrupts, otherwise poll.
81397f24f66STakanori Watanabe 	 *
81497f24f66STakanori Watanabe 	 * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
81597f24f66STakanori Watanabe 	 * the tpm chips supports them) as waiting for those can take
81697f24f66STakanori Watanabe 	 * really long.  The other TPM_STS* are not needed very often
81797f24f66STakanori Watanabe 	 * so we do not support them.
81897f24f66STakanori Watanabe 	 */
81997f24f66STakanori Watanabe 	if (sc->sc_vector != IRQUNK) {
82097f24f66STakanori Watanabe 		b = b0;
82197f24f66STakanori Watanabe 
82297f24f66STakanori Watanabe 		/*
823*453130d9SPedro F. Giffuni 		 * Wait for data ready.  This interrupt only occurs
82497f24f66STakanori Watanabe 		 * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
82597f24f66STakanori Watanabe 		 * Thus we don't have to bother with TPM_STS_VALID
82697f24f66STakanori Watanabe 		 * separately and can just return.
82797f24f66STakanori Watanabe 		 *
82897f24f66STakanori Watanabe 		 * This only holds for interrupts!  When using polling
82997f24f66STakanori Watanabe 		 * both flags have to be waited for, see below.
83097f24f66STakanori Watanabe 		 */
83197f24f66STakanori Watanabe 		if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
83297f24f66STakanori Watanabe 		    TPM_INTF_DATA_AVAIL_INT))
83397f24f66STakanori Watanabe 			return tpm_waitfor_int(sc, b, tmo, c,
83497f24f66STakanori Watanabe 			    TPM_DATA_AVAIL_INT);
83597f24f66STakanori Watanabe 
83697f24f66STakanori Watanabe 		/* Wait for status valid bit. */
83797f24f66STakanori Watanabe 		if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
83897f24f66STakanori Watanabe 		    TPM_INTF_STS_VALID_INT)) {
83997f24f66STakanori Watanabe 			rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
84097f24f66STakanori Watanabe 			if (rv != 0)
84197f24f66STakanori Watanabe 				return rv;
84297f24f66STakanori Watanabe 			else
84397f24f66STakanori Watanabe 				b = b0 & ~TPM_STS_VALID;
84497f24f66STakanori Watanabe 		}
84597f24f66STakanori Watanabe 
84697f24f66STakanori Watanabe 		/*
84797f24f66STakanori Watanabe 		 * When all flags are taken care of, return.  Otherwise
84897f24f66STakanori Watanabe 		 * use polling for eg. TPM_STS_CMD_READY.
84997f24f66STakanori Watanabe 		 */
85097f24f66STakanori Watanabe 		if (b == 0)
85197f24f66STakanori Watanabe 			return 0;
85297f24f66STakanori Watanabe 	}
85397f24f66STakanori Watanabe 
85497f24f66STakanori Watanabe 	re = 3;
85597f24f66STakanori Watanabe restart:
85697f24f66STakanori Watanabe 	/*
85797f24f66STakanori Watanabe 	 * If requested wait for TPM_STS_VALID before dealing with
85897f24f66STakanori Watanabe 	 * any other flag.  Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
85997f24f66STakanori Watanabe 	 * are requested, wait for the latter first.
86097f24f66STakanori Watanabe 	 */
86197f24f66STakanori Watanabe 	b = b0;
86297f24f66STakanori Watanabe 	if (b0 & TPM_STS_VALID)
86397f24f66STakanori Watanabe 		b = TPM_STS_VALID;
86497f24f66STakanori Watanabe 
86597f24f66STakanori Watanabe 	to = tpm_tmotohz(tmo);
86697f24f66STakanori Watanabe again:
86797f24f66STakanori Watanabe 	if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
86897f24f66STakanori Watanabe 		return rv;
86997f24f66STakanori Watanabe 
87097f24f66STakanori Watanabe 	if ((b & sc->sc_stat) == TPM_STS_VALID) {
87197f24f66STakanori Watanabe 		/* Now wait for other flags. */
87297f24f66STakanori Watanabe 		b = b0 & ~TPM_STS_VALID;
87397f24f66STakanori Watanabe 		to++;
87497f24f66STakanori Watanabe 		goto again;
87597f24f66STakanori Watanabe 	}
87697f24f66STakanori Watanabe 
87797f24f66STakanori Watanabe 	if ((sc->sc_stat & b) != b) {
87897f24f66STakanori Watanabe #ifdef TPM_DEBUG
87997f24f66STakanori Watanabe 		printf("tpm_waitfor: timeout: stat=%b b=%b\n",
88097f24f66STakanori Watanabe 		    sc->sc_stat, TPM_STS_BITS, b, TPM_STS_BITS);
88197f24f66STakanori Watanabe #endif
88297f24f66STakanori Watanabe 		if (re-- && (b0 & TPM_STS_VALID)) {
88397f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
88497f24f66STakanori Watanabe 			    TPM_STS_RESP_RETRY);
88597f24f66STakanori Watanabe 			goto restart;
88697f24f66STakanori Watanabe 		}
88797f24f66STakanori Watanabe 		return EIO;
88897f24f66STakanori Watanabe 	}
88997f24f66STakanori Watanabe 
89097f24f66STakanori Watanabe 	return 0;
89197f24f66STakanori Watanabe }
89297f24f66STakanori Watanabe 
89397f24f66STakanori Watanabe /* Start transaction. */
89497f24f66STakanori Watanabe int
89597f24f66STakanori Watanabe tpm_tis12_start(struct tpm_softc *sc, int flag)
89697f24f66STakanori Watanabe {
89797f24f66STakanori Watanabe 	int rv;
89897f24f66STakanori Watanabe 
89997f24f66STakanori Watanabe 	if (flag == UIO_READ) {
90097f24f66STakanori Watanabe 		rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
90197f24f66STakanori Watanabe 		    TPM_READ_TMO, sc->sc_read);
90297f24f66STakanori Watanabe 		return rv;
90397f24f66STakanori Watanabe 	}
90497f24f66STakanori Watanabe 
90597f24f66STakanori Watanabe 	/* Own our (0th) locality. */
90697f24f66STakanori Watanabe 	if ((rv = tpm_request_locality(sc, 0)) != 0)
90797f24f66STakanori Watanabe 		return rv;
90897f24f66STakanori Watanabe 
90997f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
91097f24f66STakanori Watanabe 	if (sc->sc_stat & TPM_STS_CMD_READY) {
91197f24f66STakanori Watanabe #ifdef TPM_DEBUG
91297f24f66STakanori Watanabe 		printf("tpm_tis12_start: UIO_WRITE status %b\n", sc->sc_stat,
91397f24f66STakanori Watanabe 		   TPM_STS_BITS);
91497f24f66STakanori Watanabe #endif
91597f24f66STakanori Watanabe 		return 0;
91697f24f66STakanori Watanabe 	}
91797f24f66STakanori Watanabe 
91897f24f66STakanori Watanabe #ifdef TPM_DEBUG
91997f24f66STakanori Watanabe 	printf("tpm_tis12_start: UIO_WRITE readying chip\n");
92097f24f66STakanori Watanabe #endif
92197f24f66STakanori Watanabe 
92297f24f66STakanori Watanabe 	/* Abort previous and restart. */
92397f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
92497f24f66STakanori Watanabe 	if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO,
92597f24f66STakanori Watanabe 	    sc->sc_write))) {
92697f24f66STakanori Watanabe #ifdef TPM_DEBUG
92797f24f66STakanori Watanabe 		printf("tpm_tis12_start: UIO_WRITE readying failed %d\n", rv);
92897f24f66STakanori Watanabe #endif
92997f24f66STakanori Watanabe 		return rv;
93097f24f66STakanori Watanabe 	}
93197f24f66STakanori Watanabe 
93297f24f66STakanori Watanabe #ifdef TPM_DEBUG
93397f24f66STakanori Watanabe 	printf("tpm_tis12_start: UIO_WRITE readying done\n");
93497f24f66STakanori Watanabe #endif
93597f24f66STakanori Watanabe 
93697f24f66STakanori Watanabe 	return 0;
93797f24f66STakanori Watanabe }
93897f24f66STakanori Watanabe 
93997f24f66STakanori Watanabe int
94097f24f66STakanori Watanabe tpm_tis12_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
94197f24f66STakanori Watanabe     int flags)
94297f24f66STakanori Watanabe {
94397f24f66STakanori Watanabe 	u_int8_t *p = buf;
94497f24f66STakanori Watanabe 	size_t cnt;
94597f24f66STakanori Watanabe 	int rv, n, bcnt;
94697f24f66STakanori Watanabe 
94797f24f66STakanori Watanabe #ifdef TPM_DEBUG
94897f24f66STakanori Watanabe 	printf("tpm_tis12_read: len %d\n", len);
94997f24f66STakanori Watanabe #endif
95097f24f66STakanori Watanabe 	cnt = 0;
95197f24f66STakanori Watanabe 	while (len > 0) {
95297f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
95397f24f66STakanori Watanabe 		    TPM_READ_TMO, sc->sc_read)))
95497f24f66STakanori Watanabe 			return rv;
95597f24f66STakanori Watanabe 
95697f24f66STakanori Watanabe 		bcnt = tpm_getburst(sc);
95797f24f66STakanori Watanabe 		n = MIN(len, bcnt);
95897f24f66STakanori Watanabe #ifdef TPM_DEBUG
95997f24f66STakanori Watanabe 		printf("tpm_tis12_read: fetching %d, burst is %d\n", n, bcnt);
96097f24f66STakanori Watanabe #endif
96197f24f66STakanori Watanabe 		for (; n--; len--) {
96297f24f66STakanori Watanabe 			*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
96397f24f66STakanori Watanabe 			cnt++;
96497f24f66STakanori Watanabe 		}
96597f24f66STakanori Watanabe 
96697f24f66STakanori Watanabe 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
96797f24f66STakanori Watanabe 			break;
96897f24f66STakanori Watanabe 	}
96997f24f66STakanori Watanabe #ifdef TPM_DEBUG
97097f24f66STakanori Watanabe 	printf("tpm_tis12_read: read %zd bytes, len %d\n", cnt, len);
97197f24f66STakanori Watanabe #endif
97297f24f66STakanori Watanabe 
97397f24f66STakanori Watanabe 	if (count)
97497f24f66STakanori Watanabe 		*count = cnt;
97597f24f66STakanori Watanabe 
97697f24f66STakanori Watanabe 	return 0;
97797f24f66STakanori Watanabe }
97897f24f66STakanori Watanabe 
97997f24f66STakanori Watanabe int
98097f24f66STakanori Watanabe tpm_tis12_write(struct tpm_softc *sc, void *buf, int len)
98197f24f66STakanori Watanabe {
98297f24f66STakanori Watanabe 	u_int8_t *p = buf;
98397f24f66STakanori Watanabe 	size_t cnt;
98497f24f66STakanori Watanabe 	int rv, r;
98597f24f66STakanori Watanabe 
98697f24f66STakanori Watanabe #ifdef TPM_DEBUG
98797f24f66STakanori Watanabe 	printf("tpm_tis12_write: sc %p buf %p len %d\n", sc, buf, len);
98897f24f66STakanori Watanabe #endif
98997f24f66STakanori Watanabe 
99097f24f66STakanori Watanabe 	if ((rv = tpm_request_locality(sc, 0)) != 0)
99197f24f66STakanori Watanabe 		return rv;
99297f24f66STakanori Watanabe 
99397f24f66STakanori Watanabe 	cnt = 0;
99497f24f66STakanori Watanabe 	while (cnt < len - 1) {
99597f24f66STakanori Watanabe 		for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) {
99697f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
99797f24f66STakanori Watanabe 			cnt++;
99897f24f66STakanori Watanabe 		}
99997f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
100097f24f66STakanori Watanabe #ifdef TPM_DEBUG
100197f24f66STakanori Watanabe 			printf("tpm_tis12_write: failed burst rv %d\n", rv);
100297f24f66STakanori Watanabe #endif
100397f24f66STakanori Watanabe 			return rv;
100497f24f66STakanori Watanabe 		}
100597f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
100697f24f66STakanori Watanabe 		if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) {
100797f24f66STakanori Watanabe #ifdef TPM_DEBUG
100897f24f66STakanori Watanabe 			printf("tpm_tis12_write: failed rv %d stat=%b\n", rv,
100997f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
101097f24f66STakanori Watanabe #endif
101197f24f66STakanori Watanabe 			return EIO;
101297f24f66STakanori Watanabe 		}
101397f24f66STakanori Watanabe 	}
101497f24f66STakanori Watanabe 
101597f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
101697f24f66STakanori Watanabe 	cnt++;
101797f24f66STakanori Watanabe 
101897f24f66STakanori Watanabe 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
101997f24f66STakanori Watanabe #ifdef TPM_DEBUG
102097f24f66STakanori Watanabe 		printf("tpm_tis12_write: failed last byte rv %d\n", rv);
102197f24f66STakanori Watanabe #endif
102297f24f66STakanori Watanabe 		return rv;
102397f24f66STakanori Watanabe 	}
102497f24f66STakanori Watanabe 	if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) {
102597f24f66STakanori Watanabe #ifdef TPM_DEBUG
102697f24f66STakanori Watanabe 		printf("tpm_tis12_write: failed rv %d stat=%b\n", rv,
102797f24f66STakanori Watanabe 		    sc->sc_stat, TPM_STS_BITS);
102897f24f66STakanori Watanabe #endif
102997f24f66STakanori Watanabe 		return EIO;
103097f24f66STakanori Watanabe 	}
103197f24f66STakanori Watanabe 
103297f24f66STakanori Watanabe #ifdef TPM_DEBUG
103397f24f66STakanori Watanabe 	printf("tpm_tis12_write: wrote %d byte\n", cnt);
103497f24f66STakanori Watanabe #endif
103597f24f66STakanori Watanabe 
103697f24f66STakanori Watanabe 	return 0;
103797f24f66STakanori Watanabe }
103897f24f66STakanori Watanabe 
103997f24f66STakanori Watanabe /* Finish transaction. */
104097f24f66STakanori Watanabe int
104197f24f66STakanori Watanabe tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
104297f24f66STakanori Watanabe {
104397f24f66STakanori Watanabe 	int rv = 0;
104497f24f66STakanori Watanabe 
104597f24f66STakanori Watanabe 	if (flag == UIO_READ) {
104697f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO,
104797f24f66STakanori Watanabe 		    sc->sc_read)))
104897f24f66STakanori Watanabe 			return rv;
104997f24f66STakanori Watanabe 
105097f24f66STakanori Watanabe 		/* Still more data? */
105197f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
105297f24f66STakanori Watanabe 		if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL) == TPM_STS_DATA_AVAIL)) {
105397f24f66STakanori Watanabe #ifdef TPM_DEBUG
105497f24f66STakanori Watanabe 			printf("tpm_tis12_end: read failed stat=%b\n",
105597f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
105697f24f66STakanori Watanabe #endif
105797f24f66STakanori Watanabe 			rv = EIO;
105897f24f66STakanori Watanabe 		}
105997f24f66STakanori Watanabe 
106097f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
106197f24f66STakanori Watanabe 		    TPM_STS_CMD_READY);
106297f24f66STakanori Watanabe 
106397f24f66STakanori Watanabe 		/* Release our (0th) locality. */
106497f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS,
106597f24f66STakanori Watanabe 		    TPM_ACCESS_ACTIVE_LOCALITY);
106697f24f66STakanori Watanabe 	} else {
106797f24f66STakanori Watanabe 		/* Hungry for more? */
106897f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
106997f24f66STakanori Watanabe 		if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) {
107097f24f66STakanori Watanabe #ifdef TPM_DEBUG
107197f24f66STakanori Watanabe 			printf("tpm_tis12_end: write failed stat=%b\n",
107297f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
107397f24f66STakanori Watanabe #endif
107497f24f66STakanori Watanabe 			rv = EIO;
107597f24f66STakanori Watanabe 		}
107697f24f66STakanori Watanabe 
107797f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
107897f24f66STakanori Watanabe 		    err ? TPM_STS_CMD_READY : TPM_STS_GO);
107997f24f66STakanori Watanabe 	}
108097f24f66STakanori Watanabe 
108197f24f66STakanori Watanabe 	return rv;
108297f24f66STakanori Watanabe }
108397f24f66STakanori Watanabe 
108497f24f66STakanori Watanabe #ifdef __FreeBSD__
108597f24f66STakanori Watanabe void
108697f24f66STakanori Watanabe #else
108797f24f66STakanori Watanabe int
108897f24f66STakanori Watanabe #endif
108997f24f66STakanori Watanabe tpm_intr(void *v)
109097f24f66STakanori Watanabe {
109197f24f66STakanori Watanabe 	struct tpm_softc *sc = v;
109297f24f66STakanori Watanabe 	u_int32_t r;
109397f24f66STakanori Watanabe #ifdef TPM_DEBUG
109497f24f66STakanori Watanabe 	static int cnt = 0;
109597f24f66STakanori Watanabe #endif
109697f24f66STakanori Watanabe 
109797f24f66STakanori Watanabe 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
109897f24f66STakanori Watanabe #ifdef TPM_DEBUG
109997f24f66STakanori Watanabe 	if (r != 0)
110097f24f66STakanori Watanabe 		printf("tpm_intr: int=%b (%d)\n", r, TPM_INTERRUPT_ENABLE_BITS,
110197f24f66STakanori Watanabe 		    cnt);
110297f24f66STakanori Watanabe 	else
110397f24f66STakanori Watanabe 		cnt++;
110497f24f66STakanori Watanabe #endif
110597f24f66STakanori Watanabe 	if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
110697f24f66STakanori Watanabe 	    TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
110797f24f66STakanori Watanabe #ifdef __FreeBSD__
110897f24f66STakanori Watanabe 		return;
110997f24f66STakanori Watanabe #else
111097f24f66STakanori Watanabe 		return 0;
111197f24f66STakanori Watanabe #endif
111297f24f66STakanori Watanabe 	if (r & TPM_STS_VALID_INT)
111397f24f66STakanori Watanabe 		wakeup(sc);
111497f24f66STakanori Watanabe 
111597f24f66STakanori Watanabe 	if (r & TPM_CMD_READY_INT)
111697f24f66STakanori Watanabe 		wakeup(sc->sc_write);
111797f24f66STakanori Watanabe 
111897f24f66STakanori Watanabe 	if (r & TPM_DATA_AVAIL_INT)
111997f24f66STakanori Watanabe 		wakeup(sc->sc_read);
112097f24f66STakanori Watanabe 
112197f24f66STakanori Watanabe 	if (r & TPM_LOCALITY_CHANGE_INT)
112297f24f66STakanori Watanabe 		wakeup(sc->sc_init);
112397f24f66STakanori Watanabe 
112497f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r);
112597f24f66STakanori Watanabe 
112697f24f66STakanori Watanabe #ifdef __FreeBSD__
112797f24f66STakanori Watanabe 	return;
112897f24f66STakanori Watanabe #else
112997f24f66STakanori Watanabe 	return 1;
113097f24f66STakanori Watanabe #endif
113197f24f66STakanori Watanabe }
113297f24f66STakanori Watanabe 
113397f24f66STakanori Watanabe /* Read single byte using legacy interface. */
113497f24f66STakanori Watanabe static inline u_int8_t
113597f24f66STakanori Watanabe tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
113697f24f66STakanori Watanabe {
113797f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 0, reg);
113897f24f66STakanori Watanabe 	return bus_space_read_1(iot, ioh, 1);
113997f24f66STakanori Watanabe }
114097f24f66STakanori Watanabe 
114129deb225SDimitry Andric #if 0
114297f24f66STakanori Watanabe /* Write single byte using legacy interface. */
114397f24f66STakanori Watanabe static inline void
114497f24f66STakanori Watanabe tpm_legacy_out(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, u_int8_t v)
114597f24f66STakanori Watanabe {
114697f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 0, reg);
114797f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 1, v);
114897f24f66STakanori Watanabe }
114929deb225SDimitry Andric #endif
115097f24f66STakanori Watanabe 
115197f24f66STakanori Watanabe /* Probe for TPM using legacy interface. */
115297f24f66STakanori Watanabe int
115397f24f66STakanori Watanabe tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase)
115497f24f66STakanori Watanabe {
115597f24f66STakanori Watanabe 	bus_space_handle_t ioh;
115697f24f66STakanori Watanabe 	u_int8_t r, v;
115797f24f66STakanori Watanabe 	int i, rv = 0;
115897f24f66STakanori Watanabe 	char id[8];
115997f24f66STakanori Watanabe 
116097f24f66STakanori Watanabe 	if (!tpm_enabled || iobase == -1)
116197f24f66STakanori Watanabe 		return 0;
116297f24f66STakanori Watanabe 
116397f24f66STakanori Watanabe 	if (bus_space_map(iot, iobase, 2, 0, &ioh))
116497f24f66STakanori Watanabe 		return 0;
116597f24f66STakanori Watanabe 
116697f24f66STakanori Watanabe 	v = bus_space_read_1(iot, ioh, 0);
116797f24f66STakanori Watanabe 	if (v == 0xff) {
116897f24f66STakanori Watanabe 		bus_space_unmap(iot, ioh, 2);
116997f24f66STakanori Watanabe 		return 0;
117097f24f66STakanori Watanabe 	}
117197f24f66STakanori Watanabe 	r = bus_space_read_1(iot, ioh, 1);
117297f24f66STakanori Watanabe 
117397f24f66STakanori Watanabe 	for (i = sizeof(id); i--; )
117497f24f66STakanori Watanabe 		id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i);
117597f24f66STakanori Watanabe 
117697f24f66STakanori Watanabe #ifdef TPM_DEBUG
117797f24f66STakanori Watanabe 	printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n",
117897f24f66STakanori Watanabe 	    &id[4], id[0], id[1], id[2], id[3]);
117997f24f66STakanori Watanabe #endif
118097f24f66STakanori Watanabe 	/*
118197f24f66STakanori Watanabe 	 * The only chips using the legacy interface we are aware of are
118297f24f66STakanori Watanabe 	 * by Atmel.  For other chips more signature would have to be added.
118397f24f66STakanori Watanabe 	 */
118497f24f66STakanori Watanabe 	if (!bcmp(&id[4], "ATML", 4))
118597f24f66STakanori Watanabe 		rv = 1;
118697f24f66STakanori Watanabe 
118797f24f66STakanori Watanabe 	if (!rv) {
118897f24f66STakanori Watanabe 		bus_space_write_1(iot, ioh, r, 1);
118997f24f66STakanori Watanabe 		bus_space_write_1(iot, ioh, v, 0);
119097f24f66STakanori Watanabe 	}
119197f24f66STakanori Watanabe 	bus_space_unmap(iot, ioh, 2);
119297f24f66STakanori Watanabe 
119397f24f66STakanori Watanabe 	return rv;
119497f24f66STakanori Watanabe }
119597f24f66STakanori Watanabe 
119697f24f66STakanori Watanabe /* Setup TPM using legacy interface. */
119797f24f66STakanori Watanabe int
119897f24f66STakanori Watanabe tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name)
119997f24f66STakanori Watanabe {
120097f24f66STakanori Watanabe 	char id[8];
120197f24f66STakanori Watanabe 	u_int8_t ioh, iol;
120297f24f66STakanori Watanabe 	int i;
120397f24f66STakanori Watanabe 
120497f24f66STakanori Watanabe 	if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) {
120597f24f66STakanori Watanabe 		printf(": cannot map tpm registers (%d)\n", i);
120697f24f66STakanori Watanabe 		tpm_enabled = 0;
120797f24f66STakanori Watanabe 		return 1;
120897f24f66STakanori Watanabe 	}
120997f24f66STakanori Watanabe 
121097f24f66STakanori Watanabe 	for (i = sizeof(id); i--; )
121197f24f66STakanori Watanabe 		id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i);
121297f24f66STakanori Watanabe 
121397f24f66STakanori Watanabe 	printf(": %.4s %d.%d @0x%x\n", &id[4], id[0], id[1], tpm_enabled);
121497f24f66STakanori Watanabe 	iol = tpm_enabled & 0xff;
121597f24f66STakanori Watanabe 	ioh = tpm_enabled >> 16;
121697f24f66STakanori Watanabe 	tpm_enabled = 0;
121797f24f66STakanori Watanabe 
121897f24f66STakanori Watanabe 	return 0;
121997f24f66STakanori Watanabe }
122097f24f66STakanori Watanabe 
122197f24f66STakanori Watanabe /* Start transaction. */
122297f24f66STakanori Watanabe int
122397f24f66STakanori Watanabe tpm_legacy_start(struct tpm_softc *sc, int flag)
122497f24f66STakanori Watanabe {
122597f24f66STakanori Watanabe 	struct timeval tv;
122697f24f66STakanori Watanabe 	u_int8_t bits, r;
122797f24f66STakanori Watanabe 	int to, rv;
122897f24f66STakanori Watanabe 
122997f24f66STakanori Watanabe 	bits = flag == UIO_READ ? TPM_LEGACY_DA : 0;
123097f24f66STakanori Watanabe 	tv.tv_sec = TPM_LEGACY_TMO;
123197f24f66STakanori Watanabe 	tv.tv_usec = 0;
123297f24f66STakanori Watanabe 	to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
123397f24f66STakanori Watanabe 	while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
123497f24f66STakanori Watanabe 	    (TPM_LEGACY_BUSY|bits)) != bits && to--) {
123597f24f66STakanori Watanabe 		rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start",
123697f24f66STakanori Watanabe 		    TPM_LEGACY_SLEEP);
123797f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK)
123897f24f66STakanori Watanabe 			return rv;
123997f24f66STakanori Watanabe 	}
124097f24f66STakanori Watanabe 
124197f24f66STakanori Watanabe #if defined(TPM_DEBUG) && !defined(__FreeBSD__)
124297f24f66STakanori Watanabe 	printf("%s: bits %b\n", sc->sc_dev.dv_xname, r, TPM_LEGACY_BITS);
124397f24f66STakanori Watanabe #endif
124497f24f66STakanori Watanabe 	if ((r & (TPM_LEGACY_BUSY|bits)) != bits)
124597f24f66STakanori Watanabe 		return EIO;
124697f24f66STakanori Watanabe 
124797f24f66STakanori Watanabe 	return 0;
124897f24f66STakanori Watanabe }
124997f24f66STakanori Watanabe 
125097f24f66STakanori Watanabe int
125197f24f66STakanori Watanabe tpm_legacy_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
125297f24f66STakanori Watanabe     int flags)
125397f24f66STakanori Watanabe {
125497f24f66STakanori Watanabe 	u_int8_t *p;
125597f24f66STakanori Watanabe 	size_t cnt;
125697f24f66STakanori Watanabe 	int to, rv;
125797f24f66STakanori Watanabe 
125897f24f66STakanori Watanabe 	cnt = rv = 0;
125997f24f66STakanori Watanabe 	for (p = buf; !rv && len > 0; len--) {
126097f24f66STakanori Watanabe 		for (to = 1000;
126197f24f66STakanori Watanabe 		    !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) &
126297f24f66STakanori Watanabe 		    TPM_LEGACY_DA); DELAY(1))
126397f24f66STakanori Watanabe 			if (!to--)
126497f24f66STakanori Watanabe 				return EIO;
126597f24f66STakanori Watanabe 
126697f24f66STakanori Watanabe 		DELAY(TPM_LEGACY_DELAY);
126797f24f66STakanori Watanabe 		*p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0);
126897f24f66STakanori Watanabe 		cnt++;
126997f24f66STakanori Watanabe 	}
127097f24f66STakanori Watanabe 
127197f24f66STakanori Watanabe 	*count = cnt;
127297f24f66STakanori Watanabe 	return 0;
127397f24f66STakanori Watanabe }
127497f24f66STakanori Watanabe 
127597f24f66STakanori Watanabe int
127697f24f66STakanori Watanabe tpm_legacy_write(struct tpm_softc *sc, void *buf, int len)
127797f24f66STakanori Watanabe {
127897f24f66STakanori Watanabe 	u_int8_t *p;
127997f24f66STakanori Watanabe 	int n;
128097f24f66STakanori Watanabe 
128197f24f66STakanori Watanabe 	for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) {
128297f24f66STakanori Watanabe 		if (!n && len != TPM_BUFSIZ) {
128397f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1,
128497f24f66STakanori Watanabe 			    TPM_LEGACY_LAST);
128597f24f66STakanori Watanabe 			DELAY(TPM_LEGACY_DELAY);
128697f24f66STakanori Watanabe 		}
128797f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++);
128897f24f66STakanori Watanabe 	}
128997f24f66STakanori Watanabe 
129097f24f66STakanori Watanabe 	return 0;
129197f24f66STakanori Watanabe }
129297f24f66STakanori Watanabe 
129397f24f66STakanori Watanabe /* Finish transaction. */
129497f24f66STakanori Watanabe int
129597f24f66STakanori Watanabe tpm_legacy_end(struct tpm_softc *sc, int flag, int rv)
129697f24f66STakanori Watanabe {
129797f24f66STakanori Watanabe 	struct timeval tv;
129897f24f66STakanori Watanabe 	u_int8_t r;
129997f24f66STakanori Watanabe 	int to;
130097f24f66STakanori Watanabe 
130197f24f66STakanori Watanabe 	if (rv || flag == UIO_READ)
130297f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT);
130397f24f66STakanori Watanabe 	else {
130497f24f66STakanori Watanabe 		tv.tv_sec = TPM_LEGACY_TMO;
130597f24f66STakanori Watanabe 		tv.tv_usec = 0;
130697f24f66STakanori Watanabe 		to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
130797f24f66STakanori Watanabe 		while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
130897f24f66STakanori Watanabe 		    TPM_LEGACY_BUSY) && to--) {
130997f24f66STakanori Watanabe 			rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end",
131097f24f66STakanori Watanabe 			    TPM_LEGACY_SLEEP);
131197f24f66STakanori Watanabe 			if (rv && rv != EWOULDBLOCK)
131297f24f66STakanori Watanabe 				return rv;
131397f24f66STakanori Watanabe 		}
131497f24f66STakanori Watanabe 
131597f24f66STakanori Watanabe #if defined(TPM_DEBUG) && !defined(__FreeBSD__)
131697f24f66STakanori Watanabe 		printf("%s: bits %b\n", sc->sc_dev.dv_xname, r, TPM_LEGACY_BITS);
131797f24f66STakanori Watanabe #endif
131897f24f66STakanori Watanabe 		if (r & TPM_LEGACY_BUSY)
131997f24f66STakanori Watanabe 			return EIO;
132097f24f66STakanori Watanabe 
132197f24f66STakanori Watanabe 		if (r & TPM_LEGACY_RE)
132297f24f66STakanori Watanabe 			return EIO;	/* XXX Retry the loop? */
132397f24f66STakanori Watanabe 	}
132497f24f66STakanori Watanabe 
132597f24f66STakanori Watanabe 	return rv;
132697f24f66STakanori Watanabe }
132797f24f66STakanori Watanabe 
132897f24f66STakanori Watanabe int
132997f24f66STakanori Watanabe #ifdef __FreeBSD__
133097f24f66STakanori Watanabe tpmopen(struct cdev *dev, int flag, int mode, struct thread *td)
133197f24f66STakanori Watanabe #else
133297f24f66STakanori Watanabe tpmopen(dev_t dev, int flag, int mode, struct proc *p)
133397f24f66STakanori Watanabe #endif
133497f24f66STakanori Watanabe {
133597f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
133697f24f66STakanori Watanabe 
133797f24f66STakanori Watanabe 	if (!sc)
133897f24f66STakanori Watanabe 		return ENXIO;
133997f24f66STakanori Watanabe 
134097f24f66STakanori Watanabe 	if (sc->sc_flags & TPM_OPEN)
134197f24f66STakanori Watanabe 		return EBUSY;
134297f24f66STakanori Watanabe 
134397f24f66STakanori Watanabe 	sc->sc_flags |= TPM_OPEN;
134497f24f66STakanori Watanabe 
134597f24f66STakanori Watanabe 	return 0;
134697f24f66STakanori Watanabe }
134797f24f66STakanori Watanabe 
134897f24f66STakanori Watanabe int
134997f24f66STakanori Watanabe #ifdef __FreeBSD__
135097f24f66STakanori Watanabe tpmclose(struct cdev *dev, int flag, int mode, struct thread *td)
135197f24f66STakanori Watanabe #else
135297f24f66STakanori Watanabe tpmclose(dev_t dev, int flag, int mode, struct proc *p)
135397f24f66STakanori Watanabe #endif
135497f24f66STakanori Watanabe {
135597f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
135697f24f66STakanori Watanabe 
135797f24f66STakanori Watanabe 	if (!sc)
135897f24f66STakanori Watanabe 		return ENXIO;
135997f24f66STakanori Watanabe 
136097f24f66STakanori Watanabe 	if (!(sc->sc_flags & TPM_OPEN))
136197f24f66STakanori Watanabe 		return EINVAL;
136297f24f66STakanori Watanabe 
136397f24f66STakanori Watanabe 	sc->sc_flags &= ~TPM_OPEN;
136497f24f66STakanori Watanabe 
136597f24f66STakanori Watanabe 	return 0;
136697f24f66STakanori Watanabe }
136797f24f66STakanori Watanabe 
136897f24f66STakanori Watanabe int
136997f24f66STakanori Watanabe #ifdef __FreeBSD__
137097f24f66STakanori Watanabe tpmread(struct cdev *dev, struct uio *uio, int flags)
137197f24f66STakanori Watanabe #else
137297f24f66STakanori Watanabe tpmread(dev_t dev, struct uio *uio, int flags)
137397f24f66STakanori Watanabe #endif
137497f24f66STakanori Watanabe {
137597f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
137697f24f66STakanori Watanabe 	u_int8_t buf[TPM_BUFSIZ], *p;
137797f24f66STakanori Watanabe 	size_t cnt;
137897f24f66STakanori Watanabe 	int n, len, rv, s;
137997f24f66STakanori Watanabe 
138097f24f66STakanori Watanabe 	if (!sc)
138197f24f66STakanori Watanabe 		return ENXIO;
138297f24f66STakanori Watanabe 
138397f24f66STakanori Watanabe 	s = spltty();
138497f24f66STakanori Watanabe 	if ((rv = (sc->sc_start)(sc, UIO_READ))) {
138597f24f66STakanori Watanabe 		splx(s);
138697f24f66STakanori Watanabe 		return rv;
138797f24f66STakanori Watanabe 	}
138897f24f66STakanori Watanabe 
138997f24f66STakanori Watanabe #ifdef TPM_DEBUG
139097f24f66STakanori Watanabe 	printf("tpmread: getting header\n");
139197f24f66STakanori Watanabe #endif
139297f24f66STakanori Watanabe 	if ((rv = (sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
139397f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
139497f24f66STakanori Watanabe 		splx(s);
139597f24f66STakanori Watanabe 		return rv;
139697f24f66STakanori Watanabe 	}
139797f24f66STakanori Watanabe 
139897f24f66STakanori Watanabe 	len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
139997f24f66STakanori Watanabe #ifdef TPM_DEBUG
140097f24f66STakanori Watanabe 	printf("tpmread: len %d, io count %d\n", len, uio->uio_resid);
140197f24f66STakanori Watanabe #endif
140297f24f66STakanori Watanabe 	if (len > uio->uio_resid) {
140397f24f66STakanori Watanabe 		rv = EIO;
140497f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
140597f24f66STakanori Watanabe #ifdef TPM_DEBUG
140697f24f66STakanori Watanabe 		printf("tpmread: bad residual io count 0x%x\n", uio->uio_resid);
140797f24f66STakanori Watanabe #endif
140897f24f66STakanori Watanabe 		splx(s);
140997f24f66STakanori Watanabe 		return rv;
141097f24f66STakanori Watanabe 	}
141197f24f66STakanori Watanabe 
141297f24f66STakanori Watanabe 	/* Copy out header. */
141397f24f66STakanori Watanabe 	if ((rv = uiomove((caddr_t)buf, cnt, uio))) {
141497f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
141597f24f66STakanori Watanabe 		splx(s);
141697f24f66STakanori Watanabe 		return rv;
141797f24f66STakanori Watanabe 	}
141897f24f66STakanori Watanabe 
141997f24f66STakanori Watanabe 	/* Get remaining part of the answer (if anything is left). */
142097f24f66STakanori Watanabe 	for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
142197f24f66STakanori Watanabe 	    n = sizeof(buf)) {
142297f24f66STakanori Watanabe 		n = MIN(n, len);
142397f24f66STakanori Watanabe #ifdef TPM_DEBUG
142497f24f66STakanori Watanabe 		printf("tpmread: n %d len %d\n", n, len);
142597f24f66STakanori Watanabe #endif
142697f24f66STakanori Watanabe 		if ((rv = (sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
142797f24f66STakanori Watanabe 			(sc->sc_end)(sc, UIO_READ, rv);
142897f24f66STakanori Watanabe 			splx(s);
142997f24f66STakanori Watanabe 			return rv;
143097f24f66STakanori Watanabe 		}
143197f24f66STakanori Watanabe 		p += n;
143297f24f66STakanori Watanabe 		if ((rv = uiomove((caddr_t)buf, p - buf, uio))) {
143397f24f66STakanori Watanabe 			(sc->sc_end)(sc, UIO_READ, rv);
143497f24f66STakanori Watanabe 			splx(s);
143597f24f66STakanori Watanabe 			return rv;
143697f24f66STakanori Watanabe 		}
143797f24f66STakanori Watanabe 	}
143897f24f66STakanori Watanabe 
143997f24f66STakanori Watanabe 	rv = (sc->sc_end)(sc, UIO_READ, rv);
144097f24f66STakanori Watanabe 	splx(s);
144197f24f66STakanori Watanabe 	return rv;
144297f24f66STakanori Watanabe }
144397f24f66STakanori Watanabe 
144497f24f66STakanori Watanabe int
144597f24f66STakanori Watanabe #ifdef __FreeBSD__
144697f24f66STakanori Watanabe tpmwrite(struct cdev *dev, struct uio *uio, int flags)
144797f24f66STakanori Watanabe #else
144897f24f66STakanori Watanabe tpmwrite(dev_t dev, struct uio *uio, int flags)
144997f24f66STakanori Watanabe #endif
145097f24f66STakanori Watanabe {
145197f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
145297f24f66STakanori Watanabe 	u_int8_t buf[TPM_BUFSIZ];
145397f24f66STakanori Watanabe 	int n, rv, s;
145497f24f66STakanori Watanabe 
145597f24f66STakanori Watanabe 	if (!sc)
145697f24f66STakanori Watanabe 		return ENXIO;
145797f24f66STakanori Watanabe 
145897f24f66STakanori Watanabe 	s = spltty();
145997f24f66STakanori Watanabe 
146097f24f66STakanori Watanabe #ifdef TPM_DEBUG
146197f24f66STakanori Watanabe 	printf("tpmwrite: io count %d\n", uio->uio_resid);
146297f24f66STakanori Watanabe #endif
146397f24f66STakanori Watanabe 
146497f24f66STakanori Watanabe 	n = MIN(sizeof(buf), uio->uio_resid);
146597f24f66STakanori Watanabe 	if ((rv = uiomove((caddr_t)buf, n, uio))) {
146697f24f66STakanori Watanabe 		splx(s);
146797f24f66STakanori Watanabe 		return rv;
146897f24f66STakanori Watanabe 	}
146997f24f66STakanori Watanabe 
147097f24f66STakanori Watanabe 	if ((rv = (sc->sc_start)(sc, UIO_WRITE))) {
147197f24f66STakanori Watanabe 		splx(s);
147297f24f66STakanori Watanabe 		return rv;
147397f24f66STakanori Watanabe 	}
147497f24f66STakanori Watanabe 
147597f24f66STakanori Watanabe 	if ((rv = (sc->sc_write(sc, buf, n)))) {
147697f24f66STakanori Watanabe 		splx(s);
147797f24f66STakanori Watanabe 		return rv;
147897f24f66STakanori Watanabe 	}
147997f24f66STakanori Watanabe 
148097f24f66STakanori Watanabe 	rv = (sc->sc_end)(sc, UIO_WRITE, rv);
148197f24f66STakanori Watanabe 	splx(s);
148297f24f66STakanori Watanabe 	return rv;
148397f24f66STakanori Watanabe }
148497f24f66STakanori Watanabe 
148597f24f66STakanori Watanabe int
148697f24f66STakanori Watanabe #ifdef __FreeBSD__
148797f24f66STakanori Watanabe tpmioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
148897f24f66STakanori Watanabe     struct thread *td)
148997f24f66STakanori Watanabe #else
149097f24f66STakanori Watanabe tpmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
149197f24f66STakanori Watanabe #endif
149297f24f66STakanori Watanabe {
149397f24f66STakanori Watanabe 	return ENOTTY;
149497f24f66STakanori Watanabe }
1495