From eb0e71c7f388bfcb3f74897f23d0cf09310fc05b Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Mon, 10 Jul 2006 04:43:59 -0700 Subject: [PATCH] Add Computone IntelliPort Plus serial hotplug support Patch Description: Add "Computone IntelliPort Plus serial" hotplug support patch location: http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=8c36723187c0fa5efe0e5c6a9b1e66ed4b824792 [akpm@osdl.org: cleanup] Cc: Randy Dunlap Signed-off-by: Chuck Short Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ip2/ip2main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 518ece7ac65..7907ae88c2f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -3186,3 +3186,10 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo MODULE_LICENSE("GPL"); + +static struct pci_device_id ip2main_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl); -- cgit v1.2.3 From 7691030bc9732f7d535522dda78cfdd36716def1 Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Mon, 10 Jul 2006 04:43:59 -0700 Subject: [PATCH] Add Specialix IO8+ card support hotplug support Patch Description: Add "Specialix IO8+ card support" hotplug support patch location: http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=d795cfc591bb44f6b3d86d8f054a227cecb44bb4 [akpm@osdl.org: cleanup] Cc: Randy Dunlap Signed-off-by: Chuck Short Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/specialix.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index cb2859249d4..a1d303f9a33 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2584,6 +2584,12 @@ static void __exit specialix_exit_module(void) func_exit(); } +static struct pci_device_id specialx_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) }, + { } +}; +MODULE_DEVICE_TABLE(pci, specialx_pci_tbl); + module_init(specialix_init_module); module_exit(specialix_exit_module); -- cgit v1.2.3 From 6e99e4582861578fb00d84d085f8f283569f51dd Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:42 -0700 Subject: [PATCH] powerpc: fix trigger handling in the new irq code This patch slightly reworks the new irq code to fix a small design error. I removed the passing of the trigger to the map() calls entirely, it was not a good idea to have one call do two different things. It also fixes a couple of corner cases. Mapping a linux virtual irq to a physical irq now does only that. Setting the trigger is a different action which has a different call. The main changes are: - I no longer call host->ops->map() for an already mapped irq, I just return the virtual number that was already mapped. It was called before to give an opportunity to change the trigger, but that was causing issues as that could happen while the interrupt was in use by a device, and because of the trigger change, map would potentially muck around with things in a racy way. That was causing much burden on a given's controller implementation of map() to get it right. This is much simpler now. map() is only called on the initial mapping of an irq, meaning that you know that this irq is _not_ being used. You can initialize the hardware if you want (though you don't have to). - Controllers that can handle different type of triggers (level/edge/etc...) now implement the standard irq_chip->set_type() call as defined by the generic code. That means that you can use the standard set_irq_type() to configure an irq line manually if you wish or (though I don't like that interface), pass explicit trigger flags to request_irq() as defined by the generic kernel interfaces. Also, using those interfaces guarantees that your controller set_type callback is called with the descriptor lock held, thus providing locking against activity on the same interrupt (including mask/unmask/etc...) automatically. A result is that, for example, MPIC's own map() implementation calls irq_set_type(NONE) to configure the hardware to the default triggers. - To allow the above, the irq_map array entry for the new mapped interrupt is now set before map() callback is called for the controller. - The irq_create_of_mapping() (also used by irq_of_parse_and_map()) function for mapping interrupts from the device-tree now also call the separate set_irq_type(), and only does so if there is a change in the trigger type. - While I was at it, I changed pci_read_irq_line() (which is the helper I would expect most archs to use in their pcibios_fixup() to get the PCI interrupt routing from the device tree) to also handle a fallback when the DT mapping fails consisting of reading the PCI_INTERRUPT_PIN to know wether the device has an interrupt at all, and the the PCI_INTERRUPT_LINE to get an interrupt number from the device. That number is then mapped using the default controller, and the trigger is set to level low. That default behaviour works for several platforms that don't have a proper interrupt tree like Pegasos. If it doesn't work for your platform, then either provide a proper interrupt tree from the firmware so that fallback isn't needed, or don't call pci_read_irq_line() - Add back a bit that got dropped by my main rework patch for properly clearing pending IPIs on pSeries when using a kexec Signed-off-by: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 56612a2dca6..41db8060e8f 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -1299,7 +1299,7 @@ static int __init hvsi_console_init(void) hp->inbuf_end = hp->inbuf; hp->state = HVSI_CLOSED; hp->vtermno = *vtermno; - hp->virq = irq_create_mapping(NULL, irq[0], 0); + hp->virq = irq_create_mapping(NULL, irq[0]); if (hp->virq == NO_IRQ) { printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", __FUNCTION__, irq[0]); -- cgit v1.2.3 From 06c67befeeb16f2995c11b0e04a348103ddbfab1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 10 Jul 2006 04:45:27 -0700 Subject: [PATCH] make valid_mmap_phys_addr_range() take a pfn Newer ARMs have a 40 bit physical address space, but mapping physical memory above 4G needs a special page table format which we (currently?) do not use for userspace mappings, so what happens instead is that mapping an address >= 4G will happily discard the upper bits and wrap. There is a valid_mmap_phys_addr_range() arch hook where we could check for >= 4G addresses and deny the mapping, but this hook takes an unsigned long address: static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t size); And drivers/char/mem.c:mmap_mem() calls it like this: static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size)) So that's not much help either. This patch makes the hook take a pfn instead of a phys address. Signed-off-by: Lennert Buytenhek Cc: Bjorn Helgaas Cc: "Luck, Tony" Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e97c32ceb79..917b2040266 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -95,7 +95,7 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t count) return 1; } -static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t size) +static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) { return 1; } @@ -242,7 +242,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; - if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size)) + if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) return -EINVAL; vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, -- cgit v1.2.3 From 38e0e8c0550eaed1af48ec5ad9ddb8a25e8b04ae Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 10 Jul 2006 04:45:30 -0700 Subject: [PATCH] char/rtc: Handle memory-mapped chips properly Handle memory-mapped chips properly, needed for example on DECstations. This support was in Linux 2.4 but for some reason got lost in 2.6. This patch is taken directly from the linux-mips repository. [akpm@osdl.org: cleanup] Signed-off-by: Maciej W. Rozycki Signed-off-by: Martin Michlmayr Cc: Paul Gortmaker Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/rtc.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index cc7bd1a3095..6ccc364c08d 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -46,13 +46,12 @@ * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer * CONFIG_HPET_EMULATE_RTC + * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. * 1.12ac Alan Cox: Allow read access to the day of week register */ #define RTC_VERSION "1.12ac" -#define RTC_IO_EXTENT 0x8 - /* * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with * interrupts disabled. Due to the index-port/data-port (0x70/0x71) @@ -337,7 +336,15 @@ static ssize_t rtc_read(struct file *file, char __user *buf, if (rtc_has_irq == 0) return -EIO; - if (count < sizeof(unsigned)) + /* + * Historically this function used to assume that sizeof(unsigned long) + * is the same in userspace and kernelspace. This lead to problems + * for configurations with multiple ABIs such a the MIPS o32 and 64 + * ABIs supported on the same kernel. So now we support read of both + * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the + * userspace ABI. + */ + if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) return -EINVAL; add_wait_queue(&rtc_wait, &wait); @@ -368,10 +375,12 @@ static ssize_t rtc_read(struct file *file, char __user *buf, schedule(); } while (1); - if (count < sizeof(unsigned long)) - retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); + if (count == sizeof(unsigned int)) + retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); else retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long); + if (!retval) + retval = count; out: current->state = TASK_RUNNING; remove_wait_queue(&rtc_wait, &wait); @@ -923,6 +932,9 @@ static int __init rtc_init(void) struct sparc_isa_device *isa_dev; #endif #endif +#ifndef __sparc__ + void *r; +#endif #ifdef __sparc__ for_each_ebus(ebus) { @@ -964,8 +976,13 @@ found: } no_irq: #else - if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) { - printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0)); + if (RTC_IOMAPPED) + r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); + else + r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); + if (!r) { + printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", + (long)(RTC_PORT(0))); return -EIO; } @@ -979,7 +996,10 @@ no_irq: if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); - release_region(RTC_PORT(0), RTC_IO_EXTENT); + if (RTC_IOMAPPED) + release_region(RTC_PORT(0), RTC_IO_EXTENT); + else + release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); return -EIO; } hpet_rtc_timer_init(); @@ -1079,7 +1099,10 @@ static void __exit rtc_exit (void) if (rtc_has_irq) free_irq (rtc_irq, &rtc_port); #else - release_region (RTC_PORT (0), RTC_IO_EXTENT); + if (RTC_IOMAPPED) + release_region(RTC_PORT(0), RTC_IO_EXTENT); + else + release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); #ifdef RTC_IRQ if (rtc_has_irq) free_irq (RTC_IRQ, NULL); -- cgit v1.2.3 From 4f197842d0f3dd994882407f8760f2eda9005191 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Mon, 10 Jul 2006 04:45:35 -0700 Subject: [PATCH] pc8736x_gpio: fix re-modprobe errors: define and use constants add constant defines - preparatory patch - adds #define CONSTs for max-pin, gpio-addr-range (for reserving region) - fix wrong max-pin check in gpio_open() - add 'Winbond' to module description. NSC sold the product, Winbond has supported us / lm-sensors Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 4005ee0aa11..5b09efcf60a 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -25,7 +25,7 @@ #define DEVNAME "pc8736x_gpio" MODULE_AUTHOR("Jim Cromie "); -MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver"); +MODULE_DESCRIPTION("NatSemi/Winbond PC-8736x GPIO Pin Driver"); MODULE_LICENSE("GPL"); static int major; /* default to dynamic major */ @@ -38,14 +38,14 @@ static u8 pc8736x_gpio_shadow[4]; #define SIO_BASE1 0x2E /* 1st command-reg to check */ #define SIO_BASE2 0x4E /* alt command-reg to check */ -#define SIO_BASE_OFFSET 0x20 #define SIO_SID 0x20 /* SuperI/O ID Register */ #define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */ #define SIO_CF1 0x21 /* chip config, bit0 is chip enable */ -#define PC8736X_GPIO_SIZE 16 +#define PC8736X_GPIO_RANGE 16 /* ioaddr range */ +#define PC8736X_GPIO_CT 32 /* minors matching 4 8 bit ports */ #define SIO_UNIT_SEL 0x7 /* unit select reg */ #define SIO_UNIT_ACT 0x30 /* unit enable */ @@ -231,7 +231,7 @@ static int pc8736x_gpio_open(struct inode *inode, struct file *file) dev_dbg(&pdev->dev, "open %d\n", m); - if (m > 63) + if (m >= PC8736X_GPIO_CT) return -EINVAL; return nonseekable_open(inode, file); } @@ -297,7 +297,7 @@ static int __init pc8736x_gpio_init(void) pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8 | superio_inb(SIO_BASE_LADDR)); - if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) { + if (!request_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE, DEVNAME)) { rc = -ENODEV; dev_err(&pdev->dev, "GPIO ioport %x busy\n", pc8736x_gpio_base); -- cgit v1.2.3 From 27385085f19a9bc9b147905554e6e2509fdaceb2 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Mon, 10 Jul 2006 04:45:36 -0700 Subject: [PATCH] pc8736x_gpio: fix re-modprobe errors: undo region reservation Fix module-init-func by repairing usage of platform_device_del/put in module-exit-func. IOW, it imitates Ingo's 'mishaps' patch, which fixed the module-init-func's undo handling. Also fixes lack of release_region to undo the earlier registration. Also starts to 'use a cdev' which was originally intended (its present in scx200_gpio). Code compiles and runs, exhibits a lesser error than previously. (re-register-chrdev fails) Since I had to add "include ", I went ahead and made 2 tweaks that fell into diff-context-window: - remove include everyone's doing it - copyright updates - current date is 'wrong' Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 5b09efcf60a..bfc45e0cc60 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -3,18 +3,18 @@ National Semiconductor PC8736x GPIO driver. Allows a user space process to play with the GPIO pins. - Copyright (c) 2005 Jim Cromie + Copyright (c) 2005,2006 Jim Cromie adapted from linux/drivers/char/scx200_gpio.c Copyright (c) 2001,2002 Christer Weinigel , */ -#include #include #include #include #include #include +#include #include #include #include @@ -255,6 +255,8 @@ static void __init pc8736x_init_shadow(void) } +static struct cdev pc8736x_gpio_cdev; + static int __init pc8736x_gpio_init(void) { int rc = 0; @@ -308,7 +310,7 @@ static int __init pc8736x_gpio_init(void) rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops); if (rc < 0) { dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc); - goto undo_platform_dev_add; + goto undo_request_region; } if (!major) { major = rc; @@ -318,6 +320,8 @@ static int __init pc8736x_gpio_init(void) pc8736x_init_shadow(); return 0; +undo_request_region: + release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); undo_platform_dev_add: platform_device_del(pdev); undo_platform_dev_alloc: @@ -328,11 +332,14 @@ undo_platform_dev_alloc: static void __exit pc8736x_gpio_cleanup(void) { - dev_dbg(&pdev->dev, " cleanup\n"); + dev_dbg(&pdev->dev, "cleanup\n"); - release_region(pc8736x_gpio_base, 16); + cdev_del(&pc8736x_gpio_cdev); + unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT); + release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); - unregister_chrdev(major, DEVNAME); + platform_device_del(pdev); + platform_device_put(pdev); } EXPORT_SYMBOL(pc8736x_access); -- cgit v1.2.3 From babcfade47371eea81fd7f24d892b5ff5b1786ea Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Mon, 10 Jul 2006 04:45:37 -0700 Subject: [PATCH] pc8736x_gpio: fix re-modprobe errors: fix/finish cdev-init - Switch from register_chrdev() to (register|alloc)_chrdev_region(). - use a cdev. This was intended for original patchset, but was overlooked. We use a single cdev for all pins (minor device-numbers), as gleaned from cs5535_gpio, and in contrast to whats currently done in scx200_gpio (which I'll fix soon) Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index bfc45e0cc60..11bd78c8062 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -259,7 +259,8 @@ static struct cdev pc8736x_gpio_cdev; static int __init pc8736x_gpio_init(void) { - int rc = 0; + int rc; + dev_t devid; pdev = platform_device_alloc(DEVNAME, 0); if (!pdev) @@ -307,7 +308,14 @@ static int __init pc8736x_gpio_init(void) } dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base); - rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops); + if (major) { + devid = MKDEV(major, 0); + rc = register_chrdev_region(devid, PC8736X_GPIO_CT, DEVNAME); + } else { + rc = alloc_chrdev_region(&devid, 0, PC8736X_GPIO_CT, DEVNAME); + major = MAJOR(devid); + } + if (rc < 0) { dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc); goto undo_request_region; @@ -318,6 +326,11 @@ static int __init pc8736x_gpio_init(void) } pc8736x_init_shadow(); + + /* ignore minor errs, and succeed */ + cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fops); + cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT); + return 0; undo_request_region: -- cgit v1.2.3 From 5c318bef5f61baf6bbda2dcfe8c2ef71007c7fea Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jul 2006 04:45:37 -0700 Subject: [PATCH] snsc: switch from force_sig to kill_proc Currently the snsc driver uses force_sig to send init a SIGPWR when the system overheats. This patch switches it to kill_proc instead which has the following advantages: (1) gets rid of one of the last remaining tasklist_lock users in modular code (2) simplifies the snsc code significantly The downside is that an init implementation could in theory block SIGPWR and it would not get delivered. The sysvinit code used by all major distributions doesn't do this and blocking this signal in init would be a rather stupid thing to do. Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/snsc_event.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 8b2210b633d..d12d4f629ce 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -220,20 +220,7 @@ scdrv_dispatch_event(char *event, int len) " Sending SIGPWR to init...\n"); /* give a SIGPWR signal to init proc */ - - /* first find init's task */ - read_lock(&tasklist_lock); - for_each_process(p) { - if (p->pid == 1) - break; - } - if (p) { - force_sig(SIGPWR, p); - } else { - printk(KERN_ERR "Failed to signal init!\n"); - snsc_shutting_down = 0; /* so can try again (?) */ - } - read_unlock(&tasklist_lock); + kill_proc(1, SIGPWR, 0); } else { /* print to system log */ printk("%s|$(0x%x)%s\n", severity, esp_code, desc); -- cgit v1.2.3 From 0f74964627e0ece4ac8da0e2cd01906ec322b4fe Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 12 Jul 2006 09:03:10 -0700 Subject: [PATCH] lockdep: HPET/RTC fix Joseph Fannin reported that hpet_rtc_interrupt() enables hardirqs in irq context: [ 25.628000] [] trace_hardirqs_on+0xce/0x200 [ 25.628000] [] _spin_unlock_irq+0x31/0x70 [ 25.628000] [] rtc_get_rtc_time+0x44/0x1a0 [ 25.628000] [] hpet_rtc_interrupt+0x21b/0x280 [ 25.628000] [] handle_IRQ_event+0x31/0x70 [ 25.628000] [] handle_edge_irq+0xe7/0x210 [ 25.628000] [] do_IRQ+0x92/0x120 [ 25.628000] [] common_interrupt+0x25/0x2c the call of rtc_get_rtc_time() is highly suspect. At a minimum we need the patch below to save/restore hardirq state. Signed-off-by: Ingo Molnar Cc: Joseph Fannin Cc: John Stultz Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/rtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6ccc364c08d..6e6a7c7a7ef 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1245,7 +1245,7 @@ static int rtc_proc_open(struct inode *inode, struct file *file) void rtc_get_rtc_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; + unsigned long uip_watchdog = jiffies, flags; unsigned char ctrl; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -1272,7 +1272,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is * only updated by the RTC when initially set to a non-zero value. */ - spin_lock_irq(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); @@ -1286,7 +1286,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) real_year = CMOS_READ(RTC_DEC_YEAR); #endif ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { -- cgit v1.2.3 From 66151bbd20c6c62dbe5b131484c885086e3a8d29 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 13 Jul 2006 17:33:03 +0900 Subject: [MIPS] vr41xx: Move IRQ numbers to asm-mips/vr41xx/irq.h Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- drivers/char/vr41xx_giu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 1b9b1f1d4c4..8116a47b80f 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -33,6 +33,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Yoichi Yuasa "); -- cgit v1.2.3 From ae2d1f2f5b59d00b39283c52dc4ee675397bbacd Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 14 Jul 2006 00:24:16 -0700 Subject: [PATCH] scx200_gpio: 1 cdev for N minors: cleanup, prep this patch is mostly cleanup of scx200_gpio : - drop #include - s/DEVNAME/DRVNAME/ apparently a convention - replace variable num_pins with #define MAX_PINS - s/dev/devid/ to clarify that its a dev_t, not a struct device dev. - move devid = MKDEV(major,0) into branch where its needed. 2 minor 'changes' : - reduced MAX_PINS from 64 to 32. Ive never tested other pins, and theyre all multiplexed with other functions, some of which may be in use on my soekris 4801, so I dont know what testing should yield. - +EXPORT_SYMBOL(scx200_access); This exposes the driver's vtable, which another driver can use along with #include , to manipulate a gpio-pin. Signed-off-by Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/scx200_gpio.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 425c58719db..e7665c1ad13 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -5,7 +5,6 @@ Copyright (c) 2001,2002 Christer Weinigel */ -#include #include #include #include @@ -22,19 +21,20 @@ #include #include -#define NAME "scx200_gpio" -#define DEVNAME NAME +#define DRVNAME "scx200_gpio" static struct platform_device *pdev; MODULE_AUTHOR("Christer Weinigel "); -MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); +MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver"); MODULE_LICENSE("GPL"); static int major = 0; /* default to dynamic major */ module_param(major, int, 0); MODULE_PARM_DESC(major, "Major device number"); +#define MAX_PINS 32 /* 64 later, when known ok */ + struct nsc_gpio_ops scx200_access = { .owner = THIS_MODULE, .gpio_config = scx200_gpio_configure, @@ -46,13 +46,14 @@ struct nsc_gpio_ops scx200_access = { .gpio_change = scx200_gpio_change, .gpio_current = scx200_gpio_current }; +EXPORT_SYMBOL(scx200_access); static int scx200_gpio_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); file->private_data = &scx200_access; - if (m > 63) + if (m >= MAX_PINS) return -EINVAL; return nonseekable_open(inode, file); } @@ -72,20 +73,19 @@ static const struct file_operations scx200_gpio_fops = { }; struct cdev *scx200_devices; -static int num_pins = 32; static int __init scx200_gpio_init(void) { int rc, i; - dev_t dev = MKDEV(major, 0); + dev_t devid; if (!scx200_gpio_present()) { - printk(KERN_ERR NAME ": no SCx200 gpio present\n"); + printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n"); return -ENODEV; } /* support dev_dbg() with pdev->dev */ - pdev = platform_device_alloc(DEVNAME, 0); + pdev = platform_device_alloc(DRVNAME, 0); if (!pdev) return -ENOMEM; @@ -96,22 +96,23 @@ static int __init scx200_gpio_init(void) /* nsc_gpio uses dev_dbg(), so needs this */ scx200_access.dev = &pdev->dev; - if (major) - rc = register_chrdev_region(dev, num_pins, "scx200_gpio"); - else { - rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio"); - major = MAJOR(dev); + if (major) { + devid = MKDEV(major, 0); + rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio"); + } else { + rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio"); + major = MAJOR(devid); } if (rc < 0) { dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); goto undo_platform_device_add; } - scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL); + scx200_devices = kzalloc(MAX_PINS * sizeof(struct cdev), GFP_KERNEL); if (!scx200_devices) { rc = -ENOMEM; goto undo_chrdev_region; } - for (i = 0; i < num_pins; i++) { + for (i = 0; i < MAX_PINS; i++) { struct cdev *cdev = &scx200_devices[i]; cdev_init(cdev, &scx200_gpio_fops); cdev->owner = THIS_MODULE; @@ -124,7 +125,7 @@ static int __init scx200_gpio_init(void) return 0; /* succeed */ undo_chrdev_region: - unregister_chrdev_region(dev, num_pins); + unregister_chrdev_region(devid, MAX_PINS); undo_platform_device_add: platform_device_del(pdev); undo_malloc: @@ -136,9 +137,8 @@ undo_malloc: static void __exit scx200_gpio_cleanup(void) { kfree(scx200_devices); - unregister_chrdev_region(MKDEV(major, 0), num_pins); + unregister_chrdev_region(MKDEV(major, 0), MAX_PINS); platform_device_unregister(pdev); - /* kfree(pdev); */ } module_init(scx200_gpio_init); -- cgit v1.2.3 From 635adb6cd25c8f816c9017a0a0349cd389eafcd3 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 14 Jul 2006 00:24:16 -0700 Subject: [PATCH] scx200_gpio: use 1 cdev for N minors, not N for N Remove the scx200_gpio's cdev-array & ksalloc, replacing it with a single static struct cdev, which is sufficient for all the pins. cdev_put is commented out since kernel wont link properly with it, and its apparently not needed. With these patches, this driver continues to work with Chris Boot's leds_48xx driver. Signed-off-by Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/scx200_gpio.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index e7665c1ad13..dd1f997944e 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -63,7 +63,6 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) return 0; } - static const struct file_operations scx200_gpio_fops = { .owner = THIS_MODULE, .write = nsc_gpio_write, @@ -72,11 +71,11 @@ static const struct file_operations scx200_gpio_fops = { .release = scx200_gpio_release, }; -struct cdev *scx200_devices; +struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ static int __init scx200_gpio_init(void) { - int rc, i; + int rc; dev_t devid; if (!scx200_gpio_present()) { @@ -107,25 +106,12 @@ static int __init scx200_gpio_init(void) dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); goto undo_platform_device_add; } - scx200_devices = kzalloc(MAX_PINS * sizeof(struct cdev), GFP_KERNEL); - if (!scx200_devices) { - rc = -ENOMEM; - goto undo_chrdev_region; - } - for (i = 0; i < MAX_PINS; i++) { - struct cdev *cdev = &scx200_devices[i]; - cdev_init(cdev, &scx200_gpio_fops); - cdev->owner = THIS_MODULE; - rc = cdev_add(cdev, MKDEV(major, i), 1); - /* tolerate 'minor' errors */ - if (rc) - dev_err(&pdev->dev, "Error %d on minor %d", rc, i); - } + + cdev_init(&scx200_gpio_cdev, &scx200_gpio_fops); + cdev_add(&scx200_gpio_cdev, devid, MAX_PINS); return 0; /* succeed */ -undo_chrdev_region: - unregister_chrdev_region(devid, MAX_PINS); undo_platform_device_add: platform_device_del(pdev); undo_malloc: @@ -136,7 +122,9 @@ undo_malloc: static void __exit scx200_gpio_cleanup(void) { - kfree(scx200_devices); + cdev_del(&scx200_gpio_cdev); + /* cdev_put(&scx200_gpio_cdev); */ + unregister_chrdev_region(MKDEV(major, 0), MAX_PINS); platform_device_unregister(pdev); } -- cgit v1.2.3 From 91e260b80d2fec559877f399dfc36b554f207874 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 14 Jul 2006 00:24:25 -0700 Subject: [PATCH] gpio: drop vtable members .gpio_set_high .gpio_set_low gpio_set is enough drops gpio_set_high, gpio_set_low from the nsc_gpio_ops vtable. While we can't drop them from scx200_gpio (or can we?), we dont need them for new users of the exported vtable; gpio_set(1), gpio_set(0) work fine. Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 2 -- drivers/char/scx200_gpio.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 11bd78c8062..0b235a90bee 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -218,8 +218,6 @@ static struct nsc_gpio_ops pc8736x_access = { .gpio_dump = nsc_gpio_dump, .gpio_get = pc8736x_gpio_get, .gpio_set = pc8736x_gpio_set, - .gpio_set_high = pc8736x_gpio_set_high, - .gpio_set_low = pc8736x_gpio_set_low, .gpio_change = pc8736x_gpio_change, .gpio_current = pc8736x_gpio_current }; diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index dd1f997944e..f65372b5a65 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -41,8 +41,6 @@ struct nsc_gpio_ops scx200_access = { .gpio_dump = nsc_gpio_dump, .gpio_get = scx200_gpio_get, .gpio_set = scx200_gpio_set, - .gpio_set_high = scx200_gpio_set_high, - .gpio_set_low = scx200_gpio_set_low, .gpio_change = scx200_gpio_change, .gpio_current = scx200_gpio_current }; -- cgit v1.2.3 From abecb6da704a71232a3103c8485c65ceb5fcd9dc Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 14 Jul 2006 00:24:26 -0700 Subject: [PATCH] gpio: cosmetics: remove needless newlines - pure cosmetics: lose needless newlines. - rename EXPORTed gpio vtables from {scx200,pc8736x}_access to _gpio_ops new name is much closer to the vtable-name struct nsc_gpio_ops, should be clearer. Also rename the _fops vtable var to _fileops to better disambiguate it from the gpio vtable. Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/nsc_gpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c index 5b91e4e2564..7719bd75810 100644 --- a/drivers/char/nsc_gpio.c +++ b/drivers/char/nsc_gpio.c @@ -68,13 +68,11 @@ ssize_t nsc_gpio_write(struct file *file, const char __user *data, amp->gpio_config(m, ~1, 0); break; case 'T': - dev_dbg(dev, "GPIO%d output is push pull\n", - m); + dev_dbg(dev, "GPIO%d output is push pull\n", m); amp->gpio_config(m, ~2, 2); break; case 't': - dev_dbg(dev, "GPIO%d output is open drain\n", - m); + dev_dbg(dev, "GPIO%d output is open drain\n", m); amp->gpio_config(m, ~2, 0); break; case 'P': -- cgit v1.2.3 From 2e8f7a3128bb8fac8351a994f1fc325717899308 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 14 Jul 2006 00:24:26 -0700 Subject: [PATCH] gpio: rename exported vtables to better match purpose - rename EXPORTed gpio vtables from {scx200,pc8736x}_access to _gpio_ops new name is much closer to the vtable-name struct nsc_gpio_ops, should be clearer. Also rename the _fops vtable var to _fileops to better disambiguate it from the gpio vtable. Signed-off-by: Jim Cromie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 13 ++++++------- drivers/char/scx200_gpio.c | 12 ++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 0b235a90bee..645eb81cb5a 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -212,7 +212,7 @@ static void pc8736x_gpio_change(unsigned index) pc8736x_gpio_set(index, !pc8736x_gpio_current(index)); } -static struct nsc_gpio_ops pc8736x_access = { +static struct nsc_gpio_ops pc8736x_gpio_ops = { .owner = THIS_MODULE, .gpio_config = pc8736x_gpio_configure, .gpio_dump = nsc_gpio_dump, @@ -221,11 +221,12 @@ static struct nsc_gpio_ops pc8736x_access = { .gpio_change = pc8736x_gpio_change, .gpio_current = pc8736x_gpio_current }; +EXPORT_SYMBOL(pc8736x_gpio_ops); static int pc8736x_gpio_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); - file->private_data = &pc8736x_access; + file->private_data = &pc8736x_gpio_ops; dev_dbg(&pdev->dev, "open %d\n", m); @@ -234,7 +235,7 @@ static int pc8736x_gpio_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static const struct file_operations pc8736x_gpio_fops = { +static const struct file_operations pc8736x_gpio_fileops = { .owner = THIS_MODULE, .open = pc8736x_gpio_open, .write = nsc_gpio_write, @@ -276,7 +277,7 @@ static int __init pc8736x_gpio_init(void) dev_err(&pdev->dev, "no device found\n"); goto undo_platform_dev_add; } - pc8736x_access.dev = &pdev->dev; + pc8736x_gpio_ops.dev = &pdev->dev; /* Verify that chip and it's GPIO unit are both enabled. My BIOS does this, so I take minimum action here @@ -326,7 +327,7 @@ static int __init pc8736x_gpio_init(void) pc8736x_init_shadow(); /* ignore minor errs, and succeed */ - cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fops); + cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops); cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT); return 0; @@ -353,7 +354,5 @@ static void __exit pc8736x_gpio_cleanup(void) platform_device_put(pdev); } -EXPORT_SYMBOL(pc8736x_access); - module_init(pc8736x_gpio_init); module_exit(pc8736x_gpio_cleanup); diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index f65372b5a65..b956c7babd1 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -35,7 +35,7 @@ MODULE_PARM_DESC(major, "Major device number"); #define MAX_PINS 32 /* 64 later, when known ok */ -struct nsc_gpio_ops scx200_access = { +struct nsc_gpio_ops scx200_gpio_ops = { .owner = THIS_MODULE, .gpio_config = scx200_gpio_configure, .gpio_dump = nsc_gpio_dump, @@ -44,12 +44,12 @@ struct nsc_gpio_ops scx200_access = { .gpio_change = scx200_gpio_change, .gpio_current = scx200_gpio_current }; -EXPORT_SYMBOL(scx200_access); +EXPORT_SYMBOL(scx200_gpio_ops); static int scx200_gpio_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); - file->private_data = &scx200_access; + file->private_data = &scx200_gpio_ops; if (m >= MAX_PINS) return -EINVAL; @@ -61,7 +61,7 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations scx200_gpio_fops = { +static const struct file_operations scx200_gpio_fileops = { .owner = THIS_MODULE, .write = nsc_gpio_write, .read = nsc_gpio_read, @@ -91,7 +91,7 @@ static int __init scx200_gpio_init(void) goto undo_malloc; /* nsc_gpio uses dev_dbg(), so needs this */ - scx200_access.dev = &pdev->dev; + scx200_gpio_ops.dev = &pdev->dev; if (major) { devid = MKDEV(major, 0); @@ -105,7 +105,7 @@ static int __init scx200_gpio_init(void) goto undo_platform_device_add; } - cdev_init(&scx200_gpio_cdev, &scx200_gpio_fops); + cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops); cdev_add(&scx200_gpio_cdev, devid, MAX_PINS); return 0; /* succeed */ -- cgit v1.2.3 From 2e82636a3dd8d3cf1ba87380608da4f6a0f6ec47 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 14 Jul 2006 00:24:28 -0700 Subject: [PATCH] TPM: fix failure path leak kfree(devname) on the misc_register() failure path. Otherwise it is lost forever. Signed-off-by: Randy Dunlap Cc: Kylene Jo Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6889e7db3af..a082a2e3425 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1141,6 +1141,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend put_device(dev); clear_bit(chip->dev_num, dev_mask); kfree(chip); + kfree(devname); return NULL; } -- cgit v1.2.3 From cab091eaa4952777d3183b6d7ce203a213cddc12 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Fri, 14 Jul 2006 00:24:30 -0700 Subject: [PATCH] tpm: interrupt clear fix Under stress testing I found that the interrupt is not always cleared. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 3232b193259..29dac1e4537 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -424,6 +424,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) iowrite32(interrupt, chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality)); + ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality)); return IRQ_HANDLED; } -- cgit v1.2.3 From 9e323d3ee0ba9381af494641e1e87a8d372f916b Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Fri, 14 Jul 2006 00:24:31 -0700 Subject: [PATCH] tpm: Add force device probe option Some machine manufacturers are not sticking to the TCG specifications and including an ACPI DSDT entry for the TPM which allows PNP discovery of the device. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 75 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 19 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 29dac1e4537..4d0df3324e4 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -432,23 +432,18 @@ static int interrupts = 1; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); -static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, - const struct pnp_device_id *pnp_id) +static int tpm_tis_init(struct device *dev, unsigned long start, unsigned long len) { u32 vendor, intfcaps, intmask; int rc, i; - unsigned long start, len; struct tpm_chip *chip; - start = pnp_mem_start(pnp_dev, 0); - len = pnp_mem_len(pnp_dev, 0); - if (!start) start = TIS_MEM_BASE; if (!len) len = TIS_MEM_LEN; - if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis))) + if (!(chip = tpm_register_hardware(dev, &tpm_tis))) return -ENODEV; chip->vendor.iobase = ioremap(start, len); @@ -465,7 +460,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - dev_info(&pnp_dev->dev, + dev_info(dev, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); @@ -473,26 +468,26 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, intfcaps = ioread32(chip->vendor.iobase + TPM_INTF_CAPS(chip->vendor.locality)); - dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n", + dev_dbg(dev, "TPM interface capabilities (0x%x):\n", intfcaps); if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) - dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n"); + dev_dbg(dev, "\tBurst Count Static\n"); if (intfcaps & TPM_INTF_CMD_READY_INT) - dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n"); + dev_dbg(dev, "\tCommand Ready Int Support\n"); if (intfcaps & TPM_INTF_INT_EDGE_FALLING) - dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n"); + dev_dbg(dev, "\tInterrupt Edge Falling\n"); if (intfcaps & TPM_INTF_INT_EDGE_RISING) - dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n"); + dev_dbg(dev, "\tInterrupt Edge Rising\n"); if (intfcaps & TPM_INTF_INT_LEVEL_LOW) - dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n"); + dev_dbg(dev, "\tInterrupt Level Low\n"); if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) - dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n"); + dev_dbg(dev, "\tInterrupt Level High\n"); if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) - dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n"); + dev_dbg(dev, "\tLocality Change Int Support\n"); if (intfcaps & TPM_INTF_STS_VALID_INT) - dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n"); + dev_dbg(dev, "\tSts Valid Int Support\n"); if (intfcaps & TPM_INTF_DATA_AVAIL_INT) - dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n"); + dev_dbg(dev, "\tData Avail Int Support\n"); if (request_locality(chip, 0) != 0) { rc = -ENODEV; @@ -595,6 +590,16 @@ out_err: return rc; } +static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, + const struct pnp_device_id *pnp_id) +{ + unsigned long start, len; + start = pnp_mem_start(pnp_dev, 0); + len = pnp_mem_len(pnp_dev, 0); + + return tpm_tis_init(&pnp_dev->dev, start, len); +} + static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) { return tpm_pm_suspend(&dev->dev, msg); @@ -629,8 +634,36 @@ 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 struct platform_device *pdev; + +static int force; +module_param(force, bool, 0444); +MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); static int __init init_tis(void) { + int rc; + + if (force) { + rc = 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, 0, 0)) != 0) { + platform_device_unregister(pdev); + driver_unregister(&tis_drv); + } + return rc; + } + return pnp_register_driver(&tis_pnp_driver); } @@ -655,7 +688,11 @@ static void __exit cleanup_tis(void) tpm_remove_hardware(chip->dev); } spin_unlock(&tis_lock); - pnp_unregister_driver(&tis_pnp_driver); + if (force) { + platform_device_unregister(pdev); + driver_unregister(&tis_drv); + } else + pnp_unregister_driver(&tis_pnp_driver); } module_init(init_tis); -- cgit v1.2.3 From c3c36aa98f8e39544afb99025bb69bc1b48e9bf0 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Fri, 14 Jul 2006 00:24:31 -0700 Subject: [PATCH] tpm_tis: use resource_size_t Fix the start and len variables that should be using the new resource_size_t. Signed_off_by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 4d0df3324e4..ee7ac6f43c6 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -432,7 +432,8 @@ static int interrupts = 1; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); -static int tpm_tis_init(struct device *dev, unsigned long start, unsigned long len) +static int tpm_tis_init(struct device *dev, resource_size_t start, + resource_size_t len) { u32 vendor, intfcaps, intmask; int rc, i; @@ -593,7 +594,7 @@ out_err: static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, const struct pnp_device_id *pnp_id) { - unsigned long start, len; + resource_size_t start, len; start = pnp_mem_start(pnp_dev, 0); len = pnp_mem_len(pnp_dev, 0); -- cgit v1.2.3 From fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Fri, 21 Jul 2006 14:44:55 -0700 Subject: [WAN]: Converted synclink drivers to use netif_carrier_*() WAN: Converted synclink drivers to use netif_carrier_*() instead of hdlc_set_carrier(). Signed-off-by: Krzysztof Halasa Signed-off-by: David S. Miller --- drivers/char/pcmcia/synclink_cs.c | 14 ++++++++++---- drivers/char/synclink.c | 14 ++++++++++---- drivers/char/synclink_gt.c | 14 ++++++++++---- drivers/char/synclinkmp.c | 14 ++++++++++---- 4 files changed, 40 insertions(+), 16 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 17bc8abd5df..00f574cbb0d 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1174,8 +1174,12 @@ static void dcd_change(MGSLPC_INFO *info) else info->input_signal_events.dcd_down++; #ifdef CONFIG_HDLC - if (info->netcount) - hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev); + if (info->netcount) { + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(info->netdev); + else + netif_carrier_off(info->netdev); + } #endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); @@ -4251,8 +4255,10 @@ static int hdlcdev_open(struct net_device *dev) spin_lock_irqsave(&info->lock, flags); get_signals(info); spin_unlock_irqrestore(&info->lock, flags); - hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); - + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(dev); + else + netif_carrier_off(dev); return 0; } diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index df782dd1098..78b1b1a2732 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1344,8 +1344,12 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) } else info->input_signal_events.dcd_down++; #ifdef CONFIG_HDLC - if (info->netcount) - hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev); + if (info->netcount) { + if (status & MISCSTATUS_DCD) + netif_carrier_on(info->netdev); + else + netif_carrier_off(info->netdev); + } #endif } if (status & MISCSTATUS_CTS_LATCHED) @@ -7844,8 +7848,10 @@ static int hdlcdev_open(struct net_device *dev) spin_lock_irqsave(&info->irq_spinlock, flags); usc_get_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock, flags); - hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); - + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(dev); + else + netif_carrier_off(dev); return 0; } diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index e829594195c..b2dbbdb1bf8 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1497,8 +1497,10 @@ static int hdlcdev_open(struct net_device *dev) spin_lock_irqsave(&info->lock, flags); get_signals(info); spin_unlock_irqrestore(&info->lock, flags); - hdlc_set_carrier(info->signals & SerialSignal_DCD, dev); - + if (info->signals & SerialSignal_DCD) + netif_carrier_on(dev); + else + netif_carrier_off(dev); return 0; } @@ -1997,8 +1999,12 @@ static void dcd_change(struct slgt_info *info) info->input_signal_events.dcd_down++; } #ifdef CONFIG_HDLC - if (info->netcount) - hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev); + if (info->netcount) { + if (info->signals & SerialSignal_DCD) + netif_carrier_on(info->netdev); + else + netif_carrier_off(info->netdev); + } #endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 1e443a233f5..66f3754fbbd 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1752,8 +1752,10 @@ static int hdlcdev_open(struct net_device *dev) spin_lock_irqsave(&info->lock, flags); get_signals(info); spin_unlock_irqrestore(&info->lock, flags); - hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); - + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(dev); + else + netif_carrier_off(dev); return 0; } @@ -2522,8 +2524,12 @@ void isr_io_pin( SLMP_INFO *info, u16 status ) } else info->input_signal_events.dcd_down++; #ifdef CONFIG_HDLC - if (info->netcount) - hdlc_set_carrier(status & SerialSignal_DCD, info->netdev); + if (info->netcount) { + if (status & SerialSignal_DCD) + netif_carrier_on(info->netdev); + else + netif_carrier_off(info->netdev); + } #endif } if (status & MISCSTATUS_CTS_LATCHED) -- cgit v1.2.3 From 5e44ef238b7eb607532e89249e7b2523faf77a92 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 30 Jul 2006 03:03:07 -0700 Subject: [PATCH] drivers/char/pc8736x_gpio.c: unexport a static struct A static struct mustn't be exported. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 645eb81cb5a..84e5a68635f 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -221,7 +221,6 @@ static struct nsc_gpio_ops pc8736x_gpio_ops = { .gpio_change = pc8736x_gpio_change, .gpio_current = pc8736x_gpio_current }; -EXPORT_SYMBOL(pc8736x_gpio_ops); static int pc8736x_gpio_open(struct inode *inode, struct file *file) { -- cgit v1.2.3 From 58690664456b597796e58958861f365e096a1609 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Jul 2006 03:04:04 -0700 Subject: [PATCH] hwrng: fix intel probe error unwind The intel hwrng leaks an iomapped resource, if hwrng_register() failes. This fixes it. Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/intel-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 6594bd5645f..ccd7e710223 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -164,7 +164,7 @@ static int __init mod_init(void) if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto out; + goto err_unmap; } out: return err; -- cgit v1.2.3 From 072d3d1acb452f4abd8d3d20af661f2e28854b59 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Jul 2006 03:04:05 -0700 Subject: [PATCH] hwrng: fix geode probe error unwind The geode hwrng leaks an iomapped resource, if hwrng_register() fails. This fixes it. Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/geode-rng.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index be61f22ee7b..d37ced0d132 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -107,10 +107,14 @@ found: if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto out; + goto err_unmap; } out: return err; + +err_unmap: + iounmap(mem); + goto out; } static void __exit mod_exit(void) -- cgit v1.2.3 From c7c17423b9ea3c5559cfb480a00844f1df9eed06 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Fri, 28 Jul 2006 10:03:55 -0500 Subject: [IA64] add platform check to snsc driver init Add a platform check to the snsc driver init function, to prevent loading on non-sn2 systems. Signed-off-by: Greg Edwards Signed-off-by: Tony Luck --- drivers/char/snsc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index afc6eda602f..07e0b75f233 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -374,7 +374,12 @@ scdrv_init(void) struct sysctl_data_s *scd; void *salbuf; dev_t first_dev, dev; - nasid_t event_nasid = ia64_sn_get_console_nasid(); + nasid_t event_nasid; + + if (!ia64_platform_is("sn2")) + return -ENODEV; + + event_nasid = ia64_sn_get_console_nasid(); if (alloc_chrdev_region(&first_dev, 0, num_cnodes, SYSCTL_BASENAME) < 0) { -- cgit v1.2.3 From 22479e1c0d111c60d29a4759408394cbdc7548a5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:51:51 -0400 Subject: Input: keyboard - change to use kzalloc Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 30a745428a0..3e90aac3751 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1297,9 +1297,9 @@ static struct input_handle *kbd_connect(struct input_handler *handler, if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) return NULL; - memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; -- cgit v1.2.3 From af2bc7d222c2700ccda060184d7bced7d7cb9fc2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 5 Aug 2006 12:14:04 -0700 Subject: [PATCH] omap-rng build fix Seems like the omap-rng driver in the main tree predates the switch from to ... now it builds OK. Signed-off-by: David Brownell Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/omap-rng.c | 51 ++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 819516b35a7..a01d796d1ee 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -25,12 +25,12 @@ #include #include #include +#include #include -#include +#include #include #include -#include #define RNG_OUT_REG 0x00 /* Output register */ #define RNG_STAT_REG 0x04 /* Status register @@ -52,7 +52,7 @@ static void __iomem *rng_base; static struct clk *rng_ick; -static struct device *rng_dev; +static struct platform_device *rng_dev; static u32 omap_rng_read_reg(int reg) { @@ -83,9 +83,8 @@ static struct hwrng omap_rng_ops = { .data_read = omap_rng_data_read, }; -static int __init omap_rng_probe(struct device *dev) +static int __init omap_rng_probe(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev); struct resource *res, *mem; int ret; @@ -95,16 +94,14 @@ static int __init omap_rng_probe(struct device *dev) */ BUG_ON(rng_dev); - if (cpu_is_omap24xx()) { + if (cpu_is_omap24xx()) { rng_ick = clk_get(NULL, "rng_ick"); if (IS_ERR(rng_ick)) { - dev_err(dev, "Could not get rng_ick\n"); + dev_err(&pdev->dev, "Could not get rng_ick\n"); ret = PTR_ERR(rng_ick); return ret; - } - else { - clk_use(rng_ick); - } + } else + clk_enable(rng_ick); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -117,7 +114,7 @@ static int __init omap_rng_probe(struct device *dev) if (mem == NULL) return -EBUSY; - dev_set_drvdata(dev, mem); + dev_set_drvdata(&pdev->dev, mem); rng_base = (u32 __iomem *)io_p2v(res->start); ret = hwrng_register(&omap_rng_ops); @@ -127,25 +124,25 @@ static int __init omap_rng_probe(struct device *dev) return ret; } - dev_info(dev, "OMAP Random Number Generator ver. %02x\n", + dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", omap_rng_read_reg(RNG_REV_REG)); omap_rng_write_reg(RNG_MASK_REG, 0x1); - rng_dev = dev; + rng_dev = pdev; return 0; } -static int __exit omap_rng_remove(struct device *dev) +static int __exit omap_rng_remove(struct platform_device *pdev) { - struct resource *mem = dev_get_drvdata(dev); + struct resource *mem = dev_get_drvdata(&pdev->dev); hwrng_unregister(&omap_rng_ops); omap_rng_write_reg(RNG_MASK_REG, 0x0); if (cpu_is_omap24xx()) { - clk_unuse(rng_ick); + clk_disable(rng_ick); clk_put(rng_ick); } @@ -157,18 +154,16 @@ static int __exit omap_rng_remove(struct device *dev) #ifdef CONFIG_PM -static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level) +static int omap_rng_suspend(struct platform_device *pdev, pm_message_t message) { omap_rng_write_reg(RNG_MASK_REG, 0x0); - return 0; } -static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) +static int omap_rng_resume(struct platform_device *pdev) { omap_rng_write_reg(RNG_MASK_REG, 0x1); - - return 1; + return 0; } #else @@ -179,9 +174,11 @@ static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) #endif -static struct device_driver omap_rng_driver = { - .name = "omap_rng", - .bus = &platform_bus_type, +static struct platform_driver omap_rng_driver = { + .driver = { + .name = "omap_rng", + .owner = THIS_MODULE, + }, .probe = omap_rng_probe, .remove = __exit_p(omap_rng_remove), .suspend = omap_rng_suspend, @@ -193,12 +190,12 @@ static int __init omap_rng_init(void) if (!cpu_is_omap16xx() && !cpu_is_omap24xx()) return -ENODEV; - return driver_register(&omap_rng_driver); + return platform_driver_register(&omap_rng_driver); } static void __exit omap_rng_exit(void) { - driver_unregister(&omap_rng_driver); + platform_driver_unregister(&omap_rng_driver); } module_init(omap_rng_init); -- cgit v1.2.3 From 229395c90aadbadef76bacf52b9cb3326f509e93 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sat, 5 Aug 2006 12:14:36 -0700 Subject: [PATCH] pSeries hvsi char driver null pointer deref Under certain rare circumstances, it appears that there can be be a NULL-pointer deref when a user fiddles with terminal emeulation programs while outpu is being sent to the console. This patch checks for and avoids a NULL-pointer deref. Signed-off-by: Hollis Blanchard Signed-off-by: Linas Vepstas Cc: Paul Fulghum Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 41db8060e8f..54cbb58b874 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -311,7 +311,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; - if (!(hp->tty->flags & CLOCAL)) + /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ + if (hp->tty && !(hp->tty->flags & CLOCAL)) *to_hangup = hp->tty; } break; -- cgit v1.2.3 From 64e0cc38b69b8d43ab9793f50e4bb09cea0e6bb9 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sat, 5 Aug 2006 12:14:39 -0700 Subject: [PATCH] pSeries: hvsi char driver janitorial cleanup A set of tty line discipline cleanup patches were introduced before the dawn of time, in kernel version 2.4.21. This patch performs that cleanup for the hvsi driver. The hvsi driver is used only on IBM pSeries PowerPC boxes. The driver was originally written by Hollis Blanchard, who has delegated maintainership to me. So this my first and maybe only patch in this official new role, because this driver is otherwise bug-free :-) Alan: "Actually its also a bug fix, tty->ldisc should be locked by refcounting and the helpers do this for you." Signed-off-by: Linas Vepstas Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 54cbb58b874..017f755632a 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -987,10 +987,7 @@ static void hvsi_write_worker(void *arg) start_j = 0; #endif /* DEBUG */ wake_up_all(&hp->emptyq); - if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags) - && hp->tty->ldisc.write_wakeup) - hp->tty->ldisc.write_wakeup(hp->tty); - wake_up_interruptible(&hp->tty->write_wait); + tty_wakeup(hp->tty); } out: -- cgit v1.2.3 From 2621e2a155140b01c6ff57b3863cda2922c2c8bd Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Wed, 5 Jul 2006 01:20:51 +0000 Subject: [WATCHDOG] Kconfig typos fix. Three typos in drivers/char/watchdog/Kconfig... Signed-off-by: Matt LaPlante Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index d53f664a4dd..fff89c2d88f 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -45,7 +45,7 @@ config WATCHDOG_NOWAYOUT comment "Watchdog Device Drivers" depends on WATCHDOG -# Architecture Independant +# Architecture Independent config SOFT_WATCHDOG tristate "Software watchdog" @@ -127,7 +127,7 @@ config S3C2410_WATCHDOG enabled. The driver is limited by the speed of the system's PCLK - signal, so with reasonbaly fast systems (PCLK around 50-66MHz) + signal, so with reasonably fast systems (PCLK around 50-66MHz) then watchdog intervals of over approximately 20seconds are unavailable. @@ -423,7 +423,7 @@ config SBC_EPX_C3_WATCHDOG is no way to know if writing to its IO address will corrupt your system or have any real effect. The only way to be sure that this driver does what you want is to make sure you - are runnning it on an EPX-C3 from Winsystems with the watchdog + are running it on an EPX-C3 from Winsystems with the watchdog timer at IO address 0x1ee and 0x1ef. It will write to both those IO ports. Basically, the assumption is made that if you compile this driver into your kernel and/or load it as a module, that you @@ -472,7 +472,7 @@ config INDYDOG tristate "Indy/I2 Hardware Watchdog" depends on WATCHDOG && SGI_IP22 help - Hardwaredriver for the Indy's/I2's watchdog. This is a + Hardware driver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second timer expired and no process has written to /dev/watchdog during that time. -- cgit v1.2.3 From cc36e7f124da139a819ad316c39d9dbcb5ba1897 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Sun, 27 Aug 2006 01:23:27 -0700 Subject: [PATCH] tty: remove bogus call to cdev_del() When cdev_add() failed there is no reason to call cdev_del(). Signed-off-by: Rolf Eike Beer Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index bfdb90242a9..d6e4eaa4853 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3094,7 +3094,6 @@ int tty_register_driver(struct tty_driver *driver) driver->cdev.owner = driver->owner; error = cdev_add(&driver->cdev, dev, driver->num); if (error) { - cdev_del(&driver->cdev); unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; driver->termios = driver->termios_locked = NULL; -- cgit v1.2.3 From 01cfaf0d12ae5fa092cc916ca4066ee1598e857d Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Sun, 27 Aug 2006 01:23:36 -0700 Subject: [PATCH] char/moxa.c: fix endianess and multiple-card issues While testing Moxa C218T/PCI on PowerPC 405EP I found that loading firmware using the linux kernel driver fails because calculation of the checksum is not endianess independent in the original code. After I fixed this I found that uploading firmware in a system with multiple cards causes a kernel oops. I had a look in the recent moxa sources and found that they do some kind of locking there. Applying this lock fixed the problem. Alan sayeth: Checksum changes are clearly correct. Other changes is an improvement but not I think enough to handle malicious firmware attacks. That said such an attacker has CAP_SYS_RAWIO anyway so that part is irrelevant except for neatness. [akpm@osdl.org: cleanups] Signed-off-by: Dirk Eibach Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/moxa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 4ea7bd5f4f5..a369dd6877d 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -142,6 +142,7 @@ typedef struct _moxa_board_conf { static moxa_board_conf moxa_boards[MAX_BOARDS]; static void __iomem *moxaBaseAddr[MAX_BOARDS]; +static int loadstat[MAX_BOARDS]; struct moxa_str { int type; @@ -1688,6 +1689,8 @@ int MoxaDriverPoll(void) if (moxaCard == 0) return (-1); for (card = 0; card < MAX_BOARDS; card++) { + if (loadstat[card] == 0) + continue; if ((ports = moxa_boards[card].numPorts) == 0) continue; if (readb(moxaIntPend[card]) == 0xff) { @@ -2903,6 +2906,7 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len) } break; } + loadstat[cardno] = 1; return (0); } @@ -2920,7 +2924,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len) len1 = len >> 1; ptr = (ushort *) moxaBuff; for (i = 0; i < len1; i++) - usum += *(ptr + i); + usum += le16_to_cpu(*(ptr + i)); retry = 0; do { len1 = len >> 1; @@ -2992,7 +2996,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor wlen = len >> 1; uptr = (ushort *) moxaBuff; for (i = 0; i < wlen; i++) - usum += uptr[i]; + usum += le16_to_cpu(uptr[i]); retry = 0; j = 0; do { -- cgit v1.2.3 From 533475d3d48eb839be2b57f6b020150abae91063 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 27 Aug 2006 01:23:39 -0700 Subject: [PATCH] vcsa attribute bits -> ioctl(VT_GETHIFONTMASK) When reading /dev/vcsa while a font with more than 256 characters is loaded, one of the attribute bits records the 9th bit of the character. But depending on the console driver (vgacon or fbcon for instance), that's bit 3 or bit 0. And there is no way for userland to know that, thus no way for userland to safely grab the screen content. So here is a (tested) patch: Add a VT_GETHIFONTMASK ioctl for knowing which bit is the 9th bit for VC text (vc_hi_font_mask field of the vc_data structure). Signed-off-by: Samuel Thibault Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index eccffaf26fa..a5628a8b662 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1011,6 +1011,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, return -EPERM; vt_dont_switch = 0; return 0; + case VT_GETHIFONTMASK: + return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); default: return -ENOIOCTLCMD; } -- cgit v1.2.3 From af9b897ee639d96b2bd29b65b50cd0a1f2b6d6c9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Aug 2006 01:24:01 -0700 Subject: [PATCH] tty layer comment the locking assumptions and functions somewhat Doesn't fix them but does show up some interesting areas that need review and fixing. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 718 +++++++++++++++++++++++++++++++++++++++++++---- drivers/char/tty_ioctl.c | 59 +++- 2 files changed, 715 insertions(+), 62 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index d6e4eaa4853..2cef982585f 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -153,6 +153,15 @@ int tty_ioctl(struct inode * inode, struct file * file, static int tty_fasync(int fd, struct file * filp, int on); static void release_mem(struct tty_struct *tty, int idx); +/** + * alloc_tty_struct - allocate a tty object + * + * Return a new empty tty structure. The data fields have not + * been initialized in any way but has been zeroed + * + * Locking: none + * FIXME: use kzalloc + */ static struct tty_struct *alloc_tty_struct(void) { @@ -166,6 +175,15 @@ static struct tty_struct *alloc_tty_struct(void) static void tty_buffer_free_all(struct tty_struct *); +/** + * free_tty_struct - free a disused tty + * @tty: tty struct to free + * + * Free the write buffers, tty queue and tty memory itself. + * + * Locking: none. Must be called after tty is definitely unused + */ + static inline void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); @@ -175,6 +193,17 @@ static inline void free_tty_struct(struct tty_struct *tty) #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) +/** + * tty_name - return tty naming + * @tty: tty structure + * @buf: buffer for output + * + * Convert a tty structure into a name. The name reflects the kernel + * naming policy and if udev is in use may not reflect user space + * + * Locking: none + */ + char *tty_name(struct tty_struct *tty, char *buf) { if (!tty) /* Hmm. NULL pointer. That's fun. */ @@ -235,6 +264,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) * Tty buffer allocation management */ + +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + static void tty_buffer_free_all(struct tty_struct *tty) { struct tty_buffer *thead; @@ -347,6 +387,18 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) } EXPORT_SYMBOL_GPL(tty_buffer_request_room); +/** + * tty_insert_flip_string - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @size: size + * + * Queue a series of bytes to the tty buffering. All the characters + * passed are marked as without error. Returns the number added. + * + * Locking: Called functions may take tty->buf.lock + */ + int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size) { @@ -370,6 +422,20 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, } EXPORT_SYMBOL(tty_insert_flip_string); +/** + * tty_insert_flip_string_flags - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @flags: flag bytes + * @size: size + * + * Queue a series of bytes to the tty buffering. For each character + * the flags array indicates the status of the character. Returns the + * number added. + * + * Locking: Called functions may take tty->buf.lock + */ + int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size) { @@ -394,6 +460,17 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, } EXPORT_SYMBOL(tty_insert_flip_string_flags); +/** + * tty_schedule_flip - push characters to ldisc + * @tty: tty to push from + * + * Takes any pending buffers and transfers their ownership to the + * ldisc side of the queue. It then schedules those characters for + * processing by the line discipline. + * + * Locking: Takes tty->buf.lock + */ + void tty_schedule_flip(struct tty_struct *tty) { unsigned long flags; @@ -405,12 +482,19 @@ void tty_schedule_flip(struct tty_struct *tty) } EXPORT_SYMBOL(tty_schedule_flip); -/* +/** + * tty_prepare_flip_string - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @size: desired size + * * Prepare a block of space in the buffer for data. Returns the length * available and buffer pointer to the space which is now allocated and * accounted for as ready for normal characters. This is used for drivers * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock */ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) @@ -427,12 +511,20 @@ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); -/* +/** + * tty_prepare_flip_string_flags - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @flags: return pointer for status flag write area + * @size: desired size + * * Prepare a block of space in the buffer for data. Returns the length * available and buffer pointer to the space which is now allocated and * accounted for as ready for characters. This is used for drivers * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock */ int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) @@ -451,10 +543,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); -/* +/** + * tty_set_termios_ldisc - set ldisc field + * @tty: tty structure + * @num: line discipline number + * * This is probably overkill for real world processors but * they are not on hot paths so a little discipline won't do * any harm. + * + * Locking: takes termios_sem */ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) @@ -474,6 +572,19 @@ static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ +/** + * tty_register_ldisc - install a line discipline + * @disc: ldisc number + * @new_ldisc: pointer to the ldisc object + * + * Installs a new line discipline into the kernel. The discipline + * is set up as unreferenced and then made available to the kernel + * from this point onwards. + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { unsigned long flags; @@ -493,6 +604,18 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) } EXPORT_SYMBOL(tty_register_ldisc); +/** + * tty_unregister_ldisc - unload a line discipline + * @disc: ldisc number + * @new_ldisc: pointer to the ldisc object + * + * Remove a line discipline from the kernel providing it is not + * currently in use. + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + int tty_unregister_ldisc(int disc) { unsigned long flags; @@ -512,6 +635,19 @@ int tty_unregister_ldisc(int disc) } EXPORT_SYMBOL(tty_unregister_ldisc); +/** + * tty_ldisc_get - take a reference to an ldisc + * @disc: ldisc number + * + * Takes a reference to a line discipline. Deals with refcounts and + * module locking counts. Returns NULL if the discipline is not available. + * Returns a pointer to the discipline and bumps the ref count if it is + * available + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + struct tty_ldisc *tty_ldisc_get(int disc) { unsigned long flags; @@ -540,6 +676,17 @@ struct tty_ldisc *tty_ldisc_get(int disc) EXPORT_SYMBOL_GPL(tty_ldisc_get); +/** + * tty_ldisc_put - drop ldisc reference + * @disc: ldisc number + * + * Drop a reference to a line discipline. Manage refcounts and + * module usage counts + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + void tty_ldisc_put(int disc) { struct tty_ldisc *ld; @@ -557,6 +704,19 @@ void tty_ldisc_put(int disc) EXPORT_SYMBOL_GPL(tty_ldisc_put); +/** + * tty_ldisc_assign - set ldisc on a tty + * @tty: tty to assign + * @ld: line discipline + * + * Install an instance of a line discipline into a tty structure. The + * ldisc must have a reference count above zero to ensure it remains/ + * The tty instance refcount starts at zero. + * + * Locking: + * Caller must hold references + */ + static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) { tty->ldisc = *ld; @@ -571,6 +731,8 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) * the tty ldisc. Return 0 on failure or 1 on success. This is * used to implement both the waiting and non waiting versions * of tty_ldisc_ref + * + * Locking: takes tty_ldisc_lock */ static int tty_ldisc_try(struct tty_struct *tty) @@ -602,6 +764,8 @@ static int tty_ldisc_try(struct tty_struct *tty) * must also be careful not to hold other locks that will deadlock * against a discipline change, such as an existing ldisc reference * (which we check for) + * + * Locking: call functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) @@ -622,6 +786,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); * Dereference the line discipline for the terminal and take a * reference to it. If the line discipline is in flux then * return NULL. Can be called from IRQ and timer functions. + * + * Locking: called functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) @@ -639,6 +805,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref); * * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May * be called in IRQ context. + * + * Locking: takes tty_ldisc_lock */ void tty_ldisc_deref(struct tty_ldisc *ld) @@ -683,6 +851,9 @@ static void tty_ldisc_enable(struct tty_struct *tty) * * Set the discipline of a tty line. Must be called from a process * context. + * + * Locking: takes tty_ldisc_lock. + * called functions take termios_sem */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) @@ -846,9 +1017,17 @@ restart: return retval; } -/* - * This routine returns a tty driver structure, given a device number +/** + * get_tty_driver - find device of a tty + * @dev_t: device identifier + * @index: returns the index of the tty + * + * This routine returns a tty driver structure, given a device number + * and also passes back the index number. + * + * Locking: caller must hold tty_mutex */ + static struct tty_driver *get_tty_driver(dev_t device, int *index) { struct tty_driver *p; @@ -863,11 +1042,17 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) return NULL; } -/* - * If we try to write to, or set the state of, a terminal and we're - * not in the foreground, send a SIGTTOU. If the signal is blocked or - * ignored, go ahead and perform the operation. (POSIX 7.2) +/** + * tty_check_change - check for POSIX terminal changes + * @tty: tty to check + * + * If we try to write to, or set the state of, a terminal and we're + * not in the foreground, send a SIGTTOU. If the signal is blocked or + * ignored, go ahead and perform the operation. (POSIX 7.2) + * + * Locking: none */ + int tty_check_change(struct tty_struct * tty) { if (current->signal->tty != tty) @@ -1005,10 +1190,27 @@ void tty_ldisc_flush(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_ldisc_flush); -/* - * This can be called by the "eventd" kernel thread. That is process synchronous, - * but doesn't hold any locks, so we need to make sure we have the appropriate - * locks for what we're doing.. +/** + * do_tty_hangup - actual handler for hangup events + * @data: tty device + * + * This can be called by the "eventd" kernel thread. That is process + * synchronous but doesn't hold any locks, so we need to make sure we + * have the appropriate locks for what we're doing. + * + * The hangup event clears any pending redirections onto the hung up + * device. It ensures future writes will error and it does the needed + * line discipline hangup and signal delivery. The tty object itself + * remains intact. + * + * Locking: + * BKL + * redirect lock for undoing redirection + * file list lock for manipulating list of ttys + * tty_ldisc_lock from called functions + * termios_sem resetting termios data + * tasklist_lock to walk task list for hangup event + * */ static void do_tty_hangup(void *data) { @@ -1133,6 +1335,14 @@ static void do_tty_hangup(void *data) fput(f); } +/** + * tty_hangup - trigger a hangup event + * @tty: tty to hangup + * + * A carrier loss (virtual or otherwise) has occurred on this like + * schedule a hangup sequence to run after this event. + */ + void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP @@ -1145,6 +1355,15 @@ void tty_hangup(struct tty_struct * tty) EXPORT_SYMBOL(tty_hangup); +/** + * tty_vhangup - process vhangup + * @tty: tty to hangup + * + * The user has asked via system call for the terminal to be hung up. + * We do this synchronously so that when the syscall returns the process + * is complete. That guarantee is neccessary for security reasons. + */ + void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP @@ -1156,6 +1375,14 @@ void tty_vhangup(struct tty_struct * tty) } EXPORT_SYMBOL(tty_vhangup); +/** + * tty_hung_up_p - was tty hung up + * @filp: file pointer of tty + * + * Return true if the tty has been subject to a vhangup or a carrier + * loss + */ + int tty_hung_up_p(struct file * filp) { return (filp->f_op == &hung_up_tty_fops); @@ -1163,19 +1390,28 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); -/* - * This function is typically called only by the session leader, when - * it wants to disassociate itself from its controlling tty. +/** + * disassociate_ctty - disconnect controlling tty + * @on_exit: true if exiting so need to "hang up" the session * - * It performs the following functions: + * This function is typically called only by the session leader, when + * it wants to disassociate itself from its controlling tty. + * + * It performs the following functions: * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. * - * The argument on_exit is set to 1 if called when a process is - * exiting; it is 0 if called by the ioctl TIOCNOTTY. + * The argument on_exit is set to 1 if called when a process is + * exiting; it is 0 if called by the ioctl TIOCNOTTY. + * + * Locking: tty_mutex is taken to protect current->signal->tty + * BKL is taken for hysterical raisins + * Tasklist lock is taken (under tty_mutex) to walk process + * lists for the session. */ + void disassociate_ctty(int on_exit) { struct tty_struct *tty; @@ -1222,6 +1458,25 @@ void disassociate_ctty(int on_exit) unlock_kernel(); } + +/** + * stop_tty - propogate flow control + * @tty: tty to stop + * + * Perform flow control to the driver. For PTY/TTY pairs we + * must also propogate the TIOCKPKT status. May be called + * on an already stopped device and will not re-call the driver + * method. + * + * This functionality is used by both the line disciplines for + * halting incoming flow and by the driver. It may therefore be + * called from any context, may be under the tty atomic_write_lock + * but not always. + * + * Locking: + * Broken. Relies on BKL which is unsafe here. + */ + void stop_tty(struct tty_struct *tty) { if (tty->stopped) @@ -1238,6 +1493,19 @@ void stop_tty(struct tty_struct *tty) EXPORT_SYMBOL(stop_tty); +/** + * start_tty - propogate flow control + * @tty: tty to start + * + * Start a tty that has been stopped if at all possible. Perform + * any neccessary wakeups and propogate the TIOCPKT status. If this + * is the tty was previous stopped and is being started then the + * driver start method is invoked and the line discipline woken. + * + * Locking: + * Broken. Relies on BKL which is unsafe here. + */ + void start_tty(struct tty_struct *tty) { if (!tty->stopped || tty->flow_stopped) @@ -1258,6 +1526,23 @@ void start_tty(struct tty_struct *tty) EXPORT_SYMBOL(start_tty); +/** + * tty_read - read method for tty device files + * @file: pointer to tty file + * @buf: user buffer + * @count: size of user buffer + * @ppos: unused + * + * Perform the read system call function on this terminal device. Checks + * for hung up devices before calling the line discipline method. + * + * Locking: + * Locks the line discipline internally while needed + * For historical reasons the line discipline read method is + * invoked under the BKL. This will go away in time so do not rely on it + * in new code. Multiple read calls may be outstanding in parallel. + */ + static ssize_t tty_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -1302,6 +1587,7 @@ static inline ssize_t do_tty_write( ssize_t ret = 0, written = 0; unsigned int chunk; + /* FIXME: O_NDELAY ... */ if (mutex_lock_interruptible(&tty->atomic_write_lock)) { return -ERESTARTSYS; } @@ -1318,6 +1604,9 @@ static inline ssize_t do_tty_write( * layer has problems with bigger chunks. It will * claim to be able to handle more characters than * it actually does. + * + * FIXME: This can probably go away now except that 64K chunks + * are too likely to fail unless switched to vmalloc... */ chunk = 2048; if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) @@ -1375,6 +1664,24 @@ static inline ssize_t do_tty_write( } +/** + * tty_write - write method for tty device file + * @file: tty file pointer + * @buf: user data to write + * @count: bytes to write + * @ppos: unused + * + * Write data to a tty device via the line discipline. + * + * Locking: + * Locks the line discipline as required + * Writes to the tty driver are serialized by the atomic_write_lock + * and are then processed in chunks to the device. The line discipline + * write method will not be involked in parallel for each device + * The line discipline write method is called under the big + * kernel lock for historical reasons. New code should not rely on this. + */ + static ssize_t tty_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { @@ -1422,7 +1729,18 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t static char ptychar[] = "pqrstuvwxyzabcde"; -static inline void pty_line_name(struct tty_driver *driver, int index, char *p) +/** + * pty_line_name - generate name for a pty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 6 bytes + * + * Generate a name from a driver reference and write it to the output + * buffer. + * + * Locking: None + */ +static void pty_line_name(struct tty_driver *driver, int index, char *p) { int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ @@ -1431,24 +1749,53 @@ static inline void pty_line_name(struct tty_driver *driver, int index, char *p) ptychar[i >> 4 & 0xf], i & 0xf); } -static inline void tty_line_name(struct tty_driver *driver, int index, char *p) +/** + * pty_line_name - generate name for a tty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 7 bytes + * + * Generate a name from a driver reference and write it to the output + * buffer. + * + * Locking: None + */ +static void tty_line_name(struct tty_driver *driver, int index, char *p) { sprintf(p, "%s%d", driver->name, index + driver->name_base); } -/* +/** + * init_dev - initialise a tty device + * @driver: tty driver we are opening a device on + * @idx: device index + * @tty: returned tty structure + * + * Prepare a tty device. This may not be a "new" clean device but + * could also be an active device. The pty drivers require special + * handling because of this. + * + * Locking: + * The function is called under the tty_mutex, which + * protects us from the tty struct or driver itself going away. + * + * On exit the tty device has the line discipline attached and + * a reference count of 1. If a pair was created for pty/tty use + * and the other was a pty master then it too has a reference count of 1. + * * WSH 06/09/97: Rewritten to remove races and properly clean up after a * failed open. The new code protects the open with a mutex, so it's * really quite straightforward. The mutex locking can probably be * relaxed for the (most common) case of reopening a tty. */ + static int init_dev(struct tty_driver *driver, int idx, struct tty_struct **ret_tty) { struct tty_struct *tty, *o_tty; struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; - int retval=0; + int retval = 0; /* check whether we're reopening an existing tty */ if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { @@ -1662,10 +2009,20 @@ release_mem_out: goto end_init; } -/* - * Releases memory associated with a tty structure, and clears out the - * driver table slots. +/** + * release_mem - release tty structure memory + * + * Releases memory associated with a tty structure, and clears out the + * driver table slots. This function is called when a device is no longer + * in use. It also gets called when setup of a device fails. + * + * Locking: + * tty_mutex - sometimes only + * takes the file list lock internally when working on the list + * of ttys that the driver keeps. + * FIXME: should we require tty_mutex is held here ?? */ + static void release_mem(struct tty_struct *tty, int idx) { struct tty_struct *o_tty; @@ -2006,18 +2363,27 @@ static void release_dev(struct file * filp) } -/* - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. +/** + * tty_open - open a tty device + * @inode: inode of device file + * @filp: file pointer to tty * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) + * tty_open and tty_release keep up the tty count that contains the + * number of opens done on a tty. We cannot use the inode-count, as + * different inodes might point to the same tty. * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. + * Open-counting is needed for pty masters, as well as for keeping + * track of serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) + * + * The termios state of a pty is reset on first open so that + * settings don't persist across reuse. + * + * Locking: tty_mutex protects current->signal->tty, get_tty_driver and + * init_dev work. tty->count should protect the rest. + * task_lock is held to update task details for sessions */ + static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; @@ -2132,6 +2498,18 @@ got_driver: } #ifdef CONFIG_UNIX98_PTYS +/** + * ptmx_open - open a unix 98 pty master + * @inode: inode of device file + * @filp: file pointer to tty + * + * Allocate a unix98 pty master device from the ptmx driver. + * + * Locking: tty_mutex protects theinit_dev work. tty->count should + protect the rest. + * allocated_ptys_lock handles the list of free pty numbers + */ + static int ptmx_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; @@ -2191,6 +2569,18 @@ out: } #endif +/** + * tty_release - vfs callback for close + * @inode: inode of tty + * @filp: file pointer for handle to tty + * + * Called the last time each file handle is closed that references + * this tty. There may however be several such references. + * + * Locking: + * Takes bkl. See release_dev + */ + static int tty_release(struct inode * inode, struct file * filp) { lock_kernel(); @@ -2199,7 +2589,18 @@ static int tty_release(struct inode * inode, struct file * filp) return 0; } -/* No kernel lock held - fine */ +/** + * tty_poll - check tty status + * @filp: file being polled + * @wait: poll wait structures to update + * + * Call the line discipline polling method to obtain the poll + * status of the device. + * + * Locking: locks called line discipline but ldisc poll method + * may be re-entered freely by other callers. + */ + static unsigned int tty_poll(struct file * filp, poll_table * wait) { struct tty_struct * tty; @@ -2243,6 +2644,21 @@ static int tty_fasync(int fd, struct file * filp, int on) return 0; } +/** + * tiocsti - fake input character + * @tty: tty to fake input into + * @p: pointer to character + * + * Fake input to a tty device. Does the neccessary locking and + * input management. + * + * FIXME: does not honour flow control ?? + * + * Locking: + * Called functions take tty_ldisc_lock + * current->signal->tty check is safe without locks + */ + static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; @@ -2258,6 +2674,18 @@ static int tiocsti(struct tty_struct *tty, char __user *p) return 0; } +/** + * tiocgwinsz - implement window query ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the kernel idea of the window size into the user buffer. No + * locking is done. + * + * FIXME: Returning random values racing a window size set is wrong + * should lock here against that + */ + static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) { if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) @@ -2265,6 +2693,24 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) return 0; } +/** + * tiocswinsz - implement window size set ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the user idea of the window size to the kernel. Traditionally + * this is just advisory information but for the Linux console it + * actually has driver level meaning and triggers a VC resize. + * + * Locking: + * The console_sem is used to ensure we do not try and resize + * the console twice at once. + * FIXME: Two racing size sets may leave the console and kernel + * parameters disagreeing. Is this exploitable ? + * FIXME: Random values racing a window size get is wrong + * should lock here against that + */ + static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, struct winsize __user * arg) { @@ -2294,6 +2740,15 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, return 0; } +/** + * tioccons - allow admin to move logical console + * @file: the file to become console + * + * Allow the adminstrator to move the redirected console device + * + * Locking: uses redirect_lock to guard the redirect information + */ + static int tioccons(struct file *file) { if (!capable(CAP_SYS_ADMIN)) @@ -2319,6 +2774,17 @@ static int tioccons(struct file *file) return 0; } +/** + * fionbio - non blocking ioctl + * @file: file to set blocking value + * @p: user parameter + * + * Historical tty interfaces had a blocking control ioctl before + * the generic functionality existed. This piece of history is preserved + * in the expected tty API of posix OS's. + * + * Locking: none, the open fle handle ensures it won't go away. + */ static int fionbio(struct file *file, int __user *p) { @@ -2334,6 +2800,23 @@ static int fionbio(struct file *file, int __user *p) return 0; } +/** + * tiocsctty - set controlling tty + * @tty: tty structure + * @arg: user argument + * + * This ioctl is used to manage job control. It permits a session + * leader to set this tty as the controlling tty for the session. + * + * Locking: + * Takes tasklist lock internally to walk sessions + * Takes task_lock() when updating signal->tty + * + * FIXME: tty_mutex is needed to protect signal->tty references. + * FIXME: why task_lock on the signal->tty reference ?? + * + */ + static int tiocsctty(struct tty_struct *tty, int arg) { struct task_struct *p; @@ -2374,6 +2857,18 @@ static int tiocsctty(struct tty_struct *tty, int arg) return 0; } +/** + * tiocgpgrp - get process group + * @tty: tty passed by user + * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @p: returned pid + * + * Obtain the process group of the tty. If there is no process group + * return an error. + * + * Locking: none. Reference to ->signal->tty is safe. + */ + static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { /* @@ -2385,6 +2880,20 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return put_user(real_tty->pgrp, p); } +/** + * tiocspgrp - attempt to set process group + * @tty: tty passed by user + * @real_tty: tty side device matching tty passed by user + * @p: pid pointer + * + * Set the process group of the tty to the session passed. Only + * permitted where the tty session is our session. + * + * Locking: None + * + * FIXME: current->signal->tty referencing is unsafe. + */ + static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { pid_t pgrp; @@ -2408,6 +2917,18 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return 0; } +/** + * tiocgsid - get session id + * @tty: tty passed by user + * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @p: pointer to returned session id + * + * Obtain the session id of the tty. If there is no session + * return an error. + * + * Locking: none. Reference to ->signal->tty is safe. + */ + static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { /* @@ -2421,6 +2942,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ return put_user(real_tty->session, p); } +/** + * tiocsetd - set line discipline + * @tty: tty device + * @p: pointer to user data + * + * Set the line discipline according to user request. + * + * Locking: see tty_set_ldisc, this function is just a helper + */ + static int tiocsetd(struct tty_struct *tty, int __user *p) { int ldisc; @@ -2430,6 +2961,21 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) return tty_set_ldisc(tty, ldisc); } +/** + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS + * + * Perform a timed break on hardware that lacks its own driver level + * timed break functionality. + * + * Locking: + * None + * + * FIXME: + * What if two overlap + */ + static int send_break(struct tty_struct *tty, unsigned int duration) { tty->driver->break_ctl(tty, -1); @@ -2442,8 +2988,19 @@ static int send_break(struct tty_struct *tty, unsigned int duration) return 0; } -static int -tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) +/** + * tiocmget - get modem status + * @tty: tty device + * @file: user file pointer + * @p: pointer to result + * + * Obtain the modem status bits from the tty driver if the feature + * is supported. Return -EINVAL if it is not available. + * + * Locking: none (up to the driver) + */ + +static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) { int retval = -EINVAL; @@ -2456,8 +3013,20 @@ tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) return retval; } -static int -tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, +/** + * tiocmset - set modem status + * @tty: tty device + * @file: user file pointer + * @cmd: command - clear bits, set bits or set all + * @p: pointer to desired bits + * + * Set the modem status bits from the tty driver if the feature + * is supported. Return -EINVAL if it is not available. + * + * Locking: none (up to the driver) + */ + +static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned __user *p) { int retval = -EINVAL; @@ -2573,6 +3142,7 @@ int tty_ioctl(struct inode * inode, struct file * file, clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: + /* FIXME: taks lock or tty_mutex ? */ if (current->signal->tty != tty) return -ENOTTY; if (current->signal->leader) @@ -2753,9 +3323,16 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); -/* - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. +/** + * flush_to_ldisc + * @private_: tty structure passed from work queue. + * + * This routine is called out of the software interrupt to flush data + * from the buffer chain to the line discipline. + * + * Locking: holds tty->buf.lock to guard buffer list. Drops the lock + * while invoking the line discipline receive_buf method. The + * receive_buf method is single threaded for each tty instance. */ static void flush_to_ldisc(void *private_) @@ -2831,6 +3408,8 @@ static int n_baud_table = ARRAY_SIZE(baud_table); * Convert termios baud rate data into a speed. This should be called * with the termios lock held if this termios is a terminal termios * structure. May change the termios data. + * + * Locking: none */ int tty_termios_baud_rate(struct termios *termios) @@ -2859,6 +3438,8 @@ EXPORT_SYMBOL(tty_termios_baud_rate); * Returns the baud rate as an integer for this terminal. The * termios lock must be held by the caller and the terminal bit * flags may be updated. + * + * Locking: none */ int tty_get_baud_rate(struct tty_struct *tty) @@ -2888,6 +3469,8 @@ EXPORT_SYMBOL(tty_get_baud_rate); * * In the event of the queue being busy for flipping the work will be * held off and retried later. + * + * Locking: tty buffer lock. Driver locks in low latency mode. */ void tty_flip_buffer_push(struct tty_struct *tty) @@ -2907,9 +3490,16 @@ void tty_flip_buffer_push(struct tty_struct *tty) EXPORT_SYMBOL(tty_flip_buffer_push); -/* - * This subroutine initializes a tty structure. +/** + * initialize_tty_struct + * @tty: tty to initialize + * + * This subroutine initializes a tty structure that has been newly + * allocated. + * + * Locking: none - tty in question must not be exposed at this point */ + static void initialize_tty_struct(struct tty_struct *tty) { memset(tty, 0, sizeof(struct tty_struct)); @@ -2935,6 +3525,7 @@ static void initialize_tty_struct(struct tty_struct *tty) /* * The default put_char routine if the driver did not define one. */ + static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) { tty->driver->write(tty, &ch, 1); @@ -2943,19 +3534,23 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) static struct class *tty_class; /** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device for this - * tty device it can be set to NULL safely. + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. * - * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). * - * This call is required to be made to register an individual tty device if - * the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If that - * bit is not set, this function should not be called by a tty driver. + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. + * + * Locking: ?? */ + struct class_device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { @@ -2977,13 +3572,16 @@ struct class_device *tty_register_device(struct tty_driver *driver, } /** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device * - * If a tty device is registered with a call to tty_register_device() then - * this function must be made when the tty device is gone. + * If a tty device is registered with a call to tty_register_device() then + * this function must be called when the tty device is gone. + * + * Locking: ?? */ + void tty_unregister_device(struct tty_driver *driver, unsigned index) { class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index f19cf9d7792..4ad47d321bd 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -36,6 +36,18 @@ #define TERMIOS_WAIT 2 #define TERMIOS_TERMIO 4 + +/** + * tty_wait_until_sent - wait for I/O to finish + * @tty: tty we are waiting for + * @timeout: how long we will wait + * + * Wait for characters pending in a tty driver to hit the wire, or + * for a timeout to occur (eg due to flow control) + * + * Locking: none + */ + void tty_wait_until_sent(struct tty_struct * tty, long timeout) { DECLARE_WAITQUEUE(wait, current); @@ -94,6 +106,18 @@ static void unset_locked_termios(struct termios *termios, old->c_cc[i] : termios->c_cc[i]; } +/** + * change_termios - update termios values + * @tty: tty to update + * @new_termios: desired new value + * + * Perform updates to the termios values set on this terminal. There + * is a bit of layering violation here with n_tty in terms of the + * internal knowledge of this function. + * + * Locking: termios_sem + */ + static void change_termios(struct tty_struct * tty, struct termios * new_termios) { int canon_change; @@ -155,6 +179,19 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios up(&tty->termios_sem); } +/** + * set_termios - set termios values for a tty + * @tty: terminal device + * @arg: user data + * @opt: option information + * + * Helper function to prepare termios data and run neccessary other + * functions before using change_termios to do the actual changes. + * + * Locking: + * Called functions take ldisc and termios_sem locks + */ + static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; @@ -284,6 +321,17 @@ static void set_sgflags(struct termios * termios, int flags) } } +/** + * set_sgttyb - set legacy terminal values + * @tty: tty structure + * @sgttyb: pointer to old style terminal structure + * + * Updates a terminal from the legacy BSD style terminal information + * structure. + * + * Locking: termios_sem + */ + static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { int retval; @@ -369,9 +417,16 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) } #endif -/* - * Send a high priority character to the tty. +/** + * send_prio_char - send priority character + * + * Send a high priority character to the tty even if stopped + * + * Locking: none + * + * FIXME: overlapping calls with start/stop tty lose state of tty */ + static void send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; -- cgit v1.2.3 From 01da5fd83d6b2c5e36b77539f6cbdd8f49849225 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Aug 2006 01:24:02 -0700 Subject: [PATCH] Fix tty layer DoS and comment relevant code Unlike the other tty comment patch this one has code changes. Specifically it limits the queue size for a tty to 64K characters (128Kbytes) worst case even if the tty is ignoring tty->throttle. This is because certain drivers don't honour the throttle value correctly, although it is a useful safeguard anyway. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 89 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 10 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 2cef982585f..bb0d9199e99 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -265,6 +265,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) */ +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + + /** * tty_buffer_free_all - free buffers used by a tty * @tty: tty to free from @@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty) kfree(thead); } tty->buf.tail = NULL; + tty->buf.memory_used = 0; } +/** + * tty_buffer_init - prepare a tty buffer structure + * @tty: tty to initialise + * + * Set up the initial state of the buffer management for a tty device. + * Must be called before the other tty buffer functions are used. + * + * Locking: none + */ + static void tty_buffer_init(struct tty_struct *tty) { spin_lock_init(&tty->buf.lock); tty->buf.head = NULL; tty->buf.tail = NULL; tty->buf.free = NULL; + tty->buf.memory_used = 0; } -static struct tty_buffer *tty_buffer_alloc(size_t size) +/** + * tty_buffer_alloc - allocate a tty buffer + * @tty: tty device + * @size: desired size (characters) + * + * Allocate a new tty buffer to hold the desired number of characters. + * Return NULL if out of memory or the allocation would exceed the + * per device queue + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) { - struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + struct tty_buffer *p; + + if (tty->buf.memory_used + size > 65536) + return NULL; + p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if(p == NULL) return NULL; p->used = 0; @@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size) p->read = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; -/* printk("Flip create %p\n", p); */ + tty->buf.memory_used += size; return p; } -/* Must be called with the tty_read lock held. This needs to acquire strategy - code to decide if we should kfree or relink a given expired buffer */ +/** + * tty_buffer_free - free a tty buffer + * @tty: tty owning the buffer + * @b: the buffer to free + * + * Free a tty buffer, or add it to the free list according to our + * internal strategy + * + * Locking: Caller must hold tty->buf.lock + */ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) { /* Dumb strategy for now - should keep some stats */ -/* printk("Flip dispose %p\n", b); */ + tty->buf.memory_used -= b->size; + WARN_ON(tty->buf.memory_used < 0); + if(b->size >= 512) kfree(b); else { @@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) } } +/** + * tty_buffer_find - find a free tty buffer + * @tty: tty owning the buffer + * @size: characters wanted + * + * Locate an existing suitable tty buffer or if we are lacking one then + * allocate a new one. We round our buffers off in 256 character chunks + * to get better allocation behaviour. + * + * Locking: Caller must hold tty->buf.lock + */ + static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) { struct tty_buffer **tbh = &tty->buf.free; @@ -339,20 +400,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) t->used = 0; t->commit = 0; t->read = 0; - /* DEBUG ONLY */ -/* memset(t->data, '*', size); */ -/* printk("Flip recycle %p\n", t); */ + tty->buf.memory_used += t->size; return t; } tbh = &((*tbh)->next); } /* Round the buffer size out */ size = (size + 0xFF) & ~ 0xFF; - return tty_buffer_alloc(size); + return tty_buffer_alloc(tty, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ int tty_buffer_request_room(struct tty_struct *tty, size_t size) { struct tty_buffer *b, *n; -- cgit v1.2.3 From 18f2905fcec3e06deafd25a02e37eabaaaaef744 Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Wed, 30 Aug 2006 23:17:55 +0100 Subject: [PATCH] drm: radeon flush TCL VAP for vertex program enable/disable The radeon requires a VAP state flush when enabling/disabling vertex programs on the r200 cards. Signed-off-by: Dave Airlie Signed-off-by: Linus Torvalds --- drivers/char/drm/radeon_state.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 5bb2234a909..39a7f685e3f 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -175,6 +175,14 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * } break; + case R200_EMIT_VAP_CTL:{ + RING_LOCALS; + BEGIN_RING(2); + OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); + ADVANCE_RING(); + } + break; + case RADEON_EMIT_RB3D_COLORPITCH: case RADEON_EMIT_RE_LINE_PATTERN: case RADEON_EMIT_SE_LINE_WIDTH: @@ -202,7 +210,6 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case R200_EMIT_TCL_LIGHT_MODEL_CTL_0: case R200_EMIT_TFACTOR_0: case R200_EMIT_VTX_FMT_0: - case R200_EMIT_VAP_CTL: case R200_EMIT_MATRIX_SELECT_0: case R200_EMIT_TEX_PROC_CTL_2: case R200_EMIT_TCL_UCP_VERT_BLEND_CTL: -- cgit v1.2.3 From 202af6d50155f8594ba01d8e0a54d77facc0152a Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Thu, 31 Aug 2006 21:27:36 -0700 Subject: [PATCH] synclink_gt: fix receive tty error handling Fix receive tty error handling in synclink_gt driver. Adrian reported compiler warning for incorrect bit test against char variable. I determined these and other device specific error bits were incorrectly defined. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink_gt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index b2dbbdb1bf8..2f07b085536 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -391,8 +391,8 @@ static MGSL_PARAMS default_params = { #define DESC_LIST_SIZE 4096 #define MASK_PARITY BIT1 -#define MASK_FRAMING BIT2 -#define MASK_BREAK BIT3 +#define MASK_FRAMING BIT0 +#define MASK_BREAK BIT14 #define MASK_OVERRUN BIT4 #define GSR 0x00 /* global status */ @@ -1800,17 +1800,17 @@ static void rx_async(struct slgt_info *info) stat = 0; - if ((status = *(p+1) & (BIT9 + BIT8))) { - if (status & BIT9) + if ((status = *(p+1) & (BIT1 + BIT0))) { + if (status & BIT1) icount->parity++; - else if (status & BIT8) + else if (status & BIT0) icount->frame++; /* discard char if tty control flags say so */ if (status & info->ignore_status_mask) continue; - if (status & BIT9) + if (status & BIT1) stat = TTY_PARITY; - else if (status & BIT8) + else if (status & BIT0) stat = TTY_FRAME; } if (tty) { -- cgit v1.2.3 From 290995fc3c06c0548ae303dd0b1371a8727f4fad Mon Sep 17 00:00:00 2001 From: "Ian E. Morgan" Date: Thu, 31 Aug 2006 21:27:42 -0700 Subject: [PATCH] SBC8360: module_param() permission fixes The last argument of module_param is permissions, not default value. Acked-by: Wim Van Sebroeck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/sbc8360.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c index 1035be5b501..41fc6f80c49 100644 --- a/drivers/char/watchdog/sbc8360.c +++ b/drivers/char/watchdog/sbc8360.c @@ -200,7 +200,7 @@ static int wd_margin = 0xB; static int wd_multiplier = 2; static int nowayout = WATCHDOG_NOWAYOUT; -module_param(timeout, int, 27); +module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, @@ -407,7 +407,7 @@ module_exit(sbc8360_exit); MODULE_AUTHOR("Ian E. Morgan "); MODULE_DESCRIPTION("SBC8360 watchdog driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0"); +MODULE_VERSION("1.01"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); /* end of sbc8360.c */ -- cgit v1.2.3 From a9eec55623f5aedfcef745d3a0e0f97f5d4f74be Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 31 Aug 2006 21:27:45 -0700 Subject: [PATCH] IPMI: fix occasional oops on module unload Olaf Kirch of SuSE tracked down a problem where module unloads of the IPMI driver would occasionally result in Oopses. He tracked that down to a variable that wasn't always initialized properly in some situations. This patch initializes that variable. Olaf sent a patch that kzalloc-ed the data, but this structure is large enough that I would perfer to not do that. Thanks Olaf! Signed-off-by: Corey Minyard Cc: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 0aa5d608fe6..843d34c8627 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3428,6 +3428,7 @@ struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC); if (rv) { + rv->user = NULL; rv->done = free_recv_msg; atomic_inc(&recv_msg_inuse_count); } -- cgit v1.2.3 From 55ebcc38a5f6d40e4c41447e413ef842b803980f Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Sat, 16 Sep 2006 12:15:36 -0700 Subject: [PATCH] IPMI: Fix oops on ipmi_msghandler removal for non ipmi systems When the ipmi_si module is loaded on a system without any ipmi device, it fails with nodev. It would be fine if all resources were freed. A call to device_unregister() is missing, resulting to a oops when you remove the ipmi_msghandler. Signed-off-by: Arnaud Patard Acked-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f57eba0bf25..31b59403b63 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2481,6 +2481,7 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_PCI pci_unregister_driver(&ipmi_pci_driver); #endif + driver_unregister(&ipmi_driver); printk("ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; } else { -- cgit v1.2.3 From b64074e46a9c2a7d5c66eff066a7c0b58377a143 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 16 Sep 2006 12:15:38 -0700 Subject: [PATCH] hvc_console suspend fix Fix http://bugzilla.kernel.org/show_bug.cgi?id=7152 Cc: Michael Tautschnig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index ca2f538e549..613d67f1c7f 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -668,6 +668,7 @@ int khvcd(void *unused) do { poll_mask = 0; hvc_kicked = 0; + try_to_freeze(); wmb(); if (cpus_empty(cpus_in_xmon)) { spin_lock(&hvc_structs_lock); -- cgit v1.2.3 From 4064d5ef26a04d9e34e4c0f348e30f14ab6828d8 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 16 Sep 2006 12:15:41 -0700 Subject: [PATCH] IPMI: fix handling of OEM flags If one of the OEM flags becomes set in the flags from the hardware, the driver could hang if no OEM handler was set. Fix the code to handle this. This was tested by setting the flags by hand after they were fetched. Signed-off-by: Corey Minyard Ackde-by: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 31b59403b63..abca98beac1 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -402,10 +402,10 @@ static void handle_flags(struct smi_info *smi_info) smi_info->curr_msg->data, smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; - } else if (smi_info->msg_flags & OEM_DATA_AVAIL) { - if (smi_info->oem_data_avail_handler) - if (smi_info->oem_data_avail_handler(smi_info)) - goto retry; + } else if (smi_info->msg_flags & OEM_DATA_AVAIL && + smi_info->oem_data_avail_handler) { + if (smi_info->oem_data_avail_handler(smi_info)) + goto retry; } else { smi_info->si_state = SI_NORMAL; } -- cgit v1.2.3