1342084Smw/*- 2342084Smw * Copyright (c) 2018 Stormshield. 3342084Smw * Copyright (c) 2018 Semihalf. 4342084Smw * All rights reserved. 5342084Smw * 6342084Smw * Redistribution and use in source and binary forms, with or without 7342084Smw * modification, are permitted provided that the following conditions 8342084Smw * are met: 9342084Smw * 1. Redistributions of source code must retain the above copyright 10342084Smw * notice, this list of conditions and the following disclaimer. 11342084Smw * 2. Redistributions in binary form must reproduce the above copyright 12342084Smw * notice, this list of conditions and the following disclaimer in the 13342084Smw * documentation and/or other materials provided with the distribution. 14342084Smw * 15342084Smw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16342084Smw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17342084Smw * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18342084Smw * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19342084Smw * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20342084Smw * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21342084Smw * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22342084Smw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23342084Smw * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24342084Smw * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25342084Smw * POSSIBILITY OF SUCH DAMAGE. 26342084Smw */ 27342084Smw 28342084Smw#include <sys/cdefs.h> 29342084Smw__FBSDID("$FreeBSD: stable/11/sys/dev/tpm/tpm_tis.c 346725 2019-04-26 01:58:36Z mw $"); 30342084Smw 31342084Smw#include "tpm20.h" 32342084Smw 33342084Smw/* 34342084Smw * TIS register space as defined in 35342084Smw * TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22 36342084Smw */ 37346725Smw#define TPM_ACCESS 0x0 38346725Smw#define TPM_INT_ENABLE 0x8 39346725Smw#define TPM_INT_VECTOR 0xc 40346725Smw#define TPM_INT_STS 0x10 41346725Smw#define TPM_INTF_CAPS 0x14 42346725Smw#define TPM_STS 0x18 43346725Smw#define TPM_DATA_FIFO 0x24 44346725Smw#define TPM_INTF_ID 0x30 45346725Smw#define TPM_XDATA_FIFO 0x80 46346725Smw#define TPM_DID_VID 0xF00 47346725Smw#define TPM_RID 0xF04 48342084Smw 49346725Smw#define TPM_ACCESS_LOC_REQ BIT(1) 50346725Smw#define TPM_ACCESS_LOC_Seize BIT(3) 51346725Smw#define TPM_ACCESS_LOC_ACTIVE BIT(5) 52346725Smw#define TPM_ACCESS_LOC_RELINQUISH BIT(5) 53346725Smw#define TPM_ACCESS_VALID BIT(7) 54342084Smw 55346725Smw#define TPM_INT_ENABLE_GLOBAL_ENABLE BIT(31) 56346725Smw#define TPM_INT_ENABLE_CMD_RDY BIT(7) 57346725Smw#define TPM_INT_ENABLE_LOC_CHANGE BIT(2) 58346725Smw#define TPM_INT_ENABLE_STS_VALID BIT(1) 59346725Smw#define TPM_INT_ENABLE_DATA_AVAIL BIT(0) 60342084Smw 61346725Smw#define TPM_INT_STS_CMD_RDY BIT(7) 62346725Smw#define TPM_INT_STS_LOC_CHANGE BIT(2) 63346725Smw#define TPM_INT_STS_VALID BIT(1) 64346725Smw#define TPM_INT_STS_DATA_AVAIL BIT(0) 65342084Smw 66346725Smw#define TPM_INTF_CAPS_VERSION 0x70000000 67346725Smw#define TPM_INTF_CAPS_TPM20 0x30000000 68342084Smw 69346725Smw#define TPM_STS_VALID BIT(7) 70346725Smw#define TPM_STS_CMD_RDY BIT(6) 71346725Smw#define TPM_STS_CMD_START BIT(5) 72346725Smw#define TPM_STS_DATA_AVAIL BIT(4) 73346725Smw#define TPM_STS_DATA_EXPECTED BIT(3) 74346725Smw#define TPM_STS_BURST_MASK 0xFFFF00 75346725Smw#define TPM_STS_BURST_OFFSET 0x8 76342084Smw 77342084Smwstatic int tpmtis_transmit(struct tpm_sc *sc, size_t length); 78342084Smw 79342084Smwstatic int tpmtis_acpi_probe(device_t dev); 80342084Smwstatic int tpmtis_attach(device_t dev); 81342084Smwstatic int tpmtis_detach(device_t dev); 82342084Smw 83342084Smwstatic void tpmtis_intr_handler(void *arg); 84342084Smw 85342084Smwstatic ACPI_STATUS tpmtis_get_SIRQ_channel(ACPI_RESOURCE *res, void *arg); 86342084Smwstatic bool tpmtis_setup_intr(struct tpm_sc *sc); 87342084Smw 88342084Smwstatic bool tpmtis_read_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf); 89342084Smwstatic bool tpmtis_write_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf); 90342084Smwstatic bool tpmtis_request_locality(struct tpm_sc *sc, int locality); 91342084Smwstatic void tpmtis_relinquish_locality(struct tpm_sc *sc); 92342084Smwstatic bool tpmtis_go_ready(struct tpm_sc *sc); 93342084Smw 94342084Smwstatic bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, 95342084Smw uint32_t mask, uint32_t val, int32_t timeout); 96346725Smw 97342084Smwstatic uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc); 98342084Smw 99342084Smwchar *tpmtis_ids[] = {"MSFT0101", NULL}; 100342084Smw 101342084Smwstatic int 102342084Smwtpmtis_acpi_probe(device_t dev) 103342084Smw{ 104346722Smw int err = 0; 105346722Smw ACPI_TABLE_TPM2 *tbl; 106346722Smw ACPI_STATUS status; 107342084Smw 108342084Smw if (ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids) == NULL) 109342084Smw return (ENXIO); 110342084Smw 111346722Smw /*Find TPM2 Header*/ 112346722Smw status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); 113346722Smw if(ACPI_FAILURE(status) || 114346722Smw tbl->StartMethod != TPM2_START_METHOD_TIS) 115346722Smw err = ENXIO; 116342084Smw 117342084Smw device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode"); 118346722Smw return (err); 119342084Smw} 120342084Smw 121342084Smwstatic int 122342084Smwtpmtis_attach(device_t dev) 123342084Smw{ 124342084Smw struct tpm_sc *sc; 125342084Smw int result; 126342084Smw 127342084Smw sc = device_get_softc(dev); 128342084Smw sc->dev = dev; 129342084Smw 130342084Smw sc->mem_rid = 0; 131342084Smw sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 132342084Smw RF_ACTIVE); 133342084Smw if (sc->mem_res == NULL) 134342084Smw return (ENXIO); 135342084Smw 136342084Smw sc->irq_rid = 0; 137342084Smw sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 138342084Smw RF_ACTIVE | RF_SHAREABLE); 139342084Smw if (sc->irq_res != NULL) { 140342084Smw if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 141342084Smw NULL, tpmtis_intr_handler, sc, &sc->intr_cookie)) 142342084Smw sc->interrupts = false; 143342084Smw else 144342084Smw sc->interrupts = tpmtis_setup_intr(sc); 145342084Smw } else { 146342084Smw sc->interrupts = false; 147342084Smw } 148342084Smw 149342084Smw sc->intr_type = -1; 150342084Smw 151342084Smw sc->transmit = tpmtis_transmit; 152342084Smw 153342084Smw result = tpm20_init(sc); 154342084Smw if (result != 0) 155342084Smw tpmtis_detach(dev); 156342084Smw 157342084Smw return (result); 158342084Smw} 159342084Smw 160342084Smwstatic int 161342084Smwtpmtis_detach(device_t dev) 162342084Smw{ 163342084Smw struct tpm_sc *sc; 164342084Smw 165342084Smw sc = device_get_softc(dev); 166346725Smw tpm20_release(sc); 167342084Smw 168342084Smw if (sc->intr_cookie != NULL) 169342084Smw bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); 170342084Smw 171342084Smw if (sc->irq_res != NULL) 172342084Smw bus_release_resource(dev, SYS_RES_IRQ, 173342084Smw sc->irq_rid, sc->irq_res); 174342084Smw 175342084Smw if (sc->mem_res != NULL) 176342084Smw bus_release_resource(dev, SYS_RES_MEMORY, 177342084Smw sc->mem_rid, sc->mem_res); 178342084Smw 179342084Smw return (0); 180342084Smw} 181342084Smw 182342084Smwstatic ACPI_STATUS 183342084Smwtpmtis_get_SIRQ_channel(ACPI_RESOURCE *res, void *arg) 184342084Smw{ 185342084Smw struct tpm_sc *sc; 186342084Smw uint8_t channel; 187342084Smw 188342084Smw sc = (struct tpm_sc *)arg; 189342084Smw 190342084Smw switch (res->Type) { 191342084Smw case ACPI_RESOURCE_TYPE_IRQ: 192342084Smw channel = res->Data.Irq.Interrupts[0]; 193342084Smw break; 194342084Smw case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 195342084Smw channel = res->Data.ExtendedIrq.Interrupts[0]; 196342084Smw break; 197342084Smw default: 198342084Smw return (AE_OK); 199342084Smw } 200342084Smw 201342084Smw WR1(sc, TPM_INT_VECTOR, channel); 202342084Smw return (AE_OK); 203342084Smw} 204342084Smw 205342084Smwstatic bool 206342084Smwtpmtis_setup_intr(struct tpm_sc *sc) 207342084Smw{ 208342084Smw ACPI_STATUS status; 209342084Smw ACPI_HANDLE handle; 210342084Smw uint32_t irq_mask; 211342084Smw 212342084Smw handle = acpi_get_handle(sc->dev); 213342084Smw 214342084Smw if(!tpmtis_request_locality(sc, 0)) 215342084Smw return (false); 216342084Smw 217342084Smw irq_mask = RD4(sc, TPM_INT_ENABLE); 218342084Smw irq_mask |= TPM_INT_ENABLE_GLOBAL_ENABLE | 219342084Smw TPM_INT_ENABLE_DATA_AVAIL | 220342084Smw TPM_INT_ENABLE_LOC_CHANGE | 221342084Smw TPM_INT_ENABLE_CMD_RDY | 222342084Smw TPM_INT_ENABLE_STS_VALID; 223342084Smw WR4(sc, TPM_INT_ENABLE, irq_mask); 224342084Smw 225342084Smw status = AcpiWalkResources(handle, "_CRS", 226342084Smw tpmtis_get_SIRQ_channel, (void *)sc); 227342084Smw 228342084Smw tpmtis_relinquish_locality(sc); 229342084Smw 230342084Smw return (ACPI_SUCCESS(status)); 231342084Smw} 232342084Smw 233342084Smwstatic void 234342084Smwtpmtis_intr_handler(void *arg) 235342084Smw{ 236342084Smw struct tpm_sc *sc; 237342084Smw uint32_t status; 238342084Smw 239342084Smw sc = (struct tpm_sc *)arg; 240342084Smw status = RD4(sc, TPM_INT_STS); 241342084Smw 242342084Smw WR4(sc, TPM_INT_STS, status); 243342084Smw if (sc->intr_type != -1 && sc->intr_type & status) 244342084Smw wakeup(sc); 245342084Smw} 246342084Smw 247342084Smwstatic bool 248342084Smwtpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val, 249342084Smw int32_t timeout) 250342084Smw{ 251342084Smw 252342084Smw /* Check for condition */ 253342084Smw if ((RD4(sc, off) & mask) == val) 254342084Smw return (true); 255342084Smw 256342084Smw /* If interrupts are enabled sleep for timeout duration */ 257342084Smw if(sc->interrupts && sc->intr_type != -1) { 258342084Smw tsleep(sc, PWAIT, "TPM WITH INTERRUPTS", timeout / tick); 259342084Smw 260342084Smw sc->intr_type = -1; 261342084Smw return ((RD4(sc, off) & mask) == val); 262342084Smw } 263342084Smw 264342084Smw /* If we don't have interrupts poll the device every tick */ 265342084Smw while (timeout > 0) { 266342084Smw if ((RD4(sc, off) & mask) == val) 267342084Smw return (true); 268342084Smw 269342084Smw pause("TPM POLLING", 1); 270342084Smw timeout -= tick; 271342084Smw } 272342084Smw return (false); 273342084Smw} 274342084Smw 275342084Smwstatic uint16_t 276342084Smwtpmtis_wait_for_burst(struct tpm_sc *sc) 277342084Smw{ 278342084Smw int timeout; 279342084Smw uint16_t burst_count; 280342084Smw 281342084Smw timeout = TPM_TIMEOUT_A; 282342084Smw 283342084Smw while (timeout-- > 0) { 284342084Smw burst_count = (RD4(sc, TPM_STS) & TPM_STS_BURST_MASK) >> 285342084Smw TPM_STS_BURST_OFFSET; 286342084Smw if (burst_count > 0) 287342084Smw break; 288342084Smw 289342084Smw DELAY(1); 290342084Smw } 291342084Smw return (burst_count); 292342084Smw} 293342084Smw 294342084Smwstatic bool 295342084Smwtpmtis_read_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf) 296342084Smw{ 297342084Smw uint16_t burst_count; 298342084Smw 299342084Smw while (count > 0) { 300342084Smw burst_count = tpmtis_wait_for_burst(sc); 301342084Smw if (burst_count == 0) 302342084Smw return (false); 303342084Smw 304342084Smw burst_count = MIN(burst_count, count); 305342084Smw count -= burst_count; 306342084Smw 307342084Smw while (burst_count-- > 0) 308342084Smw *buf++ = RD1(sc, TPM_DATA_FIFO); 309342084Smw } 310342084Smw 311342084Smw return (true); 312342084Smw} 313342084Smw 314342084Smwstatic bool 315342084Smwtpmtis_write_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf) 316342084Smw{ 317342084Smw uint16_t burst_count; 318342084Smw 319342084Smw while (count > 0) { 320342084Smw burst_count = tpmtis_wait_for_burst(sc); 321342084Smw if (burst_count == 0) 322342084Smw return (false); 323342084Smw 324342084Smw burst_count = MIN(burst_count, count); 325342084Smw count -= burst_count; 326342084Smw 327342084Smw while (burst_count-- > 0) 328342084Smw WR1(sc, TPM_DATA_FIFO, *buf++); 329342084Smw } 330342084Smw 331342084Smw return (true); 332342084Smw} 333342084Smw 334342084Smw 335342084Smwstatic bool 336342084Smwtpmtis_request_locality(struct tpm_sc *sc, int locality) 337342084Smw{ 338342084Smw uint8_t mask; 339342084Smw int timeout; 340342084Smw 341342084Smw /* Currently we only support Locality 0 */ 342342084Smw if (locality != 0) 343342084Smw return (false); 344342084Smw 345342084Smw mask = TPM_ACCESS_LOC_ACTIVE | TPM_ACCESS_VALID; 346342084Smw timeout = TPM_TIMEOUT_A; 347342084Smw sc->intr_type = TPM_INT_STS_LOC_CHANGE; 348342084Smw 349342084Smw WR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_REQ); 350342084Smw bus_barrier(sc->mem_res, TPM_ACCESS, 1, BUS_SPACE_BARRIER_WRITE); 351342084Smw if(sc->interrupts) { 352342084Smw tsleep(sc, PWAIT, "TPMLOCREQUEST with INTR", timeout / tick); 353342084Smw return ((RD1(sc, TPM_ACCESS) & mask) == mask); 354342084Smw } else { 355342084Smw while(timeout > 0) { 356342084Smw if ((RD1(sc, TPM_ACCESS) & mask) == mask) 357342084Smw return (true); 358342084Smw 359342084Smw pause("TPMLOCREQUEST POLLING", 1); 360342084Smw timeout -= tick; 361342084Smw } 362342084Smw } 363342084Smw 364342084Smw return (false); 365342084Smw} 366342084Smw 367342084Smwstatic void 368342084Smwtpmtis_relinquish_locality(struct tpm_sc *sc) 369342084Smw{ 370342084Smw 371342084Smw /* 372342084Smw * Interrupts can only be cleared when a locality is active. 373342084Smw * Clear them now in case interrupt handler didn't make it in time. 374342084Smw */ 375342084Smw if(sc->interrupts) 376342084Smw AND4(sc, TPM_INT_STS, RD4(sc, TPM_INT_STS)); 377342084Smw 378342084Smw OR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_RELINQUISH); 379342084Smw} 380342084Smw 381342084Smwstatic bool 382342084Smwtpmtis_go_ready(struct tpm_sc *sc) 383342084Smw{ 384342084Smw uint32_t mask; 385342084Smw 386342084Smw mask = TPM_STS_CMD_RDY; 387342084Smw sc->intr_type = TPM_INT_STS_CMD_RDY; 388342084Smw 389342084Smw OR4(sc, TPM_STS, TPM_STS_CMD_RDY); 390342084Smw bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); 391342084Smw if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_B)) 392342084Smw return (false); 393342084Smw 394342084Smw AND4(sc, TPM_STS, ~TPM_STS_CMD_RDY); 395342084Smw return (true); 396342084Smw} 397342084Smw 398342084Smwstatic int 399342084Smwtpmtis_transmit(struct tpm_sc *sc, size_t length) 400342084Smw{ 401342084Smw size_t bytes_available; 402342084Smw uint32_t mask, curr_cmd; 403342084Smw int timeout; 404342084Smw 405342084Smw sx_assert(&sc->dev_lock, SA_XLOCKED); 406342084Smw 407342084Smw if (!tpmtis_request_locality(sc, 0)) { 408342084Smw device_printf(sc->dev, 409342084Smw "Failed to obtain locality\n"); 410342084Smw return (EIO); 411342084Smw } 412342084Smw if (!tpmtis_go_ready(sc)) { 413342084Smw device_printf(sc->dev, 414342084Smw "Failed to switch to ready state\n"); 415342084Smw return (EIO); 416342084Smw } 417342084Smw if (!tpmtis_write_bytes(sc, length, sc->buf)) { 418342084Smw device_printf(sc->dev, 419342084Smw "Failed to write cmd to device\n"); 420342084Smw return (EIO); 421342084Smw } 422342084Smw 423342084Smw mask = TPM_STS_VALID; 424342084Smw sc->intr_type = TPM_INT_STS_VALID; 425342084Smw if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) { 426342084Smw device_printf(sc->dev, 427342084Smw "Timeout while waiting for valid bit\n"); 428342084Smw return (EIO); 429342084Smw } 430342084Smw if (RD4(sc, TPM_STS) & TPM_STS_DATA_EXPECTED) { 431342084Smw device_printf(sc->dev, 432342084Smw "Device expects more data even though we already" 433342084Smw " sent everything we had\n"); 434342084Smw return (EIO); 435342084Smw } 436342084Smw 437342084Smw /* 438342084Smw * Calculate timeout for current command. 439342084Smw * Command code is passed in bytes 6-10. 440342084Smw */ 441342084Smw curr_cmd = be32toh(*(uint32_t *) (&sc->buf[6])); 442342084Smw timeout = tpm20_get_timeout(curr_cmd); 443342084Smw 444342084Smw WR4(sc, TPM_STS, TPM_STS_CMD_START); 445342084Smw bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); 446342084Smw 447342084Smw mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; 448342084Smw sc->intr_type = TPM_INT_STS_DATA_AVAIL; 449342084Smw if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, timeout)) { 450342084Smw device_printf(sc->dev, 451342084Smw "Timeout while waiting for device to process cmd\n"); 452342084Smw /* 453342084Smw * Switching to ready state also cancels processing 454342084Smw * current command 455342084Smw */ 456342084Smw if (!tpmtis_go_ready(sc)) 457342084Smw return (EIO); 458342084Smw 459342084Smw /* 460342084Smw * After canceling a command we should get a response, 461342084Smw * check if there is one. 462342084Smw */ 463342084Smw sc->intr_type = TPM_INT_STS_DATA_AVAIL; 464342084Smw if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) 465342084Smw return (EIO); 466342084Smw } 467342084Smw /* Read response header. Length is passed in bytes 2 - 6. */ 468342084Smw if(!tpmtis_read_bytes(sc, TPM_HEADER_SIZE, sc->buf)) { 469342084Smw device_printf(sc->dev, 470342084Smw "Failed to read response header\n"); 471342084Smw return (EIO); 472342084Smw } 473342084Smw bytes_available = be32toh(*(uint32_t *) (&sc->buf[2])); 474342084Smw 475342084Smw if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) { 476342084Smw device_printf(sc->dev, 477342084Smw "Incorrect response size: %zu\n", 478342084Smw bytes_available); 479342084Smw return (EIO); 480342084Smw } 481342084Smw if(!tpmtis_read_bytes(sc, bytes_available - TPM_HEADER_SIZE, 482342084Smw &sc->buf[TPM_HEADER_SIZE])) { 483342084Smw device_printf(sc->dev, 484342084Smw "Failed to read response\n"); 485342084Smw return (EIO); 486342084Smw } 487342084Smw tpmtis_relinquish_locality(sc); 488342084Smw sc->pending_data_length = bytes_available; 489342084Smw 490342084Smw return (0); 491342084Smw} 492342084Smw 493342084Smw/* ACPI Driver */ 494342084Smwstatic device_method_t tpmtis_methods[] = { 495342084Smw DEVMETHOD(device_probe, tpmtis_acpi_probe), 496342084Smw DEVMETHOD(device_attach, tpmtis_attach), 497342084Smw DEVMETHOD(device_detach, tpmtis_detach), 498342084Smw DEVMETHOD(device_shutdown, tpm20_shutdown), 499342084Smw DEVMETHOD(device_suspend, tpm20_suspend), 500342084Smw {0, 0} 501342084Smw}; 502342084Smwstatic driver_t tpmtis_driver = { 503342084Smw "tpmtis", tpmtis_methods, sizeof(struct tpm_sc), 504342084Smw}; 505342084Smw 506342084Smwdevclass_t tpmtis_devclass; 507342084SmwDRIVER_MODULE(tpmtis, acpi, tpmtis_driver, tpmtis_devclass, 0, 0); 508