From a9bd53bc49ee8984633e57c1d9d45111c58e9457 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 28 Jul 2005 14:42:00 -0400 Subject: [ACPI] HPET driver now checks for acpi_register_gsi() errors Signed-off-by: Kenji Kaneshige Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/char/hpet.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5ec732e6ca92..a8d4c47f7add 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -906,11 +906,15 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) if (irqp->number_of_interrupts > 0) { hdp->hd_nirqs = irqp->number_of_interrupts; - for (i = 0; i < hdp->hd_nirqs; i++) - hdp->hd_irq[i] = + for (i = 0; i < hdp->hd_nirqs; i++) { + int rc = acpi_register_gsi(irqp->interrupts[i], irqp->edge_level, irqp->active_high_low); + if (rc < 0) + return AE_ERROR; + hdp->hd_irq[i] = rc; + } } } -- cgit v1.2.2 From 46acac3b4fd8ef66eec63b51de8d556a17c7d4f7 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 11 Aug 2005 20:28:56 -0700 Subject: [AGPGART] Drop duplicate setting of info->mode in agp_copy_info() Spotted by Jeremy Fitzhardinge, this change crept in with the multiple backend support. It's clearly incorrect to overwrite info->mode after we just went to lengths to determine which bits to mask out. Signed-off-by: Dave Jones --- drivers/char/agp/generic.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index f0079e991bdc..eb052427670b 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -319,7 +319,6 @@ int agp_copy_info(struct agp_bridge_data *bridge, struct agp_kern_info *info) info->mode = bridge->mode & ~AGP3_RESERVED_MASK; else info->mode = bridge->mode & ~AGP2_RESERVED_MASK; - info->mode = bridge->mode; info->aper_base = bridge->gart_bus_addr; info->aper_size = agp_return_size(); info->max_memory = bridge->max_memory_agp; -- cgit v1.2.2 From 8c8b83854ea973ee7f37db6612d10d3acc5531d9 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 17 Aug 2005 23:08:11 -0700 Subject: Fix up various printk levels and whitespace corrections. Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/char/agp/generic.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index eb052427670b..ac9da0ca36b7 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -355,7 +355,7 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start) return -EINVAL; if (curr->is_bound == TRUE) { - printk (KERN_INFO PFX "memory %p is already bound!\n", curr); + printk(KERN_INFO PFX "memory %p is already bound!\n", curr); return -EINVAL; } if (curr->is_flushed == FALSE) { @@ -390,7 +390,7 @@ int agp_unbind_memory(struct agp_memory *curr) return -EINVAL; if (curr->is_bound != TRUE) { - printk (KERN_INFO PFX "memory %p was not bound!\n", curr); + printk(KERN_INFO PFX "memory %p was not bound!\n", curr); return -EINVAL; } @@ -414,7 +414,7 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ u32 tmp; if (*requested_mode & AGP2_RESERVED_MASK) { - printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); + printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); *requested_mode &= ~AGP2_RESERVED_MASK; } @@ -422,7 +422,7 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ tmp = *requested_mode & 7; switch (tmp) { case 0: - printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to x1 mode.\n", current->comm); + printk(KERN_INFO PFX "%s tried to set rate=x0. Setting to x1 mode.\n", current->comm); *requested_mode |= AGPSTAT2_1X; break; case 1: @@ -492,18 +492,18 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ u32 tmp; if (*requested_mode & AGP3_RESERVED_MASK) { - printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); + printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); *requested_mode &= ~AGP3_RESERVED_MASK; } /* Check the speed bits make sense. */ tmp = *requested_mode & 7; if (tmp == 0) { - printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm); + printk(KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm); *requested_mode |= AGPSTAT3_4X; } if (tmp >= 3) { - printk (KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4); + printk(KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4); *requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X; } @@ -532,7 +532,7 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ * AGP2.x 4x -> AGP3.0 4x. */ if (*requested_mode & AGPSTAT2_4X) { - printk (KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n", + printk(KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n", current->comm, *requested_mode); *requested_mode &= ~AGPSTAT2_4X; *requested_mode |= AGPSTAT3_4X; @@ -543,7 +543,7 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ * but have been passed an AGP 2.x mode. * Convert AGP 1x,2x,4x -> AGP 3.0 4x. */ - printk (KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n", + printk(KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n", current->comm, *requested_mode); *requested_mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X); *requested_mode |= AGPSTAT3_4X; @@ -553,13 +553,13 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ if (!(*bridge_agpstat & AGPSTAT3_8X)) { *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); *bridge_agpstat |= AGPSTAT3_4X; - printk ("%s requested AGPx8 but bridge not capable.\n", current->comm); + printk(KERN_INFO PFX "%s requested AGPx8 but bridge not capable.\n", current->comm); return; } if (!(*vga_agpstat & AGPSTAT3_8X)) { *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); *bridge_agpstat |= AGPSTAT3_4X; - printk ("%s requested AGPx8 but graphic card not capable.\n", current->comm); + printk(KERN_INFO PFX "%s requested AGPx8 but graphic card not capable.\n", current->comm); return; } /* All set, bridge & device can do AGP x8*/ @@ -577,13 +577,13 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X)) *bridge_agpstat |= AGPSTAT3_4X; else { - printk (KERN_INFO PFX "Badness. Don't know which AGP mode to set. " + printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. " "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n", origbridge, origvga, *bridge_agpstat, *vga_agpstat); if (!(*bridge_agpstat & AGPSTAT3_4X)) - printk (KERN_INFO PFX "Bridge couldn't do AGP x4.\n"); + printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n"); if (!(*vga_agpstat & AGPSTAT3_4X)) - printk (KERN_INFO PFX "Graphic card couldn't do AGP x4.\n"); + printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n"); return; } } @@ -621,7 +621,7 @@ u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode for (;;) { device = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, device); if (!device) { - printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n"); + printk(KERN_INFO PFX "Couldn't find an AGP VGA controller.\n"); return 0; } cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); @@ -733,7 +733,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) pci_write_config_dword(bridge->dev, bridge->capndx+AGPCTRL, temp); - printk (KERN_INFO PFX "Device is in legacy mode," + printk(KERN_INFO PFX "Device is in legacy mode," " falling back to 2.x\n"); } } -- cgit v1.2.2 From 8466361ad5233d4356a4601e16b66c25277920d1 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 24 Aug 2005 12:09:07 -0400 Subject: [ACPI] delete CONFIG_ACPI_INTERPRETER it is a synonym for CONFIG_ACPI Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_si_intf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a44b97304e95..c51b02d9dfd0 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -986,7 +986,7 @@ MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for" #define IPMI_MEM_ADDR_SPACE 1 #define IPMI_IO_ADDR_SPACE 2 -#if defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_X86) || defined(CONFIG_PCI) +#if defined(CONFIG_ACPI) || defined(CONFIG_X86) || defined(CONFIG_PCI) static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr) { int i; @@ -1362,7 +1362,7 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) } -#ifdef CONFIG_ACPI_INTERPRETER +#ifdef CONFIG_ACPI #include @@ -2067,7 +2067,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) rv = try_init_mem(intf_num, &new_smi); if (rv) rv = try_init_port(intf_num, &new_smi); -#ifdef CONFIG_ACPI_INTERPRETER +#ifdef CONFIG_ACPI if ((rv) && (si_trydefaults)) { rv = try_init_acpi(intf_num, &new_smi); } -- cgit v1.2.2 From 76f58584824c61eb5b3bdbf019236815921d2e7c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 24 Aug 2005 12:10:49 -0400 Subject: [ACPI] delete CONFIG_ACPI_BUS it is a synonym for CONFIG_ACPI Signed-off-by: Len Brown --- drivers/char/tpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 79e9832ef1f3..b58adfe3ed19 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -17,7 +17,7 @@ config TCG_TPM obtained at: . To compile this driver as a module, choose M here; the module will be called tpm. If unsure, say N. - Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI_BUS + Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI and CONFIG_PNPACPI. config TCG_NSC -- cgit v1.2.2 From 4fbd1514173a80f9dc93e8ebbd6d4eb97cee123e Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Tue, 7 Jun 2005 16:54:01 +0200 Subject: [ACPI] check acpi_disabled in IPMI Signed-off-by: Yann Droneaud Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_si_intf.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index c51b02d9dfd0..adbec73b80a6 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1484,6 +1484,9 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) char *io_type; u8 addr_space; + if (acpi_disabled) + return -ENODEV; + if (acpi_failure) return -ENODEV; -- cgit v1.2.2 From 29db35edb2548c3b0299c53d62d5f26d77a8e58f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 1 Sep 2005 10:50:13 -0700 Subject: [AGPGART] Remove trailing space before \n From: Denis Vlasenko Signed-off-by: Dave Jones --- drivers/char/agp/amd64-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 59f589d733f9..0a7624a9b1c1 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -429,7 +429,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) struct pci_dev *dev1; int i; unsigned size = amd64_fetch_size(); - printk(KERN_INFO "Setting up ULi AGP. \n"); + printk(KERN_INFO "Setting up ULi AGP.\n"); dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0)); if (dev1 == NULL) { printk(KERN_INFO PFX "Detected a ULi chipset, " -- cgit v1.2.2 From ebede60741e2cec6d210f137fd22a30e37abc0be Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 2 Sep 2005 12:20:18 -0700 Subject: [SPARC32]: More dependencies fallout More stuff that got exposed to sparc32 build due to inclusion of drivers/char/Kconfig in arch/sparc/Kconfig needs to be excluded. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/char/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7333b41d4224..d6adc2614f69 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -175,7 +175,7 @@ config MOXA_INTELLIO config MOXA_SMARTIO tristate "Moxa SmartIO support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && (BROKEN || !SPARC32) help Say Y here if you have a Moxa SmartIO multiport serial card. -- cgit v1.2.2 From be3df0f94d77ba3cff40c14c3e21a753c40ba6f2 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Wed, 17 Aug 2005 01:49:24 +0200 Subject: [WATCHDOG] Makefile-probe_order-patch Re-arrange Makefile according to what we want to probe first. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Makefile | 69 ++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index c1838834ea7f..d9b0ed53dae6 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -2,42 +2,65 @@ # Makefile for the WatchDog device drivers. # +# Only one watchdog can succeed. We probe the ISA/PCI/USB based +# watchdog-cards first, then the architecture specific watchdog +# drivers and then the architecture independant "softdog" driver. +# This means that if your ISA/PCI/USB card isn't detected that +# you can fall back to an architecture specific driver and if +# that also fails then you can fall back to the software watchdog +# to give you some cover. + +# ISA-based Watchdog Cards obj-$(CONFIG_PCWATCHDOG) += pcwd.o -obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o -obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o -obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o -obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o -obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_WDT) += wdt.o + +# PCI-based Watchdog Cards +obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o obj-$(CONFIG_WDTPCI) += wdt_pci.o + +# USB-based Watchdog Cards +obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o + +# ARM Architecture obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o -obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o -obj-$(CONFIG_MACHZ_WDT) += machzwd.o -obj-$(CONFIG_SH_WDT) += shwdt.o +obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o +obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o -obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o -obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o -obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o -obj-$(CONFIG_SC520_WDT) += sc520_wdt.o -obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o + +# X86 (i386 + ia64 + x86_64) Architecture +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o -obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_SC520_WDT) += sc520_wdt.o +obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o +obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o -obj-$(CONFIG_INDYDOG) += indydog.o -obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o -obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o -obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o -obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o +obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o +obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_MACHZ_WDT) += machzwd.o + +# PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o -# Only one watchdog can succeed. We probe the hardware watchdog -# drivers first, then the softdog driver. This means if your hardware -# watchdog dies or is 'borrowed' for some reason the software watchdog -# still gives you some cover. +# MIPS Architecture +obj-$(CONFIG_INDYDOG) += indydog.o + +# S390 Architecture + +# SUPERH Architecture +obj-$(CONFIG_SH_WDT) += shwdt.o + +# SPARC64 Architecture +# Architecture Independant obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o -- cgit v1.2.2 From 09c8a9a0c0fe5b3182b6ecfa556fa77a55892c93 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sat, 3 Sep 2005 13:46:56 +0200 Subject: [WATCHDOG] Kconfig+Makefile-clean Clean the Kconfig+Makefile according to a sorted list of the drivers of each architecture (and sub-architecture). Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 43 +++++++++++++++++++++--------------------- drivers/char/watchdog/Makefile | 4 +++- 2 files changed, 25 insertions(+), 22 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index b53e2e2b5aee..f4bf6c399010 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -84,6 +84,17 @@ config 977_WATCHDOG Not sure? It's safe to say N. +config IXP2000_WATCHDOG + tristate "IXP2000 Watchdog" + depends on WATCHDOG && ARCH_IXP2000 + help + Say Y here if to include support for the watchdog timer + in the Intel IXP2000(2400, 2800, 2850) network processors. + This driver can be built as a module by choosing M. The module + will be called ixp2000_wdt. + + Say N if you are unsure. + config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" depends on WATCHDOG && ARCH_IXP4XX @@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG Say N if you are unsure. -config IXP2000_WATCHDOG - tristate "IXP2000 Watchdog" - depends on WATCHDOG && ARCH_IXP2000 - help - Say Y here if to include support for the watchdog timer - in the Intel IXP2000(2400, 2800, 2850) network processors. - This driver can be built as a module by choosing M. The module - will be called ixp2000_wdt. - - Say N if you are unsure. - config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on WATCHDOG && ARCH_S3C2410 @@ -346,6 +346,17 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +# PPC64 Architecture + +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on WATCHDOG && PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # MIPS Architecture config INDYDOG @@ -414,16 +425,6 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. -# ppc64 RTAS watchdog -config WATCHDOG_RTAS - tristate "RTAS watchdog" - depends on WATCHDOG && PPC_RTAS - help - This driver adds watchdog support for the RTAS watchdog. - - To compile this driver as a module, choose M here. The module - will be called wdrtas. - # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index d9b0ed53dae6..6f02f4ce4536 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -25,8 +25,8 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o # ARM Architecture obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o -obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o +obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o @@ -50,6 +50,8 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o # PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o + +# PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # MIPS Architecture -- cgit v1.2.2 From 2dab3cabc4b3c1ef53965233dc8a05e0ddeeb38e Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Wed, 17 Aug 2005 08:58:34 +0200 Subject: [WATCHDOG] correct sysfs name for watchdog devices While looking for possible candidates for our udev.rules package, I found a few odd ->name properties. /dev/watchdog has minor 130 according to devices.txt. Since all watchdog drivers use the misc_register() call, they will end up in /sys/class/misc/$foo. udev may create the /dev/watchdog node if the driver is loaded. I dont have such a device, so I cant test it. The drivers below provide names with spaces and even with / in it. Not a big deal, but apps may expect /dev/watchdog. Signed-off-by: Olaf Hering Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/ixp2000_wdt.c | 2 +- drivers/char/watchdog/ixp4xx_wdt.c | 2 +- drivers/char/watchdog/scx200_wdt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index e7640bc4904b..0cfb9b9c4a4b 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -182,7 +182,7 @@ static struct file_operations ixp2000_wdt_fops = static struct miscdevice ixp2000_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = "IXP2000 Watchdog", + .name = "watchdog", .fops = &ixp2000_wdt_fops, }; diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 8d916afbf4fa..b5be8b11104a 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -176,7 +176,7 @@ static struct file_operations ixp4xx_wdt_fops = static struct miscdevice ixp4xx_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = "IXP4xx Watchdog", + .name = "watchdog", .fops = &ixp4xx_wdt_fops, }; diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c index c4568569f3a8..b4a102a2d7e3 100644 --- a/drivers/char/watchdog/scx200_wdt.c +++ b/drivers/char/watchdog/scx200_wdt.c @@ -206,7 +206,7 @@ static struct file_operations scx200_wdt_fops = { static struct miscdevice scx200_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = NAME, + .name = "watchdog", .fops = &scx200_wdt_fops, }; -- cgit v1.2.2 From af4bb822bc65efb087cd36b83789f22161a6515b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 17 Aug 2005 09:03:23 +0200 Subject: [WATCHDOG] s3c2410 watchdog power management Patch from Dimitry Andric , updated by Ben Dooks . Patch is against 2.6.11-mm2 Add power management support to the s3c2410 watchdog, so that it is shut-down over suspend, and re-initialised on resume. Also add Dimitry to the list of authors. Signed-off-by: Dimitry Andric Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/s3c2410_wdt.c | 51 ++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index f85ac898a49a..522435782e73 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -27,7 +27,9 @@ * Fixed tmr_count / wdt_count confusion * Added configurable debug * - * 11-Jan-2004 BJD Fixed divide-by-2 in timeout code + * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code + * + * 25-Jan-2005 DA Added suspend/resume support * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ @@ -479,15 +481,57 @@ static int s3c2410wdt_remove(struct device *dev) return 0; } +#ifdef CONFIG_PM + +static unsigned long wtcon_save; +static unsigned long wtdat_save; + +static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_POWER_DOWN) { + /* Save watchdog state, and turn it off. */ + wtcon_save = readl(wdt_base + S3C2410_WTCON); + wtdat_save = readl(wdt_base + S3C2410_WTDAT); + + /* Note that WTCNT doesn't need to be saved. */ + s3c2410wdt_stop(); + } + + return 0; +} + +static int s3c2410wdt_resume(struct device *dev, u32 level) +{ + if (level == RESUME_POWER_ON) { + /* Restore watchdog state. */ + + writel(wtdat_save, wdt_base + S3C2410_WTDAT); + writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ + writel(wtcon_save, wdt_base + S3C2410_WTCON); + + printk(KERN_INFO PFX "watchdog %sabled\n", + (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); + } + + return 0; +} + +#else +#define s3c2410wdt_suspend NULL +#define s3c2410wdt_resume NULL +#endif /* CONFIG_PM */ + + static struct device_driver s3c2410wdt_driver = { .name = "s3c2410-wdt", .bus = &platform_bus_type, .probe = s3c2410wdt_probe, .remove = s3c2410wdt_remove, + .suspend = s3c2410wdt_suspend, + .resume = s3c2410wdt_resume, }; - static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n"; static int __init watchdog_init(void) @@ -505,7 +549,8 @@ static void __exit watchdog_exit(void) module_init(watchdog_init); module_exit(watchdog_exit); -MODULE_AUTHOR("Ben Dooks "); +MODULE_AUTHOR("Ben Dooks , " + "Dimitry Andric "); MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.2 From 94f1e9f316b10972b77a64344006c3bf8a4929b4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 17 Aug 2005 09:04:52 +0200 Subject: [WATCHDOG] s3c2410 watchdog - replace reboot notifier Patch from Dimitry Andric Change to using platfrom driver's .shutdown method instead of an reboot notifier Signed-off-by: Dimitry Andric Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/s3c2410_wdt.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 522435782e73..8b292bf343c4 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -30,6 +30,7 @@ * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code * * 25-Jan-2005 DA Added suspend/resume support + * Replaced reboot notifier with .shutdown method * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ @@ -42,8 +43,6 @@ #include #include #include -#include -#include #include #include #include @@ -319,20 +318,6 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file, } } -/* - * Notifier for system down - */ - -static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) { - /* Turn the WDT off */ - s3c2410wdt_stop(); - } - return NOTIFY_DONE; -} - /* kernel interface */ static struct file_operations s3c2410wdt_fops = { @@ -350,10 +335,6 @@ static struct miscdevice s3c2410wdt_miscdev = { .fops = &s3c2410wdt_fops, }; -static struct notifier_block s3c2410wdt_notifier = { - .notifier_call = s3c2410wdt_notify_sys, -}; - /* interrupt handler code */ static irqreturn_t s3c2410wdt_irq(int irqno, void *param, @@ -434,18 +415,10 @@ static int s3c2410wdt_probe(struct device *dev) } } - ret = register_reboot_notifier(&s3c2410wdt_notifier); - if (ret) { - printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n", - ret); - return ret; - } - ret = misc_register(&s3c2410wdt_miscdev); if (ret) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", WATCHDOG_MINOR, ret); - unregister_reboot_notifier(&s3c2410wdt_notifier); return ret; } @@ -481,6 +454,11 @@ static int s3c2410wdt_remove(struct device *dev) return 0; } +static void s3c2410wdt_shutdown(struct device *dev) +{ + s3c2410wdt_stop(); +} + #ifdef CONFIG_PM static unsigned long wtcon_save; @@ -527,6 +505,7 @@ static struct device_driver s3c2410wdt_driver = { .bus = &platform_bus_type, .probe = s3c2410wdt_probe, .remove = s3c2410wdt_remove, + .shutdown = s3c2410wdt_shutdown, .suspend = s3c2410wdt_suspend, .resume = s3c2410wdt_resume, }; @@ -543,7 +522,6 @@ static int __init watchdog_init(void) static void __exit watchdog_exit(void) { driver_unregister(&s3c2410wdt_driver); - unregister_reboot_notifier(&s3c2410wdt_notifier); } module_init(watchdog_init); -- cgit v1.2.2 From 93642ecd463df30d032da8ac37c2676cee4ad876 Mon Sep 17 00:00:00 2001 From: "P@Draig Brady" Date: Wed, 17 Aug 2005 09:06:07 +0200 Subject: [WATCHDOG] w83627hf_wdt.c-initialized_bios_bug Attached is a small update to the w83627hf watchdog driver to initialise appropriately if it was already initialised in the BIOS. On tyan motherboards for e.g. you can init the watchdog to 4 mins, then when the driver is loaded it sets the watchdog to "seconds" mode, and then machine will reboot within 4 seconds. So this patch resets the timeout to the configured value if the watchdog is already running. Signed-off-by: P@draig Brady Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/w83627hf_wdt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 465e0fd0423d..b5d821015421 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -93,6 +93,12 @@ w83627hf_init(void) w83627hf_select_wd_register(); + outb_p(0xF6, WDT_EFER); /* Select CRF6 */ + t=inb_p(WDT_EFDR); /* read CRF6 */ + if (t != 0) { + printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout); + outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ + } outb_p(0xF5, WDT_EFER); /* Select CRF5 */ t=inb_p(WDT_EFDR); /* read CRF5 */ t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */ -- cgit v1.2.2 From 1cc77248106aafc12ba529953f652d6f8db2c84d Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Fri, 19 Aug 2005 14:14:07 +0200 Subject: [WATCHDOG] softdog-timer-running-oops.patch The softdog watchdog timer has a bug that can create an oops: 1. Load the module without the nowayout option. 2. Open the driver and close it without writing 'V' before close. 3. Unload the module. The timer will continue to run... 4. Oops happens when timer fires. Reported Sun, 10 Oct 2004, by Michael Schierl Fix is easy: always take a reference on the module on open. Release it only when the device is closed and no timer is running. Tested on 2.6.13-rc6 using the soft_noboot option. While the timer is running and the device is closed, the module use count stays at 1. After the timer fires, it drops to 0. Repeatedly opening and closing the driver caused no problems. Please apply. Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/softdog.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c index 4d7ed931f5c6..20e5eb8667f2 100644 --- a/drivers/char/watchdog/softdog.c +++ b/drivers/char/watchdog/softdog.c @@ -77,7 +77,7 @@ static void watchdog_fire(unsigned long); static struct timer_list watchdog_ticktock = TIMER_INITIALIZER(watchdog_fire, 0, 0); -static unsigned long timer_alive; +static unsigned long driver_open, orphan_timer; static char expect_close; @@ -87,6 +87,9 @@ static char expect_close; static void watchdog_fire(unsigned long data) { + if (test_and_clear_bit(0, &orphan_timer)) + module_put(THIS_MODULE); + if (soft_noboot) printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); else @@ -128,9 +131,9 @@ static int softdog_set_heartbeat(int t) static int softdog_open(struct inode *inode, struct file *file) { - if(test_and_set_bit(0, &timer_alive)) + if (test_and_set_bit(0, &driver_open)) return -EBUSY; - if (nowayout) + if (!test_and_clear_bit(0, &orphan_timer)) __module_get(THIS_MODULE); /* * Activate timer @@ -147,11 +150,13 @@ static int softdog_release(struct inode *inode, struct file *file) */ if (expect_close == 42) { softdog_stop(); + module_put(THIS_MODULE); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + set_bit(0, &orphan_timer); softdog_keepalive(); } - clear_bit(0, &timer_alive); + clear_bit(0, &driver_open); expect_close = 0; return 0; } -- cgit v1.2.2 From 9b4e3b13b147e9b737de63188a9ae740eaa8c36d Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 3 Sep 2005 16:26:49 +0100 Subject: [SERIAL] Fix moxa tty driver name The moxa driver was named "ttya", which is wrong: 1) Documentation/devices.txt says that the name should be "ttyMX". 2) First 10 ports (ttya0...ttya9) clash with the legacy pty driver. This patch changes the driver name to "ttyMX". http://bugme.osdl.org/show_bug.cgi?id=5012 Signed-off-by: Sergey Vlasov Signed-off-by: Russell King --- drivers/char/moxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 95f7046ff059..79e490ef2cf2 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -339,7 +339,7 @@ static int __init moxa_init(void) init_MUTEX(&moxaBuffSem); moxaDriver->owner = THIS_MODULE; - moxaDriver->name = "ttya"; + moxaDriver->name = "ttyMX"; moxaDriver->devfs_name = "tts/a"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; -- cgit v1.2.2 From 4cee99564db7f65a6f88e4b752da52768cde3802 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sun, 4 Sep 2005 01:41:14 -0500 Subject: Input: fix checking whether new keycode fits size-wise When dev->keycodesize == sizeof(int) the old code produces incorrect result. Signed-off-by: Ian Campbell Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 523fd3c8bbaa..1ddaabeb8ef8 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -200,7 +200,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode) return -EINVAL; if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; - if (keycode >> (dev->keycodesize * 8)) + if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) return -EINVAL; oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); -- cgit v1.2.2 From e8a650150b1001bc34d506e4c44538463d368890 Mon Sep 17 00:00:00 2001 From: Marcel Selhorst Date: Sat, 3 Sep 2005 15:54:20 -0700 Subject: [PATCH] tpm_infineon: Bugfix in PNPACPI-handling This patch corrects the PNP-handling inside the tpm-driver and some minor coding style bugs. Note: the pci-device and pnp-device mixture is currently necessary, since the used "tpm"-interface requires a pci-dev in order to register the driver. This will be fixed within the next iterations. Signed-off-by: Marcel Selhorst Cc: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_infineon.c | 76 ++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 31 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dc8c540391fd..939e51e119e6 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -14,7 +14,6 @@ * License. */ -#include #include #include "tpm.h" @@ -29,9 +28,10 @@ #define TPM_MAX_TRIES 5000 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 -/* These values will be filled after ACPI-call */ +/* These values will be filled after PnP-call */ static int TPM_INF_DATA = 0; static int TPM_INF_ADDR = 0; +static int pnp_registered = 0; /* TPM header definitions */ enum infineon_tpm_header { @@ -356,24 +356,26 @@ static const struct pnp_device_id tpm_pnp_tbl[] = { {"IFX0102", 0}, {"", 0} }; +MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); -static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev, +static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); - TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); - tpm_inf.base = pnp_port_start(dev, 1); - dev_info(&dev->dev, "Found %s with ID %s\n", - dev->name, dev_id->id); - if (!((tpm_inf.base >> 8) & 0xff)) - tpm_inf.base = 0; - return 0; + if (pnp_port_valid(dev, 0)) { + TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); + TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); + tpm_inf.base = pnp_port_start(dev, 1); + dev_info(&dev->dev, "Found %s with ID %s\n", + dev->name, dev_id->id); + return 0; + } + return -ENODEV; } static struct pnp_driver tpm_inf_pnp = { .name = "tpm_inf_pnp", .id_table = tpm_pnp_tbl, - .probe = tpm_inf_acpi_probe, + .probe = tpm_inf_pnp_probe, }; static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, @@ -386,19 +388,30 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, int productid[2]; char chipname[20]; - if (pci_enable_device(pci_dev)) - return -EIO; + rc = pci_enable_device(pci_dev); + if (rc) + return rc; dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); - /* read IO-ports from ACPI */ - pnp_register_driver(&tpm_inf_pnp); - pnp_unregister_driver(&tpm_inf_pnp); + /* read IO-ports from PnP */ + rc = pnp_register_driver(&tpm_inf_pnp); + if (rc < 0) { + dev_err(&pci_dev->dev, + "Error %x from pnp_register_driver!\n",rc); + goto error2; + } + if (!rc) { + dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); + goto error; + } else { + pnp_registered = 1; + } /* Make sure, we have received valid config ports */ if (!TPM_INF_ADDR) { - pci_disable_device(pci_dev); - return -EIO; + dev_err(&pci_dev->dev, "No valid IO-ports received!\n"); + goto error; } /* query chip for its vendor, its version number a.s.o. */ @@ -418,23 +431,21 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, switch ((productid[0] << 8) | productid[1]) { case 6: - sprintf(chipname, " (SLD 9630 TT 1.1)"); + snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)"); break; case 11: - sprintf(chipname, " (SLB 9635 TT 1.2)"); + snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)"); break; default: - sprintf(chipname, " (unknown chip)"); + snprintf(chipname, sizeof(chipname), " (unknown chip)"); break; } - chipname[19] = 0; if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { if (tpm_inf.base == 0) { dev_err(&pci_dev->dev, "No IO-ports found!\n"); - pci_disable_device(pci_dev); - return -EIO; + goto error; } /* configure TPM with IO-ports */ outb(IOLIMH, TPM_INF_ADDR); @@ -452,8 +463,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, dev_err(&pci_dev->dev, "Could not set IO-ports to %04x\n", tpm_inf.base); - pci_disable_device(pci_dev); - return -EIO; + goto error; } /* activate register */ @@ -479,14 +489,16 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, productid[0], productid[1], chipname); rc = tpm_register_hardware(pci_dev, &tpm_inf); - if (rc < 0) { - pci_disable_device(pci_dev); - return -ENODEV; - } + if (rc < 0) + goto error; return 0; } else { dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); +error: + pnp_unregister_driver(&tpm_inf_pnp); +error2: pci_disable_device(pci_dev); + pnp_registered = 0; return -ENODEV; } } @@ -521,6 +533,8 @@ static int __init init_inf(void) static void __exit cleanup_inf(void) { + if (pnp_registered) + pnp_unregister_driver(&tpm_inf_pnp); pci_unregister_driver(&inf_pci_driver); } -- cgit v1.2.2 From a2f40ccd294d14e5aca464c1913e8e0d8de35fca Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 3 Sep 2005 15:55:33 -0700 Subject: [PATCH] ppc32: Added support for the Book-E style Watchdog Timer PowerPC 40x and Book-E processors support a watchdog timer at the processor core level. The timer has implementation dependent timeout frequencies that can be configured by software. One the first Watchdog timeout we get a critical exception. It is left to board specific code to determine what should happen at this point. If nothing is done and another timeout period expires the processor may attempt to reset the machine. Command line parameters: wdt=0 : disable watchdog (default) wdt=1 : enable watchdog wdt_period=N : N sets the value of the Watchdog Timer Period. The Watchdog Timer Period meaning is implementation specific. Check User Manual for the processor for more details. This patch is based off of work done by Takeharu Kato. Signed-off-by: Matt McClintock Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/Kconfig | 4 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/booke_wdt.c | 191 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 drivers/char/watchdog/booke_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index b53e2e2b5aee..95335b443a8f 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -346,6 +346,10 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +config BOOKE_WDT + tristate "PowerPC Book-E Watchdog Timer" + depends on WATCHDOG && (BOOKE || 4xx) + # MIPS Architecture config INDYDOG diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index c1838834ea7f..b16dfea28134 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o +obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # Only one watchdog can succeed. We probe the hardware watchdog # drivers first, then the softdog driver. This means if your hardware diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c new file mode 100644 index 000000000000..7281f394f682 --- /dev/null +++ b/drivers/char/watchdog/booke_wdt.c @@ -0,0 +1,191 @@ +/* + * drivers/char/watchdog/booke_wdt.c + * + * Watchdog timer for PowerPC Book-E systems + * + * Author: Matthew McClintock + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot. + * Also, the wdt_period sets the watchdog timer period timeout. + * For E500 cpus the wdt_period sets which bit changing from 0->1 will + * trigger a watchog timeout. This watchdog timeout will occur 3 times, the + * first time nothing will happen, the second time a watchdog exception will + * occur, and the final time the board will reset. + */ + +#ifdef CONFIG_FSL_BOOKE +#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ +#else +#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */ +#endif /* for timing information */ + +u32 wdt_enable = 0; +u32 wdt_period = WDT_PERIOD_DEFAULT; + +#ifdef CONFIG_FSL_BOOKE +#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15)) +#else +#define WDTP(x) (TCR_WP(x)) +#endif + +/* + * booke_wdt_enable: + */ +static __inline__ void booke_wdt_enable(void) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(wdt_period)); + + mtspr(SPRN_TCR, val); +} + +/* + * booke_wdt_ping: + */ +static __inline__ void booke_wdt_ping(void) +{ + mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); +} + +/* + * booke_wdt_write: + */ +static ssize_t booke_wdt_write (struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + booke_wdt_ping(); + return count; +} + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "PowerPC Book-E Watchdog", +}; + +/* + * booke_wdt_ioctl: + */ +static int booke_wdt_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 tmp = 0; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user ((struct watchdog_info *) arg, &ident, + sizeof(struct watchdog_info))) + return -EFAULT; + case WDIOC_GETSTATUS: + return put_user(ident.options, (u32 *) arg); + case WDIOC_GETBOOTSTATUS: + /* XXX: something is clearing TSR */ + tmp = mfspr(SPRN_TSR) & TSR_WRS(3); + /* returns 1 if last reset was caused by the WDT */ + return (tmp ? 1 : 0); + case WDIOC_KEEPALIVE: + booke_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(wdt_period, (u32 *) arg)) + return -EFAULT; + mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(wdt_period)); + return 0; + case WDIOC_GETTIMEOUT: + return put_user(wdt_period, (u32 *) arg); + case WDIOC_SETOPTIONS: + if (get_user(tmp, (u32 *) arg)) + return -EINVAL; + if (tmp == WDIOS_ENABLECARD) { + booke_wdt_ping(); + break; + } else + return -EINVAL; + return 0; + default: + return -ENOIOCTLCMD; + } + + return 0; +} +/* + * booke_wdt_open: + */ +static int booke_wdt_open (struct inode *inode, struct file *file) +{ + if (wdt_enable == 0) { + wdt_enable = 1; + booke_wdt_enable(); + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", + wdt_period); + } + + return 0; +} + +static struct file_operations booke_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = booke_wdt_write, + .ioctl = booke_wdt_ioctl, + .open = booke_wdt_open, +}; + +static struct miscdevice booke_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &booke_wdt_fops, +}; + +static void __exit booke_wdt_exit(void) +{ + misc_deregister(&booke_wdt_miscdev); +} + +/* + * booke_wdt_init: + */ +static int __init booke_wdt_init(void) +{ + int ret = 0; + + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); + ident.firmware_version = cpu_specs[0].pvr_value; + + ret = misc_register(&booke_wdt_miscdev); + if (ret) { + printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + return ret; + } + + if (wdt_enable == 1) { + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", + wdt_period); + booke_wdt_enable(); + } + + return ret; +} +device_initcall(booke_wdt_init); -- cgit v1.2.2 From 39cdc4bfb5c587c617ab6a28083c19101154e149 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 3 Sep 2005 15:55:39 -0700 Subject: [PATCH] ppc32: Cleaned up global namespace of Book-E watchdog variables Renamed global variables used to convey if the watchdog is enabled and periodicity of the timer and moved the declarations into a header for these variables Signed-off-by: Matt McClintock Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/Kconfig | 3 +++ drivers/char/watchdog/booke_wdt.c | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 95335b443a8f..c3898afce3ae 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -349,6 +349,9 @@ config 8xx_WDT config BOOKE_WDT tristate "PowerPC Book-E Watchdog Timer" depends on WATCHDOG && (BOOKE || 4xx) + ---help--- + Please see Documentation/watchdog/watchdog-api.txt for + more information. # MIPS Architecture diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c index 7281f394f682..abc30cca6645 100644 --- a/drivers/char/watchdog/booke_wdt.c +++ b/drivers/char/watchdog/booke_wdt.c @@ -23,6 +23,7 @@ #include #include +#include /* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot. * Also, the wdt_period sets the watchdog timer period timeout. @@ -38,8 +39,8 @@ #define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */ #endif /* for timing information */ -u32 wdt_enable = 0; -u32 wdt_period = WDT_PERIOD_DEFAULT; +u32 booke_wdt_enabled = 0; +u32 booke_wdt_period = WDT_PERIOD_DEFAULT; #ifdef CONFIG_FSL_BOOKE #define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15)) @@ -55,7 +56,7 @@ static __inline__ void booke_wdt_enable(void) u32 val; val = mfspr(SPRN_TCR); - val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(wdt_period)); + val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); mtspr(SPRN_TCR, val); } @@ -108,12 +109,12 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, booke_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: - if (get_user(wdt_period, (u32 *) arg)) + if (get_user(booke_wdt_period, (u32 *) arg)) return -EFAULT; - mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(wdt_period)); + mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period)); return 0; case WDIOC_GETTIMEOUT: - return put_user(wdt_period, (u32 *) arg); + return put_user(booke_wdt_period, (u32 *) arg); case WDIOC_SETOPTIONS: if (get_user(tmp, (u32 *) arg)) return -EINVAL; @@ -134,11 +135,11 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, */ static int booke_wdt_open (struct inode *inode, struct file *file) { - if (wdt_enable == 0) { - wdt_enable = 1; + if (booke_wdt_enabled == 0) { + booke_wdt_enabled = 1; booke_wdt_enable(); printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", - wdt_period); + booke_wdt_period); } return 0; @@ -180,9 +181,9 @@ static int __init booke_wdt_init(void) return ret; } - if (wdt_enable == 1) { + if (booke_wdt_enabled == 1) { printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", - wdt_period); + booke_wdt_period); booke_wdt_enable(); } -- cgit v1.2.2 From 63b799f9ded82444212afdcf61379a247d544909 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sat, 3 Sep 2005 15:56:13 -0700 Subject: [PATCH] mips: add TANBAC VR4131 multichip module This patch has added TANBAC VR4131 multichip module in arch/mips/Kconfig Signed-off-by: Yoichi Yuasa Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7333b41d4224..116a7b185999 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -842,8 +842,9 @@ config SONYPI config TANBAC_TB0219 tristate "TANBAC TB0219 base board support" - depends TANBAC_TB0229 - + depends TANBAC_TB022X + select PCI + select PCI_VR41XX menu "Ftape, the floppy tape device driver" -- cgit v1.2.2 From 466adc66cf6eea0268c8678834c8c6a56e5a2f9e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sat, 3 Sep 2005 15:56:14 -0700 Subject: [PATCH] fix warning of TANBAC_TB0219 in drivers/char/Kconfig $ make menuconfig scripts/kconfig/mconf arch/i386/Kconfig drivers/char/Kconfig:847:warning: 'select' used by config symbol 'TANBAC_TB0219' refer to undefined symbol 'PCI_VR41XX' Here is a patch for this warning fix. Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 116a7b185999..f418f45e0780 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -843,8 +843,6 @@ config SONYPI config TANBAC_TB0219 tristate "TANBAC TB0219 base board support" depends TANBAC_TB022X - select PCI - select PCI_VR41XX menu "Ftape, the floppy tape device driver" -- cgit v1.2.2 From 1d25240fcfce0e55540a273b1e1b07d304065a31 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 5 Sep 2005 23:30:15 -0700 Subject: [MOXA]: Fix this driver properly. Actually, proper fix of that breakage is embarrassingly simple - it's yet another gratitious leftover include of asm/segment.h, so incremental to the previos would be removal of that BROKEN and removal of bogus include from mxser.c itself. Signed-off-by: David S. Miller --- drivers/char/Kconfig | 2 +- drivers/char/mxser.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index df5f2b0e0750..f418f45e0780 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -175,7 +175,7 @@ config MOXA_INTELLIO config MOXA_SMARTIO tristate "Moxa SmartIO support" - depends on SERIAL_NONSTANDARD && (BROKEN || !SPARC32) + depends on SERIAL_NONSTANDARD help Say Y here if you have a Moxa SmartIO multiport serial card. diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index f022f0944434..d0ef1ae41298 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include -- cgit v1.2.2 From 53d0fc27af3a3ab22c0ffb67857adfa18977e681 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 5 Sep 2005 23:33:05 -0700 Subject: [RTC]: Use SA_SHIRQ in sparc specific code. Based upon a report from Jason Wever. Signed-off-by: David S. Miller --- drivers/char/rtc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index cd4fe8b1709f..63fff7c1244a 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -938,10 +938,9 @@ found: /* * XXX Interrupt pin #7 in Espresso is shared between RTC and - * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here - * is asking for trouble with add-on boards. Change to SA_SHIRQ. + * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ - if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) { + if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) { /* * Standard way for sparc to print irq's is to use * __irq_itoa(). I think for EBus it's ok to use %d. -- cgit v1.2.2 From c0f2f761e1ea3923952e31cce2cdb7d65f450fbd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 5 Sep 2005 23:35:41 -0700 Subject: [SPARC64]: Kconfig fix (GEN_RTC dependencies) Yet another architecture not coverd by GEN_RTC - sparc64 never picked it until now and it doesn't have asm/rtc.h to go with it, so it wouldn't compile anyway (or have these ioctls in the user-visible headers, for that matter). FWIW, I'm very tempted to introduce ARCH_HAS_GEN_RTC and have it set in arch/*/Kconfig for architectures that know what to do with this stuff - for something supposedly generic the list of architectures where it doesn't work is getting too long... Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/char/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index f418f45e0780..a1de06d76de6 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -735,7 +735,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 + depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you -- cgit v1.2.2 From f2cf8e25ba4cf4e0881e612125858b4eed563ee4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 6 Sep 2005 15:16:44 -0700 Subject: [PATCH] Clean up the old digi support and rescue it Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 +- drivers/char/digi1.h | 38 +- drivers/char/digiFep1.h | 154 ++--- drivers/char/epca.c | 1588 ++++++++++++++--------------------------------- drivers/char/epca.h | 108 ++-- 5 files changed, 610 insertions(+), 1280 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a1de06d76de6..2bc9d64db106 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -138,7 +138,7 @@ config CYZ_INTR config DIGIEPCA tristate "Digiboard Intelligent Async Support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN) + depends on SERIAL_NONSTANDARD ---help--- This is a driver for Digi International's Xx, Xeve, and Xem series of cards which provide multiple serial ports. You would need diff --git a/drivers/char/digi1.h b/drivers/char/digi1.h index 184378d23f8c..94d4eab5d3ca 100644 --- a/drivers/char/digi1.h +++ b/drivers/char/digi1.h @@ -1,46 +1,46 @@ /* Definitions for DigiBoard ditty(1) command. */ #if !defined(TIOCMODG) -#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */ -#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */ +#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ +#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ #endif #if !defined(TIOCMSET) -#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */ -#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */ +#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ +#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ #endif #if !defined(TIOCMBIC) -#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */ -#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */ +#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ +#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ #endif #if !defined(TIOCSDTR) -#define TIOCSDTR ('e'<<8) | 0 /* set DTR */ -#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */ +#define TIOCSDTR (('e'<<8) | 0) /* set DTR */ +#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ #endif /************************************************************************ * Ioctl command arguments for DIGI parameters. ************************************************************************/ -#define DIGI_GETA ('e'<<8) | 94 /* Read params */ +#define DIGI_GETA (('e'<<8) | 94) /* Read params */ -#define DIGI_SETA ('e'<<8) | 95 /* Set params */ -#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */ -#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */ +#define DIGI_SETA (('e'<<8) | 95) /* Set params */ +#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */ +#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */ -#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */ +#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ /* control characters */ -#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */ +#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ /* control characters */ -#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */ +#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ /* flow control chars */ -#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */ +#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ /* flow control chars */ -#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */ -#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */ -#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */ +#define DIGI_GETINFO (('e'<<8) | 103) /* Fill in digi_info */ +#define DIGI_POLLER (('e'<<8) | 104) /* Turn on/off poller */ +#define DIGI_INIT (('e'<<8) | 105) /* Allow things to run. */ struct digiflow_struct { diff --git a/drivers/char/digiFep1.h b/drivers/char/digiFep1.h index c47d7fcb8400..3c1f1922c798 100644 --- a/drivers/char/digiFep1.h +++ b/drivers/char/digiFep1.h @@ -13,88 +13,88 @@ struct global_data { - volatile ushort cin; - volatile ushort cout; - volatile ushort cstart; - volatile ushort cmax; - volatile ushort ein; - volatile ushort eout; - volatile ushort istart; - volatile ushort imax; + u16 cin; + u16 cout; + u16 cstart; + u16 cmax; + u16 ein; + u16 eout; + u16 istart; + u16 imax; }; struct board_chan { - int filler1; - int filler2; - volatile ushort tseg; - volatile ushort tin; - volatile ushort tout; - volatile ushort tmax; - - volatile ushort rseg; - volatile ushort rin; - volatile ushort rout; - volatile ushort rmax; - - volatile ushort tlow; - volatile ushort rlow; - volatile ushort rhigh; - volatile ushort incr; - - volatile ushort etime; - volatile ushort edelay; - volatile unchar *dev; - - volatile ushort iflag; - volatile ushort oflag; - volatile ushort cflag; - volatile ushort gmask; - - volatile ushort col; - volatile ushort delay; - volatile ushort imask; - volatile ushort tflush; - - int filler3; - int filler4; - int filler5; - int filler6; - - volatile unchar num; - volatile unchar ract; - volatile unchar bstat; - volatile unchar tbusy; - volatile unchar iempty; - volatile unchar ilow; - volatile unchar idata; - volatile unchar eflag; - - volatile unchar tflag; - volatile unchar rflag; - volatile unchar xmask; - volatile unchar xval; - volatile unchar mstat; - volatile unchar mchange; - volatile unchar mint; - volatile unchar lstat; - - volatile unchar mtran; - volatile unchar orun; - volatile unchar startca; - volatile unchar stopca; - volatile unchar startc; - volatile unchar stopc; - volatile unchar vnext; - volatile unchar hflow; - - volatile unchar fillc; - volatile unchar ochar; - volatile unchar omask; - - unchar filler7; - unchar filler8[28]; + u32 filler1; + u32 filler2; + u16 tseg; + u16 tin; + u16 tout; + u16 tmax; + + u16 rseg; + u16 rin; + u16 rout; + u16 rmax; + + u16 tlow; + u16 rlow; + u16 rhigh; + u16 incr; + + u16 etime; + u16 edelay; + unchar *dev; + + u16 iflag; + u16 oflag; + u16 cflag; + u16 gmask; + + u16 col; + u16 delay; + u16 imask; + u16 tflush; + + u32 filler3; + u32 filler4; + u32 filler5; + u32 filler6; + + u8 num; + u8 ract; + u8 bstat; + u8 tbusy; + u8 iempty; + u8 ilow; + u8 idata; + u8 eflag; + + u8 tflag; + u8 rflag; + u8 xmask; + u8 xval; + u8 mstat; + u8 mchange; + u8 mint; + u8 lstat; + + u8 mtran; + u8 orun; + u8 startca; + u8 stopca; + u8 startc; + u8 stopc; + u8 vnext; + u8 hflow; + + u8 fillc; + u8 ochar; + u8 omask; + + u8 filler7; + u8 filler8[28]; }; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 6025e1866c7e..58d3738a2b7f 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -6,6 +6,8 @@ For technical support please email digiLinux@dgii.com or call Digi tech support at (612) 912-3456 + ** This driver is no longer supported by Digi ** + Much of this design and code came from epca.c which was copyright (C) 1994, 1995 Troy De Jongh, and subsquently modified by David Nugent, Christoph Lameter, Mike McLagan. @@ -43,31 +45,19 @@ #include #include #include - -#ifdef CONFIG_PCI -#define ENABLE_PCI -#endif /* CONFIG_PCI */ - -#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2) -#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2) - -#ifdef ENABLE_PCI +#include #include #include "digiPCI.h" -#endif /* ENABLE_PCI */ + #include "digi1.h" #include "digiFep1.h" #include "epca.h" #include "epcaconfig.h" -#if BITS_PER_LONG != 32 -# error FIXME: this driver only works on 32-bit platforms -#endif - /* ---------------------- Begin defines ------------------------ */ -#define VERSION "1.3.0.1-LK" +#define VERSION "1.3.0.1-LK2.6" /* This major needs to be submitted to Linux to join the majors list */ @@ -81,13 +71,17 @@ /* ----------------- Begin global definitions ------------------- */ -static char mesg[100]; static int nbdevs, num_cards, liloconfig; static int digi_poller_inhibited = 1 ; static int setup_error_code; static int invalid_lilo_config; +/* The ISA boards do window flipping into the same spaces so its only sane + with a single lock. It's still pretty efficient */ + +static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED; + /* ----------------------------------------------------------------------- MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. @@ -129,58 +123,58 @@ static struct timer_list epca_timer; configured. ----------------------------------------------------------------------- */ -static inline void memwinon(struct board_info *b, unsigned int win); -static inline void memwinoff(struct board_info *b, unsigned int win); -static inline void globalwinon(struct channel *ch); -static inline void rxwinon(struct channel *ch); -static inline void txwinon(struct channel *ch); -static inline void memoff(struct channel *ch); -static inline void assertgwinon(struct channel *ch); -static inline void assertmemoff(struct channel *ch); +static void memwinon(struct board_info *b, unsigned int win); +static void memwinoff(struct board_info *b, unsigned int win); +static void globalwinon(struct channel *ch); +static void rxwinon(struct channel *ch); +static void txwinon(struct channel *ch); +static void memoff(struct channel *ch); +static void assertgwinon(struct channel *ch); +static void assertmemoff(struct channel *ch); /* ---- Begin more 'specific' memory functions for cx_like products --- */ -static inline void pcxem_memwinon(struct board_info *b, unsigned int win); -static inline void pcxem_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxem_globalwinon(struct channel *ch); -static inline void pcxem_rxwinon(struct channel *ch); -static inline void pcxem_txwinon(struct channel *ch); -static inline void pcxem_memoff(struct channel *ch); +static void pcxem_memwinon(struct board_info *b, unsigned int win); +static void pcxem_memwinoff(struct board_info *b, unsigned int win); +static void pcxem_globalwinon(struct channel *ch); +static void pcxem_rxwinon(struct channel *ch); +static void pcxem_txwinon(struct channel *ch); +static void pcxem_memoff(struct channel *ch); /* ------ Begin more 'specific' memory functions for the pcxe ------- */ -static inline void pcxe_memwinon(struct board_info *b, unsigned int win); -static inline void pcxe_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxe_globalwinon(struct channel *ch); -static inline void pcxe_rxwinon(struct channel *ch); -static inline void pcxe_txwinon(struct channel *ch); -static inline void pcxe_memoff(struct channel *ch); +static void pcxe_memwinon(struct board_info *b, unsigned int win); +static void pcxe_memwinoff(struct board_info *b, unsigned int win); +static void pcxe_globalwinon(struct channel *ch); +static void pcxe_rxwinon(struct channel *ch); +static void pcxe_txwinon(struct channel *ch); +static void pcxe_memoff(struct channel *ch); /* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */ /* Note : pc64xe and pcxi share the same windowing routines */ -static inline void pcxi_memwinon(struct board_info *b, unsigned int win); -static inline void pcxi_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxi_globalwinon(struct channel *ch); -static inline void pcxi_rxwinon(struct channel *ch); -static inline void pcxi_txwinon(struct channel *ch); -static inline void pcxi_memoff(struct channel *ch); +static void pcxi_memwinon(struct board_info *b, unsigned int win); +static void pcxi_memwinoff(struct board_info *b, unsigned int win); +static void pcxi_globalwinon(struct channel *ch); +static void pcxi_rxwinon(struct channel *ch); +static void pcxi_txwinon(struct channel *ch); +static void pcxi_memoff(struct channel *ch); /* - Begin 'specific' do nothing memory functions needed for some cards - */ -static inline void dummy_memwinon(struct board_info *b, unsigned int win); -static inline void dummy_memwinoff(struct board_info *b, unsigned int win); -static inline void dummy_globalwinon(struct channel *ch); -static inline void dummy_rxwinon(struct channel *ch); -static inline void dummy_txwinon(struct channel *ch); -static inline void dummy_memoff(struct channel *ch); -static inline void dummy_assertgwinon(struct channel *ch); -static inline void dummy_assertmemoff(struct channel *ch); +static void dummy_memwinon(struct board_info *b, unsigned int win); +static void dummy_memwinoff(struct board_info *b, unsigned int win); +static void dummy_globalwinon(struct channel *ch); +static void dummy_rxwinon(struct channel *ch); +static void dummy_txwinon(struct channel *ch); +static void dummy_memoff(struct channel *ch); +static void dummy_assertgwinon(struct channel *ch); +static void dummy_assertmemoff(struct channel *ch); /* ------------------- Begin declare functions ----------------------- */ -static inline struct channel *verifyChannel(register struct tty_struct *); -static inline void pc_sched_event(struct channel *, int); +static struct channel *verifyChannel(struct tty_struct *); +static void pc_sched_event(struct channel *, int); static void epca_error(int, char *); static void pc_close(struct tty_struct *, struct file *); static void shutdown(struct channel *); @@ -215,15 +209,11 @@ static void pc_unthrottle(struct tty_struct *tty); static void digi_send_break(struct channel *ch, int msec); static void setup_empty_event(struct tty_struct *tty, struct channel *ch); void epca_setup(char *, int *); -void console_print(const char *); static int get_termio(struct tty_struct *, struct termio __user *); static int pc_write(struct tty_struct *, const unsigned char *, int); -int pc_init(void); - -#ifdef ENABLE_PCI +static int pc_init(void); static int init_PCI(void); -#endif /* ENABLE_PCI */ /* ------------------------------------------------------------------ @@ -237,41 +227,41 @@ static int init_PCI(void); making direct calls deserves what they get. -------------------------------------------------------------------- */ -static inline void memwinon(struct board_info *b, unsigned int win) +static void memwinon(struct board_info *b, unsigned int win) { (b->memwinon)(b, win); } -static inline void memwinoff(struct board_info *b, unsigned int win) +static void memwinoff(struct board_info *b, unsigned int win) { (b->memwinoff)(b, win); } -static inline void globalwinon(struct channel *ch) +static void globalwinon(struct channel *ch) { (ch->board->globalwinon)(ch); } -static inline void rxwinon(struct channel *ch) +static void rxwinon(struct channel *ch) { (ch->board->rxwinon)(ch); } -static inline void txwinon(struct channel *ch) +static void txwinon(struct channel *ch) { (ch->board->txwinon)(ch); } -static inline void memoff(struct channel *ch) +static void memoff(struct channel *ch) { (ch->board->memoff)(ch); } -static inline void assertgwinon(struct channel *ch) +static void assertgwinon(struct channel *ch) { (ch->board->assertgwinon)(ch); } -static inline void assertmemoff(struct channel *ch) +static void assertmemoff(struct channel *ch) { (ch->board->assertmemoff)(ch); } @@ -281,66 +271,66 @@ static inline void assertmemoff(struct channel *ch) and CX series cards. ------------------------------------------------------------ */ -static inline void pcxem_memwinon(struct board_info *b, unsigned int win) +static void pcxem_memwinon(struct board_info *b, unsigned int win) { - outb_p(FEPWIN|win, (int)b->port + 1); + outb_p(FEPWIN|win, b->port + 1); } -static inline void pcxem_memwinoff(struct board_info *b, unsigned int win) +static void pcxem_memwinoff(struct board_info *b, unsigned int win) { - outb_p(0, (int)b->port + 1); + outb_p(0, b->port + 1); } -static inline void pcxem_globalwinon(struct channel *ch) +static void pcxem_globalwinon(struct channel *ch) { outb_p( FEPWIN, (int)ch->board->port + 1); } -static inline void pcxem_rxwinon(struct channel *ch) +static void pcxem_rxwinon(struct channel *ch) { outb_p(ch->rxwin, (int)ch->board->port + 1); } -static inline void pcxem_txwinon(struct channel *ch) +static void pcxem_txwinon(struct channel *ch) { outb_p(ch->txwin, (int)ch->board->port + 1); } -static inline void pcxem_memoff(struct channel *ch) +static void pcxem_memoff(struct channel *ch) { outb_p(0, (int)ch->board->port + 1); } /* ----------------- Begin pcxe memory window stuff ------------------ */ -static inline void pcxe_memwinon(struct board_info *b, unsigned int win) +static void pcxe_memwinon(struct board_info *b, unsigned int win) { - outb_p(FEPWIN | win, (int)b->port + 1); + outb_p(FEPWIN | win, b->port + 1); } -static inline void pcxe_memwinoff(struct board_info *b, unsigned int win) +static void pcxe_memwinoff(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) & ~FEPMEM, - (int)b->port + 1); - outb_p(0, (int)b->port + 1); + outb_p(inb(b->port) & ~FEPMEM, + b->port + 1); + outb_p(0, b->port + 1); } -static inline void pcxe_globalwinon(struct channel *ch) +static void pcxe_globalwinon(struct channel *ch) { outb_p( FEPWIN, (int)ch->board->port + 1); } -static inline void pcxe_rxwinon(struct channel *ch) +static void pcxe_rxwinon(struct channel *ch) { outb_p(ch->rxwin, (int)ch->board->port + 1); } -static inline void pcxe_txwinon(struct channel *ch) +static void pcxe_txwinon(struct channel *ch) { outb_p(ch->txwin, (int)ch->board->port + 1); } -static inline void pcxe_memoff(struct channel *ch) +static void pcxe_memoff(struct channel *ch) { outb_p(0, (int)ch->board->port); outb_p(0, (int)ch->board->port + 1); @@ -348,44 +338,44 @@ static inline void pcxe_memoff(struct channel *ch) /* ------------- Begin pc64xe and pcxi memory window stuff -------------- */ -static inline void pcxi_memwinon(struct board_info *b, unsigned int win) +static void pcxi_memwinon(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) | FEPMEM, (int)b->port); + outb_p(inb(b->port) | FEPMEM, b->port); } -static inline void pcxi_memwinoff(struct board_info *b, unsigned int win) +static void pcxi_memwinoff(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port); + outb_p(inb(b->port) & ~FEPMEM, b->port); } -static inline void pcxi_globalwinon(struct channel *ch) +static void pcxi_globalwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_rxwinon(struct channel *ch) +static void pcxi_rxwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_txwinon(struct channel *ch) +static void pcxi_txwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_memoff(struct channel *ch) +static void pcxi_memoff(struct channel *ch) { - outb_p(0, (int)ch->board->port); + outb_p(0, ch->board->port); } -static inline void pcxi_assertgwinon(struct channel *ch) +static void pcxi_assertgwinon(struct channel *ch) { - epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off"); + epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off"); } -static inline void pcxi_assertmemoff(struct channel *ch) +static void pcxi_assertmemoff(struct channel *ch) { - epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on"); + epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on"); } @@ -398,185 +388,143 @@ static inline void pcxi_assertmemoff(struct channel *ch) may or may not do anything. ---------------------------------------------------------------------------*/ -static inline void dummy_memwinon(struct board_info *b, unsigned int win) +static void dummy_memwinon(struct board_info *b, unsigned int win) { } -static inline void dummy_memwinoff(struct board_info *b, unsigned int win) +static void dummy_memwinoff(struct board_info *b, unsigned int win) { } -static inline void dummy_globalwinon(struct channel *ch) +static void dummy_globalwinon(struct channel *ch) { } -static inline void dummy_rxwinon(struct channel *ch) +static void dummy_rxwinon(struct channel *ch) { } -static inline void dummy_txwinon(struct channel *ch) +static void dummy_txwinon(struct channel *ch) { } -static inline void dummy_memoff(struct channel *ch) +static void dummy_memoff(struct channel *ch) { } -static inline void dummy_assertgwinon(struct channel *ch) +static void dummy_assertgwinon(struct channel *ch) { } -static inline void dummy_assertmemoff(struct channel *ch) +static void dummy_assertmemoff(struct channel *ch) { } /* ----------------- Begin verifyChannel function ----------------------- */ -static inline struct channel *verifyChannel(register struct tty_struct *tty) +static struct channel *verifyChannel(struct tty_struct *tty) { /* Begin verifyChannel */ - /* -------------------------------------------------------------------- This routine basically provides a sanity check. It insures that the channel returned is within the proper range of addresses as well as properly initialized. If some bogus info gets passed in through tty->driver_data this should catch it. - --------------------------------------------------------------------- */ - - if (tty) - { /* Begin if tty */ - - register struct channel *ch = (struct channel *)tty->driver_data; - - if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) - { + --------------------------------------------------------------------- */ + if (tty) { + struct channel *ch = (struct channel *)tty->driver_data; + if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) { if (ch->magic == EPCA_MAGIC) return ch; } - - } /* End if tty */ - - /* Else return a NULL for invalid */ + } return NULL; } /* End verifyChannel */ /* ------------------ Begin pc_sched_event ------------------------- */ -static inline void pc_sched_event(struct channel *ch, int event) -{ /* Begin pc_sched_event */ - - +static void pc_sched_event(struct channel *ch, int event) +{ /* ---------------------------------------------------------------------- We call this to schedule interrupt processing on some event. The kernel sees our request and calls the related routine in OUR driver. -------------------------------------------------------------------------*/ - ch->event |= 1 << event; schedule_work(&ch->tqueue); - - } /* End pc_sched_event */ /* ------------------ Begin epca_error ------------------------- */ static void epca_error(int line, char *msg) -{ /* Begin epca_error */ - +{ printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg); - return; - -} /* End epca_error */ +} /* ------------------ Begin pc_close ------------------------- */ static void pc_close(struct tty_struct * tty, struct file * filp) -{ /* Begin pc_close */ - +{ struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if ch != NULL */ - - save_flags(flags); - cli(); - - if (tty_hung_up_p(filp)) - { - restore_flags(flags); + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */ + spin_lock_irqsave(&epca_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&epca_lock, flags); return; } - /* Check to see if the channel is open more than once */ - if (ch->count-- > 1) - { /* Begin channel is open more than once */ - + if (ch->count-- > 1) { + /* Begin channel is open more than once */ /* ------------------------------------------------------------- Return without doing anything. Someone might still be using the channel. ---------------------------------------------------------------- */ - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); return; } /* End channel is open more than once */ /* Port open only once go ahead with shutdown & reset */ - - if (ch->count < 0) - { - ch->count = 0; - } + if (ch->count < 0) + BUG(); /* --------------------------------------------------------------- Let the rest of the driver know the channel is being closed. This becomes important if an open is attempted before close is finished. ------------------------------------------------------------------ */ - ch->asyncflags |= ASYNC_CLOSING; - tty->closing = 1; - if (ch->asyncflags & ASYNC_INITIALIZED) - { + spin_unlock_irqrestore(&epca_lock, flags); + + if (ch->asyncflags & ASYNC_INITIALIZED) { /* Setup an event to indicate when the transmit buffer empties */ setup_empty_event(tty, ch); tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ } - if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); + + spin_lock_irqsave(&epca_lock, flags); tty->closing = 0; ch->event = 0; ch->tty = NULL; + spin_unlock_irqrestore(&epca_lock, flags); - if (ch->blocked_open) - { /* Begin if blocked_open */ - + if (ch->blocked_open) { /* Begin if blocked_open */ if (ch->close_delay) - { msleep_interruptible(jiffies_to_msecs(ch->close_delay)); - } - wake_up_interruptible(&ch->open_wait); - } /* End if blocked_open */ - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); - - - restore_flags(flags); - } /* End if ch != NULL */ - } /* End pc_close */ /* ------------------ Begin shutdown ------------------------- */ @@ -586,15 +534,14 @@ static void shutdown(struct channel *ch) unsigned long flags; struct tty_struct *tty; - volatile struct board_chan *bc; + struct board_chan *bc; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; - save_flags(flags); - cli(); - globalwinon(ch); + spin_lock_irqsave(&epca_lock, flags); + globalwinon(ch); bc = ch->brdchan; /* ------------------------------------------------------------------ @@ -604,20 +551,17 @@ static void shutdown(struct channel *ch) --------------------------------------------------------------------- */ if (bc) - bc->idata = 0; - + writeb(0, &bc->idata); tty = ch->tty; /* ---------------------------------------------------------------- If we're a modem control device and HUPCL is on, drop RTS & DTR. ------------------------------------------------------------------ */ - if (tty->termios->c_cflag & HUPCL) - { + if (tty->termios->c_cflag & HUPCL) { ch->omodem &= ~(ch->m_rts | ch->m_dtr); fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1); } - memoff(ch); /* ------------------------------------------------------------------ @@ -628,7 +572,7 @@ static void shutdown(struct channel *ch) /* Prevent future Digi programmed interrupts from coming active */ ch->asyncflags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } /* End shutdown */ @@ -636,7 +580,6 @@ static void shutdown(struct channel *ch) static void pc_hangup(struct tty_struct *tty) { /* Begin pc_hangup */ - struct channel *ch; /* --------------------------------------------------------- @@ -644,25 +587,21 @@ static void pc_hangup(struct tty_struct *tty) if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if ch != NULL */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */ unsigned long flags; - save_flags(flags); - cli(); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); + spin_lock_irqsave(&epca_lock, flags); ch->tty = NULL; ch->event = 0; ch->count = 0; - restore_flags(flags); ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); + spin_unlock_irqrestore(&epca_lock, flags); wake_up_interruptible(&ch->open_wait); - } /* End if ch != NULL */ } /* End pc_hangup */ @@ -672,18 +611,14 @@ static void pc_hangup(struct tty_struct *tty) static int pc_write(struct tty_struct * tty, const unsigned char *buf, int bytesAvailable) { /* Begin pc_write */ - - register unsigned int head, tail; - register int dataLen; - register int size; - register int amountCopied; - - + unsigned int head, tail; + int dataLen; + int size; + int amountCopied; struct channel *ch; unsigned long flags; int remain; - volatile struct board_chan *bc; - + struct board_chan *bc; /* ---------------------------------------------------------------- pc_write is primarily called directly by the kernel routine @@ -706,24 +641,20 @@ static int pc_write(struct tty_struct * tty, bc = ch->brdchan; size = ch->txbufsize; - amountCopied = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - head = bc->tin & (size - 1); - tail = bc->tout; + head = readw(&bc->tin) & (size - 1); + tail = readw(&bc->tout); - if (tail != bc->tout) - tail = bc->tout; + if (tail != readw(&bc->tout)) + tail = readw(&bc->tout); tail &= (size - 1); /* If head >= tail, head has not wrapped around. */ - if (head >= tail) - { /* Begin head has not wrapped */ - + if (head >= tail) { /* Begin head has not wrapped */ /* --------------------------------------------------------------- remain (much like dataLen above) represents the total amount of space available on the card for data. Here dataLen represents @@ -731,26 +662,19 @@ static int pc_write(struct tty_struct * tty, buffer. This is important because a memcpy cannot be told to automatically wrap around when it hits the buffer end. ------------------------------------------------------------------ */ - dataLen = size - head; remain = size - (head - tail) - 1; - - } /* End head has not wrapped */ - else - { /* Begin head has wrapped around */ + } else { /* Begin head has wrapped around */ remain = tail - head - 1; dataLen = remain; } /* End head has wrapped around */ - /* ------------------------------------------------------------------- Check the space on the card. If we have more data than space; reduce the amount of data to fit the space. ---------------------------------------------------------------------- */ - bytesAvailable = min(remain, bytesAvailable); - txwinon(ch); while (bytesAvailable > 0) { /* Begin while there is data to copy onto card */ @@ -767,26 +691,21 @@ static int pc_write(struct tty_struct * tty, amountCopied += dataLen; bytesAvailable -= dataLen; - if (head >= size) - { + if (head >= size) { head = 0; dataLen = tail; } - } /* End while there is data to copy onto card */ - ch->statusflags |= TXBUSY; globalwinon(ch); - bc->tin = head; + writew(head, &bc->tin); - if ((ch->statusflags & LOWWAIT) == 0) - { + if ((ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; - bc->ilow = 1; + writeb(1, &bc->ilow); } memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); return(amountCopied); } /* End pc_write */ @@ -795,11 +714,7 @@ static int pc_write(struct tty_struct * tty, static void pc_put_char(struct tty_struct *tty, unsigned char c) { /* Begin pc_put_char */ - - pc_write(tty, &c, 1); - return; - } /* End pc_put_char */ /* ------------------ Begin pc_write_room ------------------------- */ @@ -811,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) struct channel *ch; unsigned long flags; unsigned int head, tail; - volatile struct board_chan *bc; + struct board_chan *bc; remain = 0; @@ -820,33 +735,29 @@ static int pc_write_room(struct tty_struct *tty) if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) != NULL) - { - save_flags(flags); - cli(); + if ((ch = verifyChannel(tty)) != NULL) { + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); bc = ch->brdchan; - head = bc->tin & (ch->txbufsize - 1); - tail = bc->tout; + head = readw(&bc->tin) & (ch->txbufsize - 1); + tail = readw(&bc->tout); - if (tail != bc->tout) - tail = bc->tout; + if (tail != readw(&bc->tout)) + tail = readw(&bc->tout); /* Wrap tail if necessary */ tail &= (ch->txbufsize - 1); if ((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; - if (remain && (ch->statusflags & LOWWAIT) == 0) - { + if (remain && (ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; - bc->ilow = 1; + writeb(1, &bc->ilow); } memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } - /* Return how much room is left on card */ return remain; @@ -862,8 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) int remain; unsigned long flags; struct channel *ch; - volatile struct board_chan *bc; - + struct board_chan *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct @@ -873,34 +783,27 @@ static int pc_chars_in_buffer(struct tty_struct *tty) if ((ch = verifyChannel(tty)) == NULL) return(0); - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); bc = ch->brdchan; - tail = bc->tout; - head = bc->tin; - ctail = ch->mailbox->cout; + tail = readw(&bc->tout); + head = readw(&bc->tin); + ctail = readw(&ch->mailbox->cout); - if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0) + if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0) chars = 0; - else - { /* Begin if some space on the card has been used */ - - head = bc->tin & (ch->txbufsize - 1); + else { /* Begin if some space on the card has been used */ + head = readw(&bc->tin) & (ch->txbufsize - 1); tail &= (ch->txbufsize - 1); - /* -------------------------------------------------------------- The logic here is basically opposite of the above pc_write_room here we are finding the amount of bytes in the buffer filled. Not the amount of bytes empty. ------------------------------------------------------------------- */ - if ((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; - chars = (int)(ch->txbufsize - remain); - /* ------------------------------------------------------------- Make it possible to wakeup anything waiting for output in tty_ioctl.c, etc. @@ -908,15 +811,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty) If not already set. Setup an event to indicate when the transmit buffer empties ----------------------------------------------------------------- */ - if (!(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); } /* End if some space on the card has been used */ - memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); /* Return number of characters residing on card. */ return(chars); @@ -930,67 +830,46 @@ static void pc_flush_buffer(struct tty_struct *tty) unsigned int tail; unsigned long flags; struct channel *ch; - volatile struct board_chan *bc; - - + struct board_chan *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) == NULL) return; - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - bc = ch->brdchan; - tail = bc->tout; - + tail = readw(&bc->tout); /* Have FEP move tout pointer; effectively flushing transmit buffer */ - fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0); - memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); - } /* End pc_flush_buffer */ /* ------------------ Begin pc_flush_chars ---------------------- */ static void pc_flush_chars(struct tty_struct *tty) { /* Begin pc_flush_chars */ - struct channel * ch; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { + if ((ch = verifyChannel(tty)) != NULL) { unsigned long flags; - - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* ---------------------------------------------------------------- If not already set and the transmitter is busy setup an event to indicate when the transmit empties. ------------------------------------------------------------------- */ - if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } - } /* End pc_flush_chars */ /* ------------------ Begin block_til_ready ---------------------- */ @@ -998,14 +877,11 @@ static void pc_flush_chars(struct tty_struct *tty) static int block_til_ready(struct tty_struct *tty, struct file *filp, struct channel *ch) { /* Begin block_til_ready */ - DECLARE_WAITQUEUE(wait,current); int retval, do_clocal = 0; unsigned long flags; - - if (tty_hung_up_p(filp)) - { + if (tty_hung_up_p(filp)) { if (ch->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else @@ -1017,8 +893,7 @@ static int block_til_ready(struct tty_struct *tty, If the device is in the middle of being closed, then block until it's done, and then try again. -------------------------------------------------------------------- */ - if (ch->asyncflags & ASYNC_CLOSING) - { + if (ch->asyncflags & ASYNC_CLOSING) { interruptible_sleep_on(&ch->close_wait); if (ch->asyncflags & ASYNC_HUP_NOTIFY) @@ -1027,43 +902,29 @@ static int block_til_ready(struct tty_struct *tty, return -ERESTARTSYS; } - if (filp->f_flags & O_NONBLOCK) - { + if (filp->f_flags & O_NONBLOCK) { /* ----------------------------------------------------------------- If non-blocking mode is set, then make the check up front and then exit. -------------------------------------------------------------------- */ - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return 0; } - - if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; - - /* Block waiting for the carrier detect and the line to become free */ + /* Block waiting for the carrier detect and the line to become free */ retval = 0; add_wait_queue(&ch->open_wait, &wait); - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* We dec count so that pc_close will know when to free things */ if (!tty_hung_up_p(filp)) ch->count--; - - restore_flags(flags); - ch->blocked_open++; - while(1) { /* Begin forever while */ - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(ch->asyncflags & ASYNC_INITIALIZED)) { @@ -1073,17 +934,14 @@ static int block_til_ready(struct tty_struct *tty, retval = -ERESTARTSYS; break; } - if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || (ch->imodem & ch->dcd))) break; - - if (signal_pending(current)) - { + if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - + spin_unlock_irqrestore(&epca_lock, flags); /* --------------------------------------------------------------- Allow someone else to be scheduled. We will occasionally go through this loop until one of the above conditions change. @@ -1091,25 +949,23 @@ static int block_til_ready(struct tty_struct *tty, prevent this loop from hogging the cpu. ------------------------------------------------------------------ */ schedule(); + spin_lock_irqsave(&epca_lock, flags); } /* End forever while */ current->state = TASK_RUNNING; remove_wait_queue(&ch->open_wait, &wait); - cli(); if (!tty_hung_up_p(filp)) ch->count++; - restore_flags(flags); - ch->blocked_open--; + spin_unlock_irqrestore(&epca_lock, flags); + if (retval) return retval; ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return 0; - } /* End block_til_ready */ /* ------------------ Begin pc_open ---------------------- */ @@ -1120,17 +976,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp) struct channel *ch; unsigned long flags; int line, retval, boardnum; - volatile struct board_chan *bc; - volatile unsigned int head; + struct board_chan *bc; + unsigned int head; line = tty->index; - if (line < 0 || line >= nbdevs) - { - printk(KERN_ERR " - pc_open : line out of range in pc_open\n"); - tty->driver_data = NULL; - return(-ENODEV); - } - + if (line < 0 || line >= nbdevs) + return -ENODEV; ch = &digi_channels[line]; boardnum = ch->boardnum; @@ -1143,66 +994,49 @@ static int pc_open(struct tty_struct *tty, struct file * filp) goes here. ---------------------------------------------------------------------- */ - if (invalid_lilo_config) - { + if (invalid_lilo_config) { if (setup_error_code & INVALID_BOARD_TYPE) - printk(KERN_ERR " - pc_open: Invalid board type specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n"); if (setup_error_code & INVALID_NUM_PORTS) - printk(KERN_ERR " - pc_open: Invalid number of ports specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n"); if (setup_error_code & INVALID_MEM_BASE) - printk(KERN_ERR " - pc_open: Invalid board memory address specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n"); if (setup_error_code & INVALID_PORT_BASE) - printk(KERN_ERR " - pc_open: Invalid board port address specified in LILO command\n"); - + printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n"); if (setup_error_code & INVALID_BOARD_STATUS) - printk(KERN_ERR " - pc_open: Invalid board status specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n"); if (setup_error_code & INVALID_ALTPIN) - printk(KERN_ERR " - pc_open: Invalid board altpin specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n"); tty->driver_data = NULL; /* Mark this device as 'down' */ - return(-ENODEV); + return -ENODEV; } - - if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) - { + if (boardnum >= num_cards || boards[boardnum].status == DISABLED) { tty->driver_data = NULL; /* Mark this device as 'down' */ return(-ENODEV); } - if (( bc = ch->brdchan) == 0) - { + if ((bc = ch->brdchan) == 0) { tty->driver_data = NULL; - return(-ENODEV); + return -ENODEV; } + spin_lock_irqsave(&epca_lock, flags); /* ------------------------------------------------------------------ Every time a channel is opened, increment a counter. This is necessary because we do not wish to flush and shutdown the channel until the last app holding the channel open, closes it. --------------------------------------------------------------------- */ - ch->count++; - /* ---------------------------------------------------------------- Set a kernel structures pointer to our local channel structure. This way we can get to it when passed only a tty struct. ------------------------------------------------------------------ */ - tty->driver_data = ch; - /* ---------------------------------------------------------------- If this is the first time the channel has been opened, initialize the tty->termios struct otherwise let pc_close handle it. -------------------------------------------------------------------- */ - - save_flags(flags); - cli(); - globalwinon(ch); ch->statusflags = 0; @@ -1213,8 +1047,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp) Set receive head and tail ptrs to each other. This indicates no data available to read. ----------------------------------------------------------------- */ - head = bc->rin; - bc->rout = head; + head = readw(&bc->rin); + writew(head, &bc->rout); /* Set the channels associated tty structure */ ch->tty = tty; @@ -1224,122 +1058,74 @@ static int pc_open(struct tty_struct *tty, struct file * filp) issues, etc.... It effect both control flags and input flags. -------------------------------------------------------------------- */ epcaparam(tty,ch); - ch->asyncflags |= ASYNC_INITIALIZED; memoff(ch); - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); retval = block_til_ready(tty, filp, ch); if (retval) - { return retval; - } - /* ------------------------------------------------------------- Set this again in case a hangup set it to zero while this open() was waiting for the line... --------------------------------------------------------------- */ + spin_lock_irqsave(&epca_lock, flags); ch->tty = tty; - - save_flags(flags); - cli(); globalwinon(ch); - /* Enable Digi Data events */ - bc->idata = 1; - + writeb(1, &bc->idata); memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); return 0; - } /* End pc_open */ -#ifdef MODULE static int __init epca_module_init(void) { /* Begin init_module */ - - unsigned long flags; - - save_flags(flags); - cli(); - - pc_init(); - - restore_flags(flags); - - return(0); + return pc_init(); } module_init(epca_module_init); -#endif -#ifdef ENABLE_PCI static struct pci_driver epca_driver; -#endif - -#ifdef MODULE -/* -------------------- Begin cleanup_module ---------------------- */ static void __exit epca_module_exit(void) { - int count, crd; struct board_info *bd; struct channel *ch; - unsigned long flags; del_timer_sync(&epca_timer); - save_flags(flags); - cli(); - if ((tty_unregister_driver(pc_driver)) || (tty_unregister_driver(pc_info))) { - printk(KERN_WARNING " - DIGI : cleanup_module failed to un-register tty driver\n"); - restore_flags(flags); + printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n"); return; } put_tty_driver(pc_driver); put_tty_driver(pc_info); - for (crd = 0; crd < num_cards; crd++) - { /* Begin for each card */ - + for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ bd = &boards[crd]; - if (!bd) { /* Begin sanity check */ printk(KERN_ERR " - Digi : cleanup_module failed\n"); return; } /* End sanity check */ - - ch = card_ptr[crd]; - + ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { /* Begin for each port */ - - if (ch) - { + if (ch) { if (ch->tty) tty_hangup(ch->tty); kfree(ch->tmp_buf); } - } /* End for each port */ } /* End for each card */ - -#ifdef ENABLE_PCI pci_unregister_driver (&epca_driver); -#endif - - restore_flags(flags); - } + module_exit(epca_module_exit); -#endif /* MODULE */ static struct tty_operations pc_ops = { .open = pc_open, @@ -1371,34 +1157,15 @@ static struct tty_operations info_ops = { /* ------------------ Begin pc_init ---------------------- */ -int __init pc_init(void) +static int __init pc_init(void) { /* Begin pc_init */ - - /* ---------------------------------------------------------------- - pc_init is called by the operating system during boot up prior to - any open calls being made. In the older versions of Linux (Prior - to 2.0.0) an entry is made into tty_io.c. A pointer to the last - memory location (from kernel space) used (kmem_start) is passed - to pc_init. It is pc_inits responsibility to modify this value - for any memory that the Digi driver might need and then return - this value to the operating system. For example if the driver - wishes to allocate 1K of kernel memory, pc_init would return - (kmem_start + 1024). This memory (Between kmem_start and kmem_start - + 1024) would then be available for use exclusively by the driver. - In this case our driver does not allocate any of this kernel - memory. - ------------------------------------------------------------------*/ - - ulong flags; int crd; struct board_info *bd; unsigned char board_id = 0; -#ifdef ENABLE_PCI int pci_boards_found, pci_count; pci_count = 0; -#endif /* ENABLE_PCI */ pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) @@ -1416,8 +1183,7 @@ int __init pc_init(void) Note : If LILO has ran epca_setup then epca_setup will handle defining num_cards as well as copying the data into the board structure. -------------------------------------------------------------------------- */ - if (!liloconfig) - { /* Begin driver has been configured via. epcaconfig */ + if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */ nbdevs = NBDEVS; num_cards = NUMCARDS; @@ -1440,8 +1206,6 @@ int __init pc_init(void) printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); -#ifdef ENABLE_PCI - /* ------------------------------------------------------------------ NOTE : This code assumes that the number of ports found in the boards array is correct. This could be wrong if @@ -1467,8 +1231,6 @@ int __init pc_init(void) pci_boards_found += init_PCI(); num_cards += pci_boards_found; -#endif /* ENABLE_PCI */ - pc_driver->owner = THIS_MODULE; pc_driver->name = "ttyD"; pc_driver->devfs_name = "tts/D"; @@ -1499,9 +1261,6 @@ int __init pc_init(void) tty_set_operations(pc_info, &info_ops); - save_flags(flags); - cli(); - for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ @@ -1610,11 +1369,7 @@ int __init pc_init(void) if ((board_id & 0x30) == 0x30) bd->memory_seg = 0x8000; - } /* End it is an XI card */ - else - { - printk(KERN_ERR " - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); - } + } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); break; } /* End switch on bd->type */ @@ -1634,9 +1389,6 @@ int __init pc_init(void) init_timer(&epca_timer); epca_timer.function = epcapoll; mod_timer(&epca_timer, jiffies + HZ/25); - - restore_flags(flags); - return 0; } /* End pc_init */ @@ -1647,10 +1399,10 @@ static void post_fep_init(unsigned int crd) { /* Begin post_fep_init */ int i; - unchar *memaddr; - volatile struct global_data *gd; + unsigned char *memaddr; + struct global_data *gd; struct board_info *bd; - volatile struct board_chan *bc; + struct board_chan *bc; struct channel *ch; int shrinkmem = 0, lowwater ; @@ -1669,9 +1421,7 @@ static void post_fep_init(unsigned int crd) after DIGI_INIT has been called will return the proper values. ------------------------------------------------------------------- */ - if (bd->type >= PCIXEM) /* If the board in question is PCI */ - { /* Begin get PCI number of ports */ - + if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */ /* -------------------------------------------------------------------- Below we use XEMPORTS as a memory offset regardless of which PCI card it is. This is because all of the supported PCI cards have @@ -1685,15 +1435,15 @@ static void post_fep_init(unsigned int crd) (FYI - The id should be located at 0x1ac (And may use up to 4 bytes if the box in question is a XEM or CX)). ------------------------------------------------------------------------ */ - - bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long) - (bd->re_map_membase + XEMPORTS)); - - + /* PCI cards are already remapped at this point ISA are not */ + bd->numports = readw(bd->re_map_membase + XEMPORTS); epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); nbdevs += (bd->numports); - - } /* End get PCI number of ports */ + } else { + /* Fix up the mappings for ISA/EISA etc */ + /* FIXME: 64K - can we be smarter ? */ + bd->re_map_membase = ioremap(bd->membase, 0x10000); + } if (crd != 0) card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports; @@ -1701,19 +1451,9 @@ static void post_fep_init(unsigned int crd) card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */ ch = card_ptr[crd]; - - epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range"); - memaddr = (unchar *)bd->re_map_membase; - - /* - The below command is necessary because newer kernels (2.1.x and - up) do not have a 1:1 virtual to physical mapping. The below - call adjust for that. - */ - - memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); + memaddr = bd->re_map_membase; /* ----------------------------------------------------------------- The below assignment will set bc to point at the BEGINING of @@ -1721,7 +1461,7 @@ static void post_fep_init(unsigned int crd) 8 and 64 of these structures. -------------------------------------------------------------------- */ - bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT); + bc = (struct board_chan *)(memaddr + CHANSTRUCT); /* ------------------------------------------------------------------- The below assignment will set gd to point at the BEGINING of @@ -1730,20 +1470,18 @@ static void post_fep_init(unsigned int crd) pointer begins at 0xd10. ---------------------------------------------------------------------- */ - gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL); + gd = (struct global_data *)(memaddr + GLOBAL); /* -------------------------------------------------------------------- XEPORTS (address 0xc22) points at the number of channels the card supports. (For 64XE, XI, XEM, and XR use 0xc02) ----------------------------------------------------------------------- */ - if (((bd->type == PCXEVE) | (bd->type == PCXE)) && - (*(ushort *)((ulong)memaddr + XEPORTS) < 3)) + if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) if (!request_region((int)bd->port, 4, board_desc[bd->type])) return; - memwinon(bd, 0); /* -------------------------------------------------------------------- @@ -1753,17 +1491,16 @@ static void post_fep_init(unsigned int crd) /* For every port on the card do ..... */ - for (i = 0; i < bd->numports; i++, ch++, bc++) - { /* Begin for each port */ + for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ + unsigned long flags; ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint, ch); ch->board = &boards[crd]; - switch (bd->type) - { /* Begin switch bd->type */ - + spin_lock_irqsave(&epca_lock, flags); + switch (bd->type) { /* ---------------------------------------------------------------- Since some of the boards use different bitmaps for their control signals we cannot hard code these values and retain @@ -1796,14 +1533,12 @@ static void post_fep_init(unsigned int crd) } /* End switch bd->type */ - if (boards[crd].altpin) - { + if (boards[crd].altpin) { ch->dsr = ch->m_dcd; ch->dcd = ch->m_dsr; ch->digiext.digi_flags |= DIGI_ALTPIN; } - else - { + else { ch->dcd = ch->m_dcd; ch->dsr = ch->m_dsr; } @@ -1813,14 +1548,12 @@ static void post_fep_init(unsigned int crd) ch->magic = EPCA_MAGIC; ch->tty = NULL; - if (shrinkmem) - { + if (shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); shrinkmem = 0; } - switch (bd->type) - { /* Begin switch bd->type */ + switch (bd->type) { case PCIXEM: case PCIXRJ: @@ -1878,13 +1611,13 @@ static void post_fep_init(unsigned int crd) fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0); - bc->edelay = 100; - bc->idata = 1; + writew(100, &bc->edelay); + writeb(1, &bc->idata); - ch->startc = bc->startc; - ch->stopc = bc->stopc; - ch->startca = bc->startca; - ch->stopca = bc->stopca; + ch->startc = readb(&bc->startc); + ch->stopc = readb(&bc->stopc); + ch->startca = readb(&bc->startca); + ch->stopca = readb(&bc->stopca); ch->fepcflag = 0; ch->fepiflag = 0; @@ -1899,27 +1632,23 @@ static void post_fep_init(unsigned int crd) ch->blocked_open = 0; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); + + spin_unlock_irqrestore(&epca_lock, flags); + ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); - if (!(ch->tmp_buf)) - { + if (!ch->tmp_buf) { printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i); release_region((int)bd->port, 4); while(i-- > 0) kfree((ch--)->tmp_buf); return; - } - else + } else memset((void *)ch->tmp_buf,0,ch->txbufsize); } /* End for each port */ printk(KERN_INFO "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); - sprintf(mesg, - "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", - VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); - console_print(mesg); - memwinoff(bd, 0); } /* End post_fep_init */ @@ -1943,9 +1672,6 @@ static void epcapoll(unsigned long ignored) buffer empty) and acts on those events. ----------------------------------------------------------------------- */ - save_flags(flags); - cli(); - for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ @@ -1961,6 +1687,8 @@ static void epcapoll(unsigned long ignored) some legacy boards. ---------------------------------------------------------------- */ + spin_lock_irqsave(&epca_lock, flags); + assertmemoff(ch); globalwinon(ch); @@ -1970,21 +1698,19 @@ static void epcapoll(unsigned long ignored) the transmit or receive queue. ------------------------------------------------------------------- */ - head = ch->mailbox->ein; - tail = ch->mailbox->eout; + head = readw(&ch->mailbox->ein); + tail = readw(&ch->mailbox->eout); /* If head isn't equal to tail we have an event */ if (head != tail) doevent(crd); - memoff(ch); - } /* End for each card */ + spin_unlock_irqrestore(&epca_lock, flags); + } /* End for each card */ mod_timer(&epca_timer, jiffies + (HZ / 25)); - - restore_flags(flags); } /* End epcapoll */ /* --------------------- Begin doevent ------------------------ */ @@ -1992,53 +1718,42 @@ static void epcapoll(unsigned long ignored) static void doevent(int crd) { /* Begin doevent */ - volatile unchar *eventbuf; + void *eventbuf; struct channel *ch, *chan0; static struct tty_struct *tty; - volatile struct board_info *bd; - volatile struct board_chan *bc; - register volatile unsigned int tail, head; - register int event, channel; - register int mstat, lstat; + struct board_info *bd; + struct board_chan *bc; + unsigned int tail, head; + int event, channel; + int mstat, lstat; /* ------------------------------------------------------------------- This subroutine is called by epcapoll when an event is detected in the event queue. This routine responds to those events. --------------------------------------------------------------------- */ - bd = &boards[crd]; chan0 = card_ptr[crd]; epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range"); - assertgwinon(chan0); - - while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) + while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */ - assertgwinon(chan0); - - eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART)); - + eventbuf = bd->re_map_membase + tail + ISTART; /* Get the channel the event occurred on */ - channel = eventbuf[0]; - + channel = readb(eventbuf); /* Get the actual event code that occurred */ - event = eventbuf[1]; - + event = readb(eventbuf + 1); /* ---------------------------------------------------------------- The two assignments below get the current modem status (mstat) and the previous modem status (lstat). These are useful becuase an event could signal a change in modem signals itself. ------------------------------------------------------------------- */ - - mstat = eventbuf[2]; - lstat = eventbuf[3]; + mstat = readb(eventbuf + 2); + lstat = readb(eventbuf + 3); ch = chan0 + channel; - - if ((unsigned)channel >= bd->numports || !ch) - { + if ((unsigned)channel >= bd->numports || !ch) { if (channel >= bd->numports) ch = chan0; bc = ch->brdchan; @@ -2048,97 +1763,53 @@ static void doevent(int crd) if ((bc = ch->brdchan) == NULL) goto next; - if (event & DATA_IND) - { /* Begin DATA_IND */ - + if (event & DATA_IND) { /* Begin DATA_IND */ receive_data(ch); assertgwinon(ch); - } /* End DATA_IND */ /* else *//* Fix for DCD transition missed bug */ - if (event & MODEMCHG_IND) - { /* Begin MODEMCHG_IND */ - + if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */ /* A modem signal change has been indicated */ - ch->imodem = mstat; - - if (ch->asyncflags & ASYNC_CHECK_CD) - { + if (ch->asyncflags & ASYNC_CHECK_CD) { if (mstat & ch->dcd) /* We are now receiving dcd */ wake_up_interruptible(&ch->open_wait); else pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */ } - } /* End MODEMCHG_IND */ - tty = ch->tty; - if (tty) - { /* Begin if valid tty */ - - if (event & BREAK_IND) - { /* Begin if BREAK_IND */ - + if (tty) { /* Begin if valid tty */ + if (event & BREAK_IND) { /* Begin if BREAK_IND */ /* A break has been indicated */ - tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; - tty_schedule_flip(tty); - - } /* End if BREAK_IND */ - else - if (event & LOWTX_IND) - { /* Begin LOWTX_IND */ - + } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */ if (ch->statusflags & LOWWAIT) { /* Begin if LOWWAIT */ - ch->statusflags &= ~LOWWAIT; tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); - } /* End if LOWWAIT */ - - } /* End LOWTX_IND */ - else - if (event & EMPTYTX_IND) - { /* Begin EMPTYTX_IND */ - + } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */ /* This event is generated by setup_empty_event */ - ch->statusflags &= ~TXBUSY; - if (ch->statusflags & EMPTYWAIT) - { /* Begin if EMPTYWAIT */ - + if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT; tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } /* End if EMPTYWAIT */ - } /* End EMPTYTX_IND */ - } /* End if valid tty */ - - next: globalwinon(ch); - - if (!bc) - printk(KERN_ERR " - bc == NULL in doevent!\n"); - else - bc->idata = 1; - - chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4); + BUG_ON(!bc); + writew(1, &bc->idata); + writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout); globalwinon(chan0); - } /* End while something in event queue */ - } /* End doevent */ /* --------------------- Begin fepcmd ------------------------ */ @@ -2146,7 +1817,6 @@ static void doevent(int crd) static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd) { /* Begin fepcmd */ - unchar *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; long count; @@ -2155,93 +1825,57 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, /* This is the routine in which commands may be passed to the card. */ if (ch->board->status == DISABLED) - { return; - } - assertgwinon(ch); - /* Remember head (As well as max) is just an offset not a base addr */ - head = ch->mailbox->cin; - + head = readw(&ch->mailbox->cin); /* cmdStart is a base address */ - cmdStart = ch->mailbox->cstart; - + cmdStart = readw(&ch->mailbox->cstart); /* ------------------------------------------------------------------ We do the addition below because we do not want a max pointer relative to cmdStart. We want a max pointer that points at the physical end of the command queue. -------------------------------------------------------------------- */ - - cmdMax = (cmdStart + 4 + (ch->mailbox->cmax)); - + cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax)); memaddr = ch->board->re_map_membase; - /* - The below command is necessary because newer kernels (2.1.x and - up) do not have a 1:1 virtual to physical mapping. The below - call adjust for that. - */ - - memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); - - if (head >= (cmdMax - cmdStart) || (head & 03)) - { - printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, - cmd, head); - printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, - cmdMax, cmdStart); + if (head >= (cmdMax - cmdStart) || (head & 03)) { + printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head); + printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart); return; } - - if (bytecmd) - { - *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; - - *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; + if (bytecmd) { + writeb(cmd, memaddr + head + cmdStart + 0); + writeb(ch->channelnum, memaddr + head + cmdStart + 1); /* Below word_or_byte is bits to set */ - *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte; + writeb(word_or_byte, memaddr + head + cmdStart + 2); /* Below byte2 is bits to reset */ - *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2; - - } - else - { - *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; - *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; - *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte; + writeb(byte2, memaddr + head + cmdStart + 3); + } else { + writeb(cmd, memaddr + head + cmdStart + 0); + writeb(ch->channelnum, memaddr + head + cmdStart + 1); + writeb(word_or_byte, memaddr + head + cmdStart + 2); } - head = (head + 4) & (cmdMax - cmdStart - 4); - ch->mailbox->cin = head; - + writew(head, &ch->mailbox->cin); count = FEPTIMEOUT; - for (;;) - { /* Begin forever loop */ - + for (;;) { /* Begin forever loop */ count--; - if (count == 0) - { + if (count == 0) { printk(KERN_ERR " - Fep not responding in fepcmd()\n"); return; } - - head = ch->mailbox->cin; - cmdTail = ch->mailbox->cout; - + head = readw(&ch->mailbox->cin); + cmdTail = readw(&ch->mailbox->cout); n = (head - cmdTail) & (cmdMax - cmdStart - 4); - /* ---------------------------------------------------------- Basically this will break when the FEP acknowledges the command by incrementing cmdTail (Making it equal to head). ------------------------------------------------------------- */ - if (n <= ncmds * (sizeof(short) * 4)) break; /* Well nearly forever :-) */ - } /* End forever loop */ - } /* End fepcmd */ /* --------------------------------------------------------------------- @@ -2255,11 +1889,9 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, static unsigned termios2digi_h(struct channel *ch, unsigned cflag) { /* Begin termios2digi_h */ - unsigned res = 0; - if (cflag & CRTSCTS) - { + if (cflag & CRTSCTS) { ch->digiext.digi_flags |= (RTSPACE | CTSPACE); res |= ((ch->m_cts) | (ch->m_rts)); } @@ -2295,7 +1927,6 @@ static unsigned termios2digi_i(struct channel *ch, unsigned iflag) unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP|IXON|IXANY|IXOFF); - if (ch->digiext.digi_flags & DIGI_AIXON) res |= IAIXON; return res; @@ -2308,28 +1939,15 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) { /* Begin termios2digi_c */ unsigned res = 0; - -#ifdef SPEED_HACK - /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */ - if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200; - if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600; -#endif /* SPEED_HACK */ - - if (cflag & CBAUDEX) - { /* Begin detected CBAUDEX */ - + if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */ ch->digiext.digi_flags |= DIGI_FAST; - /* ------------------------------------------------------------- HUPCL bit is used by FEP to indicate fast baud table is to be used. ----------------------------------------------------------------- */ - res |= FEP_HUPCL; - } /* End detected CBAUDEX */ else ch->digiext.digi_flags &= ~DIGI_FAST; - /* ------------------------------------------------------------------- CBAUD has bit position 0x1000 set these days to indicate Linux baud rate remap. Digi hardware can't handle the bit assignment. @@ -2337,7 +1955,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) bit out. ---------------------------------------------------------------------- */ res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); - /* ------------------------------------------------------------- This gets a little confusing. The Digi cards have their own representation of c_cflags controling baud rate. For the most @@ -2357,10 +1974,8 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) should be checked for a screened out prior to termios2digi_c returning. Since CLOCAL isn't used by the board this can be ignored as long as the returned value is used only by Digi hardware. - ----------------------------------------------------------------- */ - - if (cflag & CBAUDEX) - { + ----------------------------------------------------------------- */ + if (cflag & CBAUDEX) { /* ------------------------------------------------------------- The below code is trying to guarantee that only baud rates 115200 and 230400 are remapped. We use exclusive or because @@ -2371,138 +1986,96 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX)))) - { res += 1; - } } - return res; } /* End termios2digi_c */ /* --------------------- Begin epcaparam ----------------------- */ +/* Caller must hold the locks */ static void epcaparam(struct tty_struct *tty, struct channel *ch) { /* Begin epcaparam */ unsigned int cmdHead; struct termios *ts; - volatile struct board_chan *bc; + struct board_chan *bc; unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; epcaassert(bc !=0, "bc out of range"); assertgwinon(ch); - ts = tty->termios; - - if ((ts->c_cflag & CBAUD) == 0) - { /* Begin CBAUD detected */ - - cmdHead = bc->rin; + if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ + cmdHead = readw(&bc->rin); bc->rout = cmdHead; - cmdHead = bc->tin; - + cmdHead = readw(&bc->tin); /* Changing baud in mid-stream transmission can be wonderful */ /* --------------------------------------------------------------- Flush current transmit buffer by setting cmdTail pointer (tout) to cmdHead pointer (tin). Hopefully the transmit buffer is empty. ----------------------------------------------------------------- */ - fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0); mval = 0; - - } /* End CBAUD detected */ - else - { /* Begin CBAUD not detected */ - + } else { /* Begin CBAUD not detected */ /* ------------------------------------------------------------------- c_cflags have changed but that change had nothing to do with BAUD. Propagate the change to the card. ---------------------------------------------------------------------- */ - cflag = termios2digi_c(ch, ts->c_cflag); - - if (cflag != ch->fepcflag) - { + if (cflag != ch->fepcflag) { ch->fepcflag = cflag; /* Set baud rate, char size, stop bits, parity */ fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0); } - - /* ---------------------------------------------------------------- If the user has not forced CLOCAL and if the device is not a CALLOUT device (Which is always CLOCAL) we set flags such that the driver will wait on carrier detect. ------------------------------------------------------------------- */ - if (ts->c_cflag & CLOCAL) - { /* Begin it is a cud device or a ttyD device with CLOCAL on */ ch->asyncflags &= ~ASYNC_CHECK_CD; - } /* End it is a cud device or a ttyD device with CLOCAL on */ else - { /* Begin it is a ttyD device */ ch->asyncflags |= ASYNC_CHECK_CD; - } /* End it is a ttyD device */ - mval = ch->m_dtr | ch->m_rts; - } /* End CBAUD not detected */ - iflag = termios2digi_i(ch, ts->c_iflag); - /* Check input mode flags */ - - if (iflag != ch->fepiflag) - { + if (iflag != ch->fepiflag) { ch->fepiflag = iflag; - /* --------------------------------------------------------------- Command sets channels iflag structure on the board. Such things as input soft flow control, handling of parity errors, and break handling are all set here. ------------------------------------------------------------------- */ - /* break handling, parity handling, input stripping, flow control chars */ fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0); } - /* --------------------------------------------------------------- Set the board mint value for this channel. This will cause hardware events to be generated each time the DCD signal (Described in mint) changes. ------------------------------------------------------------------- */ - bc->mint = ch->dcd; - + writeb(ch->dcd, &bc->mint); if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD)) if (ch->digiext.digi_flags & DIGI_FORCEDCD) - bc->mint = 0; - - ch->imodem = bc->mstat; - + writeb(0, &bc->mint); + ch->imodem = readb(&bc->mstat); hflow = termios2digi_h(ch, ts->c_cflag); - - if (hflow != ch->hflow) - { + if (hflow != ch->hflow) { ch->hflow = hflow; - /* -------------------------------------------------------------- Hard flow control has been selected but the board is not using it. Activate hard flow control now. ----------------------------------------------------------------- */ - fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1); } - - mval ^= ch->modemfake & (mval ^ ch->modem); - if (ch->omodem ^ mval) - { + if (ch->omodem ^ mval) { ch->omodem = mval; - /* -------------------------------------------------------------- The below command sets the DTR and RTS mstat structure. If hard flow control is NOT active these changes will drive the @@ -2514,87 +2087,65 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) /* First reset DTR & RTS; then set them */ fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1); fepcmd(ch, SETMODEM, mval, 0, 0, 1); - } - - if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) - { + if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) { ch->fepstartc = ch->startc; ch->fepstopc = ch->stopc; - /* ------------------------------------------------------------ The XON / XOFF characters have changed; propagate these changes to the card. --------------------------------------------------------------- */ - fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); } - - if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) - { + if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) { ch->fepstartca = ch->startca; ch->fepstopca = ch->stopca; - /* --------------------------------------------------------------- Similar to the above, this time the auxilarly XON / XOFF characters have changed; propagate these changes to the card. ------------------------------------------------------------------ */ - fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); } - } /* End epcaparam */ /* --------------------- Begin receive_data ----------------------- */ - +/* Caller holds lock */ static void receive_data(struct channel *ch) { /* Begin receive_data */ unchar *rptr; struct termios *ts = NULL; struct tty_struct *tty; - volatile struct board_chan *bc; - register int dataToRead, wrapgap, bytesAvailable; - register unsigned int tail, head; + struct board_chan *bc; + int dataToRead, wrapgap, bytesAvailable; + unsigned int tail, head; unsigned int wrapmask; int rc; - /* --------------------------------------------------------------- This routine is called by doint when a receive data event has taken place. ------------------------------------------------------------------- */ globalwinon(ch); - if (ch->statusflags & RXSTOPPED) return; - tty = ch->tty; if (tty) ts = tty->termios; - bc = ch->brdchan; - - if (!bc) - { - printk(KERN_ERR " - bc is NULL in receive_data!\n"); - return; - } - + BUG_ON(!bc); wrapmask = ch->rxbufsize - 1; /* --------------------------------------------------------------------- Get the head and tail pointers to the receiver queue. Wrap the head pointer if it has reached the end of the buffer. ------------------------------------------------------------------------ */ - - head = bc->rin; + head = readw(&bc->rin); head &= wrapmask; - tail = bc->rout & wrapmask; + tail = readw(&bc->rout) & wrapmask; bytesAvailable = (head - tail) & wrapmask; - if (bytesAvailable == 0) return; @@ -2602,8 +2153,7 @@ static void receive_data(struct channel *ch) If CREAD bit is off or device not open, set TX tail to head --------------------------------------------------------------------- */ - if (!tty || !ts || !(ts->c_cflag & CREAD)) - { + if (!tty || !ts || !(ts->c_cflag & CREAD)) { bc->rout = head; return; } @@ -2611,64 +2161,45 @@ static void receive_data(struct channel *ch) if (tty->flip.count == TTY_FLIPBUF_SIZE) return; - if (bc->orun) - { - bc->orun = 0; - printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name); + if (readb(&bc->orun)) { + writeb(0, &bc->orun); + printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name); } - rxwinon(ch); rptr = tty->flip.char_buf_ptr; rc = tty->flip.count; - - while (bytesAvailable > 0) - { /* Begin while there is data on the card */ - + while (bytesAvailable > 0) { /* Begin while there is data on the card */ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; - /* --------------------------------------------------------------- Even if head has wrapped around only report the amount of data to be equal to the size - tail. Remember memcpy can't automaticly wrap around the receive buffer. ----------------------------------------------------------------- */ - dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; - /* -------------------------------------------------------------- Make sure we don't overflow the buffer ----------------------------------------------------------------- */ - if ((rc + dataToRead) > TTY_FLIPBUF_SIZE) dataToRead = TTY_FLIPBUF_SIZE - rc; - if (dataToRead == 0) break; - /* --------------------------------------------------------------- Move data read from our card into the line disciplines buffer for translation if necessary. ------------------------------------------------------------------ */ - - if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr) - printk(KERN_ERR " - receive_data : memcpy failed\n"); - + memcpy_fromio(rptr, ch->rxptr + tail, dataToRead); rc += dataToRead; rptr += dataToRead; tail = (tail + dataToRead) & wrapmask; bytesAvailable -= dataToRead; - } /* End while there is data on the card */ - - tty->flip.count = rc; tty->flip.char_buf_ptr = rptr; globalwinon(ch); - bc->rout = tail; - + writew(tail, &bc->rout); /* Must be called with global data */ tty_schedule_flip(ch->tty); return; - } /* End receive_data */ static int info_ioctl(struct tty_struct *tty, struct file * file, @@ -2676,17 +2207,15 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, { switch (cmd) { /* Begin switch cmd */ - case DIGI_GETINFO: { /* Begin case DIGI_GETINFO */ - struct digi_info di ; int brd; - getUser(brd, (unsigned int __user *)arg); - - if ((brd < 0) || (brd >= num_cards) || (num_cards == 0)) - return (-ENODEV); + if(get_user(brd, (unsigned int __user *)arg)) + return -EFAULT; + if (brd < 0 || brd >= num_cards || num_cards == 0) + return -ENODEV; memset(&di, 0, sizeof(di)); @@ -2694,8 +2223,9 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, di.status = boards[brd].status; di.type = boards[brd].type ; di.numports = boards[brd].numports ; - di.port = boards[brd].port ; - di.membase = boards[brd].membase ; + /* Legacy fixups - just move along nothing to see */ + di.port = (unsigned char *)boards[brd].port ; + di.membase = (unsigned char *)boards[brd].membase ; if (copy_to_user((void __user *)arg, &di, sizeof (di))) return -EFAULT; @@ -2709,39 +2239,29 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, int brd = arg & 0xff000000 >> 16 ; unsigned char state = arg & 0xff ; - if ((brd < 0) || (brd >= num_cards)) - { - printk(KERN_ERR " - DIGI POLLER : brd not valid!\n"); + if (brd < 0 || brd >= num_cards) { + printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n"); return (-ENODEV); } - digi_poller_inhibited = state ; break ; - } /* End case DIGI_POLLER */ case DIGI_INIT: { /* Begin case DIGI_INIT */ - /* ------------------------------------------------------------ This call is made by the apps to complete the initilization of the board(s). This routine is responsible for setting the card to its initial state and setting the drivers control fields to the sutianle settings for the card in question. ---------------------------------------------------------------- */ - int crd ; for (crd = 0; crd < num_cards; crd++) post_fep_init (crd); - break ; - } /* End case DIGI_INIT */ - - default: - return -ENOIOCTLCMD; - + return -ENOTTY; } /* End switch cmd */ return (0) ; } @@ -2750,43 +2270,33 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { struct channel *ch = (struct channel *) tty->driver_data; - volatile struct board_chan *bc; + struct board_chan *bc; unsigned int mstat, mflag = 0; unsigned long flags; if (ch) bc = ch->brdchan; else - { - printk(KERN_ERR " - ch is NULL in pc_tiocmget!\n"); - return(-EINVAL); - } + return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - mstat = bc->mstat; + mstat = readb(&bc->mstat); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); if (mstat & ch->m_dtr) mflag |= TIOCM_DTR; - if (mstat & ch->m_rts) mflag |= TIOCM_RTS; - if (mstat & ch->m_cts) mflag |= TIOCM_CTS; - if (mstat & ch->dsr) mflag |= TIOCM_DSR; - if (mstat & ch->m_ri) mflag |= TIOCM_RI; - if (mstat & ch->dcd) mflag |= TIOCM_CD; - return mflag; } @@ -2796,13 +2306,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, struct channel *ch = (struct channel *) tty->driver_data; unsigned long flags; - if (!ch) { - printk(KERN_ERR " - ch is NULL in pc_tiocmset!\n"); - return(-EINVAL); - } + if (!ch) + return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); /* * I think this modemfake stuff is broken. It doesn't * correctly reflect the behaviour desired by the TIOCM* @@ -2824,17 +2331,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, ch->modemfake |= ch->m_dtr; ch->modem &= ~ch->m_dtr; } - globalwinon(ch); - /* -------------------------------------------------------------- The below routine generally sets up parity, baud, flow control issues, etc.... It effect both control flags and input flags. ------------------------------------------------------------------ */ - epcaparam(tty,ch); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); return 0; } @@ -2847,19 +2351,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, unsigned long flags; unsigned int mflag, mstat; unsigned char startc, stopc; - volatile struct board_chan *bc; + struct board_chan *bc; struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; if (ch) bc = ch->brdchan; else - { - printk(KERN_ERR " - ch is NULL in pc_ioctl!\n"); - return(-EINVAL); - } - - save_flags(flags); + return -EINVAL; /* ------------------------------------------------------------------- For POSIX compliance we need to add more ioctls. See tty_ioctl.c @@ -2871,46 +2370,39 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, { /* Begin switch cmd */ case TCGETS: - if (copy_to_user(argp, - tty->termios, sizeof(struct termios))) + if (copy_to_user(argp, tty->termios, sizeof(struct termios))) return -EFAULT; - return(0); - + return 0; case TCGETA: return get_termio(tty, argp); - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); if (retval) return retval; - /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); if (!arg) digi_send_break(ch, HZ/4); /* 1/4 second */ return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); if (retval) return retval; /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4); return 0; - case TIOCGSOFTCAR: if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg)) return -EFAULT; return 0; - case TIOCSSOFTCAR: { unsigned int value; @@ -2922,75 +2414,63 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, (value ? CLOCAL : 0)); return 0; } - case TIOCMODG: mflag = pc_tiocmget(tty, file); if (put_user(mflag, (unsigned long __user *)argp)) return -EFAULT; break; - case TIOCMODS: if (get_user(mstat, (unsigned __user *)argp)) return -EFAULT; return pc_tiocmset(tty, file, mstat, ~mstat); - case TIOCSDTR: + spin_lock_irqsave(&epca_lock, flags); ch->omodem |= ch->m_dtr; - cli(); globalwinon(ch); fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; case TIOCCDTR: + spin_lock_irqsave(&epca_lock, flags); ch->omodem &= ~ch->m_dtr; - cli(); globalwinon(ch); fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; - case DIGI_GETA: if (copy_to_user(argp, &ch->digiext, sizeof(digi_t))) return -EFAULT; break; - case DIGI_SETAW: case DIGI_SETAF: - if ((cmd) == (DIGI_SETAW)) - { + if (cmd == DIGI_SETAW) { /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); - } - else - { + } else { /* ldisc lock already held in ioctl */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); } - /* Fall Thru */ - case DIGI_SETA: if (copy_from_user(&ch->digiext, argp, sizeof(digi_t))) return -EFAULT; - if (ch->digiext.digi_flags & DIGI_ALTPIN) - { + if (ch->digiext.digi_flags & DIGI_ALTPIN) { ch->dcd = ch->m_dsr; ch->dsr = ch->m_dcd; - } - else - { + } else { ch->dcd = ch->m_dcd; ch->dsr = ch->m_dsr; } - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); /* ----------------------------------------------------------------- @@ -3000,25 +2480,22 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, epcaparam(tty,ch); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; case DIGI_GETFLOW: case DIGI_GETAFLOW: - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - if ((cmd) == (DIGI_GETFLOW)) - { - dflow.startc = bc->startc; - dflow.stopc = bc->stopc; - } - else - { - dflow.startc = bc->startca; - dflow.stopc = bc->stopca; + if (cmd == DIGI_GETFLOW) { + dflow.startc = readb(&bc->startc); + dflow.stopc = readb(&bc->stopc); + } else { + dflow.startc = readb(&bc->startca); + dflow.stopc = readb(&bc->stopca); } memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); if (copy_to_user(argp, &dflow, sizeof(dflow))) return -EFAULT; @@ -3026,13 +2503,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, case DIGI_SETAFLOW: case DIGI_SETFLOW: - if ((cmd) == (DIGI_SETFLOW)) - { + if (cmd == DIGI_SETFLOW) { startc = ch->startc; stopc = ch->stopc; - } - else - { + } else { startc = ch->startca; stopc = ch->stopca; } @@ -3040,40 +2514,31 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, if (copy_from_user(&dflow, argp, sizeof(dflow))) return -EFAULT; - if (dflow.startc != startc || dflow.stopc != stopc) - { /* Begin if setflow toggled */ - cli(); + if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */ + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - if ((cmd) == (DIGI_SETFLOW)) - { + if (cmd == DIGI_SETFLOW) { ch->fepstartc = ch->startc = dflow.startc; ch->fepstopc = ch->stopc = dflow.stopc; fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); - } - else - { + } else { ch->fepstartca = ch->startca = dflow.startc; ch->fepstopca = ch->stopca = dflow.stopc; fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); } - if (ch->statusflags & TXSTOPPED) + if (ch->statusflags & TXSTOPPED) pc_start(tty); memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if setflow toggled */ break; - default: return -ENOIOCTLCMD; - } /* End switch cmd */ - return 0; - } /* End pc_ioctl */ /* --------------------- Begin pc_set_termios ----------------------- */ @@ -3083,20 +2548,16 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - save_flags(flags); - cli(); + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); epcaparam(tty, ch); memoff(ch); + spin_unlock_irqrestore(&epca_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && ((tty->termios->c_cflag & CRTSCTS) == 0)) @@ -3106,8 +2567,6 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&ch->open_wait); - restore_flags(flags); - } /* End if channel valid */ } /* End pc_set_termios */ @@ -3116,29 +2575,18 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) static void do_softint(void *private_) { /* Begin do_softint */ - struct channel *ch = (struct channel *) private_; - - /* Called in response to a modem change event */ - - if (ch && ch->magic == EPCA_MAGIC) - { /* Begin EPCA_MAGIC */ - + if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ struct tty_struct *tty = ch->tty; - if (tty && tty->driver_data) - { - if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) - { /* Begin if clear_bit */ - + if (tty && tty->driver_data) { + if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */ tty_hangup(tty); /* FIXME: module removal race here - AKPM */ wake_up_interruptible(&ch->open_wait); ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - } /* End if clear_bit */ } - } /* End EPCA_MAGIC */ } /* End do_softint */ @@ -3154,82 +2602,49 @@ static void pc_stop(struct tty_struct *tty) struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if valid channel */ - - save_flags(flags); - cli(); - - if ((ch->statusflags & TXSTOPPED) == 0) - { /* Begin if transmit stop requested */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */ + spin_lock_irqsave(&epca_lock, flags); + if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */ globalwinon(ch); - /* STOP transmitting now !! */ - fepcmd(ch, PAUSETX, 0, 0, 0, 0); - ch->statusflags |= TXSTOPPED; memoff(ch); - } /* End if transmit stop requested */ - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if valid channel */ - } /* End pc_stop */ /* --------------------- Begin pc_start ----------------------- */ static void pc_start(struct tty_struct *tty) { /* Begin pc_start */ - struct channel *ch; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ unsigned long flags; - - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* Just in case output was resumed because of a change in Digi-flow */ - if (ch->statusflags & TXSTOPPED) - { /* Begin transmit resume requested */ - - volatile struct board_chan *bc; - + if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ + struct board_chan *bc; globalwinon(ch); bc = ch->brdchan; if (ch->statusflags & LOWWAIT) - bc->ilow = 1; - + writeb(1, &bc->ilow); /* Okay, you can start transmitting again... */ - fepcmd(ch, RESUMETX, 0, 0, 0, 0); - ch->statusflags &= ~TXSTOPPED; memoff(ch); - } /* End transmit resume requested */ - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_start */ /* ------------------------------------------------------------------ @@ -3244,86 +2659,55 @@ ______________________________________________________________________ */ static void pc_throttle(struct tty_struct * tty) { /* Begin pc_throttle */ - struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - - save_flags(flags); - cli(); - - if ((ch->statusflags & RXSTOPPED) == 0) - { + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ + spin_lock_irqsave(&epca_lock, flags); + if ((ch->statusflags & RXSTOPPED) == 0) { globalwinon(ch); fepcmd(ch, PAUSERX, 0, 0, 0, 0); - ch->statusflags |= RXSTOPPED; memoff(ch); } - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_throttle */ /* --------------------- Begin unthrottle ----------------------- */ static void pc_unthrottle(struct tty_struct *tty) { /* Begin pc_unthrottle */ - struct channel *ch; unsigned long flags; - volatile struct board_chan *bc; - - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ /* Just in case output was resumed because of a change in Digi-flow */ - save_flags(flags); - cli(); - - if (ch->statusflags & RXSTOPPED) - { - + spin_lock_irqsave(&epca_lock, flags); + if (ch->statusflags & RXSTOPPED) { globalwinon(ch); - bc = ch->brdchan; fepcmd(ch, RESUMERX, 0, 0, 0, 0); - ch->statusflags &= ~RXSTOPPED; memoff(ch); } - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_unthrottle */ /* --------------------- Begin digi_send_break ----------------------- */ void digi_send_break(struct channel *ch, int msec) { /* Begin digi_send_break */ - unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - /* -------------------------------------------------------------------- Maybe I should send an infinite break here, schedule() for msec amount of time, and then stop the break. This way, @@ -3331,36 +2715,28 @@ void digi_send_break(struct channel *ch, int msec) to be called (i.e. via an ioctl()) more than once in msec amount of time. Try this for now... ------------------------------------------------------------------------ */ - fepcmd(ch, SENDBREAK, msec, 0, 10, 0); memoff(ch); - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End digi_send_break */ /* --------------------- Begin setup_empty_event ----------------------- */ +/* Caller MUST hold the lock */ + static void setup_empty_event(struct tty_struct *tty, struct channel *ch) { /* Begin setup_empty_event */ - volatile struct board_chan *bc = ch->brdchan; - unsigned long int flags; + struct board_chan *bc = ch->brdchan; - save_flags(flags); - cli(); globalwinon(ch); ch->statusflags |= EMPTYWAIT; - /* ------------------------------------------------------------------ When set the iempty flag request a event to be generated when the transmit buffer is empty (If there is no BREAK in progress). --------------------------------------------------------------------- */ - - bc->iempty = 1; + writeb(1, &bc->iempty); memoff(ch); - restore_flags(flags); - } /* End setup_empty_event */ /* --------------------- Begin get_termio ----------------------- */ @@ -3369,10 +2745,10 @@ static int get_termio(struct tty_struct * tty, struct termio __user * termio) { /* Begin get_termio */ return kernel_termios_to_user_termio(termio, tty->termios); } /* End get_termio */ + /* ---------------------- Begin epca_setup -------------------------- */ void epca_setup(char *str, int *ints) { /* Begin epca_setup */ - struct board_info board; int index, loop, last; char *temp, *t2; @@ -3394,49 +2770,41 @@ void epca_setup(char *str, int *ints) for (last = 0, index = 1; index <= ints[0]; index++) switch(index) { /* Begin parse switch */ - case 1: board.status = ints[index]; - /* --------------------------------------------------------- We check for 2 (As opposed to 1; because 2 is a flag instructing the driver to ignore epcaconfig.) For this reason we check for 2. ------------------------------------------------------------ */ - if (board.status == 2) - { /* Begin ignore epcaconfig as well as lilo cmd line */ + if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */ nbdevs = 0; num_cards = 0; return; } /* End ignore epcaconfig as well as lilo cmd line */ - if (board.status > 2) - { - printk(KERN_ERR " - epca_setup: Invalid board status 0x%x\n", board.status); + if (board.status > 2) { + printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_STATUS; return; } last = index; break; - case 2: board.type = ints[index]; - if (board.type >= PCIXEM) - { - printk(KERN_ERR " - epca_setup: Invalid board type 0x%x\n", board.type); + if (board.type >= PCIXEM) { + printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_TYPE; return; } last = index; break; - case 3: board.altpin = ints[index]; - if (board.altpin > 1) - { - printk(KERN_ERR " - epca_setup: Invalid board altpin 0x%x\n", board.altpin); + if (board.altpin > 1) { + printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin); invalid_lilo_config = 1; setup_error_code |= INVALID_ALTPIN; return; @@ -3446,9 +2814,8 @@ void epca_setup(char *str, int *ints) case 4: board.numports = ints[index]; - if ((board.numports < 2) || (board.numports > 256)) - { - printk(KERN_ERR " - epca_setup: Invalid board numports 0x%x\n", board.numports); + if (board.numports < 2 || board.numports > 256) { + printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports); invalid_lilo_config = 1; setup_error_code |= INVALID_NUM_PORTS; return; @@ -3458,10 +2825,9 @@ void epca_setup(char *str, int *ints) break; case 5: - board.port = (unsigned char *)ints[index]; - if (ints[index] <= 0) - { - printk(KERN_ERR " - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port); + board.port = ints[index]; + if (ints[index] <= 0) { + printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port); invalid_lilo_config = 1; setup_error_code |= INVALID_PORT_BASE; return; @@ -3470,10 +2836,9 @@ void epca_setup(char *str, int *ints) break; case 6: - board.membase = (unsigned char *)ints[index]; - if (ints[index] <= 0) - { - printk(KERN_ERR " - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); + board.membase = ints[index]; + if (ints[index] <= 0) { + printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; @@ -3487,21 +2852,16 @@ void epca_setup(char *str, int *ints) } /* End parse switch */ - while (str && *str) - { /* Begin while there is a string arg */ - + while (str && *str) { /* Begin while there is a string arg */ /* find the next comma or terminator */ temp = str; - /* While string is not null, and a comma hasn't been found */ while (*temp && (*temp != ',')) temp++; - if (!*temp) temp = NULL; else *temp++ = 0; - /* Set index to the number of args + 1 */ index = last + 1; @@ -3511,12 +2871,10 @@ void epca_setup(char *str, int *ints) len = strlen(str); if (strncmp("Disable", str, len) == 0) board.status = 0; - else - if (strncmp("Enable", str, len) == 0) + else if (strncmp("Enable", str, len) == 0) board.status = 1; - else - { - printk(KERN_ERR " - epca_setup: Invalid status %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid status %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_STATUS; return; @@ -3525,22 +2883,17 @@ void epca_setup(char *str, int *ints) break; case 2: - for(loop = 0; loop < EPCA_NUM_TYPES; loop++) if (strcmp(board_desc[loop], str) == 0) break; - - /* --------------------------------------------------------------- If the index incremented above refers to a legitamate board type set it here. ------------------------------------------------------------------*/ - if (index < EPCA_NUM_TYPES) board.type = loop; - else - { - printk(KERN_ERR " - epca_setup: Invalid board type: %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_TYPE; return; @@ -3552,12 +2905,10 @@ void epca_setup(char *str, int *ints) len = strlen(str); if (strncmp("Disable", str, len) == 0) board.altpin = 0; - else - if (strncmp("Enable", str, len) == 0) + else if (strncmp("Enable", str, len) == 0) board.altpin = 1; - else - { - printk(KERN_ERR " - epca_setup: Invalid altpin %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_ALTPIN; return; @@ -3570,9 +2921,8 @@ void epca_setup(char *str, int *ints) while (isdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR " - epca_setup: Invalid port count %s\n", str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid port count %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_NUM_PORTS; return; @@ -3601,15 +2951,14 @@ void epca_setup(char *str, int *ints) while (isxdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR " - epca_setup: Invalid i/o address %s\n", str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_PORT_BASE; return; } - board.port = (unsigned char *)simple_strtoul(str, NULL, 16); + board.port = simple_strtoul(str, NULL, 16); last = index; break; @@ -3618,52 +2967,38 @@ void epca_setup(char *str, int *ints) while (isxdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR " - epca_setup: Invalid memory base %s\n",str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; } - - board.membase = (unsigned char *)simple_strtoul(str, NULL, 16); + board.membase = simple_strtoul(str, NULL, 16); last = index; break; - default: - printk(KERN_ERR "PC/Xx: Too many string parms\n"); + printk(KERN_ERR "epca: Too many string parms\n"); return; } str = temp; - } /* End while there is a string arg */ - - if (last < 6) - { - printk(KERN_ERR "PC/Xx: Insufficient parms specified\n"); + if (last < 6) { + printk(KERN_ERR "epca: Insufficient parms specified\n"); return; } /* I should REALLY validate the stuff here */ - /* Copies our local copy of board into boards */ memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board)); - - /* Does this get called once per lilo arg are what ? */ - printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", num_cards, board_desc[board.type], board.numports, (int)board.port, (unsigned int) board.membase); - num_cards++; - } /* End epca_setup */ - -#ifdef ENABLE_PCI /* ------------------------ Begin init_PCI --------------------------- */ enum epic_board_types { @@ -3685,7 +3020,6 @@ static struct { { PCIXRJ, 2, }, }; - static int __devinit epca_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3711,10 +3045,8 @@ static int __devinit epca_init_one (struct pci_dev *pdev, boards[board_idx].status = ENABLED; boards[board_idx].type = epca_info_tbl[info_idx].board_type; boards[board_idx].numports = 0x0; - boards[board_idx].port = - (unsigned char *)((char *) addr + PCI_IO_OFFSET); - boards[board_idx].membase = - (unsigned char *)((char *) addr); + boards[board_idx].port = addr + PCI_IO_OFFSET; + boards[board_idx].membase = addr; if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) { printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", @@ -3775,15 +3107,13 @@ static struct pci_device_id epca_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, epca_pci_tbl); int __init init_PCI (void) -{ /* Begin init_PCI */ +{ /* Begin init_PCI */ memset (&epca_driver, 0, sizeof (epca_driver)); epca_driver.name = "epca"; epca_driver.id_table = epca_pci_tbl; epca_driver.probe = epca_init_one; return pci_register_driver(&epca_driver); -} /* End init_PCI */ - -#endif /* ENABLE_PCI */ +} MODULE_LICENSE("GPL"); diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 52205ef71314..20eeb5a70e1a 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -85,73 +85,73 @@ static char *board_desc[] = struct channel { long magic; - unchar boardnum; - unchar channelnum; - unchar omodem; /* FEP output modem status */ - unchar imodem; /* FEP input modem status */ - unchar modemfake; /* Modem values to be forced */ - unchar modem; /* Force values */ - unchar hflow; - unchar dsr; - unchar dcd; - unchar m_rts ; /* The bits used in whatever FEP */ - unchar m_dcd ; /* is indiginous to this board to */ - unchar m_dsr ; /* represent each of the physical */ - unchar m_cts ; /* handshake lines */ - unchar m_ri ; - unchar m_dtr ; - unchar stopc; - unchar startc; - unchar stopca; - unchar startca; - unchar fepstopc; - unchar fepstartc; - unchar fepstopca; - unchar fepstartca; - unchar txwin; - unchar rxwin; - ushort fepiflag; - ushort fepcflag; - ushort fepoflag; - ushort txbufhead; - ushort txbufsize; - ushort rxbufhead; - ushort rxbufsize; + unsigned char boardnum; + unsigned char channelnum; + unsigned char omodem; /* FEP output modem status */ + unsigned char imodem; /* FEP input modem status */ + unsigned char modemfake; /* Modem values to be forced */ + unsigned char modem; /* Force values */ + unsigned char hflow; + unsigned char dsr; + unsigned char dcd; + unsigned char m_rts ; /* The bits used in whatever FEP */ + unsigned char m_dcd ; /* is indiginous to this board to */ + unsigned char m_dsr ; /* represent each of the physical */ + unsigned char m_cts ; /* handshake lines */ + unsigned char m_ri ; + unsigned char m_dtr ; + unsigned char stopc; + unsigned char startc; + unsigned char stopca; + unsigned char startca; + unsigned char fepstopc; + unsigned char fepstartc; + unsigned char fepstopca; + unsigned char fepstartca; + unsigned char txwin; + unsigned char rxwin; + unsigned short fepiflag; + unsigned short fepcflag; + unsigned short fepoflag; + unsigned short txbufhead; + unsigned short txbufsize; + unsigned short rxbufhead; + unsigned short rxbufsize; int close_delay; int count; int blocked_open; - ulong event; + unsigned long event; int asyncflags; uint dev; - ulong statusflags; - ulong c_iflag; - ulong c_cflag; - ulong c_lflag; - ulong c_oflag; - unchar *txptr; - unchar *rxptr; - unchar *tmp_buf; + unsigned long statusflags; + unsigned long c_iflag; + unsigned long c_cflag; + unsigned long c_lflag; + unsigned long c_oflag; + unsigned char *txptr; + unsigned char *rxptr; + unsigned char *tmp_buf; struct board_info *board; - volatile struct board_chan *brdchan; + struct board_chan *brdchan; struct digi_struct digiext; struct tty_struct *tty; wait_queue_head_t open_wait; wait_queue_head_t close_wait; - struct work_struct tqueue; - volatile struct global_data *mailbox; + struct work_struct tqueue; + struct global_data *mailbox; }; struct board_info { - unchar status; - unchar type; - unchar altpin; - ushort numports; - unchar *port; - unchar *membase; - unchar __iomem *re_map_port; - unchar *re_map_membase; - ulong memory_seg; + unsigned char status; + unsigned char type; + unsigned char altpin; + unsigned short numports; + unsigned long port; + unsigned long membase; + unsigned char __iomem *re_map_port; + unsigned char *re_map_membase; + unsigned long memory_seg; void ( * memwinon ) (struct board_info *, unsigned int) ; void ( * memwinoff ) (struct board_info *, unsigned int) ; void ( * globalwinon ) (struct channel *) ; @@ -160,6 +160,6 @@ struct board_info void ( * memoff ) (struct channel *) ; void ( * assertgwinon ) (struct channel *) ; void ( * assertmemoff ) (struct channel *) ; - unchar poller_inhibited ; + unsigned char poller_inhibited ; }; -- cgit v1.2.2 From edf83015fcbff8976b75b42b565a77e9d450c567 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 15:16:56 -0700 Subject: [PATCH] remove a dead extern in mem.c Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 850a78c9c4bc..f182752fe918 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -35,10 +35,6 @@ # include #endif -#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) -extern void tapechar_init(void); -#endif - /* * Architectures vary in how they handle caching for addresses * outside of main memory. -- cgit v1.2.2 From 573fc113133e0b0984d2c0090e706c6506661f91 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 15:16:58 -0700 Subject: [PATCH] move m68k rtc drivers over to initcalls this gets rid of the last two explicit initializations in misc.c Signed-off-by: Christoph Hellwig Acked-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/misc.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 931efd58f87a..0c8375165e29 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -63,8 +63,6 @@ static DECLARE_MUTEX(misc_sem); #define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; -extern int rtc_DP8570A_init(void); -extern int rtc_MK48T08_init(void); extern int pmu_device_init(void); #ifdef CONFIG_PROC_FS @@ -303,12 +301,7 @@ static int __init misc_init(void) misc_class = class_create(THIS_MODULE, "misc"); if (IS_ERR(misc_class)) return PTR_ERR(misc_class); -#ifdef CONFIG_MVME16x - rtc_MK48T08_init(); -#endif -#ifdef CONFIG_BVME6000 - rtc_DP8570A_init(); -#endif + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); -- cgit v1.2.2 From a10077708233becfbae7b0104e1e8c0569359aa7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 15:16:59 -0700 Subject: [PATCH] move 68360serial.c over use initcalls this is the last serial driver not using initcalls. Signed-off-by: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6e4be3bb2d89..9d657127f313 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -153,7 +153,6 @@ static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); -extern void rs_360_init(void); static void release_mem(struct tty_struct *tty, int idx); @@ -2910,11 +2909,6 @@ void __init console_init(void) */ #ifdef CONFIG_EARLY_PRINTK disable_early_printk(); -#endif -#ifdef CONFIG_SERIAL_68360 - /* This is not a console initcall. I know not what it's doing here. - So I haven't moved it. dwmw2 */ - rs_360_init(); #endif call = __con_initcall_start; while (call < __con_initcall_end) { -- cgit v1.2.2 From d2052c1676a39cae101a81f3da8a4ade8b668c88 Mon Sep 17 00:00:00 2001 From: Erik Waling Date: Tue, 6 Sep 2005 15:17:02 -0700 Subject: [PATCH] sonypi SPIC initialisation fix Newer Sony VAIO models (VGN-S480, VGN-S460, VGN-S3XP etc) use a new method to initialize the SPIC device. The new way to initialize (and disable) the device comes directly from the AML code in the _CRS, _SRS and _DIS methods from the DSDT table. This patch adds support for the new models. Signed-off-by: Erik Waling Signed-off-by: Stelian Pop Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sonypi.c | 117 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 20 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index cefbe985e55c..35cf1edbc179 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_DEVICE_MODEL_TYPE1 1 #define SONYPI_DEVICE_MODEL_TYPE2 2 +#define SONYPI_DEVICE_MODEL_TYPE3 3 /* type1 models use those */ #define SONYPI_IRQ_PORT 0x8034 #define SONYPI_IRQ_SHIFT 22 -#define SONYPI_BASE 0x50 -#define SONYPI_G10A (SONYPI_BASE+0x14) +#define SONYPI_TYPE1_BASE 0x50 +#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14) #define SONYPI_TYPE1_REGION_SIZE 0x08 #define SONYPI_TYPE1_EVTYPE_OFFSET 0x04 @@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_TYPE2_REGION_SIZE 0x20 #define SONYPI_TYPE2_EVTYPE_OFFSET 0x12 +/* type3 series specifics */ +#define SONYPI_TYPE3_BASE 0x40 +#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */ +#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */ +#define SONYPI_TYPE3_REGION_SIZE 0x20 +#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12 + /* battery / brightness addresses */ #define SONYPI_BAT_FLAGS 0x81 #define SONYPI_LCD_LIGHT 0x96 @@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_type2_ioport_list[] = { { 0x0, 0x0 } }; +/* same as in type 2 models */ +static struct sonypi_ioport_list *sonypi_type3_ioport_list = + sonypi_type2_ioport_list; + /* The set of possible interrupts */ struct sonypi_irq_list { u16 irq; @@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = { { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ }; +/* same as in type2 models */ +static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list; + #define SONYPI_CAMERA_BRIGHTNESS 0 #define SONYPI_CAMERA_CONTRAST 1 #define SONYPI_CAMERA_HUE 2 @@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = { #define SONYPI_MEYE_MASK 0x00000400 #define SONYPI_MEMORYSTICK_MASK 0x00000800 #define SONYPI_BATTERY_MASK 0x00001000 +#define SONYPI_WIRELESS_MASK 0x00002000 struct sonypi_event { u8 data; @@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev[] = { { 0, 0 } }; +/* The set of possible wireless events */ +static struct sonypi_event sonypi_wlessev[] = { + { 0x59, SONYPI_EVENT_WIRELESS_ON }, + { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, + { 0, 0 } +}; + /* The set of possible back button events */ static struct sonypi_event sonypi_backev[] = { { 0x20, SONYPI_EVENT_BACK_PRESSED }, @@ -391,6 +414,12 @@ static struct sonypi_eventtypes { { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0 } }; @@ -563,6 +592,23 @@ static void sonypi_type2_srs(void) udelay(10); } +static void sonypi_type3_srs(void) +{ + u16 v16; + u8 v8; + + /* This model type uses the same initialiazation of + * the embedded controller as the type2 models. */ + sonypi_type2_srs(); + + /* Initialization of PCI config space of the LPC interface bridge. */ + v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); + pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); + v8 = (v8 & 0xCF) | 0x10; + pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8); +} + /* Disables the device - this comes from the AML code in the ACPI bios */ static void sonypi_type1_dis(void) { @@ -587,6 +633,13 @@ static void sonypi_type2_dis(void) printk(KERN_WARNING "ec_write failed\n"); } +static void sonypi_type3_dis(void) +{ + sonypi_type2_dis(); + udelay(10); + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0); +} + static u8 sonypi_call1(u8 dev) { u8 v1, v2; @@ -1067,10 +1120,17 @@ static struct miscdevice sonypi_misc_device = { static void sonypi_enable(unsigned int camera_on) { - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_srs(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_srs(); + break; + } sonypi_call1(0x82); sonypi_call2(0x81, 0xff); @@ -1094,10 +1154,18 @@ static int sonypi_disable(void) if (!SONYPI_ACPI_ACTIVE && fnkeyinit) outb(0xf1, 0xb2); - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_dis(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_dis(); + break; + } + return 0; } @@ -1143,12 +1211,16 @@ static int __devinit sonypi_probe(void) struct sonypi_irq_list *irq_list; struct pci_dev *pcidev; - pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; sonypi_device.dev = pcidev; - sonypi_device.model = pcidev ? - SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2; spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, @@ -1176,16 +1248,22 @@ static int __devinit sonypi_probe(void) goto out_miscreg; } - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { + ioport_list = sonypi_type1_ioport_list; + sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; + irq_list = sonypi_type1_irq_list; + } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { ioport_list = sonypi_type2_ioport_list; sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; irq_list = sonypi_type2_irq_list; } else { - ioport_list = sonypi_type1_ioport_list; - sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; - irq_list = sonypi_type1_irq_list; + ioport_list = sonypi_type3_ioport_list; + sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; + irq_list = sonypi_type3_irq_list; } for (i = 0; ioport_list[i].port1; i++) { @@ -1274,11 +1352,10 @@ static int __devinit sonypi_probe(void) printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" "v%s.\n", SONYPI_DRIVER_VERSION); - printk(KERN_INFO "sonypi: detected %s model, " + printk(KERN_INFO "sonypi: detected type%d model, " "verbose = %d, fnkeyinit = %s, camera = %s, " "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", - (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ? - "type1" : "type2", + sonypi_device.model, verbose, fnkeyinit ? "on" : "off", camera ? "on" : "off", -- cgit v1.2.2 From 9f4a6dce10941380ad7365cc9b0ef038ed56cbf9 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Tue, 6 Sep 2005 15:17:03 -0700 Subject: [PATCH] sonypi: remove obsolete event Remove old obsolete event. Signed-off-by: Stelian Pop Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sonypi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 35cf1edbc179..36ae9ad2598c 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -406,7 +406,6 @@ static struct sonypi_eventtypes { { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, - { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, -- cgit v1.2.2 From 2d237c63659c098a662b1b09d43460f04c498436 Mon Sep 17 00:00:00 2001 From: Stephane Doyon Date: Tue, 6 Sep 2005 15:17:31 -0700 Subject: [PATCH] Console blanking locking fix I've had WARN_CONSOLE_UNLOCKED warnings when calling TIOCLINUX TIOCL_BLANKSCREEN and TIOCL_UNBLANKSCREEN. (I'm blind and I use a braille display. I use those functions to blank my laptop's screen so people don't read it, and hopefully to conserve power.) The warnings are from these places: do_blank_screen at drivers/char/vt.c:2754 (Not tainted) save_screen at drivers/char/vt.c:575 (Not tainted) do_unblank_screen at drivers/char/vt.c:2822 (Not tainted) set_palette at drivers/char/vt.c:2908 (Not tainted) At a glance I would think the following patch ought to fix that. Tested on one machine. Could you please tell me if this is correct and/or forward the patch where appropriate... Signed-off-by: Stephane Doyon Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 665103ccaee8..27b6c297906a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2272,7 +2272,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = paste_selection(tty); break; case TIOCL_UNBLANKSCREEN: + acquire_console_sem(); unblank_screen(); + release_console_sem(); break; case TIOCL_SELLOADLUT: ret = sel_loadlut(p); @@ -2317,8 +2319,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) } break; case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ + acquire_console_sem(); ignore_poke = 1; do_blank_screen(0); + release_console_sem(); break; case TIOCL_BLANKEDSCREEN: ret = console_blanked; -- cgit v1.2.2 From 414edcd32aa54bad8827e7c74cace168006c5fab Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Tue, 6 Sep 2005 15:17:52 -0700 Subject: [PATCH] vt: fix possible memory corruption in complement_pos Based on a patch from Andr Pereira de Almeida It might be possible for the saved pointer (*p) to become invalid in between vc_resizes, so saving the screen offset instead of the screen pointer is saner. This bug is very hard to trigger though, but Andre probably did, if he's submitting this patch. Anyway, with Andre's patch, it's still possible for the offsets to be still illegal, if the new screen size is smaller than the old one. So I've also added checks if the offsets are still within the screenbuffer size. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 27b6c297906a..b8d0c290b0db 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -434,21 +434,25 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) /* used by selection: complement pointer position */ void complement_pos(struct vc_data *vc, int offset) { - static unsigned short *p; + static int old_offset = -1; static unsigned short old; static unsigned short oldx, oldy; WARN_CONSOLE_UNLOCKED(); - if (p) { - scr_writew(old, p); + if (old_offset != -1 && old_offset >= 0 && + old_offset < vc->vc_screenbuf_size) { + scr_writew(old, screenpos(vc, old_offset, 1)); if (DO_UPDATE(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); } - if (offset == -1) - p = NULL; - else { + + old_offset = offset; + + if (offset != -1 && offset >= 0 && + offset < vc->vc_screenbuf_size) { unsigned short new; + unsigned short *p; p = screenpos(vc, offset, 1); old = scr_readw(p); new = old ^ vc->vc_complement_mask; @@ -459,6 +463,7 @@ void complement_pos(struct vc_data *vc, int offset) vc->vc_sw->con_putc(vc, new, oldy, oldx); } } + } static void insert_char(struct vc_data *vc, unsigned int nr) -- cgit v1.2.2 From 96803820b3d9830518083c02681fd3f72987ae4d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 6 Sep 2005 15:17:54 -0700 Subject: [PATCH] hpet: fix drift and url The HPET driver is using a parts per second drift factor instead of the standard parts per million drift the time interpolator code expects. This patch fixes that problem and updates the URL for the HPET spec. Signed-off-by: Alex Williamson Cc: "Robert W. Picco" Acked-by: "Pallipadi, Venkatesh" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hpet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 762fa430fb5b..a695f25e4497 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -44,7 +44,7 @@ /* * The High Precision Event Timer driver. * This driver is closely modelled after the rtc.c driver. - * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm + * http://www.intel.com/hardwaredesign/hpetspec.htm */ #define HPET_USER_FREQ (64) #define HPET_DRIFT (500) @@ -712,7 +712,7 @@ static void hpet_register_interpolator(struct hpets *hpetp) ti->shift = 10; ti->addr = &hpetp->hp_hpet->hpet_mc; ti->frequency = hpet_time_div(hpets->hp_period); - ti->drift = ti->frequency * HPET_DRIFT / 1000000; + ti->drift = HPET_DRIFT; ti->mask = -1; hpetp->hp_interpolator = ti; -- cgit v1.2.2 From 5ba4d46dc44c5399bc4e7a39239de5a1690848a4 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Hahn Date: Tue, 6 Sep 2005 15:17:56 -0700 Subject: [PATCH] tpm: fix tpm_atmel.c on ICH6 While installing Debian on our new IBM X41 Tablet, I tried briefly to use the built-in Atmel TPM. The Athmel TPM is also located on the LPC-bus of the ICH6. To make it work I had to apply the following patch: Signed-off-by: Philipp Matthias Hahn Acked-by: Kylene Jo Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_atmel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index cc2cc77fd174..c0d64914595f 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -206,6 +206,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, {0,} -- cgit v1.2.2 From 82ca76b6b160b6fce46f78c069f87fe1a4dc0778 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Tue, 6 Sep 2005 15:18:35 -0700 Subject: [PATCH] drivers: convert kcalloc to kzalloc This patch converts kcalloc(1, ...) calls to use the new kzalloc() function. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mbcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 115dbb35334b..3fa64c631108 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -750,7 +750,7 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) dev->soft = NULL; - soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL); + soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL); if (soft == NULL) return -ENOMEM; -- cgit v1.2.2 From b224cd3a0ca376dd52f382905c1aaf5a83a54692 Mon Sep 17 00:00:00 2001 From: Andrey Panin Date: Tue, 6 Sep 2005 15:18:37 -0700 Subject: [PATCH] IPMI: use dmi_find_device() This patch replaces homebrew DMI scanning code in IPMI System Interface driver with dmi_find_device() call. Signed-off-by: Andrey Panin Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 105 +++++++-------------------------------- 1 file changed, 17 insertions(+), 88 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a44b97304e95..51ce508b2f51 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -75,6 +75,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v) #include #include "ipmi_si_sm.h" #include +#include #define IPMI_SI_VERSION "v33" @@ -1610,22 +1611,15 @@ typedef struct dmi_ipmi_data static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS]; static int dmi_data_entries; -typedef struct dmi_header +static int __init decode_dmi(struct dmi_header *dm, int intf_num) { - u8 type; - u8 length; - u16 handle; -} dmi_header_t; - -static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) -{ - u8 __iomem *data = (u8 __iomem *)dm; + u8 *data = (u8 *)dm; unsigned long base_addr; u8 reg_spacing; - u8 len = readb(&dm->length); + u8 len = dm->length; dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - ipmi_data->type = readb(&data[4]); + ipmi_data->type = data[4]; memcpy(&base_addr, data+8, sizeof(unsigned long)); if (len >= 0x11) { @@ -1640,12 +1634,12 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) } /* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ - ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4); + ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); - ipmi_data->irq = readb(&data[0x11]); + ipmi_data->irq = data[0x11]; /* The top two bits of byte 0x10 hold the register spacing. */ - reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6; + reg_spacing = (data[0x10] & 0xC0) >> 6; switch(reg_spacing){ case 0x00: /* Byte boundaries */ ipmi_data->offset = 1; @@ -1673,7 +1667,7 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) ipmi_data->offset = 1; } - ipmi_data->slave_addr = readb(&data[6]); + ipmi_data->slave_addr = data[6]; if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) { dmi_data_entries++; @@ -1685,82 +1679,17 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) return -1; } -static int dmi_table(u32 base, int len, int num) -{ - u8 __iomem *buf; - struct dmi_header __iomem *dm; - u8 __iomem *data; - int i=1; - int status=-1; - int intf_num = 0; - - buf = ioremap(base, len); - if(buf==NULL) - return -1; - - data = buf; - - while(ilength)) >= len) - break; - - if (readb(&dm->type) == 38) { - if (decode_dmi(dm, intf_num) == 0) { - intf_num++; - if (intf_num >= SI_MAX_DRIVERS) - break; - } - } - - data+=readb(&dm->length); - while((data-buf) < len && (readb(data)||readb(data+1))) - data++; - data+=2; - i++; - } - iounmap(buf); - - return status; -} - -static inline int dmi_checksum(u8 *buf) -{ - u8 sum=0; - int a; - - for(a=0; a<15; a++) - sum+=buf[a]; - return (sum==0); -} - -static int dmi_decode(void) +static void __init dmi_find_bmc(void) { - u8 buf[15]; - u32 fp=0xF0000; - -#ifdef CONFIG_SIMNOW - return -1; -#endif + struct dmi_device *dev = NULL; + int intf_num = 0; - while(fp < 0xFFFFF) - { - isa_memcpy_fromio(buf, fp, 15); - if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) - { - u16 num=buf[13]<<8|buf[12]; - u16 len=buf[7]<<8|buf[6]; - u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; + while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { + if (intf_num >= SI_MAX_DRIVERS) + break; - if(dmi_table(base, len, num) == 0) - return 0; - } - fp+=16; + decode_dmi((struct dmi_header *) dev->device_data, intf_num++); } - - return -1; } static int try_init_smbios(int intf_num, struct smi_info **new_info) @@ -2293,7 +2222,7 @@ static __init int init_ipmi_si(void) printk("\n"); #ifdef CONFIG_X86 - dmi_decode(); + dmi_find_bmc(); #endif rv = init_one_smi(0, &(smi_infos[pos])); -- cgit v1.2.2 From c14979b993021377228958498937bcdd9539cbce Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:38 -0700 Subject: [PATCH] ipmi: add per-channel IPMB addresses IPMI allows multiple IPMB channels on a single interface, and each channel might have a different IPMB address. However, the driver has only one IPMB address that it uses for everything. This patch adds new IOCTLS and a new internal interface for setting per-channel IPMB addresses and LUNs. New systems are coming out with support for multiple IPMB channels, and they are broken without this patch. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_devintf.c | 94 ++++++++++++++++++++++--- drivers/char/ipmi/ipmi_msghandler.c | 137 +++++++++++++++++++++++++----------- 2 files changed, 178 insertions(+), 53 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index e0a53570fea1..5571e92c520f 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -411,6 +411,7 @@ static int ipmi_ioctl(struct inode *inode, break; } + /* The next four are legacy, not per-channel. */ case IPMICTL_SET_MY_ADDRESS_CMD: { unsigned int val; @@ -420,22 +421,25 @@ static int ipmi_ioctl(struct inode *inode, break; } - ipmi_set_my_address(priv->user, val); - rv = 0; + rv = ipmi_set_my_address(priv->user, 0, val); break; } case IPMICTL_GET_MY_ADDRESS_CMD: { - unsigned int val; + unsigned int val; + unsigned char rval; + + rv = ipmi_get_my_address(priv->user, 0, &rval); + if (rv) + break; - val = ipmi_get_my_address(priv->user); + val = rval; if (copy_to_user(arg, &val, sizeof(val))) { rv = -EFAULT; break; } - rv = 0; break; } @@ -448,24 +452,94 @@ static int ipmi_ioctl(struct inode *inode, break; } - ipmi_set_my_LUN(priv->user, val); - rv = 0; + rv = ipmi_set_my_LUN(priv->user, 0, val); break; } case IPMICTL_GET_MY_LUN_CMD: { - unsigned int val; + unsigned int val; + unsigned char rval; + + rv = ipmi_get_my_LUN(priv->user, 0, &rval); + if (rv) + break; - val = ipmi_get_my_LUN(priv->user); + val = rval; if (copy_to_user(arg, &val, sizeof(val))) { rv = -EFAULT; break; } - rv = 0; break; } + + case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + return ipmi_set_my_address(priv->user, val.channel, val.value); + break; + } + + case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_get_my_address(priv->user, val.channel, &val.value); + if (rv) + break; + + if (copy_to_user(arg, &val, sizeof(val))) { + rv = -EFAULT; + break; + } + break; + } + + case IPMICTL_SET_MY_CHANNEL_LUN_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_set_my_LUN(priv->user, val.channel, val.value); + break; + } + + case IPMICTL_GET_MY_CHANNEL_LUN_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value); + if (rv) + break; + + if (copy_to_user(arg, &val, sizeof(val))) { + rv = -EFAULT; + break; + } + break; + } + case IPMICTL_SET_TIMING_PARMS_CMD: { struct ipmi_timing_parms parms; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e16c13fe698d..84d477c6f925 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -124,6 +124,14 @@ struct ipmi_channel { unsigned char medium; unsigned char protocol; + + /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, + but may be changed by the user. */ + unsigned char address; + + /* My LUN. This should generally stay the SMS LUN, but just in + case... */ + unsigned char lun; }; #ifdef CONFIG_PROC_FS @@ -135,7 +143,7 @@ struct ipmi_proc_entry #endif #define IPMI_IPMB_NUM_SEQ 64 -#define IPMI_MAX_CHANNELS 8 +#define IPMI_MAX_CHANNELS 16 struct ipmi_smi { /* What interface number are we? */ @@ -199,14 +207,6 @@ struct ipmi_smi this is registered. */ ipmi_user_t all_cmd_rcvr; - /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, - but may be changed by the user. */ - unsigned char my_address; - - /* My LUN. This should generally stay the SMS LUN, but just in - case... */ - unsigned char my_lun; - /* The event receiver for my BMC, only really used at panic shutdown as a place to store this. */ unsigned char event_receiver; @@ -766,26 +766,44 @@ void ipmi_get_version(ipmi_user_t user, *minor = user->intf->version_minor; } -void ipmi_set_my_address(ipmi_user_t user, - unsigned char address) +int ipmi_set_my_address(ipmi_user_t user, + unsigned int channel, + unsigned char address) { - user->intf->my_address = address; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + user->intf->channels[channel].address = address; + return 0; } -unsigned char ipmi_get_my_address(ipmi_user_t user) +int ipmi_get_my_address(ipmi_user_t user, + unsigned int channel, + unsigned char *address) { - return user->intf->my_address; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *address = user->intf->channels[channel].address; + return 0; } -void ipmi_set_my_LUN(ipmi_user_t user, - unsigned char LUN) +int ipmi_set_my_LUN(ipmi_user_t user, + unsigned int channel, + unsigned char LUN) { - user->intf->my_lun = LUN & 0x3; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + user->intf->channels[channel].lun = LUN & 0x3; + return 0; } -unsigned char ipmi_get_my_LUN(ipmi_user_t user) +int ipmi_get_my_LUN(ipmi_user_t user, + unsigned int channel, + unsigned char *address) { - return user->intf->my_lun; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *address = user->intf->channels[channel].lun; + return 0; } int ipmi_set_gets_events(ipmi_user_t user, int val) @@ -1213,7 +1231,7 @@ static inline int i_ipmi_request(ipmi_user_t user, unsigned char ipmb_seq; long seqid; - if (addr->channel > IPMI_NUM_CHANNELS) { + if (addr->channel >= IPMI_NUM_CHANNELS) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); @@ -1346,6 +1364,18 @@ static inline int i_ipmi_request(ipmi_user_t user, return rv; } +static int check_addr(ipmi_smi_t intf, + struct ipmi_addr *addr, + unsigned char *saddr, + unsigned char *lun) +{ + if (addr->channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *lun = intf->channels[addr->channel].lun; + *saddr = intf->channels[addr->channel].address; + return 0; +} + int ipmi_request_settime(ipmi_user_t user, struct ipmi_addr *addr, long msgid, @@ -1355,6 +1385,12 @@ int ipmi_request_settime(ipmi_user_t user, int retries, unsigned int retry_time_ms) { + unsigned char saddr, lun; + int rv; + + rv = check_addr(user->intf, addr, &saddr, &lun); + if (rv) + return rv; return i_ipmi_request(user, user->intf, addr, @@ -1363,8 +1399,8 @@ int ipmi_request_settime(ipmi_user_t user, user_msg_data, NULL, NULL, priority, - user->intf->my_address, - user->intf->my_lun, + saddr, + lun, retries, retry_time_ms); } @@ -1378,6 +1414,12 @@ int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_recv_msg *supplied_recv, int priority) { + unsigned char saddr, lun; + int rv; + + rv = check_addr(user->intf, addr, &saddr, &lun); + if (rv) + return rv; return i_ipmi_request(user, user->intf, addr, @@ -1387,8 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user, supplied_smi, supplied_recv, priority, - user->intf->my_address, - user->intf->my_lun, + saddr, + lun, -1, 0); } @@ -1397,8 +1439,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off, { char *out = (char *) page; ipmi_smi_t intf = data; + int i; + int rv= 0; - return sprintf(out, "%x\n", intf->my_address); + for (i=0; ichannels[i].address); + out[rv-1] = '\n'; /* Replace the final space with a newline */ + out[rv] = '\0'; + rv++; + return rv; } static int version_file_read_proc(char *page, char **start, off_t off, @@ -1592,8 +1641,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) NULL, NULL, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, -1, 0); } @@ -1696,11 +1745,13 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, new_intf->intf_num = i; new_intf->version_major = version_major; new_intf->version_minor = version_minor; - if (slave_addr == 0) - new_intf->my_address = IPMI_BMC_SLAVE_ADDR; - else - new_intf->my_address = slave_addr; - new_intf->my_lun = 2; /* the SMS LUN. */ + for (j=0; jchannels[j].address + = IPMI_BMC_SLAVE_ADDR; + new_intf->channels[j].lun = 2; + } + if (slave_addr != 0) + new_intf->channels[0].address = slave_addr; rwlock_init(&(new_intf->users_lock)); INIT_LIST_HEAD(&(new_intf->users)); new_intf->handlers = handlers; @@ -1985,7 +2036,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, msg->data[3] = msg->rsp[6]; msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); - msg->data[6] = intf->my_address; + msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; /* rqseq/lun */ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ @@ -2919,8 +2970,8 @@ static void send_panic_events(char *str) &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* Don't retry, and don't wait. */ } @@ -2965,8 +3016,8 @@ static void send_panic_events(char *str) &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* Don't retry, and don't wait. */ if (intf->local_event_generator) { @@ -2985,8 +3036,8 @@ static void send_panic_events(char *str) &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } intf->null_user_handler = NULL; @@ -2996,7 +3047,7 @@ static void send_panic_events(char *str) be zero, and it must not be my address. */ if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->my_address)) + && (intf->event_receiver != intf->channels[0].address)) { /* The event receiver is valid, send an IPMB message. */ @@ -3031,7 +3082,7 @@ static void send_panic_events(char *str) data[0] = 0; data[1] = 0; data[2] = 0xf0; /* OEM event without timestamp. */ - data[3] = intf->my_address; + data[3] = intf->channels[0].address; data[4] = j++; /* sequence # */ /* Always give 11 bytes, so strncpy will fill it with zeroes for me. */ @@ -3047,8 +3098,8 @@ static void send_panic_events(char *str) &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } } -- cgit v1.2.2 From 75b0768a396f2a25901b7b1edc87b95cdb3af4ef Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:38 -0700 Subject: [PATCH] ipmi: high-res timer support fixes Fix some problems with the high-res timer support. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 51ce508b2f51..60f2f968b689 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -61,11 +61,11 @@ # endif static inline void add_usec_to_timer(struct timer_list *t, long v) { - t->sub_expires += nsec_to_arch_cycle(v * 1000); - while (t->sub_expires >= arch_cycles_per_jiffy) + t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000); + while (t->arch_cycle_expires >= arch_cycles_per_jiffy) { t->expires++; - t->sub_expires -= arch_cycles_per_jiffy; + t->arch_cycle_expires -= arch_cycles_per_jiffy; } } #endif @@ -762,18 +762,20 @@ static void si_restart_short_timer(struct smi_info *smi_info) #if defined(CONFIG_HIGH_RES_TIMERS) unsigned long flags; unsigned long jiffies_now; + unsigned long seq; if (del_timer(&(smi_info->si_timer))) { /* If we don't delete the timer, then it will go off immediately, anyway. So we only process if we actually delete the timer. */ - /* We already have irqsave on, so no need for it - here. */ - read_lock(&xtime_lock); - jiffies_now = jiffies; - smi_info->si_timer.expires = jiffies_now; - smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now); + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + jiffies_now = jiffies; + smi_info->si_timer.expires = jiffies_now; + smi_info->si_timer.arch_cycle_expires + = get_arch_cycles(jiffies_now); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC); @@ -827,15 +829,19 @@ static void smi_timeout(unsigned long data) /* If the state machine asks for a short delay, then shorten the timer timeout. */ if (smi_result == SI_SM_CALL_WITH_DELAY) { +#if defined(CONFIG_HIGH_RES_TIMERS) + unsigned long seq; +#endif spin_lock_irqsave(&smi_info->count_lock, flags); smi_info->short_timeouts++; spin_unlock_irqrestore(&smi_info->count_lock, flags); #if defined(CONFIG_HIGH_RES_TIMERS) - read_lock(&xtime_lock); - smi_info->si_timer.expires = jiffies; - smi_info->si_timer.sub_expires - = get_arch_cycles(smi_info->si_timer.expires); - read_unlock(&xtime_lock); + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + smi_info->si_timer.expires = jiffies; + smi_info->si_timer.arch_cycle_expires + = get_arch_cycles(smi_info->si_timer.expires); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC); #else smi_info->si_timer.expires = jiffies + 1; @@ -846,7 +852,7 @@ static void smi_timeout(unsigned long data) spin_unlock_irqrestore(&smi_info->count_lock, flags); smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; #if defined(CONFIG_HIGH_RES_TIMERS) - smi_info->si_timer.sub_expires = 0; + smi_info->si_timer.arch_cycle_expires = 0; #endif } -- cgit v1.2.2 From 8f05ee9a63b414da4fd036a9dab2d27727301188 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:39 -0700 Subject: [PATCH] ipmi: watchdog/NMI interaction fixes There are some interactions between IPMI NMI timeouts and the other operations of the IPMI driver. This make sure those interactions are handled properly. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_watchdog.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index d35a953961cb..82d564342084 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -259,7 +259,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, data[1] = 0; WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state); - if (pretimeout > 0) { + if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) { WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val); data[2] = pretimeout; } else { @@ -817,15 +817,19 @@ static void ipmi_register_watchdog(int ipmi_intf) static int ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) { + /* If we are not expecting a timeout, ignore it. */ + if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) + return NOTIFY_DONE; + /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ - if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) + if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { + /* On some machines, the heartbeat will give + an error and not work unless we re-enable + the timer. So do so. */ + pretimeout_since_last_heartbeat = 1; panic(PFX "pre-timeout"); - - /* On some machines, the heartbeat will give - an error and not work unless we re-enable - the timer. So do so. */ - pretimeout_since_last_heartbeat = 1; + } return NOTIFY_DONE; } -- cgit v1.2.2 From 3ae0e0f9b15b95a2c3e64088d2a85e3f4a707681 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:41 -0700 Subject: [PATCH] ipmi: OEM flag handling and hacks for some Dell machines The ipmi driver does not have a way to handle firmware-generated events which have the OEM[012] Data Available flags set. In such a case, the SMS_ATN bit may never get cleared by firmware, leaving the driver looping infinitely but never able to make any progress. This patch first simplifies storage and use of the data returned from an IPMI Get Device ID command. It then creates a new per-OEM handler hook, which should know how to handle events with the OEM[012] Data Available flags set. It then uses this to implement a workaround for IPMI 1.5-capable Dell PowerEdge servers which are susceptable to setting the OEM[012] Data Available flags when the driver can't handle it. Signed-off-by: Matt Domsch Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 117 +++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 12 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 60f2f968b689..4fb36d4142fb 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -110,6 +110,21 @@ enum si_type { SI_KCS, SI_SMIC, SI_BT }; +struct ipmi_device_id { + unsigned char device_id; + unsigned char device_revision; + unsigned char firmware_revision_1; + unsigned char firmware_revision_2; + unsigned char ipmi_version; + unsigned char additional_device_support; + unsigned char manufacturer_id[3]; + unsigned char product_id[2]; + unsigned char aux_firmware_revision[4]; +} __attribute__((packed)); + +#define ipmi_version_major(v) ((v)->ipmi_version & 0xf) +#define ipmi_version_minor(v) ((v)->ipmi_version >> 4) + struct smi_info { ipmi_smi_t intf; @@ -132,12 +147,24 @@ struct smi_info void (*irq_cleanup)(struct smi_info *info); unsigned int io_size; + /* Per-OEM handler, called from handle_flags(). + Returns 1 when handle_flags() needs to be re-run + or 0 indicating it set si_state itself. + */ + int (*oem_data_avail_handler)(struct smi_info *smi_info); + /* Flags from the last GET_MSG_FLAGS command, used when an ATTN is set to hold the flags until we are done handling everything from the flags. */ #define RECEIVE_MSG_AVAIL 0x01 #define EVENT_MSG_BUFFER_FULL 0x02 #define WDT_PRE_TIMEOUT_INT 0x08 +#define OEM0_DATA_AVAIL 0x20 +#define OEM1_DATA_AVAIL 0x40 +#define OEM2_DATA_AVAIL 0x80 +#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \ + OEM1_DATA_AVAIL | \ + OEM2_DATA_AVAIL) unsigned char msg_flags; /* If set to true, this will request events the next time the @@ -176,11 +203,7 @@ struct smi_info interrupts. */ int interrupt_disabled; - unsigned char ipmi_si_dev_rev; - unsigned char ipmi_si_fw_rev_major; - unsigned char ipmi_si_fw_rev_minor; - unsigned char ipmi_version_major; - unsigned char ipmi_version_minor; + struct ipmi_device_id device_id; /* Slave address, could be reported from DMI. */ unsigned char slave_addr; @@ -323,6 +346,7 @@ static inline void enable_si_irq(struct smi_info *smi_info) static void handle_flags(struct smi_info *smi_info) { + retry: if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { /* Watchdog pre-timeout */ spin_lock(&smi_info->count_lock); @@ -372,6 +396,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 { smi_info->si_state = SI_NORMAL; } @@ -1927,11 +1955,8 @@ static int try_get_dev_id(struct smi_info *smi_info) } /* Record info from the get device id, in case we need it. */ - smi_info->ipmi_si_dev_rev = resp[4] & 0xf; - smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f; - smi_info->ipmi_si_fw_rev_minor = resp[6]; - smi_info->ipmi_version_major = resp[7] & 0xf; - smi_info->ipmi_version_minor = resp[7] >> 4; + memcpy(&smi_info->device_id, &resp[3], + min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id))); out: kfree(resp); @@ -1992,6 +2017,72 @@ static int stat_file_read_proc(char *page, char **start, off_t off, return (out - ((char *) page)); } +/* + * oem_data_avail_to_receive_msg_avail + * @info - smi_info structure with msg_flags set + * + * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL + * Returns 1 indicating need to re-run handle_flags(). + */ +static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) +{ + smi_info->msg_flags = (smi_info->msg_flags & ~OEM_DATA_AVAIL) | + RECEIVE_MSG_AVAIL; + return 1; +} + +/* + * setup_dell_poweredge_oem_data_handler + * @info - smi_info.device_id must be populated + * + * Systems that match, but have firmware version < 1.40 may assert + * OEM0_DATA_AVAIL on their own, without being told via Set Flags that + * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL + * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags + * as RECEIVE_MSG_AVAIL instead. + * + * As Dell has no plans to release IPMI 1.5 firmware that *ever* + * assert the OEM[012] bits, and if it did, the driver would have to + * change to handle that properly, we don't actually check for the + * firmware version. + * Device ID = 0x20 BMC on PowerEdge 8G servers + * Device Revision = 0x80 + * Firmware Revision1 = 0x01 BMC version 1.40 + * Firmware Revision2 = 0x40 BCD encoded + * IPMI Version = 0x51 IPMI 1.5 + * Manufacturer ID = A2 02 00 Dell IANA + * + */ +#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20 +#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80 +#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51 +#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} +static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) +{ + struct ipmi_device_id *id = &smi_info->device_id; + const char mfr[3]=DELL_IANA_MFR_ID; + if (!memcmp(mfr, id->manufacturer_id, sizeof(mfr)) && + id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID && + id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV && + id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { + smi_info->oem_data_avail_handler = + oem_data_avail_to_receive_msg_avail; + } +} + +/* + * setup_oem_data_handler + * @info - smi_info.device_id must be filled in already + * + * Fills in smi_info.device_id.oem_data_available_handler + * when we know what function to use there. + */ + +static void setup_oem_data_handler(struct smi_info *smi_info) +{ + setup_dell_poweredge_oem_data_handler(smi_info); +} + /* Returns 0 if initialized, or negative on an error. */ static int init_one_smi(int intf_num, struct smi_info **smi) { @@ -2090,6 +2181,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) if (rv) goto out_err; + setup_oem_data_handler(new_smi); + /* Try to claim any interrupts. */ new_smi->irq_setup(new_smi); @@ -2123,8 +2216,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) rv = ipmi_register_smi(&handlers, new_smi, - new_smi->ipmi_version_major, - new_smi->ipmi_version_minor, + ipmi_version_major(&new_smi->device_id), + ipmi_version_minor(&new_smi->device_id), new_smi->slave_addr, &(new_smi->intf)); if (rv) { -- cgit v1.2.2 From 1fdd75bd6cfa60a54b6db91d9256a711ab52fef3 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:42 -0700 Subject: [PATCH] ipmi: clean up versioning of the IPMI driver This adds MODULE_VERSION, MODULE_DESCRIPTION, and MODULE_AUTHOR tags to the IPMI driver modules. Also changes the MODULE_VERSION to remove the prepended 'v' on each value, consistent with the module versioning policy. This patch also removes all the version information from everything except the ipmi_msghandler module. Signed-off-by: Matt Domsch Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_bt_sm.c | 3 --- drivers/char/ipmi/ipmi_devintf.c | 7 +++---- drivers/char/ipmi/ipmi_kcs_sm.c | 3 --- drivers/char/ipmi/ipmi_msghandler.c | 8 ++++++-- drivers/char/ipmi/ipmi_poweroff.c | 6 +++--- drivers/char/ipmi/ipmi_si_intf.c | 14 +++----------- drivers/char/ipmi/ipmi_smic_sm.c | 3 --- drivers/char/ipmi/ipmi_watchdog.c | 9 ++++----- 8 files changed, 19 insertions(+), 34 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 5ce9c6269033..64c9afa50c13 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -31,8 +31,6 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_BT_VERSION "v33" - static int bt_debug = 0x00; /* Production value 0, see following flags */ #define BT_DEBUG_ENABLE 1 @@ -501,7 +499,6 @@ static int bt_size(void) struct si_sm_handlers bt_smi_handlers = { - .version = IPMI_BT_VERSION, .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 5571e92c520f..883ac4352be4 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -47,8 +47,6 @@ #include #include -#define IPMI_DEVINTF_VERSION "v33" - struct ipmi_file_private { ipmi_user_t user; @@ -822,8 +820,7 @@ static __init int init_ipmi_devintf(void) if (ipmi_major < 0) return -EINVAL; - printk(KERN_INFO "ipmi device interface version " - IPMI_DEVINTF_VERSION "\n"); + printk(KERN_INFO "ipmi device interface\n"); ipmi_class = class_create(THIS_MODULE, "ipmi"); if (IS_ERR(ipmi_class)) { @@ -866,3 +863,5 @@ static __exit void cleanup_ipmi(void) module_exit(cleanup_ipmi); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard "); +MODULE_DESCRIPTION("Linux device interface for the IPMI message handler."); diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 48cce24329be..d21853a594a3 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -42,8 +42,6 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_KCS_VERSION "v33" - /* Set this if you want a printout of why the state machine was hosed when it gets hosed. */ #define DEBUG_HOSED_REASON @@ -489,7 +487,6 @@ static void kcs_cleanup(struct si_sm_data *kcs) struct si_sm_handlers kcs_smi_handlers = { - .version = IPMI_KCS_VERSION, .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 84d477c6f925..05293d0e6692 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,7 +47,8 @@ #include #define PFX "IPMI message handler: " -#define IPMI_MSGHANDLER_VERSION "v33" + +#define IPMI_DRIVER_VERSION "36.0" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -3150,7 +3151,7 @@ static int ipmi_init_msghandler(void) return 0; printk(KERN_INFO "ipmi message handler version " - IPMI_MSGHANDLER_VERSION "\n"); + IPMI_DRIVER_VERSION "\n"); for (i=0; i"); +MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); +MODULE_VERSION(IPMI_DRIVER_VERSION); EXPORT_SYMBOL(ipmi_create_user); EXPORT_SYMBOL(ipmi_destroy_user); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index f951c30236c9..1583329ac2ec 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -42,7 +42,6 @@ #include #define PFX "IPMI poweroff: " -#define IPMI_POWEROFF_VERSION "v33" /* Where to we insert our poweroff function? */ extern void (*pm_power_off)(void); @@ -582,8 +581,7 @@ static int ipmi_poweroff_init (void) struct proc_dir_entry *file; printk ("Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot version " - IPMI_POWEROFF_VERSION ".\n"); + " IPMI Powerdown via sys_reboot.\n"); switch (poweroff_control) { case IPMI_CHASSIS_POWER_CYCLE: @@ -642,3 +640,5 @@ module_exit(ipmi_poweroff_cleanup); module_init(ipmi_poweroff_init); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard "); +MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4fb36d4142fb..b43172aee4c6 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -77,8 +77,6 @@ static inline void add_usec_to_timer(struct timer_list *t, long v) #include #include -#define IPMI_SI_VERSION "v33" - /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -2310,15 +2308,7 @@ static __init int init_ipmi_si(void) } } - printk(KERN_INFO "IPMI System Interface driver version " - IPMI_SI_VERSION); - if (kcs_smi_handlers.version) - printk(", KCS version %s", kcs_smi_handlers.version); - if (smic_smi_handlers.version) - printk(", SMIC version %s", smic_smi_handlers.version); - if (bt_smi_handlers.version) - printk(", BT version %s", bt_smi_handlers.version); - printk("\n"); + printk(KERN_INFO "IPMI System Interface driver.\n"); #ifdef CONFIG_X86 dmi_find_bmc(); @@ -2430,3 +2420,5 @@ static __exit void cleanup_ipmi_si(void) module_exit(cleanup_ipmi_si); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard "); +MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces."); diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index ae18747e670b..add2aa2732f0 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -46,8 +46,6 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_SMIC_VERSION "v33" - /* smic_debug is a bit-field * SMIC_DEBUG_ENABLE - turned on for now * SMIC_DEBUG_MSG - commands and their responses @@ -588,7 +586,6 @@ static int smic_size(void) struct si_sm_handlers smic_smi_handlers = { - .version = IPMI_SMIC_VERSION, .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 82d564342084..77ece1f218cd 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -53,8 +53,6 @@ #define PFX "IPMI Watchdog: " -#define IPMI_WATCHDOG_VERSION "v33" - /* * The IPMI command/response information for the watchdog timer. */ @@ -928,9 +926,6 @@ static int __init ipmi_wdog_init(void) { int rv; - printk(KERN_INFO PFX "driver version " - IPMI_WATCHDOG_VERSION "\n"); - if (strcmp(action, "reset") == 0) { action_val = WDOG_TIMEOUT_RESET; } else if (strcmp(action, "none") == 0) { @@ -1015,6 +1010,8 @@ static int __init ipmi_wdog_init(void) register_reboot_notifier(&wdog_reboot_notifier); notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); + printk(KERN_INFO PFX "driver initialized\n"); + return 0; } @@ -1066,3 +1063,5 @@ static void __exit ipmi_wdog_exit(void) module_exit(ipmi_wdog_exit); module_init(ipmi_wdog_init); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard "); +MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface."); -- cgit v1.2.2 From 56a55ec64806fb56e0cd43b0f726020b74c6689b Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:42 -0700 Subject: [PATCH] ipmi: fix panic ipmb response The "null message handler" in the IPMI driver is used in startup and panic situations to handle messages. It was only designed to work with messages from the local management controller, but in some cases it was used to get messages from remote managmenet controllers, and the system would then panic. This patch makes the "null message handler" in the IPMI driver more general so it works with any kind of message. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 107 ++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 40 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 05293d0e6692..d0ed25278cbb 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -219,7 +219,7 @@ struct ipmi_smi interface comes in with a NULL user, call this routine with it. Note that the message will still be freed by the caller. This only works on the system interface. */ - void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg); + void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); /* When we are scanning the channels for an SMI, this will tell which channel we are scanning. */ @@ -459,7 +459,27 @@ unsigned int ipmi_addr_length(int addr_type) static void deliver_response(struct ipmi_recv_msg *msg) { - msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data); + if (! msg->user) { + ipmi_smi_t intf = msg->user_msg_data; + unsigned long flags; + + /* Special handling for NULL users. */ + if (intf->null_user_handler) { + intf->null_user_handler(intf, msg); + spin_lock_irqsave(&intf->counter_lock, flags); + intf->handled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); + } else { + /* No handler, so give up. */ + spin_lock_irqsave(&intf->counter_lock, flags); + intf->unhandled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); + } + ipmi_free_recv_msg(msg); + } else { + msg->user->handler->ipmi_recv_hndl(msg, + msg->user->handler_data); + } } /* Find the next sequence number not being used and add the given @@ -1389,6 +1409,8 @@ int ipmi_request_settime(ipmi_user_t user, unsigned char saddr, lun; int rv; + if (! user) + return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) return rv; @@ -1418,6 +1440,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user, unsigned char saddr, lun; int rv; + if (! user) + return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) return rv; @@ -1638,7 +1662,7 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) (struct ipmi_addr *) &si, 0, &msg, - NULL, + intf, NULL, NULL, 0, @@ -1648,19 +1672,20 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) } static void -channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { int rv = 0; int chan; - if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) + && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ - if (msg->rsp[2] != 0) { + if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ - if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) { + if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { /* If the MC does not support this command, that is legal. We just assume it has one IPMB at channel @@ -1677,13 +1702,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) } goto next_channel; } - if (msg->rsp_size < 6) { + if (msg->msg.data_len < 4) { /* Message not big enough, just go on. */ goto next_channel; } chan = intf->curr_channel; - intf->channels[chan].medium = msg->rsp[4] & 0x7f; - intf->channels[chan].protocol = msg->rsp[5] & 0x1f; + intf->channels[chan].medium = msg->msg.data[2] & 0x7f; + intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; next_channel: intf->curr_channel++; @@ -2382,6 +2407,14 @@ static int handle_bmc_rsp(ipmi_smi_t intf, unsigned long flags; recv_msg = (struct ipmi_recv_msg *) msg->user_data; + if (recv_msg == NULL) + { + printk(KERN_WARNING"IPMI message received with no owner. This\n" + "could be because of a malformed message, or\n" + "because of a hardware error. Contact your\n" + "hardware vender for assistance\n"); + return 0; + } /* Make sure the user still exists. */ list_for_each_entry(user, &(intf->users), link) { @@ -2392,19 +2425,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf, } } - if (!found) { - /* Special handling for NULL users. */ - if (!recv_msg->user && intf->null_user_handler){ - intf->null_user_handler(intf, msg); - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); - }else{ - /* The user for the message went away, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); - } + if ((! found) && recv_msg->user) { + /* The user for the message went away, so give up. */ + spin_lock_irqsave(&intf->counter_lock, flags); + intf->unhandled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); ipmi_free_recv_msg(recv_msg); } else { struct ipmi_system_interface_addr *smi_addr; @@ -2890,28 +2915,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) } #ifdef CONFIG_IPMI_PANIC_STRING -static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { - if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD) - && (msg->rsp[2] == IPMI_CC_NO_ERROR)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) + && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ - intf->event_receiver = msg->rsp[3]; - intf->event_receiver_lun = msg->rsp[4] & 0x3; + intf->event_receiver = msg->msg.data[1]; + intf->event_receiver_lun = msg->msg.data[2] & 0x3; } } -static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { - if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD) - && (msg->rsp[2] == IPMI_CC_NO_ERROR)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) + && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get device id command, save if we are an event receiver or generator. */ - intf->local_sel_device = (msg->rsp[8] >> 2) & 1; - intf->local_event_generator = (msg->rsp[8] >> 5) & 1; + intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; + intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } } #endif @@ -2967,7 +2994,7 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, @@ -3013,7 +3040,7 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, @@ -3033,7 +3060,7 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, @@ -3095,7 +3122,7 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, -- cgit v1.2.2 From 168524d673f99550d75af49eb3f5d2850420eb66 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:43 -0700 Subject: [PATCH] ipmi: add hacks for IPMI chassis poweroff for certain Dell servers This patch allows Dell servers with IPMI controllers that predate IPMI 1.5 to use the standard poweroff or powercycle commands. These systems firmware don't set the chassis capability bit in the Get Device ID, but they do implement the standard poweroff and powercycle commands. Tested on RHEL3 kernel 2.4.21-20.ELsmp on a PowerEdge 2600. The standard ipmi_poweroff driver cannot drive these systems. With this patch, they power off or powercycle as expected. Signed-off-by: Matt Domsch Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_poweroff.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 1583329ac2ec..170590153df6 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -62,6 +62,7 @@ MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of p static unsigned int mfg_id; static unsigned int prod_id; static unsigned char capabilities; +static unsigned char ipmi_version; /* We use our own messages for this operation, we don't let the system allocate them, since we may be in a panic situation. The whole @@ -336,6 +337,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) return; } +/* + * ipmi_dell_chassis_detect() + * Dell systems with IPMI < 1.5 don't set the chassis capability bit + * but they can handle a chassis poweroff or powercycle command. + */ + +#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} +static int ipmi_dell_chassis_detect (ipmi_user_t user) +{ + const char ipmi_version_major = ipmi_version & 0xF; + const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; + const char mfr[3]=DELL_IANA_MFR_ID; + if (!memcmp(mfr, &mfg_id, sizeof(mfr)) && + ipmi_version_major <= 1 && + ipmi_version_minor < 5) + return 1; + return 0; +} + /* * Standard chassis support */ @@ -413,6 +433,9 @@ static struct poweroff_function poweroff_functions[] = { { .platform_type = "CPI1", .detect = ipmi_cpi1_detect, .poweroff_func = ipmi_poweroff_cpi1 }, + { .platform_type = "chassis", + .detect = ipmi_dell_chassis_detect, + .poweroff_func = ipmi_poweroff_chassis }, /* Chassis should generally be last, other things should override it. */ { .platform_type = "chassis", @@ -498,6 +521,7 @@ static void ipmi_po_new_smi(int if_num) prod_id = (halt_recv_msg.msg.data[10] | (halt_recv_msg.msg.data[11] << 8)); capabilities = halt_recv_msg.msg.data[6]; + ipmi_version = halt_recv_msg.msg.data[5]; /* Scan for a poweroff method */ -- cgit v1.2.2 From e8b336173b86c5db5dd5ae5ad33f3f8605878d0d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:45 -0700 Subject: [PATCH] ipmi: style cleanups Clean up various style issues in the IPMI driver. Should be no functional changes. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_bt_sm.c | 66 +++++++++++------ drivers/char/ipmi/ipmi_msghandler.c | 46 ++++++------ drivers/char/ipmi/ipmi_poweroff.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 141 ++++++++++++++++++------------------ drivers/char/ipmi/ipmi_watchdog.c | 19 +++-- 5 files changed, 146 insertions(+), 128 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 64c9afa50c13..33862670e285 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -161,7 +161,8 @@ static int bt_start_transaction(struct si_sm_data *bt, { unsigned int i; - if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1; + if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) + return -1; if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) return -2; @@ -169,7 +170,8 @@ static int bt_start_transaction(struct si_sm_data *bt, if (bt_debug & BT_DEBUG_MSG) { printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n"); printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq); - for (i = 0; i < size; i ++) printk (" %02x", data[i]); + for (i = 0; i < size; i ++) + printk (" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ @@ -208,15 +210,18 @@ static int bt_get_result(struct si_sm_data *bt, } else { data[0] = bt->read_data[1]; data[1] = bt->read_data[3]; - if (length < msg_len) bt->truncated = 1; + if (length < msg_len) + bt->truncated = 1; if (bt->truncated) { /* can be set in read_all_bytes() */ data[2] = IPMI_ERR_MSG_TRUNCATED; msg_len = 3; - } else memcpy(data + 2, bt->read_data + 4, msg_len - 2); + } else + memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { printk (KERN_WARNING "BT: res (raw)"); - for (i = 0; i < msg_len; i++) printk(" %02x", data[i]); + for (i = 0; i < msg_len; i++) + printk(" %02x", data[i]); printk ("\n"); } } @@ -229,8 +234,10 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { - if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); - if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); + if (BT_STATUS & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); + if (BT_STATUS & BT_B_BUSY) + BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION @@ -239,7 +246,8 @@ static void reset_flags(struct si_sm_data *bt) BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_B2H_ATN); BT_CONTROL(BT_CLR_RD_PTR); - for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST; + for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) + BMC2HOST; BT_CONTROL(BT_H_BUSY); } #endif @@ -256,7 +264,8 @@ static inline void write_all_bytes(struct si_sm_data *bt) printk (" %02x", bt->write_data[i]); printk ("\n"); } - for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); + for (i = 0; i < bt->write_count; i++) + HOST2BMC(bt->write_data[i]); } static inline int read_all_bytes(struct si_sm_data *bt) @@ -276,7 +285,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } - for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST; + for (i = 1; i <= bt->read_count; i++) + bt->read_data[i] = BMC2HOST; bt->read_count++; /* account for the length byte */ if (bt_debug & BT_DEBUG_MSG) { @@ -293,7 +303,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) return 1; - if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: " + if (bt_debug & BT_DEBUG_MSG) + printk(KERN_WARNING "BT: bad packet: " "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", bt->write_data[1], bt->write_data[2], bt->write_data[3], bt->read_data[1], bt->read_data[2], bt->read_data[3]); @@ -357,7 +368,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) time); bt->last_state = bt->state; - if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED; + if (bt->state == BT_STATE_HOSED) + return SI_SM_HOSED; if (bt->state != BT_STATE_IDLE) { /* do timeout test */ @@ -369,7 +381,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT (noticed in ipmi_smic_sm.c January 2004) */ - if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100; + if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) + time = 100; bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { error_recovery(bt, "timed out"); @@ -391,12 +404,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_CONTROL(BT_H_BUSY); break; } - if (status & BT_B2H_ATN) break; + if (status & BT_B2H_ATN) + break; bt->state = BT_STATE_WRITE_BYTES; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ case BT_STATE_WRITE_BYTES: - if (status & (BT_B_BUSY | BT_H2B_ATN)) break; + if (status & (BT_B_BUSY | BT_H2B_ATN)) + break; BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ @@ -404,7 +419,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ - if (status & (BT_H2B_ATN | BT_B_BUSY)) break; + if (status & (BT_H2B_ATN | BT_B_BUSY)) + break; bt->state = BT_STATE_B2H_WAIT; /* fall through with status */ @@ -413,15 +429,18 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ case BT_STATE_B2H_WAIT: - if (!(status & BT_B2H_ATN)) break; + if (!(status & BT_B2H_ATN)) + break; /* Assume ordered, uncached writes: no need to wait */ - if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */ + if (!(status & BT_H_BUSY)) + BT_CONTROL(BT_H_BUSY); /* set */ BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ i = read_all_bytes(bt); BT_CONTROL(BT_H_BUSY); /* clear */ - if (!i) break; /* Try this state again */ + if (!i) /* Try this state again */ + break; bt->state = BT_STATE_READ_END; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ @@ -434,7 +453,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) #ifdef MAKE_THIS_TRUE_IF_NECESSARY - if (status & BT_H_BUSY) break; + if (status & BT_H_BUSY) + break; #endif bt->seq++; bt->state = BT_STATE_IDLE; @@ -457,7 +477,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) break; case BT_STATE_RESET3: - if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY; + if (bt->timeout > 0) + return SI_SM_CALL_WITH_DELAY; bt->state = BT_STATE_RESTART; /* printk in debug modes */ break; @@ -483,7 +504,8 @@ static int bt_detect(struct si_sm_data *bt) but that's what you get from reading a bogus address, so we test that first. The calling routine uses negative logic. */ - if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; + if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) + return 1; reset_flags(bt); return 0; } diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d0ed25278cbb..792f4c282291 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -117,7 +117,7 @@ struct seq_table do { \ seq = ((msgid >> 26) & 0x3f); \ seqid = (msgid & 0x3fffff); \ - } while(0) + } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) @@ -326,7 +326,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) down_read(&interfaces_sem); down_write(&smi_watchers_sem); list_add(&(watcher->link), &smi_watchers); - for (i=0; inew_smi(i); } @@ -496,9 +496,9 @@ static int intf_next_seq(ipmi_smi_t intf, int rv = 0; unsigned int i; - for (i=intf->curr_seq; + for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; - i=(i+1)%IPMI_IPMB_NUM_SEQ) + i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (! intf->seq_table[i].inuse) break; @@ -733,7 +733,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user) /* Remove the user from the interfaces sequence table. */ spin_lock_irqsave(&(user->intf->seq_lock), flags); - for (i=0; iintf->seq_table[i].inuse && (user->intf->seq_table[i].recv_msg->user == user)) { @@ -1370,7 +1370,7 @@ static inline int i_ipmi_request(ipmi_user_t user, #ifdef DEBUG_MSGING { int m; - for (m=0; mdata_size; m++) + for (m = 0; m < smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); } @@ -1467,7 +1467,7 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off, int i; int rv= 0; - for (i=0; ichannels[i].address); out[rv-1] = '\n'; /* Replace the final space with a newline */ out[rv] = '\0'; @@ -1766,12 +1766,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, rv = -ENOMEM; down_write(&interfaces_sem); - for (i=0; iintf_num = i; new_intf->version_major = version_major; new_intf->version_minor = version_minor; - for (j=0; jchannels[j].address = IPMI_BMC_SLAVE_ADDR; new_intf->channels[j].lun = 2; @@ -1783,7 +1783,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, new_intf->handlers = handlers; new_intf->send_info = send_info; spin_lock_init(&(new_intf->seq_lock)); - for (j=0; jseq_table[j].inuse = 0; new_intf->seq_table[j].seqid = 0; } @@ -1891,7 +1891,7 @@ static void clean_up_interface_data(ipmi_smi_t intf) free_recv_msg_list(&(intf->waiting_events)); free_cmd_rcvr_list(&(intf->cmd_rcvrs)); - for (i=0; iseq_table[i].inuse) && (intf->seq_table[i].recv_msg)) { @@ -1910,7 +1910,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf) down_write(&interfaces_sem); if (list_empty(&(intf->users))) { - for (i=0; idata_size; m++) + for (m = 0; m < msg->data_size; m++) printk(" %2.2x", msg->data[m]); printk("\n"); } @@ -2469,7 +2469,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, #ifdef DEBUG_MSGING int m; printk("Recv:"); - for (m=0; mrsp_size; m++) + for (m = 0; m < msg->rsp_size; m++) printk(" %2.2x", msg->rsp[m]); printk("\n"); #endif @@ -2703,7 +2703,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, { int m; printk("Resend: "); - for (m=0; mdata_size; m++) + for (m = 0; m < smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); } @@ -2724,7 +2724,7 @@ ipmi_timeout_handler(long timeout_period) INIT_LIST_HEAD(&timeouts); spin_lock(&interfaces_lock); - for (i=0; iseq_lock), flags); - for (j=0; jseq_table[j]); if (!ent->inuse) continue; @@ -2789,7 +2789,7 @@ ipmi_timeout_handler(long timeout_period) spin_unlock(&intf->counter_lock); smi_msg = smi_from_recv_msg(intf, ent->recv_msg, j, ent->seqid); - if(!smi_msg) + if (! smi_msg) continue; spin_unlock_irqrestore(&(intf->seq_lock),flags); @@ -2820,7 +2820,7 @@ static void ipmi_request_event(void) int i; spin_lock(&interfaces_lock); - for (i=0; ixmit_msgs.next; } - if (!entry) { + if (! entry) { smi_info->curr_msg = NULL; rv = SI_SM_IDLE; } else { @@ -328,7 +328,7 @@ static void start_clear_flags(struct smi_info *smi_info) memory, we will re-enable the interrupt. */ static inline void disable_si_irq(struct smi_info *smi_info) { - if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { + if ((smi_info->irq) && (! smi_info->interrupt_disabled)) { disable_irq_nosync(smi_info->irq); smi_info->interrupt_disabled = 1; } @@ -359,7 +359,7 @@ static void handle_flags(struct smi_info *smi_info) } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) { /* Messages available. */ smi_info->curr_msg = ipmi_alloc_smi_msg(); - if (!smi_info->curr_msg) { + if (! smi_info->curr_msg) { disable_si_irq(smi_info); smi_info->si_state = SI_NORMAL; return; @@ -378,7 +378,7 @@ static void handle_flags(struct smi_info *smi_info) } else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) { /* Events available. */ smi_info->curr_msg = ipmi_alloc_smi_msg(); - if (!smi_info->curr_msg) { + if (! smi_info->curr_msg) { disable_si_irq(smi_info); smi_info->si_state = SI_NORMAL; return; @@ -414,7 +414,7 @@ static void handle_transaction_done(struct smi_info *smi_info) #endif switch (smi_info->si_state) { case SI_NORMAL: - if (!smi_info->curr_msg) + if (! smi_info->curr_msg) break; smi_info->curr_msg->rsp_size @@ -1047,7 +1047,7 @@ static int std_irq_setup(struct smi_info *info) { int rv; - if (!info->irq) + if (! info->irq) return 0; if (info->si_type == SI_BT) { @@ -1056,7 +1056,7 @@ static int std_irq_setup(struct smi_info *info) SA_INTERRUPT, DEVICE_NAME, info); - if (!rv) + if (! rv) /* Enable the interrupt in the BT interface. */ info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, IPMI_BT_INTMASK_ENABLE_IRQ_BIT); @@ -1081,7 +1081,7 @@ static int std_irq_setup(struct smi_info *info) static void std_irq_cleanup(struct smi_info *info) { - if (!info->irq) + if (! info->irq) return; if (info->si_type == SI_BT) @@ -1154,7 +1154,7 @@ static int port_setup(struct smi_info *info) unsigned int *addr = info->io.info; int mapsize; - if (!addr || (!*addr)) + if (! addr || (! *addr)) return -ENODEV; info->io_cleanup = port_cleanup; @@ -1197,15 +1197,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info) { struct smi_info *info; - if (!ports[intf_num]) + if (! ports[intf_num]) return -ENODEV; - if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE, + if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE, ports[intf_num])) return -ENODEV; info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n"); return -ENOMEM; } @@ -1215,10 +1215,10 @@ static int try_init_port(int intf_num, struct smi_info **new_info) info->io.info = &(ports[intf_num]); info->io.addr = NULL; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = regsizes[intf_num]; - if (!info->io.regsize) + if (! info->io.regsize) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; info->irq = 0; @@ -1303,7 +1303,7 @@ static int mem_setup(struct smi_info *info) unsigned long *addr = info->io.info; int mapsize; - if (!addr || (!*addr)) + if (! addr || (! *addr)) return -ENODEV; info->io_cleanup = mem_cleanup; @@ -1358,15 +1358,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) { struct smi_info *info; - if (!addrs[intf_num]) + if (! addrs[intf_num]) return -ENODEV; - if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE, + if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE, addrs[intf_num])) return -ENODEV; info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n"); return -ENOMEM; } @@ -1376,10 +1376,10 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) info->io.info = &addrs[intf_num]; info->io.addr = NULL; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = regsizes[intf_num]; - if (!info->io.regsize) + if (! info->io.regsize) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; info->irq = 0; @@ -1437,7 +1437,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info) { acpi_status status; - if (!info->irq) + if (! info->irq) return 0; /* FIXME - is level triggered right? */ @@ -1461,7 +1461,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info) static void acpi_gpe_irq_cleanup(struct smi_info *info) { - if (!info->irq) + if (! info->irq) return; acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe); @@ -1537,10 +1537,10 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) addr_space = IPMI_MEM_ADDR_SPACE; else addr_space = IPMI_IO_ADDR_SPACE; - if (!is_new_interface(-1, addr_space, spmi->addr.address)) + if (! is_new_interface(-1, addr_space, spmi->addr.address)) return -ENODEV; - if (!spmi->addr.register_bit_width) { + if (! spmi->addr.register_bit_width) { acpi_failure = 1; return -ENODEV; } @@ -1567,7 +1567,7 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n"); return -ENOMEM; } @@ -1645,7 +1645,7 @@ static int dmi_data_entries; static int __init decode_dmi(struct dmi_header *dm, int intf_num) { - u8 *data = (u8 *)dm; + u8 *data = (u8 *)dm; unsigned long base_addr; u8 reg_spacing; u8 len = dm->length; @@ -1714,7 +1714,7 @@ static int __init decode_dmi(struct dmi_header *dm, int intf_num) static void __init dmi_find_bmc(void) { struct dmi_device *dev = NULL; - int intf_num = 0; + int intf_num = 0; while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { if (intf_num >= SI_MAX_DRIVERS) @@ -1726,14 +1726,14 @@ static void __init dmi_find_bmc(void) static int try_init_smbios(int intf_num, struct smi_info **new_info) { - struct smi_info *info; - dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - char *io_type; + struct smi_info *info; + dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; + char *io_type; if (intf_num >= dmi_data_entries) return -ENODEV; - switch(ipmi_data->type) { + switch (ipmi_data->type) { case 0x01: /* KCS */ si_type[intf_num] = "kcs"; break; @@ -1748,7 +1748,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n"); return -ENOMEM; } @@ -1772,7 +1772,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) regspacings[intf_num] = ipmi_data->offset; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; @@ -1814,14 +1814,14 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) pci_smic_checked = 1; - if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, - NULL))) - ; - else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) && - pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID) - fe_rmc = 1; - else - return -ENODEV; + pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL); + if (! pci_dev) { + pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL); + if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)) + fe_rmc = 1; + else + return -ENODEV; + } error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr); if (error) @@ -1834,7 +1834,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) } /* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */ - if (!(base_addr & 0x0001)) + if (! (base_addr & 0x0001)) { pci_dev_put(pci_dev); printk(KERN_ERR @@ -1844,17 +1844,17 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) } base_addr &= 0xFFFE; - if (!fe_rmc) + if (! fe_rmc) /* Data register starts at base address + 1 in eRMC */ ++base_addr; - if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) { + if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) { pci_dev_put(pci_dev); return -ENODEV; } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { pci_dev_put(pci_dev); printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n"); return -ENOMEM; @@ -1865,7 +1865,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) ports[intf_num] = base_addr; info->io.info = &(ports[intf_num]); info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; @@ -1886,7 +1886,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) static int try_init_plug_and_play(int intf_num, struct smi_info **new_info) { #ifdef CONFIG_PCI - if (find_pci_smic(intf_num, new_info)==0) + if (find_pci_smic(intf_num, new_info) == 0) return 0; #endif /* Include other methods here. */ @@ -1904,7 +1904,7 @@ static int try_get_dev_id(struct smi_info *smi_info) int rv = 0; resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); - if (!resp) + if (! resp) return -ENOMEM; /* Do a Get Device ID command, since it comes back with some @@ -1986,7 +1986,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off, struct smi_info *smi = data; out += sprintf(out, "interrupts_enabled: %d\n", - smi->irq && !smi->interrupt_disabled); + smi->irq && ! smi->interrupt_disabled); out += sprintf(out, "short_timeouts: %ld\n", smi->short_timeouts); out += sprintf(out, "long_timeouts: %ld\n", @@ -2024,8 +2024,8 @@ static int stat_file_read_proc(char *page, char **start, off_t off, */ static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) { - smi_info->msg_flags = (smi_info->msg_flags & ~OEM_DATA_AVAIL) | - RECEIVE_MSG_AVAIL; + smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) | + RECEIVE_MSG_AVAIL); return 1; } @@ -2059,10 +2059,11 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) { struct ipmi_device_id *id = &smi_info->device_id; const char mfr[3]=DELL_IANA_MFR_ID; - if (!memcmp(mfr, id->manufacturer_id, sizeof(mfr)) && - id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID && - id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV && - id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { + if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) + && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID) + && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV) + && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION)) + { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; } @@ -2092,19 +2093,15 @@ static int init_one_smi(int intf_num, struct smi_info **smi) if (rv) rv = try_init_port(intf_num, &new_smi); #ifdef CONFIG_ACPI_INTERPRETER - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_acpi(intf_num, &new_smi); - } #endif #ifdef CONFIG_X86 - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_smbios(intf_num, &new_smi); - } #endif - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_plug_and_play(intf_num, &new_smi); - } - if (rv) return rv; @@ -2114,7 +2111,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) new_smi->si_sm = NULL; new_smi->handlers = NULL; - if (!new_smi->irq_setup) { + if (! new_smi->irq_setup) { new_smi->irq = irqs[intf_num]; new_smi->irq_setup = std_irq_setup; new_smi->irq_cleanup = std_irq_cleanup; @@ -2148,7 +2145,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); - if (!new_smi->si_sm) { + if (! new_smi->si_sm) { printk(" Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; @@ -2256,7 +2253,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (!new_smi->timer_stopped) { + while (! new_smi->timer_stopped) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } @@ -2296,7 +2293,7 @@ static __init int init_ipmi_si(void) /* Parse out the si_type string into its components. */ str = si_type_str; if (*str != '\0') { - for (i=0; (itimer_stopped) { + while (! to_clean->timer_stopped) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } /* Interrupts and timeouts are stopped, now make sure the interface is in a clean state. */ - while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) { + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); @@ -2410,10 +2407,10 @@ static __exit void cleanup_ipmi_si(void) { int i; - if (!initialized) + if (! initialized) return; - for (i=0; i Date: Tue, 6 Sep 2005 15:18:45 -0700 Subject: [PATCH] ipmi: remove unused fields This removes the unused "all_cmd_rcvr" variable from the IPMI driver. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 42 ++++++++++--------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 792f4c282291..463351d4f942 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -202,12 +202,6 @@ struct ipmi_smi struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ - /* This will be non-null if someone registers to receive all - IPMI commands (this is for interface emulation). There - may not be any things in the cmd_rcvrs list above when - this is registered. */ - ipmi_user_t all_cmd_rcvr; - /* The event receiver for my BMC, only really used at panic shutdown as a place to store this. */ unsigned char event_receiver; @@ -867,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t user, read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); - if (user->intf->all_cmd_rcvr != NULL) { - rv = -EBUSY; - goto out_unlock; - } - /* Make sure the command/netfn is not already registered. */ list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) { if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) { @@ -886,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, rcvr->user = user; list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs)); } - out_unlock: + write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); @@ -1799,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, rwlock_init(&(new_intf->cmd_rcvr_lock)); init_waitqueue_head(&new_intf->waitq); INIT_LIST_HEAD(&(new_intf->cmd_rcvrs)); - new_intf->all_cmd_rcvr = NULL; spin_lock_init(&(new_intf->counter_lock)); @@ -2037,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, read_lock(&(intf->cmd_rcvr_lock)); - if (intf->all_cmd_rcvr) { - user = intf->all_cmd_rcvr; - } else { - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } + /* Find the command/netfn. */ + list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { + user = rcvr->user; + break; } } read_unlock(&(intf->cmd_rcvr_lock)); @@ -2222,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, read_lock(&(intf->cmd_rcvr_lock)); - if (intf->all_cmd_rcvr) { - user = intf->all_cmd_rcvr; - } else { - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } + /* Find the command/netfn. */ + list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { + user = rcvr->user; + break; } } read_unlock(&(intf->cmd_rcvr_lock)); -- cgit v1.2.2 From 8c702e16207c70119d03df924de35f8c3629a5c4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 6 Sep 2005 15:18:46 -0700 Subject: [PATCH] ipmi poweroff: fix chassis control The IPMI power control function proc_write_chassctrl was badly written, it directly used userspace pointers, it assumed that strings were NULL terminated, and it used the evil sscanf function. This converts over to using the sysctl interface for this data and changes the semantics to be a little more logical. Signed-off-by: Corey Minyard Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_poweroff.c | 132 +++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 74 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 42ea9843b394..e82a96ba396b 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -52,11 +52,11 @@ extern void (*pm_power_off)(void); #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ /* the IPMI data command */ -static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; +static int poweroff_powercycle; /* parameter definition to allow user to flag power cycle */ -module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); -MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +module_param(poweroff_powercycle, int, 0); +MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; @@ -385,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) powercyclefailed: printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", - ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); + (poweroff_powercycle ? "cycle" : "down")); /* * Power down */ send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; - data[0] = poweroff_control; + if (poweroff_powercycle) + data[0] = IPMI_CHASSIS_POWER_CYCLE; + else + data[0] = IPMI_CHASSIS_POWER_DOWN; send_msg.data = data; send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); if (rv) { - switch (poweroff_control) { - case IPMI_CHASSIS_POWER_CYCLE: - /* power cycle failed, default to power down */ - printk(KERN_ERR PFX "Unable to send chassis power " \ - "cycle message, IPMI error 0x%x\n", rv); - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - goto powercyclefailed; - - case IPMI_CHASSIS_POWER_DOWN: - default: - printk(KERN_ERR PFX "Unable to send chassis power " \ - "down message, IPMI error 0x%x\n", rv); - break; + if (poweroff_powercycle) { + /* power cycle failed, default to power down */ + printk(KERN_ERR PFX "Unable to send chassis power " \ + "cycle message, IPMI error 0x%x\n", rv); + poweroff_powercycle = 0; + goto powercyclefailed; } - } - return; + printk(KERN_ERR PFX "Unable to send chassis power " \ + "down message, IPMI error 0x%x\n", rv); + } } @@ -561,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher = #ifdef CONFIG_PROC_FS -/* displays properties to proc */ -static int proc_read_chassctrl(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", - poweroff_control); -} +#include + +static ctl_table ipmi_table[] = { + { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE, + .procname = "poweroff_powercycle", + .data = &poweroff_powercycle, + .maxlen = sizeof(poweroff_powercycle), + .mode = 0644, + .proc_handler = &proc_dointvec }, + { } +}; -/* process property writes from proc */ -static int proc_write_chassctrl(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - int rv = count; - unsigned int newval = 0; - - sscanf(buffer, "%d", &newval); - switch (newval) { - case IPMI_CHASSIS_POWER_CYCLE: - printk(KERN_INFO PFX "power cycle is now enabled\n"); - poweroff_control = newval; - break; - - case IPMI_CHASSIS_POWER_DOWN: - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - break; - - default: - rv = -EINVAL; - break; - } +static ctl_table ipmi_dir_table[] = { + { .ctl_name = DEV_IPMI, + .procname = "ipmi", + .mode = 0555, + .child = ipmi_table }, + { } +}; - return rv; -} +static ctl_table ipmi_root_table[] = { + { .ctl_name = CTL_DEV, + .procname = "dev", + .mode = 0555, + .child = ipmi_dir_table }, + { } +}; + +static struct ctl_table_header *ipmi_table_header; #endif /* CONFIG_PROC_FS */ /* @@ -601,41 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer, */ static int ipmi_poweroff_init (void) { - int rv; - struct proc_dir_entry *file; + int rv; printk ("Copyright (C) 2004 MontaVista Software -" " IPMI Powerdown via sys_reboot.\n"); - switch (poweroff_control) { - case IPMI_CHASSIS_POWER_CYCLE: - printk(KERN_INFO PFX "Power cycle is enabled.\n"); - break; + if (poweroff_powercycle) + printk(KERN_INFO PFX "Power cycle is enabled.\n"); - case IPMI_CHASSIS_POWER_DOWN: - default: - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - break; +#ifdef CONFIG_PROC_FS + ipmi_table_header = register_sysctl_table(ipmi_root_table, 1); + if (!ipmi_table_header) { + printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); + rv = -ENOMEM; + goto out_err; } +#endif +#ifdef CONFIG_PROC_FS rv = ipmi_smi_watcher_register(&smi_watcher); +#endif if (rv) { + unregister_sysctl_table(ipmi_table_header); printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); goto out_err; } -#ifdef CONFIG_PROC_FS - file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); - if (!file) { - printk(KERN_ERR PFX "Unable to create proc power control\n"); - } else { - file->nlink = 1; - file->read_proc = proc_read_chassctrl; - file->write_proc = proc_write_chassctrl; - file->owner = THIS_MODULE; - } -#endif - out_err: return rv; } @@ -646,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void) int rv; #ifdef CONFIG_PROC_FS - remove_proc_entry("poweroff_control", proc_ipmi_root); + unregister_sysctl_table(ipmi_table_header); #endif ipmi_smi_watcher_unregister(&smi_watcher); -- cgit v1.2.2 From 982245f01734e9d5a3ab98b2b2e9761ae7719094 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 17 Jul 2005 04:22:20 +0200 Subject: [PATCH] PCI: remove CONFIG_PCI_NAMES This patch removes CONFIG_PCI_NAMES. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/char/drm/drmP.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 6f98701dfe15..121cc85f347e 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -1071,5 +1071,9 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area); extern unsigned long drm_core_get_map_ofs(drm_map_t *map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); +#ifndef pci_pretty_name +#define pci_pretty_name(dev) "" +#endif + #endif /* __KERNEL__ */ #endif -- cgit v1.2.2 From f91f4d923f4039bf3460eca299ed5a3f7ecd7b96 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" Date: Fri, 9 Sep 2005 17:02:51 +0100 Subject: [PATCH] gratuitous includes of asm/serial.h Removed gratuitous includes of asm/serial.h in synklinkmp and ip2main. Allows to remove the rest of "broken on sparc32" in drivers/char - this stuff doesn't break the build anymore. Since it got zero testing, it almost certainly won't work there, though... Signed-off-by: Al Viro Acked-by: Russell King Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 4 ++-- drivers/char/ip2main.c | 1 - drivers/char/synclinkmp.c | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2bc9d64db106..c29365d5b524 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,7 +80,7 @@ config SERIAL_NONSTANDARD config COMPUTONE tristate "Computone IntelliPort Plus serial support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (BROKEN || !SPARC32) + depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP ---help--- This driver supports the entire family of Intelliport II/Plus controllers with the exception of the MicroChannel controllers and @@ -208,7 +208,7 @@ config SYNCLINK config SYNCLINKMP tristate "SyncLink Multiport support" - depends on SERIAL_NONSTANDARD && (BROKEN || !SPARC32) + depends on SERIAL_NONSTANDARD help Enable support for the SyncLink Multiport (2 or 4 ports) serial adapter, running asynchronous and HDLC communications up diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index cf0cd58d6305..066d7b5cb76d 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -120,7 +120,6 @@ #include #include -#include #include diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index ec949e4c070f..8982eafd0fb7 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -55,7 +55,6 @@ #include #include #include -#include #include #include -- cgit v1.2.2 From ff55fe2075e3901db4dbdc00e0b44a71bef97afd Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Fri, 9 Sep 2005 13:01:57 -0700 Subject: [PATCH] pty_chars_in_buffer oops fix The idea of this patch is to lock both sides of a ptmx/pty pair during line discipline changing. This is needed to ensure that say a poll on one side of the pty doesn't occur while the line discipline is actively being changed. This resulted in an oops reported on lkml, see: http://marc.theaimsgroup.com/?l=linux-kernel&m=111342171410005&w=2 A 'hacky' approach was previously implmemented which served to eliminate the poll vs. line discipline changing race. However, this patch takes a more general approach to the issue. The patch only adds locking on a less often used path, the line-discipline changing path, as opposed to locking the ptmx/pty pair on read/write/poll paths. The patch below, takes both ldisc locks in either order b/c the locks are both taken under the same spinlock(). I thought about locking the ptmx/pty separately, such as master always first but that introduces a 3 way deadlock. For example, process 1 does a blocking read on the slave side. Then, process 2 does an ldisc change on the slave side, which acquires the master ldisc lock but not the slave's. Finally, process 3 does a write which blocks on the process 2's ldisc reference. This patch does introduce some changes in semantics. For example, a line discipline change on side 'a' of a ptmx/pty pair, will now wait for a read/write to complete on the other side, or side 'b'. The current behavior is to simply wait for any read/writes on only side 'a', not both sides 'a' and 'b'. I think this behavior makes sense, but I wanted to point it out. I've tested the patch with a bunch of read/write/poll while changing the line discipline out from underneath. This patch obviates the need for the above "hide the problem" patch. Signed-off-by: Jason Baron Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pty.c | 5 ++-- drivers/char/tty_io.c | 79 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 28 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pty.c b/drivers/char/pty.c index da32889d22c0..49f3997fd251 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -149,15 +149,14 @@ static int pty_write_room(struct tty_struct *tty) static int pty_chars_in_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; - ssize_t (*chars_in_buffer)(struct tty_struct *); int count; /* We should get the line discipline lock for "tty->link" */ - if (!to || !(chars_in_buffer = to->ldisc.chars_in_buffer)) + if (!to || !to->ldisc.chars_in_buffer) return 0; /* The ldisc must report 0 if no characters available to be read */ - count = chars_in_buffer(to); + count = to->ldisc.chars_in_buffer(to); if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 9d657127f313..6a56ae4f7725 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -469,21 +469,19 @@ static void tty_ldisc_enable(struct tty_struct *tty) static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { - int retval = 0; - struct tty_ldisc o_ldisc; + int retval = 0; + struct tty_ldisc o_ldisc; char buf[64]; int work; unsigned long flags; struct tty_ldisc *ld; + struct tty_struct *o_tty; if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; restart: - if (tty->ldisc.num == ldisc) - return 0; /* We are already in the desired discipline */ - ld = tty_ldisc_get(ldisc); /* Eduardo Blanco */ /* Cyrus Durgin */ @@ -494,45 +492,74 @@ restart: if (ld == NULL) return -EINVAL; - o_ldisc = tty->ldisc; - tty_wait_until_sent(tty, 0); + if (tty->ldisc.num == ldisc) { + tty_ldisc_put(ldisc); + return 0; + } + + o_ldisc = tty->ldisc; + o_tty = tty->link; + /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. */ - + spin_lock_irqsave(&tty_ldisc_lock, flags); - if(tty->ldisc.refcount) - { - /* Free the new ldisc we grabbed. Must drop the lock - first. */ + if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { + if(tty->ldisc.refcount) { + /* Free the new ldisc we grabbed. Must drop the lock + first. */ + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + /* + * There are several reasons we may be busy, including + * random momentary I/O traffic. We must therefore + * retry. We could distinguish between blocking ops + * and retries if we made tty_ldisc_wait() smarter. That + * is up for discussion. + */ + if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + if(o_tty && o_tty->ldisc.refcount) { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + } + + /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */ + + if (!test_bit(TTY_LDISC, &tty->flags)) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(ldisc); - /* - * There are several reasons we may be busy, including - * random momentary I/O traffic. We must therefore - * retry. We could distinguish between blocking ops - * and retries if we made tty_ldisc_wait() smarter. That - * is up for discussion. - */ - if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; + ld = tty_ldisc_ref_wait(tty); + tty_ldisc_deref(ld); goto restart; } - clear_bit(TTY_LDISC, &tty->flags); + + clear_bit(TTY_LDISC, &tty->flags); clear_bit(TTY_DONT_FLIP, &tty->flags); + if (o_tty) { + clear_bit(TTY_LDISC, &o_tty->flags); + clear_bit(TTY_DONT_FLIP, &o_tty->flags); + } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - + /* * From this point on we know nobody has an ldisc * usage reference, nor can they obtain one until * we say so later on. */ - + work = cancel_delayed_work(&tty->flip.work); /* * Wait for ->hangup_work and ->flip.work handlers to terminate @@ -583,10 +610,12 @@ restart: */ tty_ldisc_enable(tty); + if (o_tty) + tty_ldisc_enable(o_tty); /* Restart it in case no characters kick it off. Safe if already running */ - if(work) + if (work) schedule_delayed_work(&tty->flip.work, 1); return retval; } -- cgit v1.2.2 From 4a918bc233c8b9537fbc05a8bbb33928a4980cc5 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:12 -0700 Subject: [PATCH] synclink.c: compiler optimisation fix Make some fields of DMA descriptor volatile to prevent compiler optimizations. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 37c8bea8e2b0..747eb8d18166 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $ + * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -141,9 +141,9 @@ static MGSL_PARAMS default_params = { typedef struct _DMABUFFERENTRY { u32 phys_addr; /* 32-bit flat physical address of data buffer */ - u16 count; /* buffer size/data count */ - u16 status; /* Control/status field */ - u16 rcc; /* character count field */ + volatile u16 count; /* buffer size/data count */ + volatile u16 status; /* Control/status field */ + volatile u16 rcc; /* character count field */ u16 reserved; /* padding required by 16C32 */ u32 link; /* 32-bit flat link to next buffer entry */ char *virt_addr; /* virtual address of data buffer */ @@ -896,7 +896,7 @@ module_param_array(txdmabufs, int, NULL, 0); module_param_array(txholdbufs, int, NULL, 0); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.28 $"; +static char *driver_version = "$Revision: 4.37 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); -- cgit v1.2.2 From 9661239f7f698ba3a79db5e8ab5bb2f4090663d9 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:13 -0700 Subject: [PATCH] synclink.c: add clear stats Add the ability to clear statistics. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 747eb8d18166..26b421b74bb6 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1814,6 +1814,8 @@ static int startup(struct mgsl_struct * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = mgsl_tx_timeout; @@ -2470,12 +2472,12 @@ static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user * printk("%s(%d):mgsl_get_params(%s)\n", __FILE__,__LINE__, info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_get_stats(%s) user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; } return 0; -- cgit v1.2.2 From 7c1fff58cfaaf1c4b6a31a569e18cb7d2d8db0a6 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:14 -0700 Subject: [PATCH] synclink.c: add loopback to async mode Add internal loopback support for asynchronous mode operation. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 26b421b74bb6..ea2d54be4843 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -6151,6 +6151,11 @@ static void usc_set_async_mode( struct mgsl_struct *info ) usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); } + if (info->params.loopback) { + info->loopback_bits = 0x300; + outw(0x0300, info->io_base + CCAR); + } + } /* end of usc_set_async_mode() */ /* usc_loopback_frame() -- cgit v1.2.2 From 7f3edb94564d319cd58cc11c2c986b7ec25643d8 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:14 -0700 Subject: [PATCH] synclinkmp.c: fix double mapping of signals Serial signals were incorrectly mapped twice to events. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclinkmp.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 8982eafd0fb7..1bde04d66cde 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.34 2005/03/04 15:07:10 paulkf Exp $ + * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -486,7 +486,7 @@ module_param_array(maxframe, int, NULL, 0); module_param_array(dosyncppp, int, NULL, 0); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.34 $"; +static char *driver_version = "$Revision: 4.38 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -555,7 +555,6 @@ static int set_txidle(SLMP_INFO *info, int idle_mode); static int tx_enable(SLMP_INFO *info, int enable); static int tx_abort(SLMP_INFO *info); static int rx_enable(SLMP_INFO *info, int enable); -static int map_status(int signals); static int modem_input_wait(SLMP_INFO *info,int arg); static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr); static int tiocmget(struct tty_struct *tty, struct file *file); @@ -3108,16 +3107,6 @@ static int rx_enable(SLMP_INFO * info, int enable) return 0; } -static int map_status(int signals) -{ - /* Map status bits to API event bits */ - - return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) + - ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) + - ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) + - ((signals & SerialSignal_RI) ? MgslEvent_RiActive : MgslEvent_RiInactive); -} - /* wait for specified event to occur */ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) @@ -3144,7 +3133,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) /* return immediately if state matches requested events */ get_signals(info); - s = map_status(info->serial_signals); + s = info->serial_signals; events = mask & ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + -- cgit v1.2.2 From 761a444d8d059e4e2de326383b1dec4a636e0a92 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:15 -0700 Subject: [PATCH] synclinkmp.c: disable burst transfers Disable burst transfers on adapter local bus. Hardware feature does not work on latest version of adapter. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclinkmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 1bde04d66cde..d55dbf1f9e18 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -643,7 +643,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x00800029; +static u32 lcr1_brdr_value = 0x00800028; static u32 read_ahead_count = 8; -- cgit v1.2.2 From 166692e4a045348109f66b493e1b41afde6f3769 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:16 -0700 Subject: [PATCH] synclinkmp.c: add statistics clear Add ability to clear statistics. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclinkmp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index d55dbf1f9e18..eb31a3b865df 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -2748,6 +2748,8 @@ static int startup(SLMP_INFO * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + /* program hardware for current parameters */ reset_port(info); @@ -2951,12 +2953,12 @@ static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount) printk("%s(%d):%s get_params()\n", __FILE__,__LINE__, info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s get_stats() user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; } return 0; -- cgit v1.2.2 From 6e8dcee3e63f5a2cba4affff4bbb6e228f4b258a Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Fri, 9 Sep 2005 13:02:17 -0700 Subject: [PATCH] synclinkmp.c: fix async internal loopback Fix async internal loopback by not using enable_loopback function which reprograms clocking and should only be used for hdlc mode. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclinkmp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index eb31a3b865df..6fb165cf8a61 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -4479,11 +4479,13 @@ void async_mode(SLMP_INFO *info) /* MD2, Mode Register 2 * * 07..02 Reserved, must be 0 - * 01..00 CNCT<1..0> Channel connection, 0=normal + * 01..00 CNCT<1..0> Channel connection, 00=normal 11=local loopback * * 0000 0000 */ RegValue = 0x00; + if (info->params.loopback) + RegValue |= (BIT1 + BIT0); write_reg(info, MD2, RegValue); /* RXS, Receive clock source @@ -4564,9 +4566,6 @@ void async_mode(SLMP_INFO *info) write_reg(info, IE2, info->ie2_value); set_rate( info, info->params.data_rate * 16 ); - - if (info->params.loopback) - enable_loopback(info,1); } /* Program the SCA for HDLC communications. -- cgit v1.2.2 From badf16621c1f9d1ac753be056fce11b43d6e0be5 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma Date: Fri, 9 Sep 2005 13:04:10 -0700 Subject: [PATCH] files: break up files struct In order for the RCU to work, the file table array, sets and their sizes must be updated atomically. Instead of ensuring this through too many memory barriers, we put the arrays and their sizes in a separate structure. This patch takes the first step of putting the file table elements in a separate structure fdtable that is embedded withing files_struct. It also changes all the users to refer to the file table using files_fdtable() macro. Subsequent applciation of RCU becomes easier after this. Signed-off-by: Dipankar Sarma Signed-Off-By: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6a56ae4f7725..0bfc7af68917 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2454,6 +2454,7 @@ static void __do_SAK(void *arg) int i; struct file *filp; struct tty_ldisc *disc; + struct fdtable *fdt; if (!tty) return; @@ -2480,7 +2481,8 @@ static void __do_SAK(void *arg) task_lock(p); if (p->files) { spin_lock(&p->files->file_lock); - for (i=0; i < p->files->max_fds; i++) { + fdt = files_fdtable(p->files); + for (i=0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); if (!filp) continue; -- cgit v1.2.2 From b835996f628eadb55c5fb222ba46fe9395bf73c7 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma Date: Fri, 9 Sep 2005 13:04:14 -0700 Subject: [PATCH] files: lock-free fd look-up With the use of RCU in files structure, the look-up of files using fds can now be lock-free. The lookup is protected by rcu_read_lock()/rcu_read_unlock(). This patch changes the readers to use lock-free lookup. Signed-off-by: Maneesh Soni Signed-off-by: Ravikiran Thirumalai Signed-off-by: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0bfc7af68917..e5953f3433f3 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2480,7 +2480,7 @@ static void __do_SAK(void *arg) } task_lock(p); if (p->files) { - spin_lock(&p->files->file_lock); + rcu_read_lock(); fdt = files_fdtable(p->files); for (i=0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); @@ -2495,7 +2495,7 @@ static void __do_SAK(void *arg) break; } } - spin_unlock(&p->files->file_lock); + rcu_read_unlock(); } task_unlock(p); } while_each_task_pid(session, PIDTYPE_SID, p); -- cgit v1.2.2 From 3b41dc1a3c7839a765ffa560a5ae07aa5d253cc8 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Fri, 9 Sep 2005 13:04:39 -0700 Subject: [PATCH] console: Fix buffer copy on vc resize On a vc resize, the contents of the old screen buffer are transferred to the new screenbuffer. If the new screenbuffer is smaller than the old one, only the contents from the bottom are copied to new. If the contents of the old buffer are located at the top, then the contents will not be copied to the new buffer resulting in a blank screen. This bug will happen only if the vc in question is not in the foreground. Doing an fbset -a or con2fbmap will trigger this bug. To fix this problem, base the start of the copy from the location of the current cursor. If the cursor is near the top of the buffer, copy the contents at the top, and if the cursor is near the bottom of the buffer, then copy the contents at the bottom. In the unlikely case where the new row size is greater than 2x smaller than the old one, and the cursor is in the middle, copy 1/2 screenful from the top and bottom of the cursor position. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index b8d0c290b0db..1e33cb032e07 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -751,6 +751,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; + unsigned int end; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -794,20 +795,44 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) old_origin = vc->vc_origin; new_origin = (long) newscreen; new_scr_end = new_origin + new_screen_size; - if (new_rows < old_rows) - old_origin += (old_rows - new_rows) * old_row_size; + + if (vc->vc_y > new_rows) { + if (old_rows - vc->vc_y < new_rows) { + /* + * Cursor near the bottom, copy contents from the + * bottom of buffer + */ + old_origin += (old_rows - new_rows) * old_row_size; + end = vc->vc_scr_end; + } else { + /* + * Cursor is in no man's land, copy 1/2 screenful + * from the top and bottom of cursor position + */ + old_origin += (vc->vc_y - new_rows/2) * old_row_size; + end = old_origin + new_screen_size; + } + } else + /* + * Cursor near the top, copy contents from the top of buffer + */ + end = (old_rows > new_rows) ? old_origin + new_screen_size : + vc->vc_scr_end; update_attr(vc); - while (old_origin < vc->vc_scr_end) { - scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth); + while (old_origin < end) { + scr_memcpyw((unsigned short *) new_origin, + (unsigned short *) old_origin, rlth); if (rrem) - scr_memsetw((void *)(new_origin + rlth), vc->vc_video_erase_char, rrem); + scr_memsetw((void *)(new_origin + rlth), + vc->vc_video_erase_char, rrem); old_origin += old_row_size; new_origin += new_row_size; } if (new_scr_end > new_origin) - scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin); + scr_memsetw((void *)new_origin, vc->vc_video_erase_char, + new_scr_end - new_origin); if (vc->vc_kmalloced) kfree(vc->vc_screenbuf); vc->vc_screenbuf = newscreen; -- cgit v1.2.2 From 8d06afab73a75f40ae2864e6c296356bab1ab473 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 9 Sep 2005 13:10:40 -0700 Subject: [PATCH] timer initialization cleanup: DEFINE_TIMER Clean up timer initialization by introducing DEFINE_TIMER a'la DEFINE_SPINLOCK. Build and boot-tested on x86. A similar patch has been been in the -RT tree for some time. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/cyclades.c | 2 +- drivers/char/hangcheck-timer.c | 3 +-- drivers/char/ip2main.c | 2 +- drivers/char/istallion.c | 2 +- drivers/char/keyboard.c | 3 +-- drivers/char/watchdog/mixcomwd.c | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 6a5337bf0936..cf4c3648463d 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -865,7 +865,7 @@ static void cyz_poll(unsigned long); static long cyz_polling_cycle = CZ_DEF_POLL; static int cyz_timeron = 0; -static struct timer_list cyz_timerlist = TIMER_INITIALIZER(cyz_poll, 0, 0); +static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); #else /* CONFIG_CYZ_INTR */ static void cyz_rx_restart(unsigned long); diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 81d811edf3c5..a54bc93353af 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -149,8 +149,7 @@ static unsigned long long hangcheck_tsc, hangcheck_tsc_margin; static void hangcheck_fire(unsigned long); -static struct timer_list hangcheck_ticktock = - TIMER_INITIALIZER(hangcheck_fire, 0, 0); +static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0); static void hangcheck_fire(unsigned long data) diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 066d7b5cb76d..9e4e26aef94e 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -254,7 +254,7 @@ static unsigned long bh_counter = 0; * selected, the board is serviced periodically to see if anything needs doing. */ #define POLL_TIMEOUT (jiffies + 1) -static struct timer_list PollTimer = TIMER_INITIALIZER(ip2_poll, 0, 0); +static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); static char TimerOn; #ifdef IP2DEBUG_TRACE diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 52a073eee201..9c19e5435a11 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -780,7 +780,7 @@ static struct file_operations stli_fsiomem = { * much cheaper on host cpu than using interrupts. It turns out to * not increase character latency by much either... */ -static struct timer_list stli_timerlist = TIMER_INITIALIZER(stli_poll, 0, 0); +static DEFINE_TIMER(stli_timerlist, stli_poll, 0, 0); static int stli_timeron; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 523fd3c8bbaa..1745065d8f78 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -233,8 +233,7 @@ static void kd_nosound(unsigned long ignored) } } -static struct timer_list kd_mksound_timer = - TIMER_INITIALIZER(kd_nosound, 0, 0); +static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index c9b301dccec3..7fc2188386d9 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -59,7 +59,7 @@ static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; static int mixcomwd_timer_alive; -static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(mixcomwd_timer, NULL, 0, 0); static char expect_close; static int nowayout = WATCHDOG_NOWAYOUT; -- cgit v1.2.2 From 18fb9442576c79fc2f4bca1fd90c3aa4d1115e97 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" Date: Fri, 9 Sep 2005 20:14:05 +0100 Subject: [PATCH] trivial __user annotations (ipmi) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_devintf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 883ac4352be4..a09ff1080687 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -735,7 +735,8 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, case COMPAT_IPMICTL_RECEIVE_MSG: case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: { - struct ipmi_recv *precv64, recv64; + struct ipmi_recv __user *precv64; + struct ipmi_recv recv64; if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) return -EFAULT; @@ -748,7 +749,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) ? IPMICTL_RECEIVE_MSG : IPMICTL_RECEIVE_MSG_TRUNC), - (long) precv64); + (unsigned long) precv64); if (rc != 0) return rc; -- cgit v1.2.2 From 7b4af953321fa65ae5705cb3becc742ab1ba1d6f Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Thu, 8 Sep 2005 07:42:02 +0200 Subject: [WATCHDOG] s3c2410_wdt.c-state_warning.patch I've noticed that the patch from Ben Dooks (commit af4bb822bc65efb087cd36b83789f22161a6515b on your git tree) is introducing a warning. It's using 'u32 state' instead of 'pm_message_t state'. I've attached a one liner to fix it. Signed-Off-By: Arnaud Patard Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/s3c2410_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 8b292bf343c4..3625b2601b42 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev) static unsigned long wtcon_save; static unsigned long wtdat_save; -static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level) +static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level) { if (level == SUSPEND_POWER_DOWN) { /* Save watchdog state, and turn it off. */ -- cgit v1.2.2 From fe1e86049813641a518d15adf7191bd711b4f611 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Sep 2005 12:03:38 -0500 Subject: Input: clean up whitespace and formatting in drivers/char/keyboard.c Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 109 ++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 54 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index b12d58ee532b..449d029ad4f4 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -14,7 +14,7 @@ * `Sticky' modifier keys, 951006. * * 11-11-96: SAK should now work in the raw mode (Martin Mares) - * + * * Modified to provide 'generic' keyboard support by Hamish Macdonald * Merge with the m68k keyboard driver and split-off of the PC low-level * parts by Geert Uytterhoeven, May 1997 @@ -52,7 +52,7 @@ extern void ctrl_alt_del(void); /* * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * This seems a good reason to start with NumLock off. On HIL keyboards - * of PARISC machines however there is no NumLock key and everyone expects the keypad + * of PARISC machines however there is no NumLock key and everyone expects the keypad * to be used for numbers. */ @@ -76,17 +76,17 @@ void compute_shiftstate(void); k_meta, k_ascii, k_lock, k_lowercase,\ k_slock, k_dead2, k_ignore, k_ignore -typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs); static k_handler_fn K_HANDLERS; static k_handler_fn *k_handler[16] = { K_HANDLERS }; #define FN_HANDLERS\ - fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ - fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ - fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ - fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ - fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); static fn_handler_fn FN_HANDLERS; @@ -159,13 +159,13 @@ static int sysrq_alt; */ int getkeycode(unsigned int scancode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; - list_for_each(node,&kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + if (handle->dev->keycodesize) { + dev = handle->dev; break; } } @@ -181,15 +181,15 @@ int getkeycode(unsigned int scancode) int setkeycode(unsigned int scancode, unsigned int keycode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; unsigned int i, oldkey; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; - break; + if (handle->dev->keycodesize) { + dev = handle->dev; + break; } } @@ -216,11 +216,11 @@ int setkeycode(unsigned int scancode, unsigned int keycode) } /* - * Making beeps and bells. + * Making beeps and bells. */ static void kd_nosound(unsigned long ignored) { - struct list_head * node; + struct list_head *node; list_for_each(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); @@ -237,12 +237,12 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { - struct list_head * node; + struct list_head *node; del_timer(&kd_mksound_timer); if (hz) { - list_for_each_prev(node,&kbd_handler.h_list) { + list_for_each_prev(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { @@ -337,19 +337,19 @@ static void to_utf8(struct vc_data *vc, ushort c) if (c < 0x80) /* 0******* */ put_queue(vc, c); - else if (c < 0x800) { + else if (c < 0x800) { /* 110***** 10****** */ - put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0xc0 | (c >> 6)); put_queue(vc, 0x80 | (c & 0x3f)); - } else { + } else { /* 1110**** 10****** 10****** */ put_queue(vc, 0xe0 | (c >> 12)); put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); put_queue(vc, 0x80 | (c & 0x3f)); - } + } } -/* +/* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is * undefined, so that shiftkey release is seen @@ -360,7 +360,7 @@ void compute_shiftstate(void) shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); - + for (i = 0; i < ARRAY_SIZE(key_down); i++) { if (!key_down[i]) @@ -499,9 +499,9 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) if (want_console != -1) cur = want_console; - for (i = cur-1; i != cur; i--) { + for (i = cur - 1; i != cur; i--) { if (i == -1) - i = MAX_NR_CONSOLES-1; + i = MAX_NR_CONSOLES - 1; if (vc_cons_allocated(i)) break; } @@ -567,9 +567,9 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs) static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) { - if (spawnpid) - if(kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + if (spawnpid) + if (kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; } static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) @@ -603,8 +603,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct return; if (value >= ARRAY_SIZE(fn_handler)) return; - if ((kbd->kbdmode == VC_RAW || - kbd->kbdmode == VC_MEDIUMRAW) && + if ((kbd->kbdmode == VC_RAW || + kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ fn_handler[value](vc, regs); @@ -894,11 +894,11 @@ static inline unsigned char getleds(void) static void kbd_bh(unsigned long dummy) { - struct list_head * node; + struct list_head *node; unsigned char leds = getleds(); if (leds != ledstate) { - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle * handle = to_handle_h(node); input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); @@ -963,11 +963,11 @@ static int sparc_l1_a_state = 0; extern void sun_do_break(void); #endif -static int emulate_raw(struct vc_data *vc, unsigned int keycode, +static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { if (keycode > 255 || !x86_keycodes[keycode]) - return -1; + return -1; switch (keycode) { case KEY_PAUSE: @@ -981,7 +981,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, case KEY_HANJA: if (!up_flag) put_queue(vc, 0xf2); return 0; - } + } if (keycode == KEY_SYSRQ && sysrq_alt) { put_queue(vc, 0x54 | up_flag); @@ -1104,11 +1104,12 @@ static void kbd_keycode(unsigned int keycode, int down, else clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && - (!L_ECHO(tty) && tty->driver->chars_in_buffer(tty))))) { + if (rep && + (!vc_kbd_mode(kbd, VC_REPEAT) || + (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { /* * Don't repeat a key if the input buffers are not empty and the - * characters get aren't echoed locally. This makes key repeat + * characters get aren't echoed locally. This makes key repeat * usable with slow applications and under heavy loads. */ return; @@ -1130,7 +1131,8 @@ static void kbd_keycode(unsigned int keycode, int down, type = KTYP(keysym); if (type < 0xf0) { - if (down && !raw_mode) to_utf8(vc, keysym); + if (down && !raw_mode) + to_utf8(vc, keysym); return; } @@ -1154,7 +1156,7 @@ static void kbd_keycode(unsigned int keycode, int down, kbd->slockstate = 0; } -static void kbd_event(struct input_handle *handle, unsigned int event_type, +static void kbd_event(struct input_handle *handle, unsigned int event_type, unsigned int event_code, int value) { if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) @@ -1166,15 +1168,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, schedule_console_callback(); } -static char kbd_name[] = "kbd"; - /* * When a keyboard (or other input device) is found, the kbd_connect * function is called. The function then looks at the device, and if it * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static struct input_handle *kbd_connect(struct input_handler *handler, +static struct input_handle *kbd_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { @@ -1182,18 +1182,19 @@ static struct input_handle *kbd_connect(struct input_handler *handler, int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) break; + if (test_bit(i, dev->keybit)) + break; - if ((i == BTN_MISC) && !test_bit(EV_SND, dev->evbit)) + if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; - handle->name = kbd_name; + handle->name = "kbd"; input_open_device(handle); kbd_refresh_leds(handle); @@ -1212,11 +1213,11 @@ static struct input_device_id kbd_ids[] = { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_KEY) }, }, - + { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_SND) }, - }, + }, { }, /* Terminating entry */ }; -- cgit v1.2.2 From a7482a2e7775d163aecd8c95af7bb1b8c83890cc Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Sat, 10 Sep 2005 00:26:07 -0700 Subject: [PATCH] synclink_cs add statistics clear Add ability to clear statistics. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/synclink_cs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 7a0c74648124..02d7f046c10a 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $ + * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -472,7 +472,7 @@ module_param_array(dosyncppp, int, NULL, 0); MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.26 $"; +static char *driver_version = "$Revision: 4.34 $"; static struct tty_driver *serial_driver; @@ -1457,6 +1457,8 @@ static int startup(MGSLPC_INFO * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = tx_timeout; @@ -1946,9 +1948,13 @@ static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) int err; if (debug_level >= DEBUG_LEVEL_INFO) printk("get_params(%s)\n", info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; + } return 0; } -- cgit v1.2.2 From 819a3eba4233ffc6c125e1bf0a15ae093b97c3a6 Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Sat, 10 Sep 2005 00:26:29 -0700 Subject: [PATCH] applicom: fix error handling misc_register() can fail. Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/applicom.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 11f9ee581124..927a5bbe112c 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -172,7 +172,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc, void cleanup_module(void) { - int i; + unsigned int i; misc_deregister(&ac_miscdev); @@ -195,7 +195,7 @@ int __init applicom_init(void) int i, numisa = 0; struct pci_dev *dev = NULL; void __iomem *RamIO; - int boardno; + int boardno, ret; printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); @@ -294,7 +294,8 @@ int __init applicom_init(void) } if (!numisa) - printk(KERN_WARNING"ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem); + printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " + "at mem 0x%lx\n", mem); fin: init_waitqueue_head(&FlagSleepRec); @@ -304,7 +305,11 @@ int __init applicom_init(void) DeviceErrorCount = 0; if (numboards) { - misc_register(&ac_miscdev); + ret = misc_register(&ac_miscdev); + if (ret) { + printk(KERN_WARNING "ac.o: Unable to register misc device\n"); + goto out; + } for (i = 0; i < MAX_BOARD; i++) { int serial; char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; @@ -337,6 +342,17 @@ int __init applicom_init(void) else return -ENXIO; + +out: + for (i = 0; i < MAX_BOARD; i++) { + if (!apbs[i].RamIO) + continue; + if (apbs[i].irq) + free_irq(apbs[i].irq, &dummy); + iounmap(apbs[i].RamIO); + } + pci_disable_device(dev); + return ret; } -- cgit v1.2.2 From cf85d5ca880c9611906e0ca0c729fdf01c724501 Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Sat, 10 Sep 2005 00:26:32 -0700 Subject: [PATCH] drivers/char/lcd.c: misc_register() can fail Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/lcd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c index cf01a720eb2e..b77161146144 100644 --- a/drivers/char/lcd.c +++ b/drivers/char/lcd.c @@ -613,10 +613,15 @@ static struct miscdevice lcd_dev = { static int lcd_init(void) { + int ret; unsigned long data; pr_info("%s\n", LCD_DRIVER); - misc_register(&lcd_dev); + ret = misc_register(&lcd_dev); + if (ret) { + printk(KERN_WARNING LCD "Unable to register misc device.\n"); + return ret; + } /* Check region? Naaah! Just snarf it up. */ /* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ -- cgit v1.2.2 From 621a4d1a823e1ec631fbfbe6e53ad036e2d2abc6 Mon Sep 17 00:00:00 2001 From: Victor Fusco Date: Sat, 10 Sep 2005 00:26:38 -0700 Subject: [PATCH] char/n_tty: fix sparse warnings (__nocast type) Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco Signed-off-by: Domen Puncer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/n_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 09103b3d8f05..c9bdf544ed2c 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); -- cgit v1.2.2 From 887c27f369abc458556a5ce8ab22ddd498474307 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 10 Sep 2005 00:26:52 -0700 Subject: [PATCH] fix unusual placement of inline keyword in hpet With gcc -W: drivers/char/hpet.c:102: warning: `inline' is not at beginning of declaration drivers/char/hpet.c:109: warning: `inline' is not at beginning of declaration Signed-off-by: Jesper Juhl Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hpet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5fe8461271fc..de0379b6d502 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -100,14 +100,14 @@ static struct hpets *hpets; #endif #ifndef readq -static unsigned long long __inline readq(void __iomem *addr) +static inline unsigned long long readq(void __iomem *addr) { return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL); } #endif #ifndef writeq -static void __inline writeq(unsigned long long v, void __iomem *addr) +static inline void writeq(unsigned long long v, void __iomem *addr) { writel(v & 0xffffffff, addr); writel(v >> 32, addr + 4); -- cgit v1.2.2 From f9101210e7aa72daf92722d451a2f7e3af5f781f Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 10 Sep 2005 00:26:54 -0700 Subject: [PATCH] vfree and kfree cleanup in drivers/ This patch does a full cleanup of 'NULL checks before vfree', and a partial cleanup of calls to kfree for all of drivers/ - the kfree bit is partial in that I only did the files that also had vfree calls in them. The patch also gets rid of some redundant (void *) casts of pointers being passed to [vk]free, and a some tiny whitespace corrections also crept in. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/agp/backend.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 4d4e602fdc7e..82b43c541c8d 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -206,10 +206,9 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) bridge->driver->cleanup(); if (bridge->driver->free_gatt_table) bridge->driver->free_gatt_table(bridge); - if (bridge->key_list) { - vfree(bridge->key_list); - bridge->key_list = NULL; - } + + vfree(bridge->key_list); + bridge->key_list = NULL; if (bridge->driver->agp_destroy_page && bridge->driver->needs_scratch_page) -- cgit v1.2.2 From 96757701336365e30bea9fccdfac087338954e09 Mon Sep 17 00:00:00 2001 From: Marcelo Feitoza Parisi Date: Sat, 10 Sep 2005 00:26:57 -0700 Subject: [PATCH] drivers/char/lp.c : Use of the time_after() macro Use of the time_after() macro, defined at linux/jiffies.h, which deals with wrapping correctly and are nicer to read. Signed-off-by: Marcelo Feitoza Parisi Signed-off-by: Domen Puncer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/lp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 59eebe5a035f..2afb9038dbc5 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -128,6 +128,7 @@ #include #include #include +#include #include #undef LP_STATS @@ -307,7 +308,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, (LP_F(minor) & LP_ABORT)); #ifdef LP_STATS - if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) + if (time_after(jiffies, lp_table[minor].lastcall + LP_TIME(minor))) lp_table[minor].runchars = 0; lp_table[minor].lastcall = jiffies; -- cgit v1.2.2 From da4cd8dfe18ee901b880f94ca0fa79d5cc1cd0eb Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Sat, 10 Sep 2005 00:27:30 -0700 Subject: [PATCH] drivers/char: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ftape/lowlevel/fdc-io.c | 6 ++---- drivers/char/hw_random.c | 5 +---- drivers/char/ip2/i2lib.c | 6 ++---- drivers/char/ipmi/ipmi_si_intf.c | 18 ++++++------------ drivers/char/ipmi/ipmi_watchdog.c | 6 ++---- drivers/char/mxser.c | 12 ++++-------- 6 files changed, 17 insertions(+), 36 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 1704a2a57048..b2e0928e8428 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -387,10 +387,8 @@ int fdc_interrupt_wait(unsigned int time) set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && timeout) { - set_current_state(TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - } + while (!ft_interrupt_seen && timeout) + timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(¤t->sighand->siglock); current->blocked = old_sigmask; diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c index 3480535a09c5..6f673d2de0b1 100644 --- a/drivers/char/hw_random.c +++ b/drivers/char/hw_random.c @@ -513,10 +513,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, return ret ? : -EAGAIN; if(need_resched()) - { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } + schedule_timeout_interruptible(1); else udelay(200); /* FIXME: We could poll for 250uS ?? */ diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 82c5f30375ac..ba85eb1b6ec7 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -655,8 +655,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, timeout--; // So negative values == forever if (!in_interrupt()) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); // short nap + schedule_timeout_interruptible(1); // short nap } else { // we cannot sched/sleep in interrrupt silly return 0; @@ -1132,8 +1131,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) ip2trace (CHANN, ITRC_OUTPUT, 61, 0 ); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout_interruptible(2); if (signal_pending(current)) { break; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 278f84104996..b6e5cbfb09f8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1920,8 +1920,7 @@ static int try_get_dev_id(struct smi_info *smi_info) for (;;) { if (smi_result == SI_SM_CALL_WITH_DELAY) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); } @@ -2256,10 +2255,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (! new_smi->timer_stopped) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (!new_smi->timer_stopped) + schedule_timeout_uninterruptible(1); out_err: if (new_smi->intf) @@ -2379,17 +2376,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (! to_clean->timer_stopped) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (!to_clean->timer_stopped) + schedule_timeout_uninterruptible(1); /* Interrupts and timeouts are stopped, now make sure the interface is in a clean state. */ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } rv = ipmi_unregister_smi(to_clean->intf); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index e71aaae855ad..2da64bf7469c 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1037,10 +1037,8 @@ static __exit void ipmi_unregister_watchdog(void) /* Wait to make sure the message makes it out. The lower layer has pointers to our buffers, we want to make sure they are done before we release our memory. */ - while (atomic_read(&set_timeout_tofree)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (atomic_read(&set_timeout_tofree)) + schedule_timeout_uninterruptible(1); /* Disconnect from IPMI. */ rv = ipmi_destroy_user(watchdog_user); diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index d0ef1ae41298..45d012d85e8c 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1058,8 +1058,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) */ timeout = jiffies + HZ; while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(5); + schedule_timeout_interruptible(5); if (time_after(jiffies, timeout)) break; } @@ -1080,10 +1079,8 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) info->event = 0; info->tty = NULL; if (info->blocked_open) { - if (info->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); - } + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } @@ -1801,8 +1798,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + schedule_timeout_interruptible(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) -- cgit v1.2.2 From 180536f8274b76d69a589ab9af4b73d3b780e62f Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sat, 10 Sep 2005 20:53:57 +0200 Subject: [WATCHDOG] Kconfig+Makefile-clean2 Clean the Kconfig+Makefile according to a sorted list of the drivers of each architecture (and sub-architecture). Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 43 +++++++++++++++++++++--------------------- drivers/char/watchdog/Makefile | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index c3898afce3ae..f5af900704ac 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -84,6 +84,17 @@ config 977_WATCHDOG Not sure? It's safe to say N. +config IXP2000_WATCHDOG + tristate "IXP2000 Watchdog" + depends on WATCHDOG && ARCH_IXP2000 + help + Say Y here if to include support for the watchdog timer + in the Intel IXP2000(2400, 2800, 2850) network processors. + This driver can be built as a module by choosing M. The module + will be called ixp2000_wdt. + + Say N if you are unsure. + config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" depends on WATCHDOG && ARCH_IXP4XX @@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG Say N if you are unsure. -config IXP2000_WATCHDOG - tristate "IXP2000 Watchdog" - depends on WATCHDOG && ARCH_IXP2000 - help - Say Y here if to include support for the watchdog timer - in the Intel IXP2000(2400, 2800, 2850) network processors. - This driver can be built as a module by choosing M. The module - will be called ixp2000_wdt. - - Say N if you are unsure. - config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on WATCHDOG && ARCH_S3C2410 @@ -353,6 +353,17 @@ config BOOKE_WDT Please see Documentation/watchdog/watchdog-api.txt for more information. +# PPC64 Architecture + +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on WATCHDOG && PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # MIPS Architecture config INDYDOG @@ -421,16 +432,6 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. -# ppc64 RTAS watchdog -config WATCHDOG_RTAS - tristate "RTAS watchdog" - depends on WATCHDOG && PPC_RTAS - help - This driver adds watchdog support for the RTAS watchdog. - - To compile this driver as a module, choose M here. The module - will be called wdrtas. - # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index cfeac6f10137..fbd5cf63064b 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -50,10 +50,10 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o # PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o -obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # MIPS Architecture obj-$(CONFIG_INDYDOG) += indydog.o -- cgit v1.2.2 From 3be10211abcb631ba9631274d6cfe6e5b1e8559c Mon Sep 17 00:00:00 2001 From: James Chapman Date: Wed, 17 Aug 2005 09:01:33 +0200 Subject: [WATCHDOG] mv64x60_wdt.patch Add mv64x60 (Marvell Discovery) watchdog support. Signed-off-by: James Chapman Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 4 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/mv64x60_wdt.c | 252 ++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 drivers/char/watchdog/mv64x60_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index f5af900704ac..e8ad14d9a7fd 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -346,6 +346,10 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +config MV64X60_WDT + tristate "MV64X60 (Marvell Discovery) Watchdog Timer" + depends on WATCHDOG && MV64X60 + config BOOKE_WDT tristate "PowerPC Book-E Watchdog Timer" depends on WATCHDOG && (BOOKE || 4xx) diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index fbd5cf63064b..2373e1710ae7 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o # PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c new file mode 100644 index 000000000000..1436aea3b28f --- /dev/null +++ b/drivers/char/watchdog/mv64x60_wdt.c @@ -0,0 +1,252 @@ +/* + * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface + * + * Author: James Chapman + * + * Platform-specific setup code should configure the dog to generate + * interrupt or reset as required. This code only enables/disables + * and services the watchdog. + * + * Derived from mpc8xx_wdt.c, with the following copyright. + * + * 2002 (c) Florian Schirmer This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* MV64x60 WDC (config) register access definitions */ +#define MV64x60_WDC_CTL1_MASK (3 << 24) +#define MV64x60_WDC_CTL1(val) ((val & 3) << 24) +#define MV64x60_WDC_CTL2_MASK (3 << 26) +#define MV64x60_WDC_CTL2(val) ((val & 3) << 26) + +/* Flags bits */ +#define MV64x60_WDOG_FLAG_OPENED 0 +#define MV64x60_WDOG_FLAG_ENABLED 1 + +static unsigned long wdt_flags; +static int wdt_status; +static void __iomem *mv64x60_regs; +static int mv64x60_wdt_timeout; + +static void mv64x60_wdt_reg_write(u32 val) +{ + /* Allow write only to CTL1 / CTL2 fields, retaining values in + * other fields. + */ + u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC); + data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK); + data |= val; + writel(data, mv64x60_regs + MV64x60_WDT_WDC); +} + +static void mv64x60_wdt_service(void) +{ + /* Write 01 followed by 10 to CTL2 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02)); +} + +static void mv64x60_wdt_handler_disable(void) +{ + if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { + /* Write 01 followed by 10 to CTL1 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); + printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n"); + } +} + +static void mv64x60_wdt_handler_enable(void) +{ + if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { + /* Write 01 followed by 10 to CTL1 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); + printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n"); + } +} + +static int mv64x60_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) + return -EBUSY; + + mv64x60_wdt_service(); + mv64x60_wdt_handler_enable(); + + return 0; +} + +static int mv64x60_wdt_release(struct inode *inode, struct file *file) +{ + mv64x60_wdt_service(); + +#if !defined(CONFIG_WATCHDOG_NOWAYOUT) + mv64x60_wdt_handler_disable(); +#endif + + clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); + + return 0; +} + +static ssize_t mv64x60_wdt_write(struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + if (*ppos != file->f_pos) + return -ESPIPE; + + if (len) + mv64x60_wdt_service(); + + return len; +} + +static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int timeout; + static struct watchdog_info info = { + .options = WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "MV64x60 watchdog", + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(wdt_status, (int *)arg)) + return -EFAULT; + wdt_status &= ~WDIOF_KEEPALIVEPING; + break; + + case WDIOC_GETTEMP: + return -EOPNOTSUPP; + + case WDIOC_SETOPTIONS: + return -EOPNOTSUPP; + + case WDIOC_KEEPALIVE: + mv64x60_wdt_service(); + wdt_status |= WDIOF_KEEPALIVEPING; + break; + + case WDIOC_SETTIMEOUT: + return -EOPNOTSUPP; + + case WDIOC_GETTIMEOUT: + timeout = mv64x60_wdt_timeout * HZ; + if (put_user(timeout, (int *)arg)) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static struct file_operations mv64x60_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = mv64x60_wdt_write, + .ioctl = mv64x60_wdt_ioctl, + .open = mv64x60_wdt_open, + .release = mv64x60_wdt_release, +}; + +static struct miscdevice mv64x60_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mv64x60_wdt_fops, +}; + +static int __devinit mv64x60_wdt_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data; + int bus_clk = 133; + + mv64x60_wdt_timeout = 10; + if (pdata) { + mv64x60_wdt_timeout = pdata->timeout; + bus_clk = pdata->bus_clk; + } + + mv64x60_regs = mv64x60_get_bridge_vbase(); + + writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, + mv64x60_regs + MV64x60_WDT_WDC); + + return misc_register(&mv64x60_wdt_miscdev); +} + +static int __devexit mv64x60_wdt_remove(struct device *dev) +{ + misc_deregister(&mv64x60_wdt_miscdev); + + mv64x60_wdt_service(); + mv64x60_wdt_handler_disable(); + + return 0; +} + +static struct device_driver mv64x60_wdt_driver = { + .name = MV64x60_WDT_NAME, + .bus = &platform_bus_type, + .probe = mv64x60_wdt_probe, + .remove = __devexit_p(mv64x60_wdt_remove), +}; + +static struct platform_device *mv64x60_wdt_dev; + +static int __init mv64x60_wdt_init(void) +{ + int ret; + + printk(KERN_INFO "MV64x60 watchdog driver\n"); + + mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME, + -1, NULL, 0); + if (IS_ERR(mv64x60_wdt_dev)) { + ret = PTR_ERR(mv64x60_wdt_dev); + goto out; + } + + ret = driver_register(&mv64x60_wdt_driver); + out: + return ret; +} + +static void __exit mv64x60_wdt_exit(void) +{ + driver_unregister(&mv64x60_wdt_driver); + platform_device_unregister(mv64x60_wdt_dev); +} + +module_init(mv64x60_wdt_init); +module_exit(mv64x60_wdt_exit); + +MODULE_AUTHOR("James Chapman "); +MODULE_DESCRIPTION("MV64x60 watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.2 From cc90ef0f9b24d1b017c8cfa22db5195c17b5c968 Mon Sep 17 00:00:00 2001 From: David Hardeman Date: Wed, 17 Aug 2005 09:07:44 +0200 Subject: [WATCHDOG] i6300esb.patch I wrote earlier to the list[1] asking for a driver for the watchdog included in the 6300ESB chipset. I got a 2.4 driver via private email from Ross Biro which I've changed into what I hope resembles a 2.6 driver (which was done by looking a lot at the watchdog drivers already in the 2.6 tree). I've attached the result, and I'm hoping to get some feedback on the coding as a first step. I can't actually test it on the hardware right now as I won't have physical access until April. So my own tests have been limited to "compiles-without-warnings" and "can-be-insmodded-in-other-machine-without-oops". [1] http://marc.theaimsgroup.com/?l=linux-kernel&m=110711079825794&w=2 [2] http://marc.theaimsgroup.com/?l=linux-kernel&m=110711973917746&w=2 Signed-off-by: David Hardeman Signed-off-by: Andrew Morton Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 10 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/i6300esb.c | 508 +++++++++++++++++++++++++++++++++++++++ drivers/char/watchdog/i6300esb.h | 62 +++++ 4 files changed, 581 insertions(+) create mode 100644 drivers/char/watchdog/i6300esb.c create mode 100644 drivers/char/watchdog/i6300esb.h (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index e8ad14d9a7fd..742c9c5bb1a6 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -234,6 +234,16 @@ config WAFER_WDT To compile this driver as a module, choose M here: the module will be called wafer5823wdt. +config I6300ESB_WDT + tristate "Intel 6300ESB Timer/Watchdog" + depends on WATCHDOG && X86 && PCI + ---help--- + Hardware driver for the watchdog timer built into the Intel + 6300ESB controller hub. + + To compile this driver as a module, choose M here: the + module will be called i6300esb. + config I8XX_TCO tristate "Intel i8xx TCO Timer/Watchdog" depends on WATCHDOG && (X86 || IA64) && PCI diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 2373e1710ae7..2f45ba6a6d16 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o +obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c new file mode 100644 index 000000000000..87273839aead --- /dev/null +++ b/drivers/char/watchdog/i6300esb.c @@ -0,0 +1,508 @@ +/* + * i6300esb 0.03: Watchdog timer driver for Intel 6300ESB chipset + * + * (c) Copyright 2004 Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * based on i810-tco.c which is + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * which is in turn based on softdog.c by Alan Cox + * + * The timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 6300ESB chip : document number 300641-003 + * + * 2004YYZZ Ross Biro + * Initial version 0.01 + * 2004YYZZ Ross Biro + * Version 0.02 + * 20050210 David Härdeman + * Ported driver to kernel 2.6 + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "i6300esb.h" + +/* Module and version information */ +#define ESB_VERSION "0.03" +#define ESB_MODULE_NAME "i6300ESB timer" +#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION +#define PFX ESB_MODULE_NAME ": " + +/* internal variables */ +static void __iomem *BASEADDR; +static spinlock_t esb_lock; /* Guards the hardware */ +static unsigned long timer_alive; +static struct pci_dev *esb_pci; +static unsigned short triggered; /* The status of the watchdog upon boot */ +static char esb_expect_close; + +/* module parameters */ +#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1 (2 * 0x03ff)) + return -EINVAL; + + spin_lock(&esb_lock); + + /* We shift by 9, so if we are passed a value of 1 sec, + * val will be 1 << 9 = 512, then write that to two + * timers => 2 * 512 = 1024 (which is decremented at 1KHz) + */ + val = time << 9; + + /* Write timer 1 */ + esb_unlock_registers(); + writel(val, ESB_TIMER1_REG); + + /* Write timer 2 */ + esb_unlock_registers(); + writel(val, ESB_TIMER2_REG); + + /* Reload */ + esb_unlock_registers(); + writew(0x10, ESB_RELOAD_REG); + + /* FIXME: Do we need to flush everything out? */ + + /* Done */ + heartbeat = time; + spin_unlock(&esb_lock); + return 0; +} + +static int esb_timer_read (void) +{ + u32 count; + + /* This isn't documented, and doesn't take into + * acount which stage is running, but it looks + * like a 20 bit count down, so we might as well report it. + */ + pci_read_config_dword(esb_pci, 0x64, &count); + return (int)count; +} + +/* + * /dev/watchdog handling + */ + +static int esb_open (struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + esb_timer_keepalive (); + esb_timer_start (); + + return nonseekable_open(inode, file); +} + +static int esb_release (struct inode *inode, struct file *file) +{ + /* Shut off the timer. */ + if (esb_expect_close == 42) { + esb_timer_stop (); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + esb_timer_keepalive (); + } + clear_bit(0, &timer_alive); + esb_expect_close = 0; + return 0; +} + +static ssize_t esb_write (struct file *file, const char __user *data, + size_t len, loff_t * ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* note: just in case someone wrote the magic character + * five months ago... */ + esb_expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for (i = 0; i != len; i++) { + char c; + if(get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + esb_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + esb_timer_keepalive (); + } + return len; +} + +static int esb_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = ESB_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof (ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + return put_user (esb_timer_read(), p); + + case WDIOC_GETBOOTSTATUS: + return put_user (triggered, p); + + case WDIOC_KEEPALIVE: + esb_timer_keepalive (); + return 0; + + case WDIOC_SETOPTIONS: + { + if (get_user (new_options, p)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + esb_timer_stop (); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + esb_timer_keepalive (); + esb_timer_start (); + retval = 0; + } + + return retval; + } + + case WDIOC_SETTIMEOUT: + { + if (get_user(new_heartbeat, p)) + return -EFAULT; + + if (esb_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + + esb_timer_keepalive (); + /* Fall */ + } + + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + + default: + return -ENOIOCTLCMD; + } +} + +/* + * Notify system + */ + +static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) { + /* Turn the WDT off */ + esb_timer_stop (); + } + + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations esb_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = esb_write, + .ioctl = esb_ioctl, + .open = esb_open, + .release = esb_release, +}; + +static struct miscdevice esb_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &esb_fops, +}; + +static struct notifier_block esb_notifier = { + .notifier_call = esb_notify_sys, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id esb_pci_tbl[] = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE (pci, esb_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __init esb_getdevice (void) +{ + u8 val1; + unsigned short val2; + + struct pci_dev *dev = NULL; + /* + * Find the PCI device + */ + + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (pci_match_device(esb_pci_tbl, dev)) { + esb_pci = dev; + break; + } + } + + if (esb_pci) { + if (pci_enable_device(esb_pci)) { + printk (KERN_ERR PFX "failed to enable device\n"); + goto out; + } + + if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { + printk (KERN_ERR PFX "failed to request region\n"); + goto err_disable; + } + + BASEADDR = ioremap(pci_resource_start(esb_pci, 0), + pci_resource_len(esb_pci, 0)); + if (BASEADDR == NULL) { + /* Something's wrong here, BASEADDR has to be set */ + printk (KERN_ERR PFX "failed to get BASEADDR\n"); + goto err_release; + } + + /* + * The watchdog has two timers, it can be setup so that the + * expiry of timer1 results in an interrupt and the expiry of + * timer2 results in a reboot. We set it to not generate + * any interrupts as there is not much we can do with it + * right now. + * + * We also enable reboots and set the timer frequency to + * the PCI clock divided by 2^15 (approx 1KHz). + */ + pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003); + + /* Check that the WDT isn't already locked */ + pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); + if (val1 & ESB_WDT_LOCK) + printk (KERN_WARNING PFX "nowayout already set\n"); + + /* Set the timer to watchdog mode and disable it for now */ + pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); + + /* Check if the watchdog was previously triggered */ + esb_unlock_registers(); + val2 = readw(ESB_RELOAD_REG); + triggered = (val2 & (0x01 << 9) >> 9); + + /* Reset trigger flag and timers */ + esb_unlock_registers(); + writew((0x11 << 8), ESB_RELOAD_REG); + + /* Done */ + return 1; + +err_release: + pci_release_region(esb_pci, 0); +err_disable: + pci_disable_device(esb_pci); + } +out: + return 0; +} + +static int __init watchdog_init (void) +{ + int ret; + + spin_lock_init(&esb_lock); + + /* Check whether or not the hardware watchdog is there */ + if (!esb_getdevice () || esb_pci == NULL) + return -ENODEV; + + /* Check that the heartbeat value is within it's range ; if not reset to the default */ + if (esb_timer_set_heartbeat (heartbeat)) { + esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT); + printk(KERN_INFO PFX "heartbeat value must be 1, All Rights Reserved. + * http://www.kernelconcepts.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i8xx chipsets + * based on softdog.c by Alan Cox + * + * For history and the complete list of supported I/O Controller Hub's + * see i8xx_tco.c + */ + + +/* + * Some address definitions for the TCO + */ + +/* PCI configuration registers */ +#define ESB_CONFIG_REG 0x60 /* Config register */ +#define ESB_LOCK_REG 0x68 /* WDT lock register */ + +/* Memory mapped registers */ +#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */ +#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */ +#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */ +#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ + + +/* + * Some register bits + */ + +/* Lock register bits */ +#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ +#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ +#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ + +/* Config register bits */ +#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ +#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ +#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ + + +/* + * Some magic constants + */ +#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ +#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ -- cgit v1.2.2 From c69af038cad5e6ea86e927a17b70b49af1f7cbfa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 17 Aug 2005 09:09:13 +0200 Subject: [WATCHDOG] removes pci_find_device from i6300esb.c This patch changes pci_find_device to pci_get_device (encapsulated in for_each_pci_dev) in i6300esb watchdog card with appropriate adding pci_dev_put. Generated in 2.6.13-rc5-mm1 kernel version. Signed-off-by: Jiri Slaby Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/i6300esb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index 87273839aead..20ceb5fe28b6 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -368,12 +368,11 @@ static unsigned char __init esb_getdevice (void) * Find the PCI device */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) if (pci_match_device(esb_pci_tbl, dev)) { esb_pci = dev; break; } - } if (esb_pci) { if (pci_enable_device(esb_pci)) { @@ -430,6 +429,7 @@ err_release: pci_release_region(esb_pci, 0); err_disable: pci_disable_device(esb_pci); + pci_dev_put(esb_pci); } out: return 0; @@ -481,6 +481,7 @@ err_unmap: pci_release_region(esb_pci, 0); /* err_disable: */ pci_disable_device(esb_pci); + pci_dev_put(esb_pci); /* out: */ return ret; } @@ -497,6 +498,7 @@ static void __exit watchdog_cleanup (void) iounmap(BASEADDR); pci_release_region(esb_pci, 0); pci_disable_device(esb_pci); + pci_dev_put(esb_pci); } module_init(watchdog_init); -- cgit v1.2.2 From 28562af3d4b21d687dd57c44006aeeed1036c781 Mon Sep 17 00:00:00 2001 From: Naveen Gupta Date: Wed, 17 Aug 2005 09:10:10 +0200 Subject: [WATCHDOG] i6300esb.c-WDT_ENABLE-bug This patch sets the WDT_ENABLE bit of the Lock Register to enable the watchdog and WDT_LOCK bit only if nowayout is set. The old code always sets the WDT_LOCK bit of watchdog timer for Intel 6300ESB chipset. So, we end up locking the watchdog instead of enabling it. Signed-off-by: Naveen Gupta Signed-off-by: David Hardeman Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i6300esb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index 20ceb5fe28b6..f0e96fbd6489 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -97,7 +97,7 @@ static void esb_timer_start(void) u8 val; /* Enable or Enable + Lock? */ - val = 0x02 | nowayout ? 0x01 : 0x00; + val = 0x02 | (nowayout ? 0x01 : 0x00); pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); } -- cgit v1.2.2 From ce2f50b4ae71f700c7b4b0bf0ff11c328611dae8 Mon Sep 17 00:00:00 2001 From: Naveen Gupta Date: Wed, 17 Aug 2005 09:11:46 +0200 Subject: [WATCHDOG] i6300esb-set_correct_reload_register_bit This patch writes into bit 8 of the reload register to perform the correct 'Reload Sequence' instead of writing into bit 4 of Watchdog for Intel 6300ESB chipset. Signed-off-by: Naveen Gupta Signed-off-by: David Hardeman Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i6300esb.c | 6 +++--- drivers/char/watchdog/i6300esb.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index f0e96fbd6489..c04b246858ae 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -109,7 +109,7 @@ static int esb_timer_stop(void) spin_lock(&esb_lock); /* First, reset timers as suggested by the docs */ esb_unlock_registers(); - writew(0x10, ESB_RELOAD_REG); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); /* Then disable the WDT */ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0); pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val); @@ -123,7 +123,7 @@ static void esb_timer_keepalive(void) { spin_lock(&esb_lock); esb_unlock_registers(); - writew(0x10, ESB_RELOAD_REG); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); /* FIXME: Do we need to flush anything here? */ spin_unlock(&esb_lock); } @@ -153,7 +153,7 @@ static int esb_timer_set_heartbeat(int time) /* Reload */ esb_unlock_registers(); - writew(0x10, ESB_RELOAD_REG); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); /* FIXME: Do we need to flush everything out? */ diff --git a/drivers/char/watchdog/i6300esb.h b/drivers/char/watchdog/i6300esb.h index b5b47e3dda1a..20c923bbb1c9 100644 --- a/drivers/char/watchdog/i6300esb.h +++ b/drivers/char/watchdog/i6300esb.h @@ -54,6 +54,8 @@ #define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ #define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ +/* Reload register bits */ +#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ /* * Some magic constants -- cgit v1.2.2 From 811f999160487c586917937e95506cb8528472a3 Mon Sep 17 00:00:00 2001 From: Naveen Gupta Date: Sun, 21 Aug 2005 13:02:41 +0200 Subject: [WATCHDOG] i6300esb.c-pci_dev_put+nowayout-patch One pci_dev_put was misused (there was one case without putting the device). Changed nowayout according to other drivers. Signed-off-by: Jiri Slaby Signed-off-by: Naveen Gupta Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i6300esb.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index c04b246858ae..823924e4249b 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -69,11 +69,7 @@ static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1 Date: Mon, 22 Aug 2005 09:05:03 +0200 Subject: [WATCHDOG] i6300esb.c-2-bugs-little-cleanup.patch In i6300esb.c watchdog card driver were 2 bugs (misused pc_match_device and pci_dev_put wasn't called in one error case) and one little cleanup was done (long line was converted to a shorter one with using built-in macro). Signed-off-by: Jiri Slaby Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i6300esb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index 823924e4249b..575d6cd9e59a 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -345,7 +345,7 @@ static struct notifier_block esb_notifier = { * want to register another driver on the same PCI id. */ static struct pci_device_id esb_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE (pci, esb_pci_tbl); @@ -365,7 +365,7 @@ static unsigned char __init esb_getdevice (void) */ for_each_pci_dev(dev) { - if (pci_match_device(esb_pci_tbl, dev)) { + if (pci_match_id(esb_pci_tbl, dev)) { esb_pci = dev; break; } -- cgit v1.2.2 From abda5c8bd20d3bd42718b0438b8a81a73ffa4372 Mon Sep 17 00:00:00 2001 From: David Hardeman Date: Thu, 1 Sep 2005 22:34:53 +0200 Subject: [WATCHDOG] i6300.h-removal-patch the attached patch moves the content of drivers/char/watchdog/i6300.h into drivers/char/watchdog/i6300.c, since it is the only file using the defines there is no real reason to have a separate header. Also cleaned up the comments a bit and added myself to the copyright holders. Signed-off-by: David Hardeman Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i6300esb.c | 40 ++++++++++++++++++------- drivers/char/watchdog/i6300esb.h | 64 ---------------------------------------- 2 files changed, 30 insertions(+), 74 deletions(-) delete mode 100644 drivers/char/watchdog/i6300esb.h (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index 575d6cd9e59a..93785f13242e 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -1,20 +1,15 @@ /* - * i6300esb 0.03: Watchdog timer driver for Intel 6300ESB chipset + * i6300esb: Watchdog timer driver for Intel 6300ESB chipset * * (c) Copyright 2004 Google Inc. + * (c) Copyright 2005 David Härdeman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * based on i810-tco.c which is - * - * (c) Copyright 2000 kernel concepts - * developed for - * Jentro AG, Haar/Munich (Germany) - * - * which is in turn based on softdog.c by Alan Cox + * based on i810-tco.c which is in turn based on softdog.c * * The timer is implemented in the following I/O controller hubs: * (See the intel documentation on http://developer.intel.com.) @@ -47,14 +42,39 @@ #include #include -#include "i6300esb.h" - /* Module and version information */ #define ESB_VERSION "0.03" #define ESB_MODULE_NAME "i6300ESB timer" #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION #define PFX ESB_MODULE_NAME ": " +/* PCI configuration registers */ +#define ESB_CONFIG_REG 0x60 /* Config register */ +#define ESB_LOCK_REG 0x68 /* WDT lock register */ + +/* Memory mapped registers */ +#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */ +#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */ +#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */ +#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ + +/* Lock register bits */ +#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ +#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ +#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ + +/* Config register bits */ +#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ +#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ +#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ + +/* Reload register bits */ +#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ + +/* Magic constants */ +#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ +#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ + /* internal variables */ static void __iomem *BASEADDR; static spinlock_t esb_lock; /* Guards the hardware */ diff --git a/drivers/char/watchdog/i6300esb.h b/drivers/char/watchdog/i6300esb.h deleted file mode 100644 index 20c923bbb1c9..000000000000 --- a/drivers/char/watchdog/i6300esb.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * i6300esb: Watchdog timer driver for Intel 6300ESB chipset - * - * (c) Copyright 2000 kernel concepts , All Rights Reserved. - * http://www.kernelconcepts.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither kernel concepts nor Nils Faerber admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 2000 kernel concepts - * developed for - * Jentro AG, Haar/Munich (Germany) - * - * TCO timer driver for i8xx chipsets - * based on softdog.c by Alan Cox - * - * For history and the complete list of supported I/O Controller Hub's - * see i8xx_tco.c - */ - - -/* - * Some address definitions for the TCO - */ - -/* PCI configuration registers */ -#define ESB_CONFIG_REG 0x60 /* Config register */ -#define ESB_LOCK_REG 0x68 /* WDT lock register */ - -/* Memory mapped registers */ -#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */ -#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */ -#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */ -#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ - - -/* - * Some register bits - */ - -/* Lock register bits */ -#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ -#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ -#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ - -/* Config register bits */ -#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ -#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ -#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ - -/* Reload register bits */ -#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ - -/* - * Some magic constants - */ -#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ -#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ -- cgit v1.2.2 From d532134d4cad1da0ad0efc1d5db9f74475df80c6 Mon Sep 17 00:00:00 2001 From: Andrey Panin Date: Fri, 19 Aug 2005 23:15:11 +0200 Subject: [WATCHDOG] driver-for-ibm-automatic-server-restart-watchdog.patch This patch adds driver for IBM Automatic Server Restart watchdog hardware found in some IBM eServer xSeries machines. This driver is based on the ugly driver provided by IBM. Driver was tested on IBM eServer 226. Signed-off-by: Andrey Panin Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/Kconfig | 10 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/ibmasr.c | 407 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 drivers/char/watchdog/ibmasr.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 742c9c5bb1a6..5f93452188bd 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -224,6 +224,16 @@ config IB700_WDT Most people will say N. +config IBMASR + tristate "IBM Automatic Server Restart" + depends on WATCHDOG && X86 + help + This is the driver for the IBM Automatic Server Restart watchdog + timer builtin into some eServer xSeries machines. + + To compile this driver as a module, choose M here: the + module will be called ibmasr. + config WAFER_WDT tristate "ICP Wafer 5823 Single Board Computer Watchdog" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 2f45ba6a6d16..f90a802a7d3d 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o +obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c new file mode 100644 index 000000000000..a32c073d29bc --- /dev/null +++ b/drivers/char/watchdog/ibmasr.c @@ -0,0 +1,407 @@ +/* + * IBM Automatic Server Restart driver. + * + * Copyright (c) 2005 Andrey Panin + * + * Based on driver written by Pete Reynolds. + * Copyright (c) IBM Corporation, 1998-2004. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +enum { + ASMTYPE_UNKNOWN, + ASMTYPE_TOPAZ, + ASMTYPE_JASPER, + ASMTYPE_PEARL, + ASMTYPE_JUNIPER, + ASMTYPE_SPRUCE, +}; + +#define PFX "ibmasr: " + +#define TOPAZ_ASR_REG_OFFSET 4 +#define TOPAZ_ASR_TOGGLE 0x40 +#define TOPAZ_ASR_DISABLE 0x80 + +/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */ +#define PEARL_BASE 0xe04 +#define PEARL_WRITE 0xe06 +#define PEARL_READ 0xe07 + +#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */ +#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */ + +/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */ +#define JASPER_ASR_REG_OFFSET 0x38 + +#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */ +#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ + +#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */ +#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */ +#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ + +#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */ +#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */ +#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */ + + +static int nowayout = WATCHDOG_NOWAYOUT; + +static unsigned long asr_is_open; +static char asr_expect_close; + +static unsigned int asr_type, asr_base, asr_length; +static unsigned int asr_read_addr, asr_write_addr; +static unsigned char asr_toggle_mask, asr_disable_mask; + +static void asr_toggle(void) +{ + unsigned char reg = inb(asr_read_addr); + + outb(reg & ~asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg | asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg & ~asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); +} + +static void asr_enable(void) +{ + unsigned char reg; + + if (asr_type == ASMTYPE_TOPAZ) { + /* asr_write_addr == asr_read_addr */ + reg = inb(asr_read_addr); + outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE), + asr_read_addr); + } else { + /* + * First make sure the hardware timer is reset by toggling + * ASR hardware timer line. + */ + asr_toggle(); + + reg = inb(asr_read_addr); + outb(reg & ~asr_disable_mask, asr_write_addr); + } + reg = inb(asr_read_addr); +} + +static void asr_disable(void) +{ + unsigned char reg = inb(asr_read_addr); + + if (asr_type == ASMTYPE_TOPAZ) + /* asr_write_addr == asr_read_addr */ + outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE, + asr_read_addr); + else { + outb(reg | asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg | asr_disable_mask, asr_write_addr); + } + reg = inb(asr_read_addr); +} + +static int __init asr_get_base_address(void) +{ + unsigned char low, high; + const char *type = ""; + + asr_length = 1; + + switch (asr_type) { + case ASMTYPE_TOPAZ: + /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ + outb(0x07, 0x2e); + outb(0x07, 0x2f); + + /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */ + outb(0x60, 0x2e); + high = inb(0x2f); + + /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */ + outb(0x61, 0x2e); + low = inb(0x2f); + + asr_base = (high << 16) | low; + asr_read_addr = asr_write_addr = + asr_base + TOPAZ_ASR_REG_OFFSET; + asr_length = 5; + + break; + + case ASMTYPE_JASPER: + type = "Jaspers "; + + /* FIXME: need to use pci_config_lock here, but it's not exported */ + +/* spin_lock_irqsave(&pci_config_lock, flags);*/ + + /* Select the SuperIO chip in the PCI I/O port register */ + outl(0x8000f858, 0xcf8); + + /* + * Read the base address for the SuperIO chip. + * Only the lower 16 bits are valid, but the address is word + * aligned so the last bit must be masked off. + */ + asr_base = inl(0xcfc) & 0xfffe; + +/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ + + asr_read_addr = asr_write_addr = + asr_base + JASPER_ASR_REG_OFFSET; + asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; + asr_disable_mask = JASPER_ASR_DISABLE_MASK; + asr_length = JASPER_ASR_REG_OFFSET + 1; + + break; + + case ASMTYPE_PEARL: + type = "Pearls "; + asr_base = PEARL_BASE; + asr_read_addr = PEARL_READ; + asr_write_addr = PEARL_WRITE; + asr_toggle_mask = PEARL_ASR_TOGGLE_MASK; + asr_disable_mask = PEARL_ASR_DISABLE_MASK; + asr_length = 4; + break; + + case ASMTYPE_JUNIPER: + type = "Junipers "; + asr_base = JUNIPER_BASE_ADDRESS; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK; + asr_disable_mask = JUNIPER_ASR_DISABLE_MASK; + break; + + case ASMTYPE_SPRUCE: + type = "Spruce's "; + asr_base = SPRUCE_BASE_ADDRESS; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK; + asr_disable_mask = SPRUCE_ASR_DISABLE_MASK; + break; + } + + if (!request_region(asr_base, asr_length, "ibmasr")) { + printk(KERN_ERR PFX "address %#x already in use\n", + asr_base); + return -EBUSY; + } + + printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base); + + return 0; +} + + +static ssize_t asr_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + if (count) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + asr_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + asr_expect_close = 42; + } + } + asr_toggle(); + } + return count; +} + +static int asr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static const struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, + .identity = "IBM ASR" + }; + void __user *argp = (void __user *)arg; + int __user *p = argp; + int heartbeat; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? + -EFAULT : 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_KEEPALIVE: + asr_toggle(); + return 0; + + + case WDIOC_SETTIMEOUT: + if (get_user(heartbeat, p)) + return -EFAULT; + /* Fall */ + + case WDIOC_GETTIMEOUT: + heartbeat = 256; + return put_user(heartbeat, p); + + case WDIOC_SETOPTIONS: { + int new_options, retval = -EINVAL; + + if (get_user(new_options, p)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + asr_disable(); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + asr_enable(); + asr_toggle(); + retval = 0; + } + + return retval; + } + } + + return -ENOIOCTLCMD; +} + +static int asr_open(struct inode *inode, struct file *file) +{ + if(test_and_set_bit(0, &asr_is_open)) + return -EBUSY; + + asr_toggle(); + asr_enable(); + + return nonseekable_open(inode, file); +} + +static int asr_release(struct inode *inode, struct file *file) +{ + if (asr_expect_close == 42) + asr_disable(); + else { + printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); + asr_toggle(); + } + clear_bit(0, &asr_is_open); + asr_expect_close = 0; + return 0; +} + +static struct file_operations asr_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = asr_write, + .ioctl = asr_ioctl, + .open = asr_open, + .release = asr_release, +}; + +static struct miscdevice asr_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &asr_fops, +}; + + +struct ibmasr_id { + const char *desc; + int type; +}; + +static struct ibmasr_id __initdata ibmasr_id_table[] = { + { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ }, + { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL }, + { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER }, + { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER }, + { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE }, + { NULL } +}; + +static int __init ibmasr_init(void) +{ + struct ibmasr_id *id; + int rc; + + for (id = ibmasr_id_table; id->desc; id++) { + if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) { + asr_type = id->type; + break; + } + } + + if (!asr_type) + return -ENODEV; + + rc = misc_register(&asr_miscdev); + if (rc < 0) { + printk(KERN_ERR PFX "failed to register misc device\n"); + return rc; + } + + rc = asr_get_base_address(); + if (rc) { + misc_deregister(&asr_miscdev); + return rc; + } + + return 0; +} + +static void __exit ibmasr_exit(void) +{ + if (!nowayout) + asr_disable(); + + misc_deregister(&asr_miscdev); + + release_region(asr_base, asr_length); +} + +module_init(ibmasr_init); +module_exit(ibmasr_exit); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); +MODULE_AUTHOR("Andrey Panin"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.2 From cd7b80079b120406de902ee1eaa2dbdaa867dada Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 19 Aug 2005 23:21:01 +0200 Subject: [WATCHDOG] driver-for-ibm-automatic-server-restart-watchdog-fix Add fixed timeout comments Cc: Andrey Panin Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/ibmasr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index a32c073d29bc..4f90015be7dd 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c @@ -267,7 +267,10 @@ static int asr_ioctl(struct inode *inode, struct file *file, asr_toggle(); return 0; - + /* + * The hardware has a fixed timeout value, so WDIOC_SETTIMEOUT + * is a noop and WDIOC_GETTIMEOUT always returns 256. + */ case WDIOC_SETTIMEOUT: if (get_user(heartbeat, p)) return -EFAULT; -- cgit v1.2.2 From 266aa1c4b3d004123d330eb412cc26a3d10f9029 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 19 Aug 2005 23:31:41 +0200 Subject: [WATCHDOG] driver-for-ibm-automatic-server-restart-watchdog-fix2.patch The device/watchdog has a fixed timeout/heartbeat. So we don't support the WDIOC_SETTIMEOUT ioctl call and we also may not set the WDIOF_SETTIMEOUT flag. Cc: Andrey Panin Cc: Andrew Morton Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/ibmasr.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index 4f90015be7dd..294c474ae485 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c @@ -246,7 +246,7 @@ static int asr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static const struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "IBM ASR" }; @@ -268,14 +268,9 @@ static int asr_ioctl(struct inode *inode, struct file *file, return 0; /* - * The hardware has a fixed timeout value, so WDIOC_SETTIMEOUT - * is a noop and WDIOC_GETTIMEOUT always returns 256. + * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT + * and WDIOC_GETTIMEOUT always returns 256. */ - case WDIOC_SETTIMEOUT: - if (get_user(heartbeat, p)) - return -EFAULT; - /* Fall */ - case WDIOC_GETTIMEOUT: heartbeat = 256; return put_user(heartbeat, p); -- cgit v1.2.2 From 3809ad384af43ad883f47ee22a6faa33cedd61bc Mon Sep 17 00:00:00 2001 From: "Ian E. Morgan" Date: Thu, 1 Sep 2005 22:49:17 +0200 Subject: [WATCHDOG] New SBC8360 watchdog driver (revised) New SBC8360 watchdog driver patch From: Ian E. Morgan Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/Kconfig | 13 ++ drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/sbc8360.c | 419 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 drivers/char/watchdog/sbc8360.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 5f93452188bd..e18a4102163f 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -309,6 +309,19 @@ config 60XX_WDT You can compile this driver directly into the kernel, or use it as a module. The module will be called sbc60xxwdt. +config SBC8360_WDT + tristate "SBC8360 Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + + This is the driver for the hardware watchdog on the SBC8360 Single + Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com). + + To compile this driver as a module, choose M here: the + module will be called sbc8360.ko. + + Most people will say N. + config CPU5_WDT tristate "SMA CPU5 Watchdog" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index f90a802a7d3d..c7f74026bd3c 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c new file mode 100644 index 000000000000..06daf426d5b6 --- /dev/null +++ b/drivers/char/watchdog/sbc8360.c @@ -0,0 +1,419 @@ +/* + * SBC8360 Watchdog driver + * + * (c) Copyright 2005 Webcon, Inc. + * + * Based on ib700wdt.c, which is based on advantechwdt.c which is based + * on acquirewdt.c which is based on wdt.c. + * + * (c) Copyright 2001 Charles Howes + * + * Based on advantechwdt.c which is based on acquirewdt.c which + * is based on wdt.c. + * + * (c) Copyright 2000-2001 Marek Michalkiewicz + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static unsigned long sbc8360_is_open; +static spinlock_t sbc8360_lock; +static char expect_close; + +#define PFX "sbc8360: " + +/* + * + * Watchdog Timer Configuration + * + * The function of the watchdog timer is to reset the system automatically + * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer + * and allow the system to reset, write appropriate values from the table + * below to I/O port 0120H and 0121H. To disable the timer, write a zero + * value to I/O port 0121H for the system to stop the watchdog function. + * + * The following describes how the timer should be programmed (according to + * the vendor documentation) + * + * Enabling Watchdog: + * MOV AX,000AH (enable, phase I) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000BH (enable, phase II) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000nH (set multiplier n, from 1-4) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000mH (set base timer m, from 0-F) + * MOV DX,0121H + * OUT DX,AX + * + * Reset timer: + * MOV AX,000mH (same as set base timer, above) + * MOV DX,0121H + * OUT DX,AX + * + * Disabling Watchdog: + * MOV AX,0000H (a zero value) + * MOV DX,0120H + * OUT DX,AX + * + * Watchdog timeout configuration values: + * N + * M | 1 2 3 4 + * --|---------------------------------- + * 0 | 0.5s 5s 50s 100s + * 1 | 1s 10s 100s 200s + * 2 | 1.5s 15s 150s 300s + * 3 | 2s 20s 200s 400s + * 4 | 2.5s 25s 250s 500s + * 5 | 3s 30s 300s 600s + * 6 | 3.5s 35s 350s 700s + * 7 | 4s 40s 400s 800s + * 8 | 4.5s 45s 450s 900s + * 9 | 5s 50s 500s 1000s + * A | 5.5s 55s 550s 1100s + * B | 6s 60s 600s 1200s + * C | 6.5s 65s 650s 1300s + * D | 7s 70s 700s 1400s + * E | 7.5s 75s 750s 1500s + * F | 8s 80s 800s 1600s + * + * Another way to say the same things is: + * For N=1, Timeout = (M+1) * 0.5s + * For N=2, Timeout = (M+1) * 5s + * For N=3, Timeout = (M+1) * 50s + * For N=4, Timeout = (M+1) * 100s + * + */ + +static int wd_times[64][2] = { + {0, 1}, /* 0 = 0.5s */ + {1, 1}, /* 1 = 1s */ + {2, 1}, /* 2 = 1.5s */ + {3, 1}, /* 3 = 2s */ + {4, 1}, /* 4 = 2.5s */ + {5, 1}, /* 5 = 3s */ + {6, 1}, /* 6 = 3.5s */ + {7, 1}, /* 7 = 4s */ + {8, 1}, /* 8 = 4.5s */ + {9, 1}, /* 9 = 5s */ + {0xA, 1}, /* 10 = 5.5s */ + {0xB, 1}, /* 11 = 6s */ + {0xC, 1}, /* 12 = 6.5s */ + {0xD, 1}, /* 13 = 7s */ + {0xE, 1}, /* 14 = 7.5s */ + {0xF, 1}, /* 15 = 8s */ + {0, 2}, /* 16 = 5s */ + {1, 2}, /* 17 = 10s */ + {2, 2}, /* 18 = 15s */ + {3, 2}, /* 19 = 20s */ + {4, 2}, /* 20 = 25s */ + {5, 2}, /* 21 = 30s */ + {6, 2}, /* 22 = 35s */ + {7, 2}, /* 23 = 40s */ + {8, 2}, /* 24 = 45s */ + {9, 2}, /* 25 = 50s */ + {0xA, 2}, /* 26 = 55s */ + {0xB, 2}, /* 27 = 60s */ + {0xC, 2}, /* 28 = 65s */ + {0xD, 2}, /* 29 = 70s */ + {0xE, 2}, /* 30 = 75s */ + {0xF, 2}, /* 31 = 80s */ + {0, 3}, /* 32 = 50s */ + {1, 3}, /* 33 = 100s */ + {2, 3}, /* 34 = 150s */ + {3, 3}, /* 35 = 200s */ + {4, 3}, /* 36 = 250s */ + {5, 3}, /* 37 = 300s */ + {6, 3}, /* 38 = 350s */ + {7, 3}, /* 39 = 400s */ + {8, 3}, /* 40 = 450s */ + {9, 3}, /* 41 = 500s */ + {0xA, 3}, /* 42 = 550s */ + {0xB, 3}, /* 43 = 600s */ + {0xC, 3}, /* 44 = 650s */ + {0xD, 3}, /* 45 = 700s */ + {0xE, 3}, /* 46 = 750s */ + {0xF, 3}, /* 47 = 800s */ + {0, 4}, /* 48 = 100s */ + {1, 4}, /* 49 = 200s */ + {2, 4}, /* 50 = 300s */ + {3, 4}, /* 51 = 400s */ + {4, 4}, /* 52 = 500s */ + {5, 4}, /* 53 = 600s */ + {6, 4}, /* 54 = 700s */ + {7, 4}, /* 55 = 800s */ + {8, 4}, /* 56 = 900s */ + {9, 4}, /* 57 = 1000s */ + {0xA, 4}, /* 58 = 1100s */ + {0xB, 4}, /* 59 = 1200s */ + {0xC, 4}, /* 60 = 1300s */ + {0xD, 4}, /* 61 = 1400s */ + {0xE, 4}, /* 62 = 1500s */ + {0xF, 4} /* 63 = 1600s */ +}; + +#define SBC8360_ENABLE 0x120 +#define SBC8360_BASETIME 0x121 + +static int timeout = 27; +static int wd_margin = 0xB; +static int wd_multiplier = 2; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +module_param(timeout, int, 27); +MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + +/* Activate and pre-configure watchdog */ +static void sbc8360_activate(void) +{ + /* Enable the watchdog */ + outb(0x0A, SBC8360_ENABLE); + msleep_interruptible(100); + outb(0x0B, SBC8360_ENABLE); + msleep_interruptible(100); + /* Set timeout multiplier */ + outb(wd_multiplier, SBC8360_ENABLE); + msleep_interruptible(100); + /* Nothing happens until first sbc8360_ping() */ +} + +/* Kernel pings watchdog */ +static void sbc8360_ping(void) +{ + /* Write the base timer register */ + outb(wd_margin, SBC8360_BASETIME); +} + +/* Userspace pings kernel driver, or requests clean close */ +static ssize_t sbc8360_write(struct file *file, const char __user * buf, + size_t count, loff_t * ppos) +{ + if (count) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + sbc8360_ping(); + } + return count; +} + +static int sbc8360_open(struct inode *inode, struct file *file) +{ + spin_lock(&sbc8360_lock); + if (test_and_set_bit(0, &sbc8360_is_open)) { + spin_unlock(&sbc8360_lock); + return -EBUSY; + } + if (nowayout) + __module_get(THIS_MODULE); + + /* Activate and ping once to start the countdown */ + spin_unlock(&sbc8360_lock); + sbc8360_activate(); + sbc8360_ping(); + return nonseekable_open(inode, file); +} + +static int sbc8360_close(struct inode *inode, struct file *file) +{ + spin_lock(&sbc8360_lock); + if (expect_close == 42) + outb(0, SBC8360_ENABLE); + else + printk(KERN_CRIT PFX + "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); + + clear_bit(0, &sbc8360_is_open); + expect_close = 0; + spin_unlock(&sbc8360_lock); + return 0; +} + +/* + * Notifier for system down + */ + +static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Disable the SBC8360 Watchdog */ + outb(0, SBC8360_ENABLE); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations sbc8360_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = sbc8360_write, + .open = sbc8360_open, + .release = sbc8360_close, +}; + +static struct miscdevice sbc8360_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sbc8360_fops, +}; + +/* + * The SBC8360 needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block sbc8360_notifier = { + .notifier_call = sbc8360_notify_sys, +}; + +static int __init sbc8360_init(void) +{ + int res; + unsigned long int mseconds = 60000; + + spin_lock_init(&sbc8360_lock); + res = misc_register(&sbc8360_miscdev); + if (res) { + printk(KERN_ERR PFX "failed to register misc device\n"); + goto out_nomisc; + } + + if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) { + printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n", + SBC8360_ENABLE); + res = -EIO; + goto out_noenablereg; + } + if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) { + printk(KERN_ERR PFX + "BASETIME method I/O %X is not available.\n", + SBC8360_BASETIME); + res = -EIO; + goto out_nobasetimereg; + } + + res = register_reboot_notifier(&sbc8360_notifier); + if (res) { + printk(KERN_ERR PFX "Failed to register reboot notifier.\n"); + goto out_noreboot; + } + + if (timeout < 0 || timeout > 63) { + printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); + res = -EINVAL; + goto out_noreboot; + } + + wd_margin = wd_times[timeout][0]; + wd_multiplier = wd_times[timeout][1]; + + if (wd_multiplier == 1) + mseconds = (wd_margin + 1) * 500; + else if (wd_multiplier == 2) + mseconds = (wd_margin + 1) * 5000; + else if (wd_multiplier == 3) + mseconds = (wd_margin + 1) * 50000; + else if (wd_multiplier == 4) + mseconds = (wd_margin + 1) * 100000; + + /* My kingdom for the ability to print "0.5 seconds" in the kernel! */ + printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds); + + return 0; + + out_noreboot: + release_region(SBC8360_ENABLE, 1); + release_region(SBC8360_BASETIME, 1); + out_noenablereg: + out_nobasetimereg: + misc_deregister(&sbc8360_miscdev); + out_nomisc: + return res; +} + +static void __exit sbc8360_exit(void) +{ + misc_deregister(&sbc8360_miscdev); + unregister_reboot_notifier(&sbc8360_notifier); + release_region(SBC8360_ENABLE, 1); + release_region(SBC8360_BASETIME, 1); +} + +module_init(sbc8360_init); +module_exit(sbc8360_exit); + +MODULE_AUTHOR("Ian E. Morgan "); +MODULE_DESCRIPTION("SBC8360 watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +/* end of sbc8360.c */ -- cgit v1.2.2 From b4cc4aa24ca47b6a2bdb9029020502cff7c6e774 Mon Sep 17 00:00:00 2001 From: Jose Miguel Goncalves Date: Tue, 6 Sep 2005 17:05:30 -0700 Subject: [WATCHDOG] w83977f-watchdog-driver.patch In a project for my company I've needed to use the watchdog device in a PCM-5335 SBC from AAEON. The watchdog timer is from a Winbond's SuperIO chip, the W83977F. I've made this driver based on two others already on the kernel tree, the w83877f_wdt and the wdt977. Signed-off-by: Jose Goncalves Signed-off-by: Andrew Morton Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 13 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/w83977f_wdt.c | 548 ++++++++++++++++++++++++++++++++++++ 3 files changed, 562 insertions(+) create mode 100644 drivers/char/watchdog/w83977f_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index e18a4102163f..2d78962b4de7 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -360,6 +360,19 @@ config W83877F_WDT Most people will say N. +config W83977F_WDT + tristate "W83977F (PCM-5335) Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + This is the driver for the hardware watchdog on the W83977F I/O chip + as used in AAEON's PCM-5335 SBC (and likely others). This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + To compile this driver as a module, choose M here: the + module will be called w83977f_wdt. + config MACHZ_WDT tristate "ZF MachZ Watchdog" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index c7f74026bd3c..3ca8a12a1510 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o # PowerPC Architecture diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c new file mode 100644 index 000000000000..366d47bca16e --- /dev/null +++ b/drivers/char/watchdog/w83977f_wdt.c @@ -0,0 +1,548 @@ +/* + * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip + * + * (c) Copyright 2005 Jose Goncalves + * + * Based on w83877f_wdt.c by Scott Jennings, + * and wdt977.c by Woody Suwalski + * + * ----------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define WATCHDOG_VERSION "1.00" +#define WATCHDOG_NAME "W83977F WDT" +#define PFX WATCHDOG_NAME ": " +#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" + +#define IO_INDEX_PORT 0x3F0 +#define IO_DATA_PORT (IO_INDEX_PORT+1) + +#define UNLOCK_DATA 0x87 +#define LOCK_DATA 0xAA +#define DEVICE_REGISTER 0x07 + +#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */ + +static int timeout = DEFAULT_TIMEOUT; +static int timeoutW; /* timeout in watchdog counter units */ +static unsigned long timer_alive; +static int testmode; +static char expect_close; +static spinlock_t spinlock; + +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); +module_param(testmode, int, 0); +MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Start the watchdog + */ + +static int wdt_start(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* + * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. + * F2 has the timeout in watchdog counter units. + * F3 is set to enable watchdog LED blink at timeout. + * F4 is used to just clear the TIMEOUT'ed state (bit 0). + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(timeoutW,IO_DATA_PORT); + outb_p(0xF3,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + + /* Set device Aux2 active */ + outb_p(0x30,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* + * Select device Aux1 (dev=7) to set GP16 as the watchdog output + * (in reg E6) and GP13 as the watchdog LED output (in reg E3). + * Map GP16 at pin 119. + * In test mode watch the bit 0 on F4 to indicate "triggered" or + * check watchdog LED on SBC. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x07,IO_DATA_PORT); + if (!testmode) + { + unsigned pin_map; + + outb_p(0xE6,IO_INDEX_PORT); + outb_p(0x0A,IO_DATA_PORT); + outb_p(0x2C,IO_INDEX_PORT); + pin_map = inb_p(IO_DATA_PORT); + pin_map |= 0x10; + pin_map &= ~(0x20); + outb_p(0x2C,IO_INDEX_PORT); + outb_p(pin_map,IO_DATA_PORT); + } + outb_p(0xE3,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + + /* Set device Aux1 active */ + outb_p(0x30,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + printk(KERN_INFO PFX "activated.\n"); + + return 0; +} + +/* + * Stop the watchdog + */ + +static int wdt_stop(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* + * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. + * F2 is reset to its default value (watchdog timer disabled). + * F3 is reset to its default state. + * F4 clears the TIMEOUT'ed state (bit 0) - back to default. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(0xFF,IO_DATA_PORT); + outb_p(0xF3,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + + /* + * Select device Aux1 (dev=7) to set GP16 (in reg E6) and + * Gp13 (in reg E3) as inputs. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x07,IO_DATA_PORT); + if (!testmode) + { + outb_p(0xE6,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + } + outb_p(0xE3,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + printk(KERN_INFO PFX "shutdown.\n"); + + return 0; +} + +/* + * Send a keepalive ping to the watchdog + * This is done by simply re-writing the timeout to reg. 0xF2 + */ + +static int wdt_keepalive(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* Select device Aux2 (device=8) to kick watchdog reg F2 */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(timeoutW,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + return 0; +} + +/* + * Set the watchdog timeout value + */ + +static int wdt_set_timeout(int t) +{ + int tmrval; + + /* + * Convert seconds to watchdog counter time units, rounding up. + * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup + * value. This information is supplied in the PCM-5335 manual and was + * checked by me on a real board. This is a bit strange because W83977f + * datasheet says counter unit is in minutes! + */ + if (t < 15) + return -EINVAL; + + tmrval = ((t + 15) + 29) / 30; + + if (tmrval > 255) + return -EINVAL; + + /* + * timeout is the timeout in seconds, + * timeoutW is the timeout in watchdog counter units. + */ + timeoutW = tmrval; + timeout = (timeoutW * 30) - 15; + return 0; +} + +/* + * Get the watchdog status + */ + +static int wdt_get_status(int *status) +{ + int new_status; + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* Select device Aux2 (device=8) to read watchdog reg F4 */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + new_status = inb_p(IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + *status = 0; + if (new_status & 1) + *status |= WDIOF_CARDRESET; + + return 0; +} + + +/* + * /dev/watchdog handling + */ + +static int wdt_open(struct inode *inode, struct file *file) +{ + /* If the watchdog is alive we don't need to start it again */ + if( test_and_set_bit(0, &timer_alive) ) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + wdt_start(); + return nonseekable_open(inode, file); +} + +static int wdt_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (expect_close == 42) + { + wdt_stop(); + clear_bit(0, &timer_alive); + } else { + wdt_keepalive(); + printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); + } + expect_close = 0; + return 0; +} + +/* + * wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if(count) + { + if (!nowayout) + { + size_t ofs; + + /* note: just in case someone wrote the magic character long ago */ + expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if (get_user(c, buf + ofs)) + return -EFAULT; + if (c == 'V') { + expect_close = 42; + } + } + } + + /* someone wrote to us, we should restart timer */ + wdt_keepalive(); + } + return count; +} + +/* + * wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = WATCHDOG_NAME, +}; + +static int wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int status; + int new_options, retval = -EINVAL; + int new_timeout; + union { + struct watchdog_info __user *ident; + int __user *i; + } uarg; + + uarg.i = (int __user *)arg; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + + case WDIOC_GETSUPPORT: + return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + wdt_get_status(&status); + return put_user(status, uarg.i); + + case WDIOC_GETBOOTSTATUS: + return put_user(0, uarg.i); + + case WDIOC_KEEPALIVE: + wdt_keepalive(); + return 0; + + case WDIOC_SETOPTIONS: + if (get_user (new_options, uarg.i)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + wdt_stop(); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + wdt_start(); + retval = 0; + } + + return retval; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; + + if (wdt_set_timeout(new_timeout)) + return -EINVAL; + + wdt_keepalive(); + /* Fall */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout, uarg.i); + + } +} + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) + wdt_stop(); + return NOTIFY_DONE; +} + +static struct file_operations wdt_fops= +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wdt_write, + .ioctl = wdt_ioctl, + .open = wdt_open, + .release = wdt_release, +}; + +static struct miscdevice wdt_miscdev= +{ + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdt_fops, +}; + +static struct notifier_block wdt_notifier = { + .notifier_call = wdt_notify_sys, +}; + +static int __init w83977f_wdt_init(void) +{ + int rc; + + printk(KERN_INFO PFX DRIVER_VERSION); + + spin_lock_init(&spinlock); + + /* + * Check that the timeout value is within it's range ; + * if not reset to the default + */ + if (wdt_set_timeout(timeout)) { + wdt_set_timeout(DEFAULT_TIMEOUT); + printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n", + DEFAULT_TIMEOUT); + } + + if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + IO_INDEX_PORT); + rc = -EIO; + goto err_out; + } + + rc = misc_register(&wdt_miscdev); + if (rc) + { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_region; + } + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); + goto err_out_miscdev; + } + + printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", + timeout, nowayout, testmode); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region: + release_region(IO_INDEX_PORT,2); +err_out: + return rc; +} + +static void __exit w83977f_wdt_exit(void) +{ + wdt_stop(); + misc_deregister(&wdt_miscdev); + unregister_reboot_notifier(&wdt_notifier); + release_region(IO_INDEX_PORT,2); +} + +module_init(w83977f_wdt_init); +module_exit(w83977f_wdt_exit); + +MODULE_AUTHOR("Jose Goncalves "); +MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.2 From 3908bb1867e7455c4ea132b758970c312513c37d Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 11 Sep 2005 23:58:22 +0200 Subject: [WATCHDOG] sbc8360+w83977f_wdt-consolidate_CONFIG_WATCHDOG_NOWAYOUT_handling Attached patch removes #ifdef CONFIG_WATCHDOG_NOWAYOUT mess and replaces it with common define in linux/watchdog.h. Signed-Off-By: Wim Van Sebroeck --- drivers/char/watchdog/sbc8360.c | 7 +------ drivers/char/watchdog/w83977f_wdt.c | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c index 06daf426d5b6..c6cbf808d8c2 100644 --- a/drivers/char/watchdog/sbc8360.c +++ b/drivers/char/watchdog/sbc8360.c @@ -199,12 +199,7 @@ static int wd_times[64][2] = { static int timeout = 27; static int wd_margin = 0xB; static int wd_multiplier = 2; - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif +static int nowayout = WATCHDOG_NOWAYOUT; module_param(timeout, int, 27); MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c index 366d47bca16e..a7ff64c8921f 100644 --- a/drivers/char/watchdog/w83977f_wdt.c +++ b/drivers/char/watchdog/w83977f_wdt.c @@ -58,12 +58,7 @@ MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MO module_param(testmode, int, 0); MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - +static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); -- cgit v1.2.2 From c315b7e840a1f336ffefb21d3130f9799af2ecd6 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 12 Sep 2005 00:21:19 +0200 Subject: [WATCHDOG] pcwd_pci-include+WDIOC_SETOPTIONS-patch Clean-up includes Check results for start + stop in the WDIOC_SETOPTIONS ioctl call Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/pcwd_pci.c | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 2b13afb09c5d..5a80adbf8032 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -29,27 +29,29 @@ * Includes, defines, variables, module parameters, ... */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include /* For CONFIG_WATCHDOG_NOWAYOUT/... */ +#include /* For module specific items */ +#include /* For new moduleparam's */ +#include /* For standard types (like size_t) */ +#include /* For the -ENODEV/... values */ +#include /* For printk/panic/... */ +#include /* For mdelay function */ +#include /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include /* For the watchdog specific items */ +#include /* For notifier support */ +#include /* For reboot_notifier stuff */ +#include /* For __init/__exit/... */ +#include /* For file operations */ +#include /* For pci functions */ +#include /* For io-port access */ +#include /* For spin_lock/spin_unlock/... */ + +#include /* For copy_to_user/put_user/... */ +#include /* For inb/outb/... */ /* Module and version information */ #define WATCHDOG_VERSION "1.01" -#define WATCHDOG_DATE "15 Mar 2005" +#define WATCHDOG_DATE "02 Sep 2005" #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" #define WATCHDOG_NAME "pcwd_pci" #define PFX WATCHDOG_NAME ": " @@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, return -EFAULT; if (new_options & WDIOS_DISABLECARD) { - pcipcwd_stop(); + if (pcipcwd_stop()) + return -EIO; retval = 0; } if (new_options & WDIOS_ENABLECARD) { - pcipcwd_start(); + if (pcipcwd_start()) + return -EIO; retval = 0; } -- cgit v1.2.2 From b9d36b851a5085d35b9598235a456604532f306e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 12 Sep 2005 22:56:56 +0100 Subject: [ARM SMP] Add MPCore watchdog driver Add platform independent parts of the ARM MPCore watchdog driver. Signed-off-by: Russell King --- drivers/char/watchdog/Kconfig | 9 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/mpcore_wdt.c | 434 +++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 drivers/char/watchdog/mpcore_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index c3898afce3ae..fa789ea36bbe 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -139,6 +139,15 @@ config SA1100_WATCHDOG To compile this driver as a module, choose M here: the module will be called sa1100_wdt. +config MPCORE_WATCHDOG + tristate "MPcore watchdog" + depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS + help + Watchdog timer embedded into the MPcore system. + + To compile this driver as a module, choose M here: the + module will be called mpcore_wdt. + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index cfeac6f10137..bc6f5fe88c8c 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o +obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c new file mode 100644 index 000000000000..c694eee1fb24 --- /dev/null +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -0,0 +1,434 @@ +/* + * Watchdog driver for the mpcore watchdog timer + * + * (c) Copyright 2004 ARM Limited + * + * Based on the SoftDog driver: + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mpcore_wdt { + unsigned long timer_alive; + struct device *dev; + void __iomem *base; + int irq; + unsigned int perturb; + char expect_close; +}; + +static struct platform_device *mpcore_wdt_dev; + +extern unsigned int mpcore_timer_rate; + +#define TIMER_MARGIN 60 +static int mpcore_margin = TIMER_MARGIN; +module_param(mpcore_margin, int, 0); +MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0base + TWD_WDOG_INTSTAT)) { + dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n"); + + /* Clear the interrupt on the watchdog */ + writel(1, wdt->base + TWD_WDOG_INTSTAT); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +/* + * mpcore_wdt_keepalive - reload the timer + * + * Note that the spec says a DIFFERENT value must be written to the reload + * register each time. The "perturb" variable deals with this by adding 1 + * to the count every other time the function is called. + */ +static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt) +{ + unsigned int count; + + /* Assume prescale is set to 256 */ + count = (mpcore_timer_rate / 256) * mpcore_margin; + + /* Reload the counter */ + writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); + + wdt->perturb = wdt->perturb ? 0 : 1; +} + +static void mpcore_wdt_stop(struct mpcore_wdt *wdt) +{ + writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); + writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); + writel(0x0, wdt->base + TWD_WDOG_CONTROL); +} + +static void mpcore_wdt_start(struct mpcore_wdt *wdt) +{ + dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); + + /* This loads the count register but does NOT start the count yet */ + mpcore_wdt_keepalive(wdt); + + if (mpcore_noboot) { + /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */ + writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL); + } else { + /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ + writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); + } +} + +static int mpcore_wdt_set_heartbeat(int t) +{ + if (t < 0x0001 || t > 0xFFFF) + return -EINVAL; + + mpcore_margin = t; + return 0; +} + +/* + * /dev/watchdog handling + */ +static int mpcore_wdt_open(struct inode *inode, struct file *file) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(&mpcore_wdt_dev->dev); + + if (test_and_set_bit(0, &wdt->timer_alive)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + file->private_data = wdt; + + /* + * Activate timer + */ + mpcore_wdt_start(wdt); + + return nonseekable_open(inode, file); +} + +static int mpcore_wdt_release(struct inode *inode, struct file *file) +{ + struct mpcore_wdt *wdt = file->private_data; + + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (wdt->expect_close == 42) { + mpcore_wdt_stop(wdt); + } else { + dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n"); + mpcore_wdt_keepalive(wdt); + } + clear_bit(0, &wdt->timer_alive); + wdt->expect_close = 0; + return 0; +} + +static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + struct mpcore_wdt *wdt = file->private_data; + + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + wdt->expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + wdt->expect_close = 42; + } + } + mpcore_wdt_keepalive(wdt); + } + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .identity = "MPcore Watchdog", +}; + +static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mpcore_wdt *wdt = file->private_data; + int ret; + union { + struct watchdog_info ident; + int i; + } uarg; + + if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg)) + return -ENOIOCTLCMD; + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd)); + if (ret) + return -EFAULT; + } + + switch (cmd) { + case WDIOC_GETSUPPORT: + uarg.ident = ident; + ret = 0; + break; + + case WDIOC_SETOPTIONS: + ret = -EINVAL; + if (uarg.i & WDIOS_DISABLECARD) { + mpcore_wdt_stop(wdt); + ret = 0; + } + if (uarg.i & WDIOS_ENABLECARD) { + mpcore_wdt_start(wdt); + ret = 0; + } + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + uarg.i = 0; + ret = 0; + break; + + case WDIOC_KEEPALIVE: + mpcore_wdt_keepalive(wdt); + ret = 0; + break; + + case WDIOC_SETTIMEOUT: + ret = mpcore_wdt_set_heartbeat(uarg.i); + if (ret) + break; + + mpcore_wdt_keepalive(wdt); + /* Fall */ + case WDIOC_GETTIMEOUT: + uarg.i = mpcore_margin; + ret = 0; + break; + + default: + return -ENOIOCTLCMD; + } + + if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { + ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd)); + if (ret) + ret = -EFAULT; + } + return ret; +} + +/* + * System shutdown handler. Turn off the watchdog if we're + * restarting or halting the system. + */ +static void mpcore_wdt_shutdown(struct device *_dev) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(_dev); + + if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT) + mpcore_wdt_stop(wdt); +} + +/* + * Kernel Interfaces + */ +static struct file_operations mpcore_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = mpcore_wdt_write, + .ioctl = mpcore_wdt_ioctl, + .open = mpcore_wdt_open, + .release = mpcore_wdt_release, +}; + +static struct miscdevice mpcore_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mpcore_wdt_fops, +}; + +static int __devinit mpcore_wdt_probe(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct mpcore_wdt *wdt; + struct resource *res; + int ret; + + /* We only accept one device, and it must have an id of -1 */ + if (dev->id != -1) + return -ENODEV; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto err_out; + } + + wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL); + if (!wdt) { + ret = -ENOMEM; + goto err_out; + } + memset(wdt, 0, sizeof(struct mpcore_wdt)); + + wdt->dev = &dev->dev; + wdt->irq = platform_get_irq(dev, 0); + wdt->base = ioremap(res->start, res->end - res->start + 1); + if (!wdt->base) { + ret = -ENOMEM; + goto err_free; + } + + mpcore_wdt_miscdev.dev = &dev->dev; + ret = misc_register(&mpcore_wdt_miscdev); + if (ret) { + dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto err_misc; + } + + ret = request_irq(wdt->irq, mpcore_wdt_fire, SA_INTERRUPT, "mpcore_wdt", wdt); + if (ret) { + dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq); + goto err_irq; + } + + mpcore_wdt_stop(wdt); + dev_set_drvdata(&dev->dev, wdt); + mpcore_wdt_dev = dev; + + return 0; + + err_irq: + misc_deregister(&mpcore_wdt_miscdev); + err_misc: + iounmap(wdt->base); + err_free: + kfree(wdt); + err_out: + return ret; +} + +static int __devexit mpcore_wdt_remove(struct device *dev) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + misc_deregister(&mpcore_wdt_miscdev); + + mpcore_wdt_dev = NULL; + + free_irq(wdt->irq, wdt); + iounmap(wdt->base); + kfree(wdt); + return 0; +} + +static struct device_driver mpcore_wdt_driver = { + .name = "mpcore_wdt", + .bus = &platform_bus_type, + .probe = mpcore_wdt_probe, + .remove = __devexit_p(mpcore_wdt_remove), + .shutdown = mpcore_wdt_shutdown, +}; + +static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n"; + +static int __init mpcore_wdt_init(void) +{ + /* + * Check that the margin value is within it's range; + * if not reset to the default + */ + if (mpcore_wdt_set_heartbeat(mpcore_margin)) { + mpcore_wdt_set_heartbeat(TIMER_MARGIN); + printk(KERN_INFO "mpcore_margin value must be 0 Date: Tue, 13 Sep 2005 01:25:15 -0700 Subject: [PATCH] Remove unnecessary check_region references in comments Remove check_region references from comments and printk statements so that searching for real users of this deprecated function gets easier. Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/amiserial.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 2a36561eec68..a124f8c5d062 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -2053,10 +2053,6 @@ static int __init rs_init(void) state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; - /* - if(state->port && check_region(state->port,REGION_LENGTH(state))) - continue; - */ printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", state->line); -- cgit v1.2.2 From ad4162f3712ddf25e148cff1e7dc37eafdff3e51 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 14 Sep 2005 09:56:38 +0100 Subject: [ARM SMP] Add timer/watchdog defines for MPCore The timer/watchdog register definitions were missing from the mpcore watchdog patch. Add them. Signed-off-by: Russell King --- drivers/char/watchdog/mpcore_wdt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index c694eee1fb24..75ca84ed4adf 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -30,6 +30,8 @@ #include #include #include + +#include #include struct mpcore_wdt { -- cgit v1.2.2 From ef4cbee0b0d0f791bb593f99b702410f3c0efce6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 14 Sep 2005 14:19:18 -0700 Subject: [PATCH] hvc_console: start kernel thread before registering tty Its possible that we can write to the hvc_console tty as soon it is registered. Recently this started happening due to (what looks like) a change to the hotplug code. Unfortunately at this stage we have not started the khvcd kernel thread and oops. The solution is to start the kernel thread before registering the tty. Signed-off-by: Anton Blanchard Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index cddb789902db..f92177634677 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -839,9 +839,6 @@ int __init hvc_init(void) hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); - if (tty_register_driver(hvc_driver)) - panic("Couldn't register hvc console driver\n"); - /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); @@ -851,6 +848,9 @@ int __init hvc_init(void) return -EIO; } + if (tty_register_driver(hvc_driver)) + panic("Couldn't register hvc console driver\n"); + return 0; } module_init(hvc_init); -- cgit v1.2.2 From 065d9cac98a5406ecd5a1368f8fd38f55739dee9 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Thu, 15 Sep 2005 21:34:33 +0800 Subject: [PATCH] vc: Use correct size on buffer copy in vc_resize In the unlikely case of the new screen width much wider then the old, use (old_row_size * new_rows) instead of new_screen_size to prevent a buffer overrun during the copy. Signed-off-by: Antonino Daplas Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1e33cb032e07..e91268e86833 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -810,13 +810,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) * from the top and bottom of cursor position */ old_origin += (vc->vc_y - new_rows/2) * old_row_size; - end = old_origin + new_screen_size; + end = old_origin + (old_row_size * new_rows); } } else /* * Cursor near the top, copy contents from the top of buffer */ - end = (old_rows > new_rows) ? old_origin + new_screen_size : + end = (old_rows > new_rows) ? old_origin + + (old_row_size * new_rows) : vc->vc_scr_end; update_attr(vc); -- cgit v1.2.2 From 24b8e0cc09483adc0fdd9c68914b19597bb9fddc Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Thu, 15 Sep 2005 15:36:35 +1000 Subject: [IA64] Remove warnings for gcc 4.0 IA64 compilation. This patch removes some compilation warnings, mostly trivially. acpi.c fix also noted by Kenji Kaneshige. Signed-off-by; Peter Chubb Signed-off-by: Tony Luck --- drivers/char/agp/hp-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 99762b6c19ae..de5d6d212674 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -252,7 +252,7 @@ hp_zx1_configure (void) readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); readl(hp->ioc_regs+HP_ZX1_TCNFG); - writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK); + writel((unsigned int)(~(HP_ZX1_IOVA_SIZE-1)), hp->ioc_regs+HP_ZX1_IMASK); readl(hp->ioc_regs+HP_ZX1_IMASK); writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); readl(hp->ioc_regs+HP_ZX1_IBASE); -- cgit v1.2.2 From bc9a5154a24d16d41cc79dbf1442de34454bc7db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 15 Sep 2005 22:53:28 +0100 Subject: [PATCH] epca iomem annotations + several missing readw() [originally sent to Alan, he had no problems with it] - iomem pointers marked as such - several direct dereferencings of such pointers replaced with read[bw](). Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/epca.c | 84 ++++++++++++++++++++++++++++------------------------- drivers/char/epca.h | 12 ++++---- 2 files changed, 50 insertions(+), 46 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 58d3738a2b7f..407708a001e4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -534,7 +534,7 @@ static void shutdown(struct channel *ch) unsigned long flags; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; @@ -618,7 +618,7 @@ static int pc_write(struct tty_struct * tty, struct channel *ch; unsigned long flags; int remain; - struct board_chan *bc; + struct board_chan __iomem *bc; /* ---------------------------------------------------------------- pc_write is primarily called directly by the kernel routine @@ -685,7 +685,7 @@ static int pc_write(struct tty_struct * tty, ------------------------------------------------------------------- */ dataLen = min(bytesAvailable, dataLen); - memcpy(ch->txptr + head, buf, dataLen); + memcpy_toio(ch->txptr + head, buf, dataLen); buf += dataLen; head += dataLen; amountCopied += dataLen; @@ -726,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) struct channel *ch; unsigned long flags; unsigned int head, tail; - struct board_chan *bc; + struct board_chan __iomem *bc; remain = 0; @@ -773,7 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) int remain; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct @@ -830,7 +830,7 @@ static void pc_flush_buffer(struct tty_struct *tty) unsigned int tail; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. @@ -976,7 +976,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) struct channel *ch; unsigned long flags; int line, retval, boardnum; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int head; line = tty->index; @@ -1041,7 +1041,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ch->statusflags = 0; /* Save boards current modem status */ - ch->imodem = bc->mstat; + ch->imodem = readb(&bc->mstat); /* ---------------------------------------------------------------- Set receive head and tail ptrs to each other. This indicates @@ -1399,10 +1399,10 @@ static void post_fep_init(unsigned int crd) { /* Begin post_fep_init */ int i; - unsigned char *memaddr; - struct global_data *gd; + void __iomem *memaddr; + struct global_data __iomem *gd; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch; int shrinkmem = 0, lowwater ; @@ -1461,7 +1461,7 @@ static void post_fep_init(unsigned int crd) 8 and 64 of these structures. -------------------------------------------------------------------- */ - bc = (struct board_chan *)(memaddr + CHANSTRUCT); + bc = memaddr + CHANSTRUCT; /* ------------------------------------------------------------------- The below assignment will set gd to point at the BEGINING of @@ -1470,7 +1470,7 @@ static void post_fep_init(unsigned int crd) pointer begins at 0xd10. ---------------------------------------------------------------------- */ - gd = (struct global_data *)(memaddr + GLOBAL); + gd = memaddr + GLOBAL; /* -------------------------------------------------------------------- XEPORTS (address 0xc22) points at the number of channels the @@ -1493,6 +1493,7 @@ static void post_fep_init(unsigned int crd) for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ unsigned long flags; + u16 tseg, rseg; ch->brdchan = bc; ch->mailbox = gd; @@ -1553,50 +1554,53 @@ static void post_fep_init(unsigned int crd) shrinkmem = 0; } + tseg = readw(&bc->tseg); + rseg = readw(&bc->rseg); + switch (bd->type) { case PCIXEM: case PCIXRJ: case PCIXR: /* Cover all the 2MEG cards */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x1fffff); + ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEM: case EISAXEM: /* Cover all the 32K windowed cards */ /* Mask equal to window size - 1 */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x7fff); + ch->rxptr = memaddr + ((rseg << 4) & 0x7fff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEVE: case PCXE: - ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); - ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); - ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); - ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); + ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff); + ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9); + ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff); + ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 ); break; case PCXI: case PC64XE: - ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); - ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); + ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4); + ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4); ch->txwin = ch->rxwin = 0; break; } /* End switch bd->type */ ch->txbufhead = 0; - ch->txbufsize = bc->tmax + 1; + ch->txbufsize = readw(&bc->tmax) + 1; ch->rxbufhead = 0; - ch->rxbufsize = bc->rmax + 1; + ch->rxbufsize = readw(&bc->rmax) + 1; lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); @@ -1718,11 +1722,11 @@ static void epcapoll(unsigned long ignored) static void doevent(int crd) { /* Begin doevent */ - void *eventbuf; + void __iomem *eventbuf; struct channel *ch, *chan0; static struct tty_struct *tty; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int tail, head; int event, channel; int mstat, lstat; @@ -1817,7 +1821,7 @@ static void doevent(int crd) static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd) { /* Begin fepcmd */ - unchar *memaddr; + unchar __iomem *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; long count; int n; @@ -2000,7 +2004,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) unsigned int cmdHead; struct termios *ts; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; @@ -2010,7 +2014,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ts = tty->termios; if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ cmdHead = readw(&bc->rin); - bc->rout = cmdHead; + writew(cmdHead, &bc->rout); cmdHead = readw(&bc->tin); /* Changing baud in mid-stream transmission can be wonderful */ /* --------------------------------------------------------------- @@ -2116,7 +2120,7 @@ static void receive_data(struct channel *ch) unchar *rptr; struct termios *ts = NULL; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; int dataToRead, wrapgap, bytesAvailable; unsigned int tail, head; unsigned int wrapmask; @@ -2154,7 +2158,7 @@ static void receive_data(struct channel *ch) --------------------------------------------------------------------- */ if (!tty || !ts || !(ts->c_cflag & CREAD)) { - bc->rout = head; + writew(head, &bc->rout); return; } @@ -2270,7 +2274,7 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { struct channel *ch = (struct channel *) tty->driver_data; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int mstat, mflag = 0; unsigned long flags; @@ -2351,7 +2355,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, unsigned long flags; unsigned int mflag, mstat; unsigned char startc, stopc; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; @@ -2633,7 +2637,7 @@ static void pc_start(struct tty_struct *tty) spin_lock_irqsave(&epca_lock, flags); /* Just in case output was resumed because of a change in Digi-flow */ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ - struct board_chan *bc; + struct board_chan __iomem *bc; globalwinon(ch); bc = ch->brdchan; if (ch->statusflags & LOWWAIT) @@ -2727,7 +2731,7 @@ void digi_send_break(struct channel *ch, int msec) static void setup_empty_event(struct tty_struct *tty, struct channel *ch) { /* Begin setup_empty_event */ - struct board_chan *bc = ch->brdchan; + struct board_chan __iomem *bc = ch->brdchan; globalwinon(ch); ch->statusflags |= EMPTYWAIT; diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 20eeb5a70e1a..456d6c8f94a8 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -128,17 +128,17 @@ struct channel unsigned long c_cflag; unsigned long c_lflag; unsigned long c_oflag; - unsigned char *txptr; - unsigned char *rxptr; + unsigned char __iomem *txptr; + unsigned char __iomem *rxptr; unsigned char *tmp_buf; struct board_info *board; - struct board_chan *brdchan; + struct board_chan __iomem *brdchan; struct digi_struct digiext; struct tty_struct *tty; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct work_struct tqueue; - struct global_data *mailbox; + struct global_data __iomem *mailbox; }; struct board_info @@ -149,8 +149,8 @@ struct board_info unsigned short numports; unsigned long port; unsigned long membase; - unsigned char __iomem *re_map_port; - unsigned char *re_map_membase; + void __iomem *re_map_port; + void __iomem *re_map_membase; unsigned long memory_seg; void ( * memwinon ) (struct board_info *, unsigned int) ; void ( * memwinoff ) (struct board_info *, unsigned int) ; -- cgit v1.2.2 From 609725f87709724218047a1049913ed233f79d3c Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 22 Sep 2005 21:43:59 -0700 Subject: [PATCH] Fix mmap() of /dev/hpet The address passed to io_remap_pfn_range() in hpet_mmap() does not need to be converted using __pa(): it is already a physical address. This bug was found and the patch suggested by Clay Harris. I introduced this particular bug when making io_remap_pfn_range changes a few months ago. In fact mmap()ing /dev/hpet has *never* previously worked: before my changes __pa() was being executed on an ioremap()ed virtual address, which is also invalid. Signed-off-by: Keir Fraser Cc: Robert Picco Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hpet.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index de0379b6d502..c055bb630ffc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -273,7 +273,6 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_flags |= VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - addr = __pa(addr); if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) { -- cgit v1.2.2 From e7c965084392e23a3494f0247c75795360a3fa0d Mon Sep 17 00:00:00 2001 From: Hironobu Ishii Date: Fri, 23 Sep 2005 13:24:08 -0700 Subject: [PATCH] ipmi_msghandler: inconsistent spin_lock usage I found an inconsistent spin_lock usage in ipmi_smi_msg_received. Signed-off-by: Hironobu Ishii Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 463351d4f942..32fa82c78c73 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2620,7 +2620,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); if (!list_empty(&(intf->waiting_msgs))) { list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock(&(intf->waiting_msgs_lock)); + spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); goto out_unlock; } spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); @@ -2629,9 +2629,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, if (rv > 0) { /* Could not handle the message now, just add it to a list to handle later. */ - spin_lock(&(intf->waiting_msgs_lock)); + spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock(&(intf->waiting_msgs_lock)); + spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); } else if (rv == 0) { ipmi_free_smi_msg(msg); } -- cgit v1.2.2