OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [tpm/] [tpm_infineon.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Description:
3
 * Device Driver for the Infineon Technologies
4
 * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
5
 * Specifications at www.trustedcomputinggroup.org
6
 *
7
 * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de>
8
 * Sirrix AG - security technologies, http://www.sirrix.com and
9
 * Applied Data Security Group, Ruhr-University Bochum, Germany
10
 * Project-Homepage: http://www.prosec.rub.de/tpm
11
 *
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License as
14
 * published by the Free Software Foundation, version 2 of the
15
 * License.
16
 */
17
 
18
#include <linux/init.h>
19
#include <linux/pnp.h>
20
#include "tpm.h"
21
 
22
/* Infineon specific definitions */
23
/* maximum number of WTX-packages */
24
#define TPM_MAX_WTX_PACKAGES    50
25
/* msleep-Time for WTX-packages */
26
#define TPM_WTX_MSLEEP_TIME     20
27
/* msleep-Time --> Interval to check status register */
28
#define TPM_MSLEEP_TIME         3
29
/* gives number of max. msleep()-calls before throwing timeout */
30
#define TPM_MAX_TRIES           5000
31
#define TPM_INFINEON_DEV_VEN_VALUE      0x15D1
32
 
33
#define TPM_INF_IO_PORT         0x0
34
#define TPM_INF_IO_MEM          0x1
35
 
36
#define TPM_INF_ADDR            0x0
37
#define TPM_INF_DATA            0x1
38
 
39
struct tpm_inf_dev {
40
        int iotype;
41
 
42
        void __iomem *mem_base;         /* MMIO ioremap'd addr */
43
        unsigned long map_base;         /* phys MMIO base */
44
        unsigned long map_size;         /* MMIO region size */
45
        unsigned int index_off;         /* index register offset */
46
 
47
        unsigned int data_regs;         /* Data registers */
48
        unsigned int data_size;
49
 
50
        unsigned int config_port;       /* IO Port config index reg */
51
        unsigned int config_size;
52
};
53
 
54
static struct tpm_inf_dev tpm_dev;
55
 
56
static inline void tpm_data_out(unsigned char data, unsigned char offset)
57
{
58
        if (tpm_dev.iotype == TPM_INF_IO_PORT)
59
                outb(data, tpm_dev.data_regs + offset);
60
        else
61
                writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
62
}
63
 
64
static inline unsigned char tpm_data_in(unsigned char offset)
65
{
66
        if (tpm_dev.iotype == TPM_INF_IO_PORT)
67
                return inb(tpm_dev.data_regs + offset);
68
        else
69
                return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
70
}
71
 
72
static inline void tpm_config_out(unsigned char data, unsigned char offset)
73
{
74
        if (tpm_dev.iotype == TPM_INF_IO_PORT)
75
                outb(data, tpm_dev.config_port + offset);
76
        else
77
                writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
78
}
79
 
80
static inline unsigned char tpm_config_in(unsigned char offset)
81
{
82
        if (tpm_dev.iotype == TPM_INF_IO_PORT)
83
                return inb(tpm_dev.config_port + offset);
84
        else
85
                return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
86
}
87
 
88
/* TPM header definitions */
89
enum infineon_tpm_header {
90
        TPM_VL_VER = 0x01,
91
        TPM_VL_CHANNEL_CONTROL = 0x07,
92
        TPM_VL_CHANNEL_PERSONALISATION = 0x0A,
93
        TPM_VL_CHANNEL_TPM = 0x0B,
94
        TPM_VL_CONTROL = 0x00,
95
        TPM_INF_NAK = 0x15,
96
        TPM_CTRL_WTX = 0x10,
97
        TPM_CTRL_WTX_ABORT = 0x18,
98
        TPM_CTRL_WTX_ABORT_ACK = 0x18,
99
        TPM_CTRL_ERROR = 0x20,
100
        TPM_CTRL_CHAININGACK = 0x40,
101
        TPM_CTRL_CHAINING = 0x80,
102
        TPM_CTRL_DATA = 0x04,
103
        TPM_CTRL_DATA_CHA = 0x84,
104
        TPM_CTRL_DATA_CHA_ACK = 0xC4
105
};
106
 
107
enum infineon_tpm_register {
108
        WRFIFO = 0x00,
109
        RDFIFO = 0x01,
110
        STAT = 0x02,
111
        CMD = 0x03
112
};
113
 
114
enum infineon_tpm_command_bits {
115
        CMD_DIS = 0x00,
116
        CMD_LP = 0x01,
117
        CMD_RES = 0x02,
118
        CMD_IRQC = 0x06
119
};
120
 
121
enum infineon_tpm_status_bits {
122
        STAT_XFE = 0x00,
123
        STAT_LPA = 0x01,
124
        STAT_FOK = 0x02,
125
        STAT_TOK = 0x03,
126
        STAT_IRQA = 0x06,
127
        STAT_RDA = 0x07
128
};
129
 
130
/* some outgoing values */
131
enum infineon_tpm_values {
132
        CHIP_ID1 = 0x20,
133
        CHIP_ID2 = 0x21,
134
        TPM_DAR = 0x30,
135
        RESET_LP_IRQC_DISABLE = 0x41,
136
        ENABLE_REGISTER_PAIR = 0x55,
137
        IOLIMH = 0x60,
138
        IOLIML = 0x61,
139
        DISABLE_REGISTER_PAIR = 0xAA,
140
        IDVENL = 0xF1,
141
        IDVENH = 0xF2,
142
        IDPDL = 0xF3,
143
        IDPDH = 0xF4
144
};
145
 
146
static int number_of_wtx;
147
 
148
static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
149
{
150
        int status;
151
        int check = 0;
152
        int i;
153
 
154
        if (clear_wrfifo) {
155
                for (i = 0; i < 4096; i++) {
156
                        status = tpm_data_in(WRFIFO);
157
                        if (status == 0xff) {
158
                                if (check == 5)
159
                                        break;
160
                                else
161
                                        check++;
162
                        }
163
                }
164
        }
165
        /* Note: The values which are currently in the FIFO of the TPM
166
           are thrown away since there is no usage for them. Usually,
167
           this has nothing to say, since the TPM will give its answer
168
           immediately or will be aborted anyway, so the data here is
169
           usually garbage and useless.
170
           We have to clean this, because the next communication with
171
           the TPM would be rubbish, if there is still some old data
172
           in the Read FIFO.
173
         */
174
        i = 0;
175
        do {
176
                status = tpm_data_in(RDFIFO);
177
                status = tpm_data_in(STAT);
178
                i++;
179
                if (i == TPM_MAX_TRIES)
180
                        return -EIO;
181
        } while ((status & (1 << STAT_RDA)) != 0);
182
        return 0;
183
}
184
 
185
static int wait(struct tpm_chip *chip, int wait_for_bit)
186
{
187
        int status;
188
        int i;
189
        for (i = 0; i < TPM_MAX_TRIES; i++) {
190
                status = tpm_data_in(STAT);
191
                /* check the status-register if wait_for_bit is set */
192
                if (status & 1 << wait_for_bit)
193
                        break;
194
                msleep(TPM_MSLEEP_TIME);
195
        }
196
        if (i == TPM_MAX_TRIES) {       /* timeout occurs */
197
                if (wait_for_bit == STAT_XFE)
198
                        dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
199
                if (wait_for_bit == STAT_RDA)
200
                        dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
201
                return -EIO;
202
        }
203
        return 0;
204
};
205
 
206
static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
207
{
208
        wait(chip, STAT_XFE);
209
        tpm_data_out(sendbyte, WRFIFO);
210
}
211
 
212
    /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
213
       calculation time, it sends a WTX-package, which has to be acknowledged
214
       or aborted. This usually occurs if you are hammering the TPM with key
215
       creation. Set the maximum number of WTX-packages in the definitions
216
       above, if the number is reached, the waiting-time will be denied
217
       and the TPM command has to be resend.
218
     */
219
 
220
static void tpm_wtx(struct tpm_chip *chip)
221
{
222
        number_of_wtx++;
223
        dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
224
                 number_of_wtx, TPM_MAX_WTX_PACKAGES);
225
        wait_and_send(chip, TPM_VL_VER);
226
        wait_and_send(chip, TPM_CTRL_WTX);
227
        wait_and_send(chip, 0x00);
228
        wait_and_send(chip, 0x00);
229
        msleep(TPM_WTX_MSLEEP_TIME);
230
}
231
 
232
static void tpm_wtx_abort(struct tpm_chip *chip)
233
{
234
        dev_info(chip->dev, "Aborting WTX\n");
235
        wait_and_send(chip, TPM_VL_VER);
236
        wait_and_send(chip, TPM_CTRL_WTX_ABORT);
237
        wait_and_send(chip, 0x00);
238
        wait_and_send(chip, 0x00);
239
        number_of_wtx = 0;
240
        msleep(TPM_WTX_MSLEEP_TIME);
241
}
242
 
243
static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
244
{
245
        int i;
246
        int ret;
247
        u32 size = 0;
248
        number_of_wtx = 0;
249
 
250
recv_begin:
251
        /* start receiving header */
252
        for (i = 0; i < 4; i++) {
253
                ret = wait(chip, STAT_RDA);
254
                if (ret)
255
                        return -EIO;
256
                buf[i] = tpm_data_in(RDFIFO);
257
        }
258
 
259
        if (buf[0] != TPM_VL_VER) {
260
                dev_err(chip->dev,
261
                        "Wrong transport protocol implementation!\n");
262
                return -EIO;
263
        }
264
 
265
        if (buf[1] == TPM_CTRL_DATA) {
266
                /* size of the data received */
267
                size = ((buf[2] << 8) | buf[3]);
268
 
269
                for (i = 0; i < size; i++) {
270
                        wait(chip, STAT_RDA);
271
                        buf[i] = tpm_data_in(RDFIFO);
272
                }
273
 
274
                if ((size == 0x6D00) && (buf[1] == 0x80)) {
275
                        dev_err(chip->dev, "Error handling on vendor layer!\n");
276
                        return -EIO;
277
                }
278
 
279
                for (i = 0; i < size; i++)
280
                        buf[i] = buf[i + 6];
281
 
282
                size = size - 6;
283
                return size;
284
        }
285
 
286
        if (buf[1] == TPM_CTRL_WTX) {
287
                dev_info(chip->dev, "WTX-package received\n");
288
                if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
289
                        tpm_wtx(chip);
290
                        goto recv_begin;
291
                } else {
292
                        tpm_wtx_abort(chip);
293
                        goto recv_begin;
294
                }
295
        }
296
 
297
        if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
298
                dev_info(chip->dev, "WTX-abort acknowledged\n");
299
                return size;
300
        }
301
 
302
        if (buf[1] == TPM_CTRL_ERROR) {
303
                dev_err(chip->dev, "ERROR-package received:\n");
304
                if (buf[4] == TPM_INF_NAK)
305
                        dev_err(chip->dev,
306
                                "-> Negative acknowledgement"
307
                                " - retransmit command!\n");
308
                return -EIO;
309
        }
310
        return -EIO;
311
}
312
 
313
static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
314
{
315
        int i;
316
        int ret;
317
        u8 count_high, count_low, count_4, count_3, count_2, count_1;
318
 
319
        /* Disabling Reset, LP and IRQC */
320
        tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
321
 
322
        ret = empty_fifo(chip, 1);
323
        if (ret) {
324
                dev_err(chip->dev, "Timeout while clearing FIFO\n");
325
                return -EIO;
326
        }
327
 
328
        ret = wait(chip, STAT_XFE);
329
        if (ret)
330
                return -EIO;
331
 
332
        count_4 = (count & 0xff000000) >> 24;
333
        count_3 = (count & 0x00ff0000) >> 16;
334
        count_2 = (count & 0x0000ff00) >> 8;
335
        count_1 = (count & 0x000000ff);
336
        count_high = ((count + 6) & 0xffffff00) >> 8;
337
        count_low = ((count + 6) & 0x000000ff);
338
 
339
        /* Sending Header */
340
        wait_and_send(chip, TPM_VL_VER);
341
        wait_and_send(chip, TPM_CTRL_DATA);
342
        wait_and_send(chip, count_high);
343
        wait_and_send(chip, count_low);
344
 
345
        /* Sending Data Header */
346
        wait_and_send(chip, TPM_VL_VER);
347
        wait_and_send(chip, TPM_VL_CHANNEL_TPM);
348
        wait_and_send(chip, count_4);
349
        wait_and_send(chip, count_3);
350
        wait_and_send(chip, count_2);
351
        wait_and_send(chip, count_1);
352
 
353
        /* Sending Data */
354
        for (i = 0; i < count; i++) {
355
                wait_and_send(chip, buf[i]);
356
        }
357
        return count;
358
}
359
 
360
static void tpm_inf_cancel(struct tpm_chip *chip)
361
{
362
        /*
363
           Since we are using the legacy mode to communicate
364
           with the TPM, we have no cancel functions, but have
365
           a workaround for interrupting the TPM through WTX.
366
         */
367
}
368
 
369
static u8 tpm_inf_status(struct tpm_chip *chip)
370
{
371
        return tpm_data_in(STAT);
372
}
373
 
374
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
375
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
376
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
377
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
378
 
379
static struct attribute *inf_attrs[] = {
380
        &dev_attr_pubek.attr,
381
        &dev_attr_pcrs.attr,
382
        &dev_attr_caps.attr,
383
        &dev_attr_cancel.attr,
384
        NULL,
385
};
386
 
387
static struct attribute_group inf_attr_grp = {.attrs = inf_attrs };
388
 
389
static const struct file_operations inf_ops = {
390
        .owner = THIS_MODULE,
391
        .llseek = no_llseek,
392
        .open = tpm_open,
393
        .read = tpm_read,
394
        .write = tpm_write,
395
        .release = tpm_release,
396
};
397
 
398
static const struct tpm_vendor_specific tpm_inf = {
399
        .recv = tpm_inf_recv,
400
        .send = tpm_inf_send,
401
        .cancel = tpm_inf_cancel,
402
        .status = tpm_inf_status,
403
        .req_complete_mask = 0,
404
        .req_complete_val = 0,
405
        .attr_group = &inf_attr_grp,
406
        .miscdev = {.fops = &inf_ops,},
407
};
408
 
409
static const struct pnp_device_id tpm_pnp_tbl[] = {
410
        /* Infineon TPMs */
411
        {"IFX0101", 0},
412
        {"IFX0102", 0},
413
        {"", 0}
414
};
415
 
416
MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
417
 
418
static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
419
                                       const struct pnp_device_id *dev_id)
420
{
421
        int rc = 0;
422
        u8 iol, ioh;
423
        int vendorid[2];
424
        int version[2];
425
        int productid[2];
426
        char chipname[20];
427
        struct tpm_chip *chip;
428
 
429
        /* read IO-ports through PnP */
430
        if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
431
            !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
432
 
433
                tpm_dev.iotype = TPM_INF_IO_PORT;
434
 
435
                tpm_dev.config_port = pnp_port_start(dev, 0);
436
                tpm_dev.config_size = pnp_port_len(dev, 0);
437
                tpm_dev.data_regs = pnp_port_start(dev, 1);
438
                tpm_dev.data_size = pnp_port_len(dev, 1);
439
                if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
440
                        rc = -EINVAL;
441
                        goto err_last;
442
                }
443
                dev_info(&dev->dev, "Found %s with ID %s\n",
444
                         dev->name, dev_id->id);
445
                if (!((tpm_dev.data_regs >> 8) & 0xff)) {
446
                        rc = -EINVAL;
447
                        goto err_last;
448
                }
449
                /* publish my base address and request region */
450
                if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
451
                                   "tpm_infineon0") == NULL) {
452
                        rc = -EINVAL;
453
                        goto err_last;
454
                }
455
                if (request_region(tpm_dev.config_port, tpm_dev.config_size,
456
                                   "tpm_infineon0") == NULL) {
457
                        release_region(tpm_dev.data_regs, tpm_dev.data_size);
458
                        rc = -EINVAL;
459
                        goto err_last;
460
                }
461
        } else if (pnp_mem_valid(dev, 0) &&
462
                   !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
463
 
464
                tpm_dev.iotype = TPM_INF_IO_MEM;
465
 
466
                tpm_dev.map_base = pnp_mem_start(dev, 0);
467
                tpm_dev.map_size = pnp_mem_len(dev, 0);
468
 
469
                dev_info(&dev->dev, "Found %s with ID %s\n",
470
                         dev->name, dev_id->id);
471
 
472
                /* publish my base address and request region */
473
                if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
474
                                       "tpm_infineon0") == NULL) {
475
                        rc = -EINVAL;
476
                        goto err_last;
477
                }
478
 
479
                tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
480
                if (tpm_dev.mem_base == NULL) {
481
                        release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
482
                        rc = -EINVAL;
483
                        goto err_last;
484
                }
485
 
486
                /*
487
                 * The only known MMIO based Infineon TPM system provides
488
                 * a single large mem region with the device config
489
                 * registers at the default TPM_ADDR.  The data registers
490
                 * seem like they could be placed anywhere within the MMIO
491
                 * region, but lets just put them at zero offset.
492
                 */
493
                tpm_dev.index_off = TPM_ADDR;
494
                tpm_dev.data_regs = 0x0;
495
        } else {
496
                rc = -EINVAL;
497
                goto err_last;
498
        }
499
 
500
        /* query chip for its vendor, its version number a.s.o. */
501
        tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
502
        tpm_config_out(IDVENL, TPM_INF_ADDR);
503
        vendorid[1] = tpm_config_in(TPM_INF_DATA);
504
        tpm_config_out(IDVENH, TPM_INF_ADDR);
505
        vendorid[0] = tpm_config_in(TPM_INF_DATA);
506
        tpm_config_out(IDPDL, TPM_INF_ADDR);
507
        productid[1] = tpm_config_in(TPM_INF_DATA);
508
        tpm_config_out(IDPDH, TPM_INF_ADDR);
509
        productid[0] = tpm_config_in(TPM_INF_DATA);
510
        tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
511
        version[1] = tpm_config_in(TPM_INF_DATA);
512
        tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
513
        version[0] = tpm_config_in(TPM_INF_DATA);
514
 
515
        switch ((productid[0] << 8) | productid[1]) {
516
        case 6:
517
                snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
518
                break;
519
        case 11:
520
                snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
521
                break;
522
        default:
523
                snprintf(chipname, sizeof(chipname), " (unknown chip)");
524
                break;
525
        }
526
 
527
        if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
528
 
529
                /* configure TPM with IO-ports */
530
                tpm_config_out(IOLIMH, TPM_INF_ADDR);
531
                tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
532
                tpm_config_out(IOLIML, TPM_INF_ADDR);
533
                tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
534
 
535
                /* control if IO-ports are set correctly */
536
                tpm_config_out(IOLIMH, TPM_INF_ADDR);
537
                ioh = tpm_config_in(TPM_INF_DATA);
538
                tpm_config_out(IOLIML, TPM_INF_ADDR);
539
                iol = tpm_config_in(TPM_INF_DATA);
540
 
541
                if ((ioh << 8 | iol) != tpm_dev.data_regs) {
542
                        dev_err(&dev->dev,
543
                                "Could not set IO-data registers to 0x%x\n",
544
                                tpm_dev.data_regs);
545
                        rc = -EIO;
546
                        goto err_release_region;
547
                }
548
 
549
                /* activate register */
550
                tpm_config_out(TPM_DAR, TPM_INF_ADDR);
551
                tpm_config_out(0x01, TPM_INF_DATA);
552
                tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
553
 
554
                /* disable RESET, LP and IRQC */
555
                tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
556
 
557
                /* Finally, we're done, print some infos */
558
                dev_info(&dev->dev, "TPM found: "
559
                         "config base 0x%lx, "
560
                         "data base 0x%lx, "
561
                         "chip version 0x%02x%02x, "
562
                         "vendor id 0x%x%x (Infineon), "
563
                         "product id 0x%02x%02x"
564
                         "%s\n",
565
                         tpm_dev.iotype == TPM_INF_IO_PORT ?
566
                                tpm_dev.config_port :
567
                                tpm_dev.map_base + tpm_dev.index_off,
568
                         tpm_dev.iotype == TPM_INF_IO_PORT ?
569
                                tpm_dev.data_regs :
570
                                tpm_dev.map_base + tpm_dev.data_regs,
571
                         version[0], version[1],
572
                         vendorid[0], vendorid[1],
573
                         productid[0], productid[1], chipname);
574
 
575
                if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
576
                        goto err_release_region;
577
 
578
                return 0;
579
        } else {
580
                rc = -ENODEV;
581
                goto err_release_region;
582
        }
583
 
584
err_release_region:
585
        if (tpm_dev.iotype == TPM_INF_IO_PORT) {
586
                release_region(tpm_dev.data_regs, tpm_dev.data_size);
587
                release_region(tpm_dev.config_port, tpm_dev.config_size);
588
        } else {
589
                iounmap(tpm_dev.mem_base);
590
                release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
591
        }
592
 
593
err_last:
594
        return rc;
595
}
596
 
597
static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
598
{
599
        struct tpm_chip *chip = pnp_get_drvdata(dev);
600
 
601
        if (chip) {
602
                if (tpm_dev.iotype == TPM_INF_IO_PORT) {
603
                        release_region(tpm_dev.data_regs, tpm_dev.data_size);
604
                        release_region(tpm_dev.config_port,
605
                                       tpm_dev.config_size);
606
                } else {
607
                        iounmap(tpm_dev.mem_base);
608
                        release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
609
                }
610
                tpm_remove_hardware(chip->dev);
611
        }
612
}
613
 
614
static struct pnp_driver tpm_inf_pnp = {
615
        .name = "tpm_inf_pnp",
616
        .driver = {
617
                .owner = THIS_MODULE,
618
                .suspend = tpm_pm_suspend,
619
                .resume = tpm_pm_resume,
620
        },
621
        .id_table = tpm_pnp_tbl,
622
        .probe = tpm_inf_pnp_probe,
623
        .remove = __devexit_p(tpm_inf_pnp_remove),
624
};
625
 
626
static int __init init_inf(void)
627
{
628
        return pnp_register_driver(&tpm_inf_pnp);
629
}
630
 
631
static void __exit cleanup_inf(void)
632
{
633
        pnp_unregister_driver(&tpm_inf_pnp);
634
}
635
 
636
module_init(init_inf);
637
module_exit(cleanup_inf);
638
 
639
MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
640
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
641
MODULE_VERSION("1.9");
642
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.