diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-26 18:23:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-26 18:23:24 -0400 |
commit | 08abe18af1f78ee80c3c3a5ac47c3e0ae0beadf6 (patch) | |
tree | 2be39bf8942edca1bcec735145e144a682ca9cd3 /drivers/char | |
parent | f0de70f8bb56952f6e016a65a8a8d006918f5bf6 (diff) | |
parent | 0384e2959127a56d0640505d004d8dd92f9c29f5 (diff) |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts:
drivers/net/wimax/i2400m/usb-notif.c
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/agp/amd64-agp.c | 13 | ||||
-rw-r--r-- | drivers/char/agp/intel-agp.c | 8 | ||||
-rw-r--r-- | drivers/char/agp/parisc-agp.c | 23 | ||||
-rw-r--r-- | drivers/char/hvcs.c | 9 | ||||
-rw-r--r-- | drivers/char/hvsi.c | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/Kconfig | 14 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/timeriomem-rng.c | 151 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.c | 530 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 142 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 28 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 28 | ||||
-rw-r--r-- | drivers/char/vc_screen.c | 16 | ||||
-rw-r--r-- | drivers/char/vt.c | 5 |
14 files changed, 630 insertions, 339 deletions
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 52f4361eb6e..d765afda9c2 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -271,15 +271,15 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, | |||
271 | nb_order = (nb_order >> 1) & 7; | 271 | nb_order = (nb_order >> 1) & 7; |
272 | pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); | 272 | pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); |
273 | nb_aper = nb_base << 25; | 273 | nb_aper = nb_base << 25; |
274 | if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) { | ||
275 | return 0; | ||
276 | } | ||
277 | 274 | ||
278 | /* Northbridge seems to contain crap. Try the AGP bridge. */ | 275 | /* Northbridge seems to contain crap. Try the AGP bridge. */ |
279 | 276 | ||
280 | pci_read_config_word(agp, cap+0x14, &apsize); | 277 | pci_read_config_word(agp, cap+0x14, &apsize); |
281 | if (apsize == 0xffff) | 278 | if (apsize == 0xffff) { |
279 | if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) | ||
280 | return 0; | ||
282 | return -1; | 281 | return -1; |
282 | } | ||
283 | 283 | ||
284 | apsize &= 0xfff; | 284 | apsize &= 0xfff; |
285 | /* Some BIOS use weird encodings not in the AGPv3 table. */ | 285 | /* Some BIOS use weird encodings not in the AGPv3 table. */ |
@@ -301,6 +301,11 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, | |||
301 | order = nb_order; | 301 | order = nb_order; |
302 | } | 302 | } |
303 | 303 | ||
304 | if (nb_order >= order) { | ||
305 | if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) | ||
306 | return 0; | ||
307 | } | ||
308 | |||
304 | dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", | 309 | dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", |
305 | aper, 32 << order); | 310 | aper, 32 << order); |
306 | if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) | 311 | if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) |
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index c7714185f83..4373adb2119 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c | |||
@@ -633,13 +633,15 @@ static void intel_i830_init_gtt_entries(void) | |||
633 | break; | 633 | break; |
634 | } | 634 | } |
635 | } | 635 | } |
636 | if (gtt_entries > 0) | 636 | if (gtt_entries > 0) { |
637 | dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", | 637 | dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", |
638 | gtt_entries / KB(1), local ? "local" : "stolen"); | 638 | gtt_entries / KB(1), local ? "local" : "stolen"); |
639 | else | 639 | gtt_entries /= KB(4); |
640 | } else { | ||
640 | dev_info(&agp_bridge->dev->dev, | 641 | dev_info(&agp_bridge->dev->dev, |
641 | "no pre-allocated video memory detected\n"); | 642 | "no pre-allocated video memory detected\n"); |
642 | gtt_entries /= KB(4); | 643 | gtt_entries = 0; |
644 | } | ||
643 | 645 | ||
644 | intel_private.gtt_entries = gtt_entries; | 646 | intel_private.gtt_entries = gtt_entries; |
645 | } | 647 | } |
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index db60539bf67..699e3422ad9 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c | |||
@@ -359,9 +359,16 @@ fail: | |||
359 | return error; | 359 | return error; |
360 | } | 360 | } |
361 | 361 | ||
362 | static struct device *next_device(struct klist_iter *i) { | 362 | static int |
363 | struct klist_node * n = klist_next(i); | 363 | find_quicksilver(struct device *dev, void *data) |
364 | return n ? container_of(n, struct device, knode_parent) : NULL; | 364 | { |
365 | struct parisc_device **lba = data; | ||
366 | struct parisc_device *padev = to_parisc_device(dev); | ||
367 | |||
368 | if (IS_QUICKSILVER(padev)) | ||
369 | *lba = padev; | ||
370 | |||
371 | return 0; | ||
365 | } | 372 | } |
366 | 373 | ||
367 | static int | 374 | static int |
@@ -372,8 +379,6 @@ parisc_agp_init(void) | |||
372 | int err = -1; | 379 | int err = -1; |
373 | struct parisc_device *sba = NULL, *lba = NULL; | 380 | struct parisc_device *sba = NULL, *lba = NULL; |
374 | struct lba_device *lbadev = NULL; | 381 | struct lba_device *lbadev = NULL; |
375 | struct device *dev = NULL; | ||
376 | struct klist_iter i; | ||
377 | 382 | ||
378 | if (!sba_list) | 383 | if (!sba_list) |
379 | goto out; | 384 | goto out; |
@@ -386,13 +391,7 @@ parisc_agp_init(void) | |||
386 | } | 391 | } |
387 | 392 | ||
388 | /* Now search our Pluto for our precious AGP device... */ | 393 | /* Now search our Pluto for our precious AGP device... */ |
389 | klist_iter_init(&sba->dev.klist_children, &i); | 394 | device_for_each_child(&sba->dev, &lba, find_quicksilver); |
390 | while ((dev = next_device(&i))) { | ||
391 | struct parisc_device *padev = to_parisc_device(dev); | ||
392 | if (IS_QUICKSILVER(padev)) | ||
393 | lba = padev; | ||
394 | } | ||
395 | klist_iter_exit(&i); | ||
396 | 395 | ||
397 | if (!lba) { | 396 | if (!lba) { |
398 | printk(KERN_INFO DRVPFX "No AGP devices found.\n"); | 397 | printk(KERN_INFO DRVPFX "No AGP devices found.\n"); |
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 6e6eb445d37..c76bccf5354 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -1139,15 +1139,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) | |||
1139 | hvcsd->tty = tty; | 1139 | hvcsd->tty = tty; |
1140 | tty->driver_data = hvcsd; | 1140 | tty->driver_data = hvcsd; |
1141 | 1141 | ||
1142 | /* | ||
1143 | * Set this driver to low latency so that we actually have a chance at | ||
1144 | * catching a throttled TTY after we flip_buffer_push. Otherwise the | ||
1145 | * flush_to_async may not execute until after the kernel_thread has | ||
1146 | * yielded and resumed the next flip_buffer_push resulting in data | ||
1147 | * loss. | ||
1148 | */ | ||
1149 | tty->low_latency = 1; | ||
1150 | |||
1151 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); | 1142 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); |
1152 | 1143 | ||
1153 | /* | 1144 | /* |
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 406f8742a26..2989056a9e3 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c | |||
@@ -810,7 +810,6 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) | |||
810 | hp = &hvsi_ports[line]; | 810 | hp = &hvsi_ports[line]; |
811 | 811 | ||
812 | tty->driver_data = hp; | 812 | tty->driver_data = hp; |
813 | tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */ | ||
814 | 813 | ||
815 | mb(); | 814 | mb(); |
816 | if (hp->state == HVSI_FSP_DIED) | 815 | if (hp->state == HVSI_FSP_DIED) |
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 8822eca58ff..5fab6470f4b 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -20,6 +20,20 @@ config HW_RANDOM | |||
20 | 20 | ||
21 | If unsure, say Y. | 21 | If unsure, say Y. |
22 | 22 | ||
23 | config HW_RANDOM_TIMERIOMEM | ||
24 | tristate "Timer IOMEM HW Random Number Generator support" | ||
25 | depends on HW_RANDOM && HAS_IOMEM | ||
26 | ---help--- | ||
27 | This driver provides kernel-side support for a generic Random | ||
28 | Number Generator used by reading a 'dumb' iomem address that | ||
29 | is to be read no faster than, for example, once a second; | ||
30 | the default FPGA bitstream on the TS-7800 has such functionality. | ||
31 | |||
32 | To compile this driver as a module, choose M here: the | ||
33 | module will be called timeriomem-rng. | ||
34 | |||
35 | If unsure, say Y. | ||
36 | |||
23 | config HW_RANDOM_INTEL | 37 | config HW_RANDOM_INTEL |
24 | tristate "Intel HW Random Number Generator support" | 38 | tristate "Intel HW Random Number Generator support" |
25 | depends on HW_RANDOM && (X86 || IA64) && PCI | 39 | depends on HW_RANDOM && (X86 || IA64) && PCI |
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index b6effb7522c..e81d21a5f28 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_HW_RANDOM) += rng-core.o | 5 | obj-$(CONFIG_HW_RANDOM) += rng-core.o |
6 | rng-core-y := core.o | 6 | rng-core-y := core.o |
7 | obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o | ||
7 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | 8 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o |
8 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | 9 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o |
9 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o | 10 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o |
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c new file mode 100644 index 00000000000..10ad41be589 --- /dev/null +++ b/drivers/char/hw_random/timeriomem-rng.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * drivers/char/hw_random/timeriomem-rng.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk> | ||
5 | * | ||
6 | * Derived from drivers/char/hw_random/omap-rng.c | ||
7 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
8 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Overview: | ||
15 | * This driver is useful for platforms that have an IO range that provides | ||
16 | * periodic random data from a single IO memory address. All the platform | ||
17 | * has to do is provide the address and 'wait time' that new data becomes | ||
18 | * available. | ||
19 | * | ||
20 | * TODO: add support for reading sizes other than 32bits and masking | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/hw_random.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/timeriomem-rng.h> | ||
29 | #include <linux/jiffies.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/timer.h> | ||
32 | #include <linux/completion.h> | ||
33 | |||
34 | static struct timeriomem_rng_data *timeriomem_rng_data; | ||
35 | |||
36 | static void timeriomem_rng_trigger(unsigned long); | ||
37 | static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0); | ||
38 | |||
39 | /* | ||
40 | * have data return 1, however return 0 if we have nothing | ||
41 | */ | ||
42 | static int timeriomem_rng_data_present(struct hwrng *rng, int wait) | ||
43 | { | ||
44 | if (rng->priv == 0) | ||
45 | return 1; | ||
46 | |||
47 | if (!wait || timeriomem_rng_data->present) | ||
48 | return timeriomem_rng_data->present; | ||
49 | |||
50 | wait_for_completion(&timeriomem_rng_data->completion); | ||
51 | |||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data) | ||
56 | { | ||
57 | unsigned long cur; | ||
58 | s32 delay; | ||
59 | |||
60 | *data = readl(timeriomem_rng_data->address); | ||
61 | |||
62 | if (rng->priv != 0) { | ||
63 | cur = jiffies; | ||
64 | |||
65 | delay = cur - timeriomem_rng_timer.expires; | ||
66 | delay = rng->priv - (delay % rng->priv); | ||
67 | |||
68 | timeriomem_rng_timer.expires = cur + delay; | ||
69 | timeriomem_rng_data->present = 0; | ||
70 | |||
71 | init_completion(&timeriomem_rng_data->completion); | ||
72 | add_timer(&timeriomem_rng_timer); | ||
73 | } | ||
74 | |||
75 | return 4; | ||
76 | } | ||
77 | |||
78 | static void timeriomem_rng_trigger(unsigned long dummy) | ||
79 | { | ||
80 | timeriomem_rng_data->present = 1; | ||
81 | complete(&timeriomem_rng_data->completion); | ||
82 | } | ||
83 | |||
84 | static struct hwrng timeriomem_rng_ops = { | ||
85 | .name = "timeriomem", | ||
86 | .data_present = timeriomem_rng_data_present, | ||
87 | .data_read = timeriomem_rng_data_read, | ||
88 | .priv = 0, | ||
89 | }; | ||
90 | |||
91 | static int __init timeriomem_rng_probe(struct platform_device *pdev) | ||
92 | { | ||
93 | int ret; | ||
94 | |||
95 | timeriomem_rng_data = pdev->dev.platform_data; | ||
96 | |||
97 | if (timeriomem_rng_data->period != 0 | ||
98 | && usecs_to_jiffies(timeriomem_rng_data->period) > 0) { | ||
99 | timeriomem_rng_timer.expires = jiffies; | ||
100 | |||
101 | timeriomem_rng_ops.priv = usecs_to_jiffies( | ||
102 | timeriomem_rng_data->period); | ||
103 | } | ||
104 | timeriomem_rng_data->present = 1; | ||
105 | |||
106 | ret = hwrng_register(&timeriomem_rng_ops); | ||
107 | if (ret) { | ||
108 | dev_err(&pdev->dev, "problem registering\n"); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", | ||
113 | timeriomem_rng_data->address, | ||
114 | timeriomem_rng_data->period); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int __devexit timeriomem_rng_remove(struct platform_device *pdev) | ||
120 | { | ||
121 | del_timer_sync(&timeriomem_rng_timer); | ||
122 | hwrng_unregister(&timeriomem_rng_ops); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static struct platform_driver timeriomem_rng_driver = { | ||
128 | .driver = { | ||
129 | .name = "timeriomem_rng", | ||
130 | .owner = THIS_MODULE, | ||
131 | }, | ||
132 | .probe = timeriomem_rng_probe, | ||
133 | .remove = __devexit_p(timeriomem_rng_remove), | ||
134 | }; | ||
135 | |||
136 | static int __init timeriomem_rng_init(void) | ||
137 | { | ||
138 | return platform_driver_register(&timeriomem_rng_driver); | ||
139 | } | ||
140 | |||
141 | static void __exit timeriomem_rng_exit(void) | ||
142 | { | ||
143 | platform_driver_unregister(&timeriomem_rng_driver); | ||
144 | } | ||
145 | |||
146 | module_init(timeriomem_rng_init); | ||
147 | module_exit(timeriomem_rng_exit); | ||
148 | |||
149 | MODULE_LICENSE("GPL"); | ||
150 | MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>"); | ||
151 | MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver"); | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9c47dc48c9f..ccdd828adce 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -429,134 +429,148 @@ out: | |||
429 | #define TPM_DIGEST_SIZE 20 | 429 | #define TPM_DIGEST_SIZE 20 |
430 | #define TPM_ERROR_SIZE 10 | 430 | #define TPM_ERROR_SIZE 10 |
431 | #define TPM_RET_CODE_IDX 6 | 431 | #define TPM_RET_CODE_IDX 6 |
432 | #define TPM_GET_CAP_RET_SIZE_IDX 10 | ||
433 | #define TPM_GET_CAP_RET_UINT32_1_IDX 14 | ||
434 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 | ||
435 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 | ||
436 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 | ||
437 | #define TPM_GET_CAP_PERM_DISABLE_IDX 16 | ||
438 | #define TPM_GET_CAP_PERM_INACTIVE_IDX 18 | ||
439 | #define TPM_GET_CAP_RET_BOOL_1_IDX 14 | ||
440 | #define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 | ||
441 | |||
442 | #define TPM_CAP_IDX 13 | ||
443 | #define TPM_CAP_SUBCAP_IDX 21 | ||
444 | 432 | ||
445 | enum tpm_capabilities { | 433 | enum tpm_capabilities { |
446 | TPM_CAP_FLAG = 4, | 434 | TPM_CAP_FLAG = cpu_to_be32(4), |
447 | TPM_CAP_PROP = 5, | 435 | TPM_CAP_PROP = cpu_to_be32(5), |
436 | CAP_VERSION_1_1 = cpu_to_be32(0x06), | ||
437 | CAP_VERSION_1_2 = cpu_to_be32(0x1A) | ||
448 | }; | 438 | }; |
449 | 439 | ||
450 | enum tpm_sub_capabilities { | 440 | enum tpm_sub_capabilities { |
451 | TPM_CAP_PROP_PCR = 0x1, | 441 | TPM_CAP_PROP_PCR = cpu_to_be32(0x101), |
452 | TPM_CAP_PROP_MANUFACTURER = 0x3, | 442 | TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), |
453 | TPM_CAP_FLAG_PERM = 0x8, | 443 | TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), |
454 | TPM_CAP_FLAG_VOL = 0x9, | 444 | TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), |
455 | TPM_CAP_PROP_OWNER = 0x11, | 445 | TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), |
456 | TPM_CAP_PROP_TIS_TIMEOUT = 0x15, | 446 | TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), |
457 | TPM_CAP_PROP_TIS_DURATION = 0x20, | 447 | TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), |
458 | }; | ||
459 | 448 | ||
460 | /* | ||
461 | * This is a semi generic GetCapability command for use | ||
462 | * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG | ||
463 | * and their associated sub_capabilities. | ||
464 | */ | ||
465 | |||
466 | static const u8 tpm_cap[] = { | ||
467 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
468 | 0, 0, 0, 22, /* length */ | ||
469 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
470 | 0, 0, 0, 0, /* TPM_CAP_<TYPE> */ | ||
471 | 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */ | ||
472 | 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */ | ||
473 | }; | 449 | }; |
474 | 450 | ||
475 | static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, | 451 | static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, |
476 | char *desc) | 452 | int len, const char *desc) |
477 | { | 453 | { |
478 | int err; | 454 | int err; |
479 | 455 | ||
480 | len = tpm_transmit(chip, data, len); | 456 | len = tpm_transmit(chip,(u8 *) cmd, len); |
481 | if (len < 0) | 457 | if (len < 0) |
482 | return len; | 458 | return len; |
483 | if (len == TPM_ERROR_SIZE) { | 459 | if (len == TPM_ERROR_SIZE) { |
484 | err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); | 460 | err = be32_to_cpu(cmd->header.out.return_code); |
485 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | 461 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); |
486 | return err; | 462 | return err; |
487 | } | 463 | } |
488 | return 0; | 464 | return 0; |
489 | } | 465 | } |
490 | 466 | ||
467 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
468 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | ||
469 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | ||
470 | |||
471 | static const struct tpm_input_header tpm_getcap_header = { | ||
472 | .tag = TPM_TAG_RQU_COMMAND, | ||
473 | .length = cpu_to_be32(22), | ||
474 | .ordinal = TPM_ORD_GET_CAP | ||
475 | }; | ||
476 | |||
477 | ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, | ||
478 | const char *desc) | ||
479 | { | ||
480 | struct tpm_cmd_t tpm_cmd; | ||
481 | int rc; | ||
482 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
483 | |||
484 | tpm_cmd.header.in = tpm_getcap_header; | ||
485 | if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { | ||
486 | tpm_cmd.params.getcap_in.cap = subcap_id; | ||
487 | /*subcap field not necessary */ | ||
488 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); | ||
489 | tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); | ||
490 | } else { | ||
491 | if (subcap_id == TPM_CAP_FLAG_PERM || | ||
492 | subcap_id == TPM_CAP_FLAG_VOL) | ||
493 | tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; | ||
494 | else | ||
495 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | ||
496 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
497 | tpm_cmd.params.getcap_in.subcap = subcap_id; | ||
498 | } | ||
499 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); | ||
500 | if (!rc) | ||
501 | *cap = tpm_cmd.params.getcap_out.cap; | ||
502 | return rc; | ||
503 | } | ||
504 | |||
491 | void tpm_gen_interrupt(struct tpm_chip *chip) | 505 | void tpm_gen_interrupt(struct tpm_chip *chip) |
492 | { | 506 | { |
493 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | 507 | struct tpm_cmd_t tpm_cmd; |
494 | ssize_t rc; | 508 | ssize_t rc; |
495 | 509 | ||
496 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 510 | tpm_cmd.header.in = tpm_getcap_header; |
497 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 511 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
498 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | 512 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
513 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
499 | 514 | ||
500 | rc = transmit_cmd(chip, data, sizeof(data), | 515 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
501 | "attempting to determine the timeouts"); | 516 | "attempting to determine the timeouts"); |
502 | } | 517 | } |
503 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | 518 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); |
504 | 519 | ||
505 | void tpm_get_timeouts(struct tpm_chip *chip) | 520 | void tpm_get_timeouts(struct tpm_chip *chip) |
506 | { | 521 | { |
507 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | 522 | struct tpm_cmd_t tpm_cmd; |
523 | struct timeout_t *timeout_cap; | ||
524 | struct duration_t *duration_cap; | ||
508 | ssize_t rc; | 525 | ssize_t rc; |
509 | u32 timeout; | 526 | u32 timeout; |
510 | 527 | ||
511 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 528 | tpm_cmd.header.in = tpm_getcap_header; |
512 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 529 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
513 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | 530 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
531 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
514 | 532 | ||
515 | rc = transmit_cmd(chip, data, sizeof(data), | 533 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
516 | "attempting to determine the timeouts"); | 534 | "attempting to determine the timeouts"); |
517 | if (rc) | 535 | if (rc) |
518 | goto duration; | 536 | goto duration; |
519 | 537 | ||
520 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | 538 | if (be32_to_cpu(tpm_cmd.header.out.length) |
521 | != 4 * sizeof(u32)) | 539 | != 4 * sizeof(u32)) |
522 | goto duration; | 540 | goto duration; |
523 | 541 | ||
542 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | ||
524 | /* Don't overwrite default if value is 0 */ | 543 | /* Don't overwrite default if value is 0 */ |
525 | timeout = | 544 | timeout = be32_to_cpu(timeout_cap->a); |
526 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); | ||
527 | if (timeout) | 545 | if (timeout) |
528 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); | 546 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); |
529 | timeout = | 547 | timeout = be32_to_cpu(timeout_cap->b); |
530 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); | ||
531 | if (timeout) | 548 | if (timeout) |
532 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); | 549 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); |
533 | timeout = | 550 | timeout = be32_to_cpu(timeout_cap->c); |
534 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); | ||
535 | if (timeout) | 551 | if (timeout) |
536 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); | 552 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); |
537 | timeout = | 553 | timeout = be32_to_cpu(timeout_cap->d); |
538 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); | ||
539 | if (timeout) | 554 | if (timeout) |
540 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); | 555 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); |
541 | 556 | ||
542 | duration: | 557 | duration: |
543 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 558 | tpm_cmd.header.in = tpm_getcap_header; |
544 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 559 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
545 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; | 560 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
561 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; | ||
546 | 562 | ||
547 | rc = transmit_cmd(chip, data, sizeof(data), | 563 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
548 | "attempting to determine the durations"); | 564 | "attempting to determine the durations"); |
549 | if (rc) | 565 | if (rc) |
550 | return; | 566 | return; |
551 | 567 | ||
552 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | 568 | if (be32_to_cpu(tpm_cmd.header.out.return_code) |
553 | != 3 * sizeof(u32)) | 569 | != 3 * sizeof(u32)) |
554 | return; | 570 | return; |
555 | 571 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | |
556 | chip->vendor.duration[TPM_SHORT] = | 572 | chip->vendor.duration[TPM_SHORT] = |
557 | usecs_to_jiffies(be32_to_cpu | 573 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); |
558 | (*((__be32 *) (data + | ||
559 | TPM_GET_CAP_RET_UINT32_1_IDX)))); | ||
560 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above | 574 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above |
561 | * value wrong and apparently reports msecs rather than usecs. So we | 575 | * value wrong and apparently reports msecs rather than usecs. So we |
562 | * fix up the resulting too-small TPM_SHORT value to make things work. | 576 | * fix up the resulting too-small TPM_SHORT value to make things work. |
@@ -565,13 +579,9 @@ duration: | |||
565 | chip->vendor.duration[TPM_SHORT] = HZ; | 579 | chip->vendor.duration[TPM_SHORT] = HZ; |
566 | 580 | ||
567 | chip->vendor.duration[TPM_MEDIUM] = | 581 | chip->vendor.duration[TPM_MEDIUM] = |
568 | usecs_to_jiffies(be32_to_cpu | 582 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); |
569 | (*((__be32 *) (data + | ||
570 | TPM_GET_CAP_RET_UINT32_2_IDX)))); | ||
571 | chip->vendor.duration[TPM_LONG] = | 583 | chip->vendor.duration[TPM_LONG] = |
572 | usecs_to_jiffies(be32_to_cpu | 584 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); |
573 | (*((__be32 *) (data + | ||
574 | TPM_GET_CAP_RET_UINT32_3_IDX)))); | ||
575 | } | 585 | } |
576 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 586 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
577 | 587 | ||
@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
587 | } | 597 | } |
588 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | 598 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); |
589 | 599 | ||
590 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
591 | |||
592 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | 600 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, |
593 | char *buf) | 601 | char *buf) |
594 | { | 602 | { |
595 | u8 *data; | 603 | cap_t cap; |
596 | ssize_t rc; | 604 | ssize_t rc; |
597 | 605 | ||
598 | struct tpm_chip *chip = dev_get_drvdata(dev); | 606 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, |
599 | if (chip == NULL) | 607 | "attempting to determine the permanent enabled state"); |
600 | return -ENODEV; | 608 | if (rc) |
601 | |||
602 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
603 | if (!data) | ||
604 | return -ENOMEM; | ||
605 | |||
606 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
607 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
608 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
609 | |||
610 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
611 | "attemtping to determine the permanent enabled state"); | ||
612 | if (rc) { | ||
613 | kfree(data); | ||
614 | return 0; | 609 | return 0; |
615 | } | ||
616 | |||
617 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | ||
618 | 610 | ||
619 | kfree(data); | 611 | rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); |
620 | return rc; | 612 | return rc; |
621 | } | 613 | } |
622 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | 614 | EXPORT_SYMBOL_GPL(tpm_show_enabled); |
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled); | |||
624 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | 616 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, |
625 | char *buf) | 617 | char *buf) |
626 | { | 618 | { |
627 | u8 *data; | 619 | cap_t cap; |
628 | ssize_t rc; | 620 | ssize_t rc; |
629 | 621 | ||
630 | struct tpm_chip *chip = dev_get_drvdata(dev); | 622 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, |
631 | if (chip == NULL) | 623 | "attempting to determine the permanent active state"); |
632 | return -ENODEV; | 624 | if (rc) |
633 | |||
634 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
635 | if (!data) | ||
636 | return -ENOMEM; | ||
637 | |||
638 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
639 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
640 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
641 | |||
642 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
643 | "attemtping to determine the permanent active state"); | ||
644 | if (rc) { | ||
645 | kfree(data); | ||
646 | return 0; | 625 | return 0; |
647 | } | ||
648 | 626 | ||
649 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | 627 | rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); |
650 | |||
651 | kfree(data); | ||
652 | return rc; | 628 | return rc; |
653 | } | 629 | } |
654 | EXPORT_SYMBOL_GPL(tpm_show_active); | 630 | EXPORT_SYMBOL_GPL(tpm_show_active); |
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active); | |||
656 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | 632 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, |
657 | char *buf) | 633 | char *buf) |
658 | { | 634 | { |
659 | u8 *data; | 635 | cap_t cap; |
660 | ssize_t rc; | 636 | ssize_t rc; |
661 | 637 | ||
662 | struct tpm_chip *chip = dev_get_drvdata(dev); | 638 | rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, |
663 | if (chip == NULL) | 639 | "attempting to determine the owner state"); |
664 | return -ENODEV; | 640 | if (rc) |
665 | |||
666 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
667 | if (!data) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
671 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
672 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; | ||
673 | |||
674 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
675 | "attempting to determine the owner state"); | ||
676 | if (rc) { | ||
677 | kfree(data); | ||
678 | return 0; | 641 | return 0; |
679 | } | ||
680 | |||
681 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | ||
682 | 642 | ||
683 | kfree(data); | 643 | rc = sprintf(buf, "%d\n", cap.owned); |
684 | return rc; | 644 | return rc; |
685 | } | 645 | } |
686 | EXPORT_SYMBOL_GPL(tpm_show_owned); | 646 | EXPORT_SYMBOL_GPL(tpm_show_owned); |
@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned); | |||
688 | ssize_t tpm_show_temp_deactivated(struct device * dev, | 648 | ssize_t tpm_show_temp_deactivated(struct device * dev, |
689 | struct device_attribute * attr, char *buf) | 649 | struct device_attribute * attr, char *buf) |
690 | { | 650 | { |
691 | u8 *data; | 651 | cap_t cap; |
692 | ssize_t rc; | 652 | ssize_t rc; |
693 | 653 | ||
694 | struct tpm_chip *chip = dev_get_drvdata(dev); | 654 | rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, |
695 | if (chip == NULL) | 655 | "attempting to determine the temporary state"); |
696 | return -ENODEV; | 656 | if (rc) |
657 | return 0; | ||
697 | 658 | ||
698 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 659 | rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); |
699 | if (!data) | 660 | return rc; |
700 | return -ENOMEM; | 661 | } |
662 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
701 | 663 | ||
702 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 664 | /* |
703 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 665 | * tpm_chip_find_get - return tpm_chip for given chip number |
704 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | 666 | */ |
667 | static struct tpm_chip *tpm_chip_find_get(int chip_num) | ||
668 | { | ||
669 | struct tpm_chip *pos, *chip = NULL; | ||
705 | 670 | ||
706 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | 671 | rcu_read_lock(); |
707 | "attempting to determine the temporary state"); | 672 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { |
708 | if (rc) { | 673 | if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) |
709 | kfree(data); | 674 | continue; |
710 | return 0; | 675 | |
676 | if (try_module_get(pos->dev->driver->owner)) { | ||
677 | chip = pos; | ||
678 | break; | ||
679 | } | ||
711 | } | 680 | } |
681 | rcu_read_unlock(); | ||
682 | return chip; | ||
683 | } | ||
712 | 684 | ||
713 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | 685 | #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) |
686 | #define READ_PCR_RESULT_SIZE 30 | ||
687 | static struct tpm_input_header pcrread_header = { | ||
688 | .tag = TPM_TAG_RQU_COMMAND, | ||
689 | .length = cpu_to_be32(14), | ||
690 | .ordinal = TPM_ORDINAL_PCRREAD | ||
691 | }; | ||
714 | 692 | ||
715 | kfree(data); | 693 | int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) |
694 | { | ||
695 | int rc; | ||
696 | struct tpm_cmd_t cmd; | ||
697 | |||
698 | cmd.header.in = pcrread_header; | ||
699 | cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
700 | BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE); | ||
701 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
702 | "attempting to read a pcr value"); | ||
703 | |||
704 | if (rc == 0) | ||
705 | memcpy(res_buf, cmd.params.pcrread_out.pcr_result, | ||
706 | TPM_DIGEST_SIZE); | ||
716 | return rc; | 707 | return rc; |
717 | } | 708 | } |
718 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
719 | 709 | ||
720 | static const u8 pcrread[] = { | 710 | /** |
721 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 711 | * tpm_pcr_read - read a pcr value |
722 | 0, 0, 0, 14, /* length */ | 712 | * @chip_num: tpm idx # or ANY |
723 | 0, 0, 0, 21, /* TPM_ORD_PcrRead */ | 713 | * @pcr_idx: pcr idx to retrieve |
724 | 0, 0, 0, 0 /* PCR index */ | 714 | * @res_buf: TPM_PCR value |
715 | * size of res_buf is 20 bytes (or NULL if you don't care) | ||
716 | * | ||
717 | * The TPM driver should be built-in, but for whatever reason it | ||
718 | * isn't, protect against the chip disappearing, by incrementing | ||
719 | * the module usage count. | ||
720 | */ | ||
721 | int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) | ||
722 | { | ||
723 | struct tpm_chip *chip; | ||
724 | int rc; | ||
725 | |||
726 | chip = tpm_chip_find_get(chip_num); | ||
727 | if (chip == NULL) | ||
728 | return -ENODEV; | ||
729 | rc = __tpm_pcr_read(chip, pcr_idx, res_buf); | ||
730 | module_put(chip->dev->driver->owner); | ||
731 | return rc; | ||
732 | } | ||
733 | EXPORT_SYMBOL_GPL(tpm_pcr_read); | ||
734 | |||
735 | /** | ||
736 | * tpm_pcr_extend - extend pcr value with hash | ||
737 | * @chip_num: tpm idx # or AN& | ||
738 | * @pcr_idx: pcr idx to extend | ||
739 | * @hash: hash value used to extend pcr value | ||
740 | * | ||
741 | * The TPM driver should be built-in, but for whatever reason it | ||
742 | * isn't, protect against the chip disappearing, by incrementing | ||
743 | * the module usage count. | ||
744 | */ | ||
745 | #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) | ||
746 | #define EXTEND_PCR_SIZE 34 | ||
747 | static struct tpm_input_header pcrextend_header = { | ||
748 | .tag = TPM_TAG_RQU_COMMAND, | ||
749 | .length = cpu_to_be32(34), | ||
750 | .ordinal = TPM_ORD_PCR_EXTEND | ||
725 | }; | 751 | }; |
726 | 752 | ||
753 | int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) | ||
754 | { | ||
755 | struct tpm_cmd_t cmd; | ||
756 | int rc; | ||
757 | struct tpm_chip *chip; | ||
758 | |||
759 | chip = tpm_chip_find_get(chip_num); | ||
760 | if (chip == NULL) | ||
761 | return -ENODEV; | ||
762 | |||
763 | cmd.header.in = pcrextend_header; | ||
764 | BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE); | ||
765 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
766 | memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); | ||
767 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
768 | "attempting extend a PCR value"); | ||
769 | |||
770 | module_put(chip->dev->driver->owner); | ||
771 | return rc; | ||
772 | } | ||
773 | EXPORT_SYMBOL_GPL(tpm_pcr_extend); | ||
774 | |||
727 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 775 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
728 | char *buf) | 776 | char *buf) |
729 | { | 777 | { |
730 | u8 *data; | 778 | cap_t cap; |
779 | u8 digest[TPM_DIGEST_SIZE]; | ||
731 | ssize_t rc; | 780 | ssize_t rc; |
732 | int i, j, num_pcrs; | 781 | int i, j, num_pcrs; |
733 | __be32 index; | ||
734 | char *str = buf; | 782 | char *str = buf; |
735 | |||
736 | struct tpm_chip *chip = dev_get_drvdata(dev); | 783 | struct tpm_chip *chip = dev_get_drvdata(dev); |
737 | if (chip == NULL) | ||
738 | return -ENODEV; | ||
739 | 784 | ||
740 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 785 | rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, |
741 | if (!data) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
745 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
746 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; | ||
747 | |||
748 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
749 | "attempting to determine the number of PCRS"); | 786 | "attempting to determine the number of PCRS"); |
750 | if (rc) { | 787 | if (rc) |
751 | kfree(data); | ||
752 | return 0; | 788 | return 0; |
753 | } | ||
754 | 789 | ||
755 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 790 | num_pcrs = be32_to_cpu(cap.num_pcrs); |
756 | for (i = 0; i < num_pcrs; i++) { | 791 | for (i = 0; i < num_pcrs; i++) { |
757 | memcpy(data, pcrread, sizeof(pcrread)); | 792 | rc = __tpm_pcr_read(chip, i, digest); |
758 | index = cpu_to_be32(i); | ||
759 | memcpy(data + 10, &index, 4); | ||
760 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
761 | "attempting to read a PCR"); | ||
762 | if (rc) | 793 | if (rc) |
763 | goto out; | 794 | break; |
764 | str += sprintf(str, "PCR-%02d: ", i); | 795 | str += sprintf(str, "PCR-%02d: ", i); |
765 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 796 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
766 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 797 | str += sprintf(str, "%02X ", digest[j]); |
767 | str += sprintf(str, "\n"); | 798 | str += sprintf(str, "\n"); |
768 | } | 799 | } |
769 | out: | ||
770 | kfree(data); | ||
771 | return str - buf; | 800 | return str - buf; |
772 | } | 801 | } |
773 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | 802 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); |
774 | 803 | ||
775 | #define READ_PUBEK_RESULT_SIZE 314 | 804 | #define READ_PUBEK_RESULT_SIZE 314 |
776 | static const u8 readpubek[] = { | 805 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
777 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 806 | struct tpm_input_header tpm_readpubek_header = { |
778 | 0, 0, 0, 30, /* length */ | 807 | .tag = TPM_TAG_RQU_COMMAND, |
779 | 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ | 808 | .length = cpu_to_be32(30), |
809 | .ordinal = TPM_ORD_READPUBEK | ||
780 | }; | 810 | }; |
781 | 811 | ||
782 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | 812 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, |
783 | char *buf) | 813 | char *buf) |
784 | { | 814 | { |
785 | u8 *data; | 815 | u8 *data; |
816 | struct tpm_cmd_t tpm_cmd; | ||
786 | ssize_t err; | 817 | ssize_t err; |
787 | int i, rc; | 818 | int i, rc; |
788 | char *str = buf; | 819 | char *str = buf; |
789 | 820 | ||
790 | struct tpm_chip *chip = dev_get_drvdata(dev); | 821 | struct tpm_chip *chip = dev_get_drvdata(dev); |
791 | if (chip == NULL) | ||
792 | return -ENODEV; | ||
793 | 822 | ||
794 | data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); | 823 | tpm_cmd.header.in = tpm_readpubek_header; |
795 | if (!data) | 824 | err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, |
796 | return -ENOMEM; | ||
797 | |||
798 | memcpy(data, readpubek, sizeof(readpubek)); | ||
799 | |||
800 | err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, | ||
801 | "attempting to read the PUBEK"); | 825 | "attempting to read the PUBEK"); |
802 | if (err) | 826 | if (err) |
803 | goto out; | 827 | goto out; |
@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
812 | 256 byte modulus | 836 | 256 byte modulus |
813 | ignore checksum 20 bytes | 837 | ignore checksum 20 bytes |
814 | */ | 838 | */ |
815 | 839 | data = tpm_cmd.params.readpubek_out_buffer; | |
816 | str += | 840 | str += |
817 | sprintf(str, | 841 | sprintf(str, |
818 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 842 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" |
@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
832 | } | 856 | } |
833 | out: | 857 | out: |
834 | rc = str - buf; | 858 | rc = str - buf; |
835 | kfree(data); | ||
836 | return rc; | 859 | return rc; |
837 | } | 860 | } |
838 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 861 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
839 | 862 | ||
840 | #define CAP_VERSION_1_1 6 | ||
841 | #define CAP_VERSION_1_2 0x1A | ||
842 | #define CAP_VERSION_IDX 13 | ||
843 | static const u8 cap_version[] = { | ||
844 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
845 | 0, 0, 0, 18, /* length */ | ||
846 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
847 | 0, 0, 0, 0, | ||
848 | 0, 0, 0, 0 | ||
849 | }; | ||
850 | 863 | ||
851 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 864 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
852 | char *buf) | 865 | char *buf) |
853 | { | 866 | { |
854 | u8 *data; | 867 | cap_t cap; |
855 | ssize_t rc; | 868 | ssize_t rc; |
856 | char *str = buf; | 869 | char *str = buf; |
857 | 870 | ||
858 | struct tpm_chip *chip = dev_get_drvdata(dev); | 871 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, |
859 | if (chip == NULL) | ||
860 | return -ENODEV; | ||
861 | |||
862 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
863 | if (!data) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
867 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
868 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
869 | |||
870 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
871 | "attempting to determine the manufacturer"); | 872 | "attempting to determine the manufacturer"); |
872 | if (rc) { | 873 | if (rc) |
873 | kfree(data); | ||
874 | return 0; | 874 | return 0; |
875 | } | ||
876 | |||
877 | str += sprintf(str, "Manufacturer: 0x%x\n", | 875 | str += sprintf(str, "Manufacturer: 0x%x\n", |
878 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 876 | be32_to_cpu(cap.manufacturer_id)); |
879 | 877 | ||
880 | memcpy(data, cap_version, sizeof(cap_version)); | 878 | rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, |
881 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | 879 | "attempting to determine the 1.1 version"); |
882 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
883 | "attempting to determine the 1.1 version"); | ||
884 | if (rc) | 880 | if (rc) |
885 | goto out; | 881 | return 0; |
886 | |||
887 | str += sprintf(str, | 882 | str += sprintf(str, |
888 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 883 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
889 | (int) data[14], (int) data[15], (int) data[16], | 884 | cap.tpm_version.Major, cap.tpm_version.Minor, |
890 | (int) data[17]); | 885 | cap.tpm_version.revMajor, cap.tpm_version.revMinor); |
891 | |||
892 | out: | ||
893 | kfree(data); | ||
894 | return str - buf; | 886 | return str - buf; |
895 | } | 887 | } |
896 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 888 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps); | |||
898 | ssize_t tpm_show_caps_1_2(struct device * dev, | 890 | ssize_t tpm_show_caps_1_2(struct device * dev, |
899 | struct device_attribute * attr, char *buf) | 891 | struct device_attribute * attr, char *buf) |
900 | { | 892 | { |
901 | u8 *data; | 893 | cap_t cap; |
902 | ssize_t len; | 894 | ssize_t rc; |
903 | char *str = buf; | 895 | char *str = buf; |
904 | 896 | ||
905 | struct tpm_chip *chip = dev_get_drvdata(dev); | 897 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, |
906 | if (chip == NULL) | 898 | "attempting to determine the manufacturer"); |
907 | return -ENODEV; | 899 | if (rc) |
908 | |||
909 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
910 | if (!data) | ||
911 | return -ENOMEM; | ||
912 | |||
913 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
914 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
915 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
916 | |||
917 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); | ||
918 | if (len <= TPM_ERROR_SIZE) { | ||
919 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | ||
920 | "attempting to determine the manufacturer\n", | ||
921 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
922 | kfree(data); | ||
923 | return 0; | 900 | return 0; |
924 | } | ||
925 | |||
926 | str += sprintf(str, "Manufacturer: 0x%x\n", | 901 | str += sprintf(str, "Manufacturer: 0x%x\n", |
927 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 902 | be32_to_cpu(cap.manufacturer_id)); |
928 | 903 | rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, | |
929 | memcpy(data, cap_version, sizeof(cap_version)); | 904 | "attempting to determine the 1.2 version"); |
930 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | 905 | if (rc) |
931 | 906 | return 0; | |
932 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); | ||
933 | if (len <= TPM_ERROR_SIZE) { | ||
934 | dev_err(chip->dev, "A TPM error (%d) occurred " | ||
935 | "attempting to determine the 1.2 version\n", | ||
936 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
937 | goto out; | ||
938 | } | ||
939 | str += sprintf(str, | 907 | str += sprintf(str, |
940 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 908 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
941 | (int) data[16], (int) data[17], (int) data[18], | 909 | cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, |
942 | (int) data[19]); | 910 | cap.tpm_version_1_2.revMajor, |
943 | 911 | cap.tpm_version_1_2.revMinor); | |
944 | out: | ||
945 | kfree(data); | ||
946 | return str - buf; | 912 | return str - buf; |
947 | } | 913 | } |
948 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 914 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8e30df4a438..8e00b4ddd08 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/miscdevice.h> | 26 | #include <linux/miscdevice.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/tpm.h> | ||
29 | 30 | ||
30 | enum tpm_timeout { | 31 | enum tpm_timeout { |
31 | TPM_TIMEOUT = 5, /* msecs */ | 32 | TPM_TIMEOUT = 5, /* msecs */ |
@@ -123,6 +124,147 @@ static inline void tpm_write_index(int base, int index, int value) | |||
123 | outb(index, base); | 124 | outb(index, base); |
124 | outb(value & 0xFF, base+1); | 125 | outb(value & 0xFF, base+1); |
125 | } | 126 | } |
127 | struct tpm_input_header { | ||
128 | __be16 tag; | ||
129 | __be32 length; | ||
130 | __be32 ordinal; | ||
131 | }__attribute__((packed)); | ||
132 | |||
133 | struct tpm_output_header { | ||
134 | __be16 tag; | ||
135 | __be32 length; | ||
136 | __be32 return_code; | ||
137 | }__attribute__((packed)); | ||
138 | |||
139 | struct stclear_flags_t { | ||
140 | __be16 tag; | ||
141 | u8 deactivated; | ||
142 | u8 disableForceClear; | ||
143 | u8 physicalPresence; | ||
144 | u8 physicalPresenceLock; | ||
145 | u8 bGlobalLock; | ||
146 | }__attribute__((packed)); | ||
147 | |||
148 | struct tpm_version_t { | ||
149 | u8 Major; | ||
150 | u8 Minor; | ||
151 | u8 revMajor; | ||
152 | u8 revMinor; | ||
153 | }__attribute__((packed)); | ||
154 | |||
155 | struct tpm_version_1_2_t { | ||
156 | __be16 tag; | ||
157 | u8 Major; | ||
158 | u8 Minor; | ||
159 | u8 revMajor; | ||
160 | u8 revMinor; | ||
161 | }__attribute__((packed)); | ||
162 | |||
163 | struct timeout_t { | ||
164 | __be32 a; | ||
165 | __be32 b; | ||
166 | __be32 c; | ||
167 | __be32 d; | ||
168 | }__attribute__((packed)); | ||
169 | |||
170 | struct duration_t { | ||
171 | __be32 tpm_short; | ||
172 | __be32 tpm_medium; | ||
173 | __be32 tpm_long; | ||
174 | }__attribute__((packed)); | ||
175 | |||
176 | struct permanent_flags_t { | ||
177 | __be16 tag; | ||
178 | u8 disable; | ||
179 | u8 ownership; | ||
180 | u8 deactivated; | ||
181 | u8 readPubek; | ||
182 | u8 disableOwnerClear; | ||
183 | u8 allowMaintenance; | ||
184 | u8 physicalPresenceLifetimeLock; | ||
185 | u8 physicalPresenceHWEnable; | ||
186 | u8 physicalPresenceCMDEnable; | ||
187 | u8 CEKPUsed; | ||
188 | u8 TPMpost; | ||
189 | u8 TPMpostLock; | ||
190 | u8 FIPS; | ||
191 | u8 operator; | ||
192 | u8 enableRevokeEK; | ||
193 | u8 nvLocked; | ||
194 | u8 readSRKPub; | ||
195 | u8 tpmEstablished; | ||
196 | u8 maintenanceDone; | ||
197 | u8 disableFullDALogicInfo; | ||
198 | }__attribute__((packed)); | ||
199 | |||
200 | typedef union { | ||
201 | struct permanent_flags_t perm_flags; | ||
202 | struct stclear_flags_t stclear_flags; | ||
203 | bool owned; | ||
204 | __be32 num_pcrs; | ||
205 | struct tpm_version_t tpm_version; | ||
206 | struct tpm_version_1_2_t tpm_version_1_2; | ||
207 | __be32 manufacturer_id; | ||
208 | struct timeout_t timeout; | ||
209 | struct duration_t duration; | ||
210 | } cap_t; | ||
211 | |||
212 | struct tpm_getcap_params_in { | ||
213 | __be32 cap; | ||
214 | __be32 subcap_size; | ||
215 | __be32 subcap; | ||
216 | }__attribute__((packed)); | ||
217 | |||
218 | struct tpm_getcap_params_out { | ||
219 | __be32 cap_size; | ||
220 | cap_t cap; | ||
221 | }__attribute__((packed)); | ||
222 | |||
223 | struct tpm_readpubek_params_out { | ||
224 | u8 algorithm[4]; | ||
225 | u8 encscheme[2]; | ||
226 | u8 sigscheme[2]; | ||
227 | u8 parameters[12]; /*assuming RSA*/ | ||
228 | __be32 keysize; | ||
229 | u8 modulus[256]; | ||
230 | u8 checksum[20]; | ||
231 | }__attribute__((packed)); | ||
232 | |||
233 | typedef union { | ||
234 | struct tpm_input_header in; | ||
235 | struct tpm_output_header out; | ||
236 | } tpm_cmd_header; | ||
237 | |||
238 | #define TPM_DIGEST_SIZE 20 | ||
239 | struct tpm_pcrread_out { | ||
240 | u8 pcr_result[TPM_DIGEST_SIZE]; | ||
241 | }__attribute__((packed)); | ||
242 | |||
243 | struct tpm_pcrread_in { | ||
244 | __be32 pcr_idx; | ||
245 | }__attribute__((packed)); | ||
246 | |||
247 | struct tpm_pcrextend_in { | ||
248 | __be32 pcr_idx; | ||
249 | u8 hash[TPM_DIGEST_SIZE]; | ||
250 | }__attribute__((packed)); | ||
251 | |||
252 | typedef union { | ||
253 | struct tpm_getcap_params_out getcap_out; | ||
254 | struct tpm_readpubek_params_out readpubek_out; | ||
255 | u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; | ||
256 | struct tpm_getcap_params_in getcap_in; | ||
257 | struct tpm_pcrread_in pcrread_in; | ||
258 | struct tpm_pcrread_out pcrread_out; | ||
259 | struct tpm_pcrextend_in pcrextend_in; | ||
260 | } tpm_cmd_params; | ||
261 | |||
262 | struct tpm_cmd_t { | ||
263 | tpm_cmd_header header; | ||
264 | tpm_cmd_params params; | ||
265 | }__attribute__((packed)); | ||
266 | |||
267 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); | ||
126 | 268 | ||
127 | extern void tpm_get_timeouts(struct tpm_chip *); | 269 | extern void tpm_get_timeouts(struct tpm_chip *); |
128 | extern void tpm_gen_interrupt(struct tpm_chip *); | 270 | extern void tpm_gen_interrupt(struct tpm_chip *); |
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index d0e7926eb48..c64a1bc6534 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
@@ -168,12 +168,22 @@ static void atml_plat_remove(void) | |||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | static struct device_driver atml_drv = { | 171 | static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg) |
172 | .name = "tpm_atmel", | 172 | { |
173 | .bus = &platform_bus_type, | 173 | return tpm_pm_suspend(&dev->dev, msg); |
174 | .owner = THIS_MODULE, | 174 | } |
175 | .suspend = tpm_pm_suspend, | 175 | |
176 | .resume = tpm_pm_resume, | 176 | static int tpm_atml_resume(struct platform_device *dev) |
177 | { | ||
178 | return tpm_pm_resume(&dev->dev); | ||
179 | } | ||
180 | static struct platform_driver atml_drv = { | ||
181 | .driver = { | ||
182 | .name = "tpm_atmel", | ||
183 | .owner = THIS_MODULE, | ||
184 | }, | ||
185 | .suspend = tpm_atml_suspend, | ||
186 | .resume = tpm_atml_resume, | ||
177 | }; | 187 | }; |
178 | 188 | ||
179 | static int __init init_atmel(void) | 189 | static int __init init_atmel(void) |
@@ -184,7 +194,7 @@ static int __init init_atmel(void) | |||
184 | unsigned long base; | 194 | unsigned long base; |
185 | struct tpm_chip *chip; | 195 | struct tpm_chip *chip; |
186 | 196 | ||
187 | rc = driver_register(&atml_drv); | 197 | rc = platform_driver_register(&atml_drv); |
188 | if (rc) | 198 | if (rc) |
189 | return rc; | 199 | return rc; |
190 | 200 | ||
@@ -223,13 +233,13 @@ err_rel_reg: | |||
223 | atmel_release_region(base, | 233 | atmel_release_region(base, |
224 | region_size); | 234 | region_size); |
225 | err_unreg_drv: | 235 | err_unreg_drv: |
226 | driver_unregister(&atml_drv); | 236 | platform_driver_unregister(&atml_drv); |
227 | return rc; | 237 | return rc; |
228 | } | 238 | } |
229 | 239 | ||
230 | static void __exit cleanup_atmel(void) | 240 | static void __exit cleanup_atmel(void) |
231 | { | 241 | { |
232 | driver_unregister(&atml_drv); | 242 | platform_driver_unregister(&atml_drv); |
233 | atml_plat_remove(); | 243 | atml_plat_remove(); |
234 | } | 244 | } |
235 | 245 | ||
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 717af7ad1bd..aec1931608a 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -654,12 +654,22 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, | |||
654 | sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); | 654 | sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); |
655 | MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); | 655 | MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); |
656 | 656 | ||
657 | static struct device_driver tis_drv = { | 657 | static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg) |
658 | .name = "tpm_tis", | 658 | { |
659 | .bus = &platform_bus_type, | 659 | return tpm_pm_suspend(&dev->dev, msg); |
660 | .owner = THIS_MODULE, | 660 | } |
661 | .suspend = tpm_pm_suspend, | 661 | |
662 | .resume = tpm_pm_resume, | 662 | static int tpm_tis_resume(struct platform_device *dev) |
663 | { | ||
664 | return tpm_pm_resume(&dev->dev); | ||
665 | } | ||
666 | static struct platform_driver tis_drv = { | ||
667 | .driver = { | ||
668 | .name = "tpm_tis", | ||
669 | .owner = THIS_MODULE, | ||
670 | }, | ||
671 | .suspend = tpm_tis_suspend, | ||
672 | .resume = tpm_tis_resume, | ||
663 | }; | 673 | }; |
664 | 674 | ||
665 | static struct platform_device *pdev; | 675 | static struct platform_device *pdev; |
@@ -672,14 +682,14 @@ static int __init init_tis(void) | |||
672 | int rc; | 682 | int rc; |
673 | 683 | ||
674 | if (force) { | 684 | if (force) { |
675 | rc = driver_register(&tis_drv); | 685 | rc = platform_driver_register(&tis_drv); |
676 | if (rc < 0) | 686 | if (rc < 0) |
677 | return rc; | 687 | return rc; |
678 | if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0))) | 688 | if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0))) |
679 | return PTR_ERR(pdev); | 689 | return PTR_ERR(pdev); |
680 | if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) { | 690 | if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) { |
681 | platform_device_unregister(pdev); | 691 | platform_device_unregister(pdev); |
682 | driver_unregister(&tis_drv); | 692 | platform_driver_unregister(&tis_drv); |
683 | } | 693 | } |
684 | return rc; | 694 | return rc; |
685 | } | 695 | } |
@@ -711,7 +721,7 @@ static void __exit cleanup_tis(void) | |||
711 | 721 | ||
712 | if (force) { | 722 | if (force) { |
713 | platform_device_unregister(pdev); | 723 | platform_device_unregister(pdev); |
714 | driver_unregister(&tis_drv); | 724 | platform_driver_unregister(&tis_drv); |
715 | } else | 725 | } else |
716 | pnp_unregister_driver(&tis_pnp_driver); | 726 | pnp_unregister_driver(&tis_pnp_driver); |
717 | } | 727 | } |
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 4f3b3f95fc4..d94d25c12aa 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c | |||
@@ -479,18 +479,18 @@ static const struct file_operations vcs_fops = { | |||
479 | 479 | ||
480 | static struct class *vc_class; | 480 | static struct class *vc_class; |
481 | 481 | ||
482 | void vcs_make_sysfs(struct tty_struct *tty) | 482 | void vcs_make_sysfs(int index) |
483 | { | 483 | { |
484 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), NULL, | 484 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, |
485 | "vcs%u", tty->index + 1); | 485 | "vcs%u", index + 1); |
486 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), NULL, | 486 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, |
487 | "vcsa%u", tty->index + 1); | 487 | "vcsa%u", index + 1); |
488 | } | 488 | } |
489 | 489 | ||
490 | void vcs_remove_sysfs(struct tty_struct *tty) | 490 | void vcs_remove_sysfs(int index) |
491 | { | 491 | { |
492 | device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); | 492 | device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); |
493 | device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); | 493 | device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); |
494 | } | 494 | } |
495 | 495 | ||
496 | int __init vcs_init(void) | 496 | int __init vcs_init(void) |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7900bd63b36..2c1d133819b 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -778,6 +778,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
778 | } | 778 | } |
779 | vc->vc_kmalloced = 1; | 779 | vc->vc_kmalloced = 1; |
780 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); | 780 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); |
781 | vcs_make_sysfs(currcons); | ||
781 | atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); | 782 | atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); |
782 | } | 783 | } |
783 | return 0; | 784 | return 0; |
@@ -987,7 +988,9 @@ void vc_deallocate(unsigned int currcons) | |||
987 | if (vc_cons_allocated(currcons)) { | 988 | if (vc_cons_allocated(currcons)) { |
988 | struct vc_data *vc = vc_cons[currcons].d; | 989 | struct vc_data *vc = vc_cons[currcons].d; |
989 | struct vt_notifier_param param = { .vc = vc }; | 990 | struct vt_notifier_param param = { .vc = vc }; |
991 | |||
990 | atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); | 992 | atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); |
993 | vcs_remove_sysfs(currcons); | ||
991 | vc->vc_sw->con_deinit(vc); | 994 | vc->vc_sw->con_deinit(vc); |
992 | put_pid(vc->vt_pid); | 995 | put_pid(vc->vt_pid); |
993 | module_put(vc->vc_sw->owner); | 996 | module_put(vc->vc_sw->owner); |
@@ -2775,7 +2778,6 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2775 | tty->termios->c_iflag |= IUTF8; | 2778 | tty->termios->c_iflag |= IUTF8; |
2776 | else | 2779 | else |
2777 | tty->termios->c_iflag &= ~IUTF8; | 2780 | tty->termios->c_iflag &= ~IUTF8; |
2778 | vcs_make_sysfs(tty); | ||
2779 | release_console_sem(); | 2781 | release_console_sem(); |
2780 | return ret; | 2782 | return ret; |
2781 | } | 2783 | } |
@@ -2795,7 +2797,6 @@ static void con_shutdown(struct tty_struct *tty) | |||
2795 | BUG_ON(vc == NULL); | 2797 | BUG_ON(vc == NULL); |
2796 | acquire_console_sem(); | 2798 | acquire_console_sem(); |
2797 | vc->vc_tty = NULL; | 2799 | vc->vc_tty = NULL; |
2798 | vcs_remove_sysfs(tty); | ||
2799 | release_console_sem(); | 2800 | release_console_sem(); |
2800 | tty_shutdown(tty); | 2801 | tty_shutdown(tty); |
2801 | } | 2802 | } |