diff options
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 52f4361eb6e4..d765afda9c2a 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, nb_order = (nb_order >> 1) & 7; pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); nb_aper = nb_base << 25; - if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) { - return 0; - } /* Northbridge seems to contain crap. Try the AGP bridge. */ pci_read_config_word(agp, cap+0x14, &apsize); - if (apsize == 0xffff) + if (apsize == 0xffff) { + if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) + return 0; return -1; + } apsize &= 0xfff; /* 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, order = nb_order; } + if (nb_order >= order) { + if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) + return 0; + } + dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", aper, 32 << order); 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 c7714185f831..4373adb2119a 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) break; } } - if (gtt_entries > 0) + if (gtt_entries > 0) { dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); - else + gtt_entries /= KB(4); + } else { dev_info(&agp_bridge->dev->dev, "no pre-allocated video memory detected\n"); - gtt_entries /= KB(4); + gtt_entries = 0; + } intel_private.gtt_entries = gtt_entries; } diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index db60539bf67a..699e3422ad93 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -359,9 +359,16 @@ fail: return error; } -static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); - return n ? container_of(n, struct device, knode_parent) : NULL; +static int +find_quicksilver(struct device *dev, void *data) +{ + struct parisc_device **lba = data; + struct parisc_device *padev = to_parisc_device(dev); + + if (IS_QUICKSILVER(padev)) + *lba = padev; + + return 0; } static int @@ -372,8 +379,6 @@ parisc_agp_init(void) int err = -1; struct parisc_device *sba = NULL, *lba = NULL; struct lba_device *lbadev = NULL; - struct device *dev = NULL; - struct klist_iter i; if (!sba_list) goto out; @@ -386,13 +391,7 @@ parisc_agp_init(void) } /* Now search our Pluto for our precious AGP device... */ - klist_iter_init(&sba->dev.klist_children, &i); - while ((dev = next_device(&i))) { - struct parisc_device *padev = to_parisc_device(dev); - if (IS_QUICKSILVER(padev)) - lba = padev; - } - klist_iter_exit(&i); + device_for_each_child(&sba->dev, &lba, find_quicksilver); if (!lba) { printk(KERN_INFO DRVPFX "No AGP devices found.\n"); diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 6e6eb445d374..c76bccf5354d 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) hvcsd->tty = tty; tty->driver_data = hvcsd; - /* - * Set this driver to low latency so that we actually have a chance at - * catching a throttled TTY after we flip_buffer_push. Otherwise the - * flush_to_async may not execute until after the kernel_thread has - * yielded and resumed the next flip_buffer_push resulting in data - * loss. - */ - tty->low_latency = 1; - memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); /* diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 406f8742a260..2989056a9e39 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) hp = &hvsi_ports[line]; tty->driver_data = hp; - tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */ mb(); if (hp->state == HVSI_FSP_DIED) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 8822eca58ffa..5fab6470f4b2 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -20,6 +20,20 @@ config HW_RANDOM If unsure, say Y. +config HW_RANDOM_TIMERIOMEM + tristate "Timer IOMEM HW Random Number Generator support" + depends on HW_RANDOM && HAS_IOMEM + ---help--- + This driver provides kernel-side support for a generic Random + Number Generator used by reading a 'dumb' iomem address that + is to be read no faster than, for example, once a second; + the default FPGA bitstream on the TS-7800 has such functionality. + + To compile this driver as a module, choose M here: the + module will be called timeriomem-rng. + + If unsure, say Y. + config HW_RANDOM_INTEL tristate "Intel HW Random Number Generator support" depends on HW_RANDOM && (X86 || IA64) && PCI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index b6effb7522c2..e81d21a5f28f 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_HW_RANDOM) += rng-core.o rng-core-y := core.o +obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o 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 000000000000..10ad41be5897 --- /dev/null +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -0,0 +1,151 @@ +/* + * drivers/char/hw_random/timeriomem-rng.c + * + * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk> + * + * Derived from drivers/char/hw_random/omap-rng.c + * Copyright 2005 (c) MontaVista Software, Inc. + * Author: Deepak Saxena <dsaxena@plexity.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This driver is useful for platforms that have an IO range that provides + * periodic random data from a single IO memory address. All the platform + * has to do is provide the address and 'wait time' that new data becomes + * available. + * + * TODO: add support for reading sizes other than 32bits and masking + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/hw_random.h> +#include <linux/io.h> +#include <linux/timeriomem-rng.h> +#include <linux/jiffies.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/completion.h> + +static struct timeriomem_rng_data *timeriomem_rng_data; + +static void timeriomem_rng_trigger(unsigned long); +static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0); + +/* + * have data return 1, however return 0 if we have nothing + */ +static int timeriomem_rng_data_present(struct hwrng *rng, int wait) +{ + if (rng->priv == 0) + return 1; + + if (!wait || timeriomem_rng_data->present) + return timeriomem_rng_data->present; + + wait_for_completion(&timeriomem_rng_data->completion); + + return 1; +} + +static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data) +{ + unsigned long cur; + s32 delay; + + *data = readl(timeriomem_rng_data->address); + + if (rng->priv != 0) { + cur = jiffies; + + delay = cur - timeriomem_rng_timer.expires; + delay = rng->priv - (delay % rng->priv); + + timeriomem_rng_timer.expires = cur + delay; + timeriomem_rng_data->present = 0; + + init_completion(&timeriomem_rng_data->completion); + add_timer(&timeriomem_rng_timer); + } + + return 4; +} + +static void timeriomem_rng_trigger(unsigned long dummy) +{ + timeriomem_rng_data->present = 1; + complete(&timeriomem_rng_data->completion); +} + +static struct hwrng timeriomem_rng_ops = { + .name = "timeriomem", + .data_present = timeriomem_rng_data_present, + .data_read = timeriomem_rng_data_read, + .priv = 0, +}; + +static int __init timeriomem_rng_probe(struct platform_device *pdev) +{ + int ret; + + timeriomem_rng_data = pdev->dev.platform_data; + + if (timeriomem_rng_data->period != 0 + && usecs_to_jiffies(timeriomem_rng_data->period) > 0) { + timeriomem_rng_timer.expires = jiffies; + + timeriomem_rng_ops.priv = usecs_to_jiffies( + timeriomem_rng_data->period); + } + timeriomem_rng_data->present = 1; + + ret = hwrng_register(&timeriomem_rng_ops); + if (ret) { + dev_err(&pdev->dev, "problem registering\n"); + return ret; + } + + dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", + timeriomem_rng_data->address, + timeriomem_rng_data->period); + + return 0; +} + +static int __devexit timeriomem_rng_remove(struct platform_device *pdev) +{ + del_timer_sync(&timeriomem_rng_timer); + hwrng_unregister(&timeriomem_rng_ops); + + return 0; +} + +static struct platform_driver timeriomem_rng_driver = { + .driver = { + .name = "timeriomem_rng", + .owner = THIS_MODULE, + }, + .probe = timeriomem_rng_probe, + .remove = __devexit_p(timeriomem_rng_remove), +}; + +static int __init timeriomem_rng_init(void) +{ + return platform_driver_register(&timeriomem_rng_driver); +} + +static void __exit timeriomem_rng_exit(void) +{ + platform_driver_unregister(&timeriomem_rng_driver); +} + +module_init(timeriomem_rng_init); +module_exit(timeriomem_rng_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>"); +MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver"); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9c47dc48c9fd..ccdd828adcef 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -429,134 +429,148 @@ out: #define TPM_DIGEST_SIZE 20 #define TPM_ERROR_SIZE 10 #define TPM_RET_CODE_IDX 6 -#define TPM_GET_CAP_RET_SIZE_IDX 10 -#define TPM_GET_CAP_RET_UINT32_1_IDX 14 -#define TPM_GET_CAP_RET_UINT32_2_IDX 18 -#define TPM_GET_CAP_RET_UINT32_3_IDX 22 -#define TPM_GET_CAP_RET_UINT32_4_IDX 26 -#define TPM_GET_CAP_PERM_DISABLE_IDX 16 -#define TPM_GET_CAP_PERM_INACTIVE_IDX 18 -#define TPM_GET_CAP_RET_BOOL_1_IDX 14 -#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 - -#define TPM_CAP_IDX 13 -#define TPM_CAP_SUBCAP_IDX 21 enum tpm_capabilities { - TPM_CAP_FLAG = 4, - TPM_CAP_PROP = 5, + TPM_CAP_FLAG = cpu_to_be32(4), + TPM_CAP_PROP = cpu_to_be32(5), + CAP_VERSION_1_1 = cpu_to_be32(0x06), + CAP_VERSION_1_2 = cpu_to_be32(0x1A) }; enum tpm_sub_capabilities { - TPM_CAP_PROP_PCR = 0x1, - TPM_CAP_PROP_MANUFACTURER = 0x3, - TPM_CAP_FLAG_PERM = 0x8, - TPM_CAP_FLAG_VOL = 0x9, - TPM_CAP_PROP_OWNER = 0x11, - TPM_CAP_PROP_TIS_TIMEOUT = 0x15, - TPM_CAP_PROP_TIS_DURATION = 0x20, -}; + TPM_CAP_PROP_PCR = cpu_to_be32(0x101), + TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), + TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), + TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), + TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), + TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), + TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), -/* - * This is a semi generic GetCapability command for use - * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG - * and their associated sub_capabilities. - */ - -static const u8 tpm_cap[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 22, /* length */ - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 0, /* TPM_CAP_<TYPE> */ - 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */ - 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */ }; -static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, - char *desc) +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, + int len, const char *desc) { int err; - len = tpm_transmit(chip, data, len); + len = tpm_transmit(chip,(u8 *) cmd, len); if (len < 0) return len; if (len == TPM_ERROR_SIZE) { - err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); + err = be32_to_cpu(cmd->header.out.return_code); dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); return err; } return 0; } +#define TPM_INTERNAL_RESULT_SIZE 200 +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193) +#define TPM_ORD_GET_CAP cpu_to_be32(101) + +static const struct tpm_input_header tpm_getcap_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(22), + .ordinal = TPM_ORD_GET_CAP +}; + +ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, + const char *desc) +{ + struct tpm_cmd_t tpm_cmd; + int rc; + struct tpm_chip *chip = dev_get_drvdata(dev); + + tpm_cmd.header.in = tpm_getcap_header; + if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { + tpm_cmd.params.getcap_in.cap = subcap_id; + /*subcap field not necessary */ + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); + tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); + } else { + if (subcap_id == TPM_CAP_FLAG_PERM || + subcap_id == TPM_CAP_FLAG_VOL) + tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; + else + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = subcap_id; + } + rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + if (!rc) + *cap = tpm_cmd.params.getcap_out.cap; + return rc; +} + void tpm_gen_interrupt(struct tpm_chip *chip) { - u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + struct tpm_cmd_t tpm_cmd; ssize_t rc; - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + tpm_cmd.header.in = tpm_getcap_header; + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, data, sizeof(data), + rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); void tpm_get_timeouts(struct tpm_chip *chip) { - u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + struct tpm_cmd_t tpm_cmd; + struct timeout_t *timeout_cap; + struct duration_t *duration_cap; ssize_t rc; u32 timeout; - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + tpm_cmd.header.in = tpm_getcap_header; + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, data, sizeof(data), + rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, "attempting to determine the timeouts"); if (rc) goto duration; - if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + if (be32_to_cpu(tpm_cmd.header.out.length) != 4 * sizeof(u32)) goto duration; + timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; /* Don't overwrite default if value is 0 */ - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + timeout = be32_to_cpu(timeout_cap->a); if (timeout) chip->vendor.timeout_a = usecs_to_jiffies(timeout); - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + timeout = be32_to_cpu(timeout_cap->b); if (timeout) chip->vendor.timeout_b = usecs_to_jiffies(timeout); - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + timeout = be32_to_cpu(timeout_cap->c); if (timeout) chip->vendor.timeout_c = usecs_to_jiffies(timeout); - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); + timeout = be32_to_cpu(timeout_cap->d); if (timeout) chip->vendor.timeout_d = usecs_to_jiffies(timeout); duration: - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; + tpm_cmd.header.in = tpm_getcap_header; + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = transmit_cmd(chip, data, sizeof(data), + rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, "attempting to determine the durations"); if (rc) return; - if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + if (be32_to_cpu(tpm_cmd.header.out.return_code) != 3 * sizeof(u32)) return; - + duration_cap = &tpm_cmd.params.getcap_out.cap.duration; chip->vendor.duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu - (*((__be32 *) (data + - TPM_GET_CAP_RET_UINT32_1_IDX)))); + usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above * value wrong and apparently reports msecs rather than usecs. So we * fix up the resulting too-small TPM_SHORT value to make things work. @@ -565,13 +579,9 @@ duration: chip->vendor.duration[TPM_SHORT] = HZ; chip->vendor.duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu - (*((__be32 *) (data + - TPM_GET_CAP_RET_UINT32_2_IDX)))); + usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); chip->vendor.duration[TPM_LONG] = - usecs_to_jiffies(be32_to_cpu - (*((__be32 *) (data + - TPM_GET_CAP_RET_UINT32_3_IDX)))); + usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); } EXPORT_SYMBOL_GPL(tpm_get_timeouts); @@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_continue_selftest); -#define TPM_INTERNAL_RESULT_SIZE 200 - ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, char *buf) { - u8 *data; + cap_t cap; ssize_t rc; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_FLAG; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; - - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attemtping to determine the permanent enabled state"); - if (rc) { - kfree(data); + rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, + "attempting to determine the permanent enabled state"); + if (rc) return 0; - } - - rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); - kfree(data); + rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); return rc; } EXPORT_SYMBOL_GPL(tpm_show_enabled); @@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled); ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, char *buf) { - u8 *data; + cap_t cap; ssize_t rc; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_FLAG; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; - - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attemtping to determine the permanent active state"); - if (rc) { - kfree(data); + rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, + "attempting to determine the permanent active state"); + if (rc) return 0; - } - rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); - - kfree(data); + rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); return rc; } EXPORT_SYMBOL_GPL(tpm_show_active); @@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active); ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, char *buf) { - u8 *data; + cap_t cap; ssize_t rc; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; - - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the owner state"); - if (rc) { - kfree(data); + rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, + "attempting to determine the owner state"); + if (rc) return 0; - } - - rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); - kfree(data); + rc = sprintf(buf, "%d\n", cap.owned); return rc; } EXPORT_SYMBOL_GPL(tpm_show_owned); @@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned); ssize_t tpm_show_temp_deactivated(struct device * dev, struct device_attribute * attr, char *buf) { - u8 *data; + cap_t cap; ssize_t rc; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; + rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, + "attempting to determine the temporary state"); + if (rc) + return 0; - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; + rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_FLAG; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; +/* + * tpm_chip_find_get - return tpm_chip for given chip number + */ +static struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + struct tpm_chip *pos, *chip = NULL; - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the temporary state"); - if (rc) { - kfree(data); - return 0; + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) + continue; + + if (try_module_get(pos->dev->driver->owner)) { + chip = pos; + break; + } } + rcu_read_unlock(); + return chip; +} - rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); +#define TPM_ORDINAL_PCRREAD cpu_to_be32(21) +#define READ_PCR_RESULT_SIZE 30 +static struct tpm_input_header pcrread_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(14), + .ordinal = TPM_ORDINAL_PCRREAD +}; - kfree(data); +int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) +{ + int rc; + struct tpm_cmd_t cmd; + + cmd.header.in = pcrread_header; + cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); + BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE); + rc = transmit_cmd(chip, &cmd, cmd.header.in.length, + "attempting to read a pcr value"); + + if (rc == 0) + memcpy(res_buf, cmd.params.pcrread_out.pcr_result, + TPM_DIGEST_SIZE); return rc; } -EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); -static const u8 pcrread[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 14, /* length */ - 0, 0, 0, 21, /* TPM_ORD_PcrRead */ - 0, 0, 0, 0 /* PCR index */ +/** + * tpm_pcr_read - read a pcr value + * @chip_num: tpm idx # or ANY + * @pcr_idx: pcr idx to retrieve + * @res_buf: TPM_PCR value + * size of res_buf is 20 bytes (or NULL if you don't care) + * + * The TPM driver should be built-in, but for whatever reason it + * isn't, protect against the chip disappearing, by incrementing + * the module usage count. + */ +int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +{ + struct tpm_chip *chip; + int rc; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL) + return -ENODEV; + rc = __tpm_pcr_read(chip, pcr_idx, res_buf); + module_put(chip->dev->driver->owner); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_pcr_read); + +/** + * tpm_pcr_extend - extend pcr value with hash + * @chip_num: tpm idx # or AN& + * @pcr_idx: pcr idx to extend + * @hash: hash value used to extend pcr value + * + * The TPM driver should be built-in, but for whatever reason it + * isn't, protect against the chip disappearing, by incrementing + * the module usage count. + */ +#define TPM_ORD_PCR_EXTEND cpu_to_be32(20) +#define EXTEND_PCR_SIZE 34 +static struct tpm_input_header pcrextend_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(34), + .ordinal = TPM_ORD_PCR_EXTEND }; +int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +{ + struct tpm_cmd_t cmd; + int rc; + struct tpm_chip *chip; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL) + return -ENODEV; + + cmd.header.in = pcrextend_header; + BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE); + cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); + memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); + rc = transmit_cmd(chip, &cmd, cmd.header.in.length, + "attempting extend a PCR value"); + + module_put(chip->dev->driver->owner); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_pcr_extend); + ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 *data; + cap_t cap; + u8 digest[TPM_DIGEST_SIZE]; ssize_t rc; int i, j, num_pcrs; - __be32 index; char *str = buf; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; - - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, "attempting to determine the number of PCRS"); - if (rc) { - kfree(data); + if (rc) return 0; - } - num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); + num_pcrs = be32_to_cpu(cap.num_pcrs); for (i = 0; i < num_pcrs; i++) { - memcpy(data, pcrread, sizeof(pcrread)); - index = cpu_to_be32(i); - memcpy(data + 10, &index, 4); - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attempting to read a PCR"); + rc = __tpm_pcr_read(chip, i, digest); if (rc) - goto out; + break; str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) - str += sprintf(str, "%02X ", *(data + 10 + j)); + str += sprintf(str, "%02X ", digest[j]); str += sprintf(str, "\n"); } -out: - kfree(data); return str - buf; } EXPORT_SYMBOL_GPL(tpm_show_pcrs); #define READ_PUBEK_RESULT_SIZE 314 -static const u8 readpubek[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 30, /* length */ - 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ +#define TPM_ORD_READPUBEK cpu_to_be32(124) +struct tpm_input_header tpm_readpubek_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(30), + .ordinal = TPM_ORD_READPUBEK }; ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, char *buf) { u8 *data; + struct tpm_cmd_t tpm_cmd; ssize_t err; int i, rc; char *str = buf; struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, readpubek, sizeof(readpubek)); - - err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, + tpm_cmd.header.in = tpm_readpubek_header; + err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, "attempting to read the PUBEK"); if (err) goto out; @@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, 256 byte modulus ignore checksum 20 bytes */ - + data = tpm_cmd.params.readpubek_out_buffer; str += sprintf(str, "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, } out: rc = str - buf; - kfree(data); return rc; } EXPORT_SYMBOL_GPL(tpm_show_pubek); -#define CAP_VERSION_1_1 6 -#define CAP_VERSION_1_2 0x1A -#define CAP_VERSION_IDX 13 -static const u8 cap_version[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 18, /* length */ - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 0, - 0, 0, 0, 0 -}; ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, char *buf) { - u8 *data; + cap_t cap; ssize_t rc; char *str = buf; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; - - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, "attempting to determine the manufacturer"); - if (rc) { - kfree(data); + if (rc) return 0; - } - str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); + be32_to_cpu(cap.manufacturer_id)); - memcpy(data, cap_version, sizeof(cap_version)); - data[CAP_VERSION_IDX] = CAP_VERSION_1_1; - rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the 1.1 version"); + rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, + "attempting to determine the 1.1 version"); if (rc) - goto out; - + return 0; str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", - (int) data[14], (int) data[15], (int) data[16], - (int) data[17]); - -out: - kfree(data); + cap.tpm_version.Major, cap.tpm_version.Minor, + cap.tpm_version.revMajor, cap.tpm_version.revMinor); return str - buf; } EXPORT_SYMBOL_GPL(tpm_show_caps); @@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps); ssize_t tpm_show_caps_1_2(struct device * dev, struct device_attribute * attr, char *buf) { - u8 *data; - ssize_t len; + cap_t cap; + ssize_t rc; char *str = buf; - struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip == NULL) - return -ENODEV; - - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); - if (!data) - return -ENOMEM; - - memcpy(data, tpm_cap, sizeof(tpm_cap)); - data[TPM_CAP_IDX] = TPM_CAP_PROP; - data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; - - len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); - if (len <= TPM_ERROR_SIZE) { - dev_dbg(chip->dev, "A TPM error (%d) occurred " - "attempting to determine the manufacturer\n", - be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); - kfree(data); + rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, + "attempting to determine the manufacturer"); + if (rc) return 0; - } - str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); - - memcpy(data, cap_version, sizeof(cap_version)); - data[CAP_VERSION_IDX] = CAP_VERSION_1_2; - - len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); - if (len <= TPM_ERROR_SIZE) { - dev_err(chip->dev, "A TPM error (%d) occurred " - "attempting to determine the 1.2 version\n", - be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); - goto out; - } + be32_to_cpu(cap.manufacturer_id)); + rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, + "attempting to determine the 1.2 version"); + if (rc) + return 0; str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", - (int) data[16], (int) data[17], (int) data[18], - (int) data[19]); - -out: - kfree(data); + cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, + cap.tpm_version_1_2.revMajor, + cap.tpm_version_1_2.revMinor); return str - buf; } EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8e30df4a4388..8e00b4ddd083 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -26,6 +26,7 @@ #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/tpm.h> enum tpm_timeout { TPM_TIMEOUT = 5, /* msecs */ @@ -123,6 +124,147 @@ static inline void tpm_write_index(int base, int index, int value) outb(index, base); outb(value & 0xFF, base+1); } +struct tpm_input_header { + __be16 tag; + __be32 length; + __be32 ordinal; +}__attribute__((packed)); + +struct tpm_output_header { + __be16 tag; + __be32 length; + __be32 return_code; +}__attribute__((packed)); + +struct stclear_flags_t { + __be16 tag; + u8 deactivated; + u8 disableForceClear; + u8 physicalPresence; + u8 physicalPresenceLock; + u8 bGlobalLock; +}__attribute__((packed)); + +struct tpm_version_t { + u8 Major; + u8 Minor; + u8 revMajor; + u8 revMinor; +}__attribute__((packed)); + +struct tpm_version_1_2_t { + __be16 tag; + u8 Major; + u8 Minor; + u8 revMajor; + u8 revMinor; +}__attribute__((packed)); + +struct timeout_t { + __be32 a; + __be32 b; + __be32 c; + __be32 d; +}__attribute__((packed)); + +struct duration_t { + __be32 tpm_short; + __be32 tpm_medium; + __be32 tpm_long; +}__attribute__((packed)); + +struct permanent_flags_t { + __be16 tag; + u8 disable; + u8 ownership; + u8 deactivated; + u8 readPubek; + u8 disableOwnerClear; + u8 allowMaintenance; + u8 physicalPresenceLifetimeLock; + u8 physicalPresenceHWEnable; + u8 physicalPresenceCMDEnable; + u8 CEKPUsed; + u8 TPMpost; + u8 TPMpostLock; + u8 FIPS; + u8 operator; + u8 enableRevokeEK; + u8 nvLocked; + u8 readSRKPub; + u8 tpmEstablished; + u8 maintenanceDone; + u8 disableFullDALogicInfo; +}__attribute__((packed)); + +typedef union { + struct permanent_flags_t perm_flags; + struct stclear_flags_t stclear_flags; + bool owned; + __be32 num_pcrs; + struct tpm_version_t tpm_version; + struct tpm_version_1_2_t tpm_version_1_2; + __be32 manufacturer_id; + struct timeout_t timeout; + struct duration_t duration; +} cap_t; + +struct tpm_getcap_params_in { + __be32 cap; + __be32 subcap_size; + __be32 subcap; +}__attribute__((packed)); + +struct tpm_getcap_params_out { + __be32 cap_size; + cap_t cap; +}__attribute__((packed)); + +struct tpm_readpubek_params_out { + u8 algorithm[4]; + u8 encscheme[2]; + u8 sigscheme[2]; + u8 parameters[12]; /*assuming RSA*/ + __be32 keysize; + u8 modulus[256]; + u8 checksum[20]; +}__attribute__((packed)); + +typedef union { + struct tpm_input_header in; + struct tpm_output_header out; +} tpm_cmd_header; + +#define TPM_DIGEST_SIZE 20 +struct tpm_pcrread_out { + u8 pcr_result[TPM_DIGEST_SIZE]; +}__attribute__((packed)); + +struct tpm_pcrread_in { + __be32 pcr_idx; +}__attribute__((packed)); + +struct tpm_pcrextend_in { + __be32 pcr_idx; + u8 hash[TPM_DIGEST_SIZE]; +}__attribute__((packed)); + +typedef union { + struct tpm_getcap_params_out getcap_out; + struct tpm_readpubek_params_out readpubek_out; + u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; + struct tpm_getcap_params_in getcap_in; + struct tpm_pcrread_in pcrread_in; + struct tpm_pcrread_out pcrread_out; + struct tpm_pcrextend_in pcrextend_in; +} tpm_cmd_params; + +struct tpm_cmd_t { + tpm_cmd_header header; + tpm_cmd_params params; +}__attribute__((packed)); + +ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); extern void tpm_get_timeouts(struct tpm_chip *); 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 d0e7926eb486..c64a1bc65349 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) } } -static struct device_driver atml_drv = { - .name = "tpm_atmel", - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, +static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg) +{ + return tpm_pm_suspend(&dev->dev, msg); +} + +static int tpm_atml_resume(struct platform_device *dev) +{ + return tpm_pm_resume(&dev->dev); +} +static struct platform_driver atml_drv = { + .driver = { + .name = "tpm_atmel", + .owner = THIS_MODULE, + }, + .suspend = tpm_atml_suspend, + .resume = tpm_atml_resume, }; static int __init init_atmel(void) @@ -184,7 +194,7 @@ static int __init init_atmel(void) unsigned long base; struct tpm_chip *chip; - rc = driver_register(&atml_drv); + rc = platform_driver_register(&atml_drv); if (rc) return rc; @@ -223,13 +233,13 @@ err_rel_reg: atmel_release_region(base, region_size); err_unreg_drv: - driver_unregister(&atml_drv); + platform_driver_unregister(&atml_drv); return rc; } static void __exit cleanup_atmel(void) { - driver_unregister(&atml_drv); + platform_driver_unregister(&atml_drv); atml_plat_remove(); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 717af7ad1bdf..aec1931608aa 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, sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); -static struct device_driver tis_drv = { - .name = "tpm_tis", - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, +static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg) +{ + return tpm_pm_suspend(&dev->dev, msg); +} + +static int tpm_tis_resume(struct platform_device *dev) +{ + return tpm_pm_resume(&dev->dev); +} +static struct platform_driver tis_drv = { + .driver = { + .name = "tpm_tis", + .owner = THIS_MODULE, + }, + .suspend = tpm_tis_suspend, + .resume = tpm_tis_resume, }; static struct platform_device *pdev; @@ -672,14 +682,14 @@ static int __init init_tis(void) int rc; if (force) { - rc = driver_register(&tis_drv); + rc = platform_driver_register(&tis_drv); if (rc < 0) return rc; if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0))) return PTR_ERR(pdev); if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) { platform_device_unregister(pdev); - driver_unregister(&tis_drv); + platform_driver_unregister(&tis_drv); } return rc; } @@ -711,7 +721,7 @@ static void __exit cleanup_tis(void) if (force) { platform_device_unregister(pdev); - driver_unregister(&tis_drv); + platform_driver_unregister(&tis_drv); } else pnp_unregister_driver(&tis_pnp_driver); } diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 4f3b3f95fc42..d94d25c12aa8 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -479,18 +479,18 @@ static const struct file_operations vcs_fops = { static struct class *vc_class; -void vcs_make_sysfs(struct tty_struct *tty) +void vcs_make_sysfs(int index) { - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), NULL, - "vcs%u", tty->index + 1); - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), NULL, - "vcsa%u", tty->index + 1); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, + "vcs%u", index + 1); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, + "vcsa%u", index + 1); } -void vcs_remove_sysfs(struct tty_struct *tty) +void vcs_remove_sysfs(int index) { - device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); - device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); + device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); + device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); } int __init vcs_init(void) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7900bd63b36d..2c1d133819b5 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 */ } vc->vc_kmalloced = 1; vc_init(vc, vc->vc_rows, vc->vc_cols, 1); + vcs_make_sysfs(currcons); atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); } return 0; @@ -987,7 +988,9 @@ void vc_deallocate(unsigned int currcons) if (vc_cons_allocated(currcons)) { struct vc_data *vc = vc_cons[currcons].d; struct vt_notifier_param param = { .vc = vc }; + atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); + vcs_remove_sysfs(currcons); vc->vc_sw->con_deinit(vc); put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); @@ -2775,7 +2778,6 @@ static int con_open(struct tty_struct *tty, struct file *filp) tty->termios->c_iflag |= IUTF8; else tty->termios->c_iflag &= ~IUTF8; - vcs_make_sysfs(tty); release_console_sem(); return ret; } @@ -2795,7 +2797,6 @@ static void con_shutdown(struct tty_struct *tty) BUG_ON(vc == NULL); acquire_console_sem(); vc->vc_tty = NULL; - vcs_remove_sysfs(tty); release_console_sem(); tty_shutdown(tty); } |