diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-10-12 21:27:47 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-10-12 21:27:47 -0400 |
commit | b981d8b3f5e008ff10d993be633ad00564fc22cd (patch) | |
tree | e292dc07b22308912cf6a58354a608b9e5e8e1fd /drivers/char | |
parent | b11d2127c4893a7315d1e16273bc8560049fa3ca (diff) | |
parent | 2b9e0aae1d50e880c58d46788e5e3ebd89d75d62 (diff) | |
download | op-kernel-dev-b981d8b3f5e008ff10d993be633ad00564fc22cd.zip op-kernel-dev-b981d8b3f5e008ff10d993be633ad00564fc22cd.tar.gz |
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/macintosh/adbhid.c
Diffstat (limited to 'drivers/char')
104 files changed, 2997 insertions, 711 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d8d7125..b391776 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -130,6 +130,7 @@ config ROCKETPORT config CYCLADES tristate "Cyclades async mux support" depends on SERIAL_NONSTANDARD && (PCI || ISA) + select FW_LOADER ---help--- This driver supports Cyclades Z and Y multiserial boards. You would need something like this to connect more than two modems to @@ -185,7 +186,7 @@ config ESPSERIAL config MOXA_INTELLIO tristate "Moxa Intellio support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) help Say Y here if you have a Moxa Intellio multiport serial card. @@ -241,7 +242,7 @@ config SYNCLINK config SYNCLINKMP tristate "SyncLink Multiport support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && PCI help Enable support for the SyncLink Multiport (2 or 4 ports) serial adapter, running asynchronous and HDLC communications up @@ -372,39 +373,6 @@ config ISTALLION To compile this driver as a module, choose M here: the module will be called istallion. -config SERIAL_DEC - bool "DECstation serial support" - depends on MACH_DECSTATION - default y - help - This selects whether you want to be asked about drivers for - DECstation serial ports. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about DECstation serial ports. - -config SERIAL_DEC_CONSOLE - bool "Support for console on a DECstation serial port" - depends on SERIAL_DEC - default y - help - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). Note that the firmware uses ttyS0 as the serial console on - the Maxine and ttyS2 on the others. - - If unsure, say Y. - -config ZS - bool "Z85C30 Serial Support" - depends on SERIAL_DEC - default y - help - Documentation on the Zilog 85C350 serial communications controller - is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf> - config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP @@ -637,6 +605,14 @@ config HVC_BEAT help Toshiba's Cell Reference Set Beat Console device driver +config HVC_XEN + bool "Xen Hypervisor Console support" + depends on XEN + select HVC_DRIVER + default y + help + Xen virtual console device driver + config HVCS tristate "IBM Hypervisor Virtual Console Server support" depends on PPC_PSERIES @@ -751,7 +727,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390 + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 ---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 @@ -775,6 +751,28 @@ config RTC To compile this driver as a module, choose M here: the module will be called rtc. +config JS_RTC + tristate "Enhanced Real Time Clock Support" + depends on SPARC32 && PCI + ---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 + will get access to the real time clock (or hardware clock) built + into your computer. + + Every PC has such a clock built in. It can be used to generate + signals from as low as 1Hz up to 8192Hz, and can also be used + as a 24 hour alarm. It reports status information via the file + /proc/driver/rtc and its behaviour is set by various ioctls on + /dev/rtc. + + If you think you have a use for such a device (such as periodic data + sampling), then say Y here, and read <file:Documentation/rtc.txt> + for details. + + To compile this driver as a module, choose M here: the + module will be called js-rtc. + config SGI_DS1286 tristate "SGI DS1286 RTC support" depends on SGI_IP22 diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f2996a9..c78ff26 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -42,12 +42,14 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o +obj-$(CONFIG_LGUEST_GUEST) += hvc_lguest.o obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o @@ -95,7 +97,6 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o -obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ @@ -105,6 +106,11 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ +obj-$(CONFIG_PS3_FLASH) += ps3flash.o + +obj-$(CONFIG_JS_RTC) += js-rtc.o +js-rtc-y = rtc.o + # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c @@ -123,7 +129,7 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c ifdef GENERATE_KEYMAP -$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map +$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map loadkeys --mktable $< > $@.tmp sed -e 's/^static *//' $@.tmp > $@ rm $@.tmp diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index a9f9c48..713533d 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -50,7 +50,7 @@ config AGP_ATI config AGP_AMD tristate "AMD Irongate, 761, and 762 chipset support" - depends on AGP && X86_32 + depends on AGP && (X86_32 || ALPHA) help This option gives you AGP support for the GLX component of X on AMD Irongate, 761, and 762 chipsets. diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 35ab1a9..8955e7f 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -176,7 +176,7 @@ struct agp_bridge_data { #define I830_GMCH_MEM_MASK 0x1 #define I830_GMCH_MEM_64M 0x1 #define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0xF0 +#define I830_GMCH_GMS_MASK 0x70 #define I830_GMCH_GMS_DISABLED 0x00 #define I830_GMCH_GMS_LOCAL 0x10 #define I830_GMCH_GMS_STOLEN_512 0x20 @@ -190,6 +190,7 @@ struct agp_bridge_data { #define INTEL_I830_ERRSTS 0x92 /* Intel 855GM/852GM registers */ +#define I855_GMCH_GMS_MASK 0xF0 #define I855_GMCH_GMS_STOLEN_0M 0x0 #define I855_GMCH_GMS_STOLEN_1M (0x1 << 4) #define I855_GMCH_GMS_STOLEN_4M (0x2 << 4) diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index df0ddf1..f60bca7 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -223,6 +223,8 @@ static int amd_irongate_configure(void) pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp); temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); + if (!amd_irongate_private.registers) + return -ENOMEM; /* Write out the address of the gatt table */ writel(agp_bridge->gatt_bus_addr, amd_irongate_private.registers+AMD_ATTBASE); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 780e59e..2d46b71 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -123,21 +123,16 @@ static int ati_create_gatt_pages(int nr_tables) for (i = 0; i < nr_tables; i++) { entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL); + tables[i] = entry; if (entry == NULL) { - while (i > 0) { - kfree(tables[i-1]); - i--; - } - kfree(tables); retval = -ENOMEM; break; } - tables[i] = entry; retval = ati_create_page_map(entry); if (retval != 0) break; } - ati_generic_private.num_tables = nr_tables; + ati_generic_private.num_tables = i; ati_generic_private.gatt_pages = tables; if (retval != 0) @@ -218,6 +213,9 @@ static int ati_configure(void) temp = (temp & 0xfffff000); ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); + if (!ati_generic_private.registers) + return -ENOMEM; + if (is_r200()) pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); else diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index fcb4b1b..ecd4248 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/fs.h> #include <linux/agpgart.h> #include <asm/uaccess.h> #include "agp.h" diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index df8da72..d78cd09 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -375,6 +375,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, if (!r->start && r->end) { if (pci_assign_resource(pdev, 0)) { printk(KERN_ERR PFX "could not assign resource 0\n"); + agp_put_bridge(bridge); return -ENODEV; } } @@ -386,6 +387,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, */ if (pci_enable_device(pdev)) { printk(KERN_ERR PFX "Unable to Enable PCI device\n"); + agp_put_bridge(bridge); return -ENODEV; } diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index c7ed617..7791e98 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -37,6 +37,7 @@ #include <linux/agpgart.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/fs.h> #include <linux/sched.h> #include <asm/uaccess.h> #include <asm/pgtable.h> diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index d535c40..3db4f40 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1170,7 +1170,6 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) map_page_into_agp(page); get_page(page); - SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); } @@ -1187,7 +1186,6 @@ void agp_generic_destroy_page(void *addr) page = virt_to_page(addr); unmap_page_from_agp(page); put_page(page); - unlock_page(page); free_page((unsigned long)addr); atomic_dec(&agp_bridge->current_memory_agp); } diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index bcdb149..313a133 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -221,6 +221,7 @@ hp_zx1_lba_init (u64 hpa) if (cap != PCI_CAP_ID_AGP) { printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n", cap, hp->lba_cap_offset); + iounmap(hp->lba_regs); return -ENODEV; } diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 53354bf..75d2aca 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -249,6 +249,10 @@ static int i460_create_gatt_table (struct agp_bridge_data *bridge) num_entries = A_SIZE_8(temp)->num_entries; i460.gatt = ioremap(INTEL_I460_ATTBASE, PAGE_SIZE << page_order); + if (!i460.gatt) { + printk(KERN_ERR PFX "ioremap failed\n"); + return -ENOMEM; + } /* These are no good, the should be removed from the agp_bridge strucure... */ agp_bridge->gatt_table_real = NULL; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a124060..141ca17 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -20,7 +20,9 @@ #define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 #define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00 #define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02 +#define PCI_DEVICE_ID_INTEL_82965GME_HB 0x2A10 #define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12 +#define PCI_DEVICE_ID_INTEL_82945GME_HB 0x27AC #define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE #define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0 #define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2 @@ -33,7 +35,8 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB) #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ @@ -213,7 +216,6 @@ static void *i8xx_alloc_pages(void) } global_flush_tlb(); get_page(page); - SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); } @@ -229,7 +231,6 @@ static void i8xx_destroy_pages(void *addr) change_page_attr(page, 4, PAGE_KERNEL); global_flush_tlb(); put_page(page); - unlock_page(page); __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } @@ -505,7 +506,7 @@ static void intel_i830_init_gtt_entries(void) break; } } else { - switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: gtt_entries = MB(1) - KB(size); break; @@ -527,6 +528,7 @@ static void intel_i830_init_gtt_entries(void) agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || IS_I965 || IS_G33) gtt_entries = MB(48) - KB(size); else @@ -538,6 +540,7 @@ static void intel_i830_init_gtt_entries(void) agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || IS_I965 || IS_G33) gtt_entries = MB(64) - KB(size); else @@ -911,6 +914,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; + int gtt_map_size = 256 * 1024; size = agp_bridge->current_size; page_order = size->page_order; @@ -920,15 +924,19 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2); - intel_private.gtt = ioremap(temp2, 256 * 1024); + if (IS_G33) + gtt_map_size = 1024 * 1024; /* 1M on G33 */ + intel_private.gtt = ioremap(temp2, gtt_map_size); if (!intel_private.gtt) return -ENOMEM; temp &= 0xfff80000; intel_private.registers = ioremap(temp,128 * 4096); - if (!intel_private.registers) + if (!intel_private.registers) { + iounmap(intel_private.gtt); return -ENOMEM; + } temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ @@ -982,13 +990,15 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) temp &= 0xfff00000; intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); - if (!intel_private.gtt) - return -ENOMEM; + if (!intel_private.gtt) + return -ENOMEM; intel_private.registers = ioremap(temp,128 * 4096); - if (!intel_private.registers) - return -ENOMEM; + if (!intel_private.registers) { + iounmap(intel_private.gtt); + return -ENOMEM; + } temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ @@ -1848,9 +1858,9 @@ static const struct intel_driver_description { NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G", NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM", + { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM", NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", + { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ", NULL, &intel_i965_driver }, @@ -1860,9 +1870,9 @@ static const struct intel_driver_description { NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM", + { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", + { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL }, { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL }, @@ -2051,11 +2061,13 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82915GM_HB), ID(PCI_DEVICE_ID_INTEL_82945G_HB), ID(PCI_DEVICE_ID_INTEL_82945GM_HB), + ID(PCI_DEVICE_ID_INTEL_82945GME_HB), ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), ID(PCI_DEVICE_ID_INTEL_82965Q_HB), ID(PCI_DEVICE_ID_INTEL_82965G_HB), ID(PCI_DEVICE_ID_INTEL_82965GM_HB), + ID(PCI_DEVICE_ID_INTEL_82965GME_HB), ID(PCI_DEVICE_ID_INTEL_G33_HB), ID(PCI_DEVICE_ID_INTEL_Q35_HB), ID(PCI_DEVICE_ID_INTEL_Q33_HB), diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 6cd7373..225ed2a 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -157,6 +157,9 @@ static int nvidia_configure(void) nvidia_private.aperture = (volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE); + if (!nvidia_private.aperture) + return -ENOMEM; + return 0; } diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index cda608c..98cf8ab 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -51,7 +51,6 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) return NULL; get_page(page); - SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); } diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 9aaf401..0ecc54d 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -399,6 +399,11 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata = .device_id = PCI_DEVICE_ID_VIA_P4M890, .chipset_name = "P4M890", }, + /* P4M900 */ + { + .device_id = PCI_DEVICE_ID_VIA_VT3364, + .chipset_name = "P4M900", + }, { }, /* dummy final entry, always present */ }; diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 7b02bf1..3d468f5 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1721,12 +1721,11 @@ static int get_async_struct(int line, struct async_struct **ret_info) *ret_info = sstate->info; return 0; } - info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); if (!info) { sstate->count--; return -ENOMEM; } - memset(info, 0, sizeof(struct async_struct)); #ifdef DECLARE_WAITQUEUE init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c deleted file mode 100644 index 8ea2bea..0000000 --- a/drivers/char/decserial.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * sercons.c - * choose the right serial device at boot time - * - * triemer 6-SEP-1998 - * sercons.c is designed to allow the three different kinds - * of serial devices under the decstation world to co-exist - * in the same kernel. The idea here is to abstract - * the pieces of the drivers that are common to this file - * so that they do not clash at compile time and runtime. - * - * HK 16-SEP-1998 v0.002 - * removed the PROM console as this is not a real serial - * device. Added support for PROM console in drivers/char/tty_io.c - * instead. Although it may work to enable more than one - * console device I strongly recommend to use only one. - */ - -#include <linux/init.h> -#include <asm/dec/machtype.h> - -#ifdef CONFIG_ZS -extern int zs_init(void); -#endif - -#ifdef CONFIG_SERIAL_CONSOLE - -#ifdef CONFIG_ZS -extern void zs_serial_console_init(void); -#endif - -#endif - -/* rs_init - starts up the serial interface - - handle normal case of starting up the serial interface */ - -#ifdef CONFIG_SERIAL - -int __init rs_init(void) -{ -#ifdef CONFIG_ZS - if (IOASIC) - return zs_init(); -#endif - return -ENXIO; -} - -__initcall(rs_init); - -#endif - -#ifdef CONFIG_SERIAL_CONSOLE - -/* serial_console_init handles the special case of starting - * up the console on the serial port - */ -static int __init decserial_console_init(void) -{ -#ifdef CONFIG_ZS - if (IOASIC) - zs_serial_console_init(); -#endif - return 0; -} -console_initcall(decserial_console_init); - -#endif diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 923174c..c115b39 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -177,8 +177,14 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, MTRR_TYPE_WRCOMB, 1); } } - if (map->type == _DRM_REGISTERS) + if (map->type == _DRM_REGISTERS) { map->handle = ioremap(map->offset, map->size); + if (!map->handle) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + } + break; case _DRM_SHM: list = drm_find_matching_map(dev, map); @@ -479,11 +485,6 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, return -EINVAL; } - if (!map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - /* Register and framebuffer maps are permanent */ if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { mutex_unlock(&dev->struct_mutex); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 3359cc2..8e7d713 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -184,6 +184,8 @@ static int i915_initialize(struct drm_device * dev, * private backbuffer/depthbuffer usage. */ dev_priv->use_mi_batchbuffer_start = 0; + if (IS_I965G(dev)) /* 965 doesn't support older method */ + dev_priv->use_mi_batchbuffer_start = 1; /* Allow hardware batchbuffers unless told otherwise. */ @@ -517,8 +519,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, if (dev_priv->use_mi_batchbuffer_start) { BEGIN_LP_RING(2); - OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); - OUT_RING(batch->start | MI_BATCH_NON_SECURE); + if (IS_I965G(dev)) { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); + OUT_RING(batch->start); + } else { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + } ADVANCE_LP_RING(); } else { BEGIN_LP_RING(4); @@ -735,7 +742,8 @@ static int i915_setparam(DRM_IOCTL_ARGS) switch (param.param) { case I915_SETPARAM_USE_MI_BATCHBUFFER_START: - dev_priv->use_mi_batchbuffer_start = param.value; + if (!IS_I965G(dev)) + dev_priv->use_mi_batchbuffer_start = param.value; break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: dev_priv->tex_lru_log_granularity = param.value; diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index fd91856..28b9873 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -210,6 +210,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 +#define I915REG_PIPEASTAT 0x70024 +#define I915REG_PIPEBSTAT 0x71024 + +#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define I915_VBLANK_CLEAR (1UL<<1) + #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 @@ -282,6 +288,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_BATCH_BUFFER_START (0x31<<23) #define MI_BATCH_BUFFER_END (0xA<<23) #define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_WAIT_FOR_EVENT ((0x3<<23)) #define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 4b4b2ce..bb8e9e9 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -214,6 +214,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 temp; + u32 pipea_stats, pipeb_stats; + + pipea_stats = I915_READ(I915REG_PIPEASTAT); + pipeb_stats = I915_READ(I915REG_PIPEBSTAT); temp = I915_READ16(I915REG_INT_IDENTITY_R); @@ -225,6 +229,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + DRM_READMEMORYBARRIER(); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -252,6 +258,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); + I915_WRITE(I915REG_PIPEASTAT, + pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); + I915_WRITE(I915REG_PIPEBSTAT, + pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); } return IRQ_HANDLED; diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index fdb8609..3dd1ed3 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -273,10 +273,9 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg) vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / vsg->descriptors_per_page; - if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL))) + if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL))) return DRM_ERR(ENOMEM); - memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages); vsg->state = dr_via_desc_pages_alloc; for (i=0; i<vsg->num_desc_pages; ++i) { if (NULL == (vsg->desc_pages[i] = @@ -561,7 +560,7 @@ via_init_dmablit(struct drm_device *dev) blitq->head = 0; blitq->cur = 0; blitq->serviced = 0; - blitq->num_free = VIA_NUM_BLIT_SLOTS; + blitq->num_free = VIA_NUM_BLIT_SLOTS - 1; blitq->num_outstanding = 0; blitq->is_active = 0; blitq->aborting = 0; diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e..acbfe1c 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 74cd511..2e7ae42 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2459,7 +2459,7 @@ static int __init espserial_init(void) return 1; } - info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); + info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) { @@ -2469,7 +2469,6 @@ static int __init espserial_init(void) return 1; } - memset((void *)info, 0, sizeof(struct esp_struct)); spin_lock_init(&info->lock); /* rx_trigger, tx_trigger are needed by autoconfig */ info->config.rx_trigger = rx_trigger; @@ -2527,7 +2526,7 @@ static int __init espserial_init(void) if (!dma) info->stat_flags |= ESP_STAT_NEVER_DMA; - info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); + info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) { printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); @@ -2536,7 +2535,6 @@ static int __init espserial_init(void) return 0; } - memset((void *)info, 0, sizeof(struct esp_struct)); /* rx_trigger, tx_trigger are needed by autoconfig */ info->config.rx_trigger = rx_trigger; info->config.tx_trigger = tx_trigger; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 0be700f..4c16778 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -29,6 +29,7 @@ #include <linux/bcd.h> #include <linux/seq_file.h> #include <linux/bitops.h> +#include <linux/clocksource.h> #include <asm/current.h> #include <asm/uaccess.h> @@ -51,8 +52,37 @@ #define HPET_RANGE_SIZE 1024 /* from HPET spec */ +#if BITS_PER_LONG == 64 +#define write_counter(V, MC) writeq(V, MC) +#define read_counter(MC) readq(MC) +#else +#define write_counter(V, MC) writel(V, MC) +#define read_counter(MC) readl(MC) +#endif + static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; +/* This clocksource driver currently only works on ia64 */ +#ifdef CONFIG_IA64 +static void __iomem *hpet_mctr; + +static cycle_t read_hpet(void) +{ + return (cycle_t)read_counter((void __iomem *)hpet_mctr); +} + +static struct clocksource clocksource_hpet = { + .name = "hpet", + .rating = 250, + .read = read_hpet, + .mask = CLOCKSOURCE_MASK(64), + .mult = 0, /*to be caluclated*/ + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; +static struct clocksource *hpet_clocksource; +#endif + /* A lock for concurrent access by app and isr hpet activity. */ static DEFINE_SPINLOCK(hpet_lock); /* A lock for concurrent intermodule access to hpet and isr hpet activity. */ @@ -79,7 +109,7 @@ struct hpets { struct hpets *hp_next; struct hpet __iomem *hp_hpet; unsigned long hp_hpet_phys; - struct time_interpolator *hp_interpolator; + struct clocksource *hp_clocksource; unsigned long long hp_tick_freq; unsigned long hp_delta; unsigned int hp_ntimer; @@ -94,13 +124,6 @@ static struct hpets *hpets; #define HPET_PERIODIC 0x0004 #define HPET_SHARED_IRQ 0x0008 -#if BITS_PER_LONG == 64 -#define write_counter(V, MC) writeq(V, MC) -#define read_counter(MC) readq(MC) -#else -#define write_counter(V, MC) writel(V, MC) -#define read_counter(MC) readl(MC) -#endif #ifndef readq static inline unsigned long long readq(void __iomem *addr) @@ -737,27 +760,6 @@ static ctl_table dev_root[] = { static struct ctl_table_header *sysctl_header; -static void hpet_register_interpolator(struct hpets *hpetp) -{ -#ifdef CONFIG_TIME_INTERPOLATION - struct time_interpolator *ti; - - ti = kzalloc(sizeof(*ti), GFP_KERNEL); - if (!ti) - return; - - ti->source = TIME_SOURCE_MMIO64; - ti->shift = 10; - ti->addr = &hpetp->hp_hpet->hpet_mc; - ti->frequency = hpetp->hp_tick_freq; - ti->drift = HPET_DRIFT; - ti->mask = -1; - - hpetp->hp_interpolator = ti; - register_time_interpolator(ti); -#endif -} - /* * Adjustment for when arming the timer with * initial conditions. That is, main counter @@ -909,7 +911,19 @@ int hpet_alloc(struct hpet_data *hdp) } hpetp->hp_delta = hpet_calibrate(hpetp); - hpet_register_interpolator(hpetp); + +/* This clocksource driver currently only works on ia64 */ +#ifdef CONFIG_IA64 + if (!hpet_clocksource) { + hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc; + CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr); + clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq, + clocksource_hpet.shift); + clocksource_register(&clocksource_hpet); + hpetp->hp_clocksource = &clocksource_hpet; + hpet_clocksource = &clocksource_hpet; + } +#endif return 0; } @@ -932,14 +946,14 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) printk(KERN_DEBUG "%s: 0x%lx is busy\n", __FUNCTION__, hdp->hd_phys_address); iounmap(hdp->hd_address); - return -EBUSY; + return AE_ALREADY_EXISTS; } } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { struct acpi_resource_fixed_memory32 *fixmem32; fixmem32 = &res->data.fixed_memory32; if (!fixmem32) - return -EINVAL; + return AE_NO_MEMORY; hdp->hd_phys_address = fixmem32->address; hdp->hd_address = ioremap(fixmem32->address, @@ -949,7 +963,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) printk(KERN_DEBUG "%s: 0x%lx is busy\n", __FUNCTION__, hdp->hd_phys_address); iounmap(hdp->hd_address); - return -EBUSY; + return AE_ALREADY_EXISTS; } } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { struct acpi_resource_extended_irq *irqp; @@ -995,13 +1009,19 @@ static int hpet_acpi_add(struct acpi_device *device) static int hpet_acpi_remove(struct acpi_device *device, int type) { - /* XXX need to unregister interpolator, dealloc mem, etc */ + /* XXX need to unregister clocksource, dealloc mem, etc */ return -EINVAL; } +static const struct acpi_device_id hpet_device_ids[] = { + {"PNP0103", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, hpet_device_ids); + static struct acpi_driver hpet_acpi_driver = { .name = "hpet", - .ids = "PNP0103", + .ids = hpet_device_ids, .ops = { .add = hpet_acpi_add, .remove = hpet_acpi_remove, diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 6f019f1..e74bb94 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -97,7 +97,7 @@ static int hvc_beat_config(char *p) return 0; } -static int hvc_beat_console_init(void) +static int __init hvc_beat_console_init(void) { if (hvc_beat_useit && machine_is_compatible("Beat")) { hvc_instantiate(0, 0, &hvc_beat_get_put_ops); @@ -106,7 +106,7 @@ static int hvc_beat_console_init(void) } /* temp */ -static int hvc_beat_init(void) +static int __init hvc_beat_init(void) { struct hvc_struct *hp; diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index b37f1d5..a08f8f9 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -472,7 +472,7 @@ static void hvc_handle_event(struct HvLpEvent *event) } } -static int send_open(HvLpIndex remoteLp, void *sem) +static int __init send_open(HvLpIndex remoteLp, void *sem) { return HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, @@ -484,7 +484,7 @@ static int send_open(HvLpIndex remoteLp, void *sem) 0, 0, 0, 0); } -static int hvc_vio_init(void) +static int __init hvc_vio_init(void) { atomic_t wait_flag; int rc; @@ -552,14 +552,14 @@ static int hvc_vio_init(void) } module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ -static void hvc_vio_exit(void) +static void __exit hvc_vio_exit(void) { vio_unregister_driver(&hvc_vio_driver); } module_exit(hvc_vio_exit); /* the device tree order defines our numbering */ -static int hvc_find_vtys(void) +static int __init hvc_find_vtys(void) { struct device_node *vty; int num_found = 0; diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c new file mode 100644 index 0000000..3d6bd0b --- /dev/null +++ b/drivers/char/hvc_lguest.c @@ -0,0 +1,177 @@ +/*D:300 + * The Guest console driver + * + * This is a trivial console driver: we use lguest's DMA mechanism to send + * bytes out, and register a DMA buffer to receive bytes in. It is assumed to + * be present and available from the very beginning of boot. + * + * Writing console drivers is one of the few remaining Dark Arts in Linux. + * Fortunately for us, the path of virtual consoles has been well-trodden by + * the PowerPC folks, who wrote "hvc_console.c" to generically support any + * virtual console. We use that infrastructure which only requires us to write + * the basic put_chars and get_chars functions and call the right register + * functions. + :*/ + +/*M:002 The console can be flooded: while the Guest is processing input the + * Host can send more. Buffering in the Host could alleviate this, but it is a + * difficult problem in general. :*/ +/* Copyright (C) 2006 Rusty Russell, IBM Corporation + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/err.h> +#include <linux/init.h> +#include <linux/lguest_bus.h> +#include <asm/paravirt.h> +#include "hvc_console.h" + +/*D:340 This is our single console input buffer, with associated "struct + * lguest_dma" referring to it. Note the 0-terminated length array, and the + * use of physical address for the buffer itself. */ +static char inbuf[256]; +static struct lguest_dma cons_input = { .used_len = 0, + .addr[0] = __pa(inbuf), + .len[0] = sizeof(inbuf), + .len[1] = 0 }; + +/*D:310 The put_chars() callback is pretty straightforward. + * + * First we put the pointer and length in a "struct lguest_dma": we only have + * one pointer, so we set the second length to 0. Then we use SEND_DMA to send + * the data to (Host) buffers attached to the console key. Usually a device's + * key is a physical address within the device's memory, but because the + * console device doesn't have any associated physical memory, we use the + * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */ +static int put_chars(u32 vtermno, const char *buf, int count) +{ + struct lguest_dma dma; + + /* FIXME: DMA buffers in a "struct lguest_dma" are not allowed + * to go over page boundaries. This never seems to happen, + * but if it did we'd need to fix this code. */ + dma.len[0] = count; + dma.len[1] = 0; + dma.addr[0] = __pa(buf); + + lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma); + /* We're expected to return the amount of data we wrote: all of it. */ + return count; +} + +/*D:350 get_chars() is the callback from the hvc_console infrastructure when + * an interrupt is received. + * + * Firstly we see if our buffer has been filled: if not, we return. The rest + * of the code deals with the fact that the hvc_console() infrastructure only + * asks us for 16 bytes at a time. We keep a "cons_offset" variable for + * partially-read buffers. */ +static int get_chars(u32 vtermno, char *buf, int count) +{ + static int cons_offset; + + /* Nothing left to see here... */ + if (!cons_input.used_len) + return 0; + + /* You want more than we have to give? Well, try wanting less! */ + if (cons_input.used_len - cons_offset < count) + count = cons_input.used_len - cons_offset; + + /* Copy across to their buffer and increment offset. */ + memcpy(buf, inbuf + cons_offset, count); + cons_offset += count; + + /* Finished? Zero offset, and reset cons_input so Host will use it + * again. */ + if (cons_offset == cons_input.used_len) { + cons_offset = 0; + cons_input.used_len = 0; + } + return count; +} +/*:*/ + +static struct hv_ops lguest_cons = { + .get_chars = get_chars, + .put_chars = put_chars, +}; + +/*D:320 Console drivers are initialized very early so boot messages can go + * out. At this stage, the console is output-only. Our driver checks we're a + * Guest, and if so hands hvc_instantiate() the console number (0), priority + * (0), and the struct hv_ops containing the put_chars() function. */ +static int __init cons_init(void) +{ + if (strcmp(paravirt_ops.name, "lguest") != 0) + return 0; + + return hvc_instantiate(0, 0, &lguest_cons); +} +console_initcall(cons_init); + +/*D:370 To set up and manage our virtual console, we call hvc_alloc() and + * stash the result in the private pointer of the "struct lguest_device". + * Since we never remove the console device we never need this pointer again, + * but using ->private is considered good form, and you never know who's going + * to copy your driver. + * + * Once the console is set up, we bind our input buffer ready for input. */ +static int lguestcons_probe(struct lguest_device *lgdev) +{ + int err; + + /* The first argument of hvc_alloc() is the virtual console number, so + * we use zero. The second argument is the interrupt number. + * + * The third argument is a "struct hv_ops" containing the put_chars() + * and get_chars() pointers. The final argument is the output buffer + * size: we use 256 and expect the Host to have room for us to send + * that much. */ + lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256); + if (IS_ERR(lgdev->private)) + return PTR_ERR(lgdev->private); + + /* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY. + * "cons_input" is that statically-initialized global DMA buffer we saw + * above, and we also give the interrupt we want. */ + err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1, + lgdev_irq(lgdev)); + if (err) + printk("lguest console: failed to bind buffer.\n"); + return err; +} +/* Note the use of lgdev_irq() for the interrupt number. We tell hvc_alloc() + * to expect input when this interrupt is triggered, and then tell + * lguest_bind_dma() that is the interrupt to send us when input comes in. */ + +/*D:360 From now on the console driver follows standard Guest driver form: + * register_lguest_driver() registers the device type and probe function, and + * the probe function sets up the device. + * + * The standard "struct lguest_driver": */ +static struct lguest_driver lguestcons_drv = { + .name = "lguestcons", + .owner = THIS_MODULE, + .device_type = LGUEST_DEVICE_T_CONSOLE, + .probe = lguestcons_probe, +}; + +/* The standard init function */ +static int __init hvc_lguest_init(void) +{ + return register_lguest_driver(&lguestcons_drv); +} +module_init(hvc_lguest_init); diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index 4b97eaf..bb09413 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c @@ -115,7 +115,7 @@ static void __exit hvc_rtas_exit(void) module_exit(hvc_rtas_exit); /* This will happen prior to module init. There is no tty at this time? */ -static int hvc_rtas_console_init(void) +static int __init hvc_rtas_console_init(void) { rtascons_put_char_token = rtas_token("put-term-char"); if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c new file mode 100644 index 0000000..dd68f85 --- /dev/null +++ b/drivers/char/hvc_xen.c @@ -0,0 +1,159 @@ +/* + * xen console driver interface to hvc_console.c + * + * (c) 2007 Gerd Hoffmann <kraxel@suse.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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/types.h> + +#include <asm/xen/hypervisor.h> +#include <xen/page.h> +#include <xen/events.h> +#include <xen/interface/io/console.h> +#include <xen/hvc-console.h> + +#include "hvc_console.h" + +#define HVC_COOKIE 0x58656e /* "Xen" in hex */ + +static struct hvc_struct *hvc; +static int xencons_irq; + +/* ------------------------------------------------------------------ */ + +static inline struct xencons_interface *xencons_interface(void) +{ + return mfn_to_virt(xen_start_info->console.domU.mfn); +} + +static inline void notify_daemon(void) +{ + /* Use evtchn: this is called early, before irq is set up. */ + notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); +} + +static int write_console(uint32_t vtermno, const char *data, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); /* update queue values before going on */ + BUG_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + wmb(); /* write ring before updating pointer */ + intf->out_prod = prod; + + notify_daemon(); + return sent; +} + +static int read_console(uint32_t vtermno, char *buf, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int recv = 0; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); /* get pointers before reading ring */ + BUG_ON((prod - cons) > sizeof(intf->in)); + + while (cons != prod && recv < len) + buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; + + mb(); /* read ring before consuming */ + intf->in_cons = cons; + + notify_daemon(); + return recv; +} + +static struct hv_ops hvc_ops = { + .get_chars = read_console, + .put_chars = write_console, +}; + +static int __init xen_init(void) +{ + struct hvc_struct *hp; + + if (!is_running_on_xen()) + return 0; + + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + if (xencons_irq < 0) + xencons_irq = 0 /* NO_IRQ */; + hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc = hp; + return 0; +} + +static void __exit xen_fini(void) +{ + if (hvc) + hvc_remove(hvc); +} + +static int xen_cons_init(void) +{ + if (!is_running_on_xen()) + return 0; + + hvc_instantiate(HVC_COOKIE, 0, &hvc_ops); + return 0; +} + +module_init(xen_init); +module_exit(xen_fini); +console_initcall(xen_cons_init); + +static void xenboot_write_console(struct console *console, const char *string, + unsigned len) +{ + unsigned int linelen, off = 0; + const char *pos; + + while (off < len && NULL != (pos = strchr(string+off, '\n'))) { + linelen = pos-string+off; + if (off + linelen > len) + break; + write_console(0, string+off, linelen); + write_console(0, "\r\n", 2); + off += linelen + 1; + } + if (off < len) + write_console(0, string+off, len-off); +} + +struct console xenboot_console = { + .name = "xenboot", + .write = xenboot_write_console, + .flags = CON_PRINTBUFFER | CON_BOOT, +}; diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 207f734..69d8866 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -210,9 +210,9 @@ static struct ktermios hvcs_tty_termios = { static int hvcs_parm_num_devs = -1; module_param(hvcs_parm_num_devs, int, 0); -char hvcs_driver_name[] = "hvcs"; -char hvcs_device_node[] = "hvcs"; -char hvcs_driver_string[] +static const char hvcs_driver_name[] = "hvcs"; +static const char hvcs_device_node[] = "hvcs"; +static const char hvcs_driver_string[] = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; /* Status of partner info rescan triggered via sysfs. */ @@ -784,12 +784,10 @@ static int __devinit hvcs_probe( return -EFAULT; } - hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL); + hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL); if (!hvcsd) return -ENODEV; - /* hvcsd->tty is zeroed out with the memset */ - memset(hvcsd, 0x00, sizeof(*hvcsd)); spin_lock_init(&hvcsd->lock); /* Automatically incs the refcount the first time */ @@ -1094,7 +1092,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when * calling this function or you will get deadlock. */ -struct hvcs_struct *hvcs_get_by_index(int index) +static struct hvcs_struct *hvcs_get_by_index(int index) { struct hvcs_struct *hvcsd = NULL; unsigned long flags; diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 7cda04b..2d7cd48 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -41,7 +41,7 @@ config HW_RANDOM_AMD config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" - depends on HW_RANDOM && X86 && PCI + depends on HW_RANDOM && X86_32 && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 0289705..cd40641 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -98,9 +98,9 @@ struct smm_regs { unsigned int edi __attribute__ ((packed)); }; -static inline char *i8k_get_dmi_data(int field) +static inline const char *i8k_get_dmi_data(int field) { - char *dmi_data = dmi_get_system_info(field); + const char *dmi_data = dmi_get_system_info(field); return dmi_data && *dmi_data ? dmi_data : "?"; } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 83c7258..bd94d5f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -425,9 +425,7 @@ cleanup_module(void) printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); } put_tty_driver(ip2_tty_driver); - if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { - printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); - } + unregister_chrdev(IP2_IPL_MAJOR, pcIpl); remove_proc_entry("ip2mem", &proc_root); // free memory @@ -502,7 +500,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) { int i, j, box; int err = 0; - int status = 0; static int loaded; i2eBordStrPtr pB = NULL; int rc = -1; @@ -590,6 +587,8 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) case PCI: #ifdef CONFIG_PCI { + int status; + pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); if (pci_dev_i != NULL) { @@ -719,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44e..0246a2b8 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b5df7e6..6a01dd9 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2639,10 +2639,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, return -ENODEV; } - intf = kmalloc(sizeof(*intf), GFP_KERNEL); + intf = kzalloc(sizeof(*intf), GFP_KERNEL); if (!intf) return -ENOMEM; - memset(intf, 0, sizeof(*intf)); intf->ipmi_version_major = ipmi_version_major(device_id); intf->ipmi_version_minor = ipmi_version_minor(device_id); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4edfdda..a2894d4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1965,10 +1965,10 @@ struct dmi_ipmi_data u8 slave_addr; }; -static int __devinit decode_dmi(struct dmi_header *dm, +static int __devinit decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { - u8 *data = (u8 *)dm; + const u8 *data = (const u8 *)dm; unsigned long base_addr; u8 reg_spacing; u8 len = dm->length; @@ -2050,6 +2050,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) info->si_type = SI_BT; break; default: + kfree(info); return; } @@ -2090,13 +2091,14 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) static void __devinit dmi_find_bmc(void) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; int rv; while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { memset(&data, 0, sizeof(data)); - rv = decode_dmi((struct dmi_header *) dev->device_data, &data); + rv = decode_dmi((const struct dmi_header *) dev->device_data, + &data); if (!rv) try_init_dmi(&data); } @@ -2214,7 +2216,8 @@ static int ipmi_pci_resume(struct pci_dev *pdev) static struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, - { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } + { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); @@ -2250,19 +2253,19 @@ static int __devinit ipmi_of_probe(struct of_device *dev, return ret; } - regsize = get_property(np, "reg-size", &proplen); + regsize = of_get_property(np, "reg-size", &proplen); if (regsize && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); return -EINVAL; } - regspacing = get_property(np, "reg-spacing", &proplen); + regspacing = of_get_property(np, "reg-spacing", &proplen); if (regspacing && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); return -EINVAL; } - regshift = get_property(np, "reg-shift", &proplen); + regshift = of_get_property(np, "reg-shift", &proplen); if (regshift && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); return -EINVAL; @@ -2291,7 +2294,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->irq = irq_of_parse_and_map(dev->node, 0); info->dev = &dev->dev; - dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n", + dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n", info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f40..1f27be1 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 2ce0af1..d95f316 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1022,10 +1022,6 @@ static const unsigned short x86_keycodes[256] = 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; -#ifdef CONFIG_MAC_EMUMOUSEBTN -extern int mac_hid_mouse_emulate_buttons(int, int, int); -#endif /* CONFIG_MAC_EMUMOUSEBTN */ - #ifdef CONFIG_SPARC static int sparc_l1_a_state = 0; extern void sun_do_break(void); diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c index 1f09626..4fe9206 100644 --- a/drivers/char/lcd.c +++ b/drivers/char/lcd.c @@ -25,7 +25,6 @@ #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> -#include <linux/delay.h> #include "lcd.h" diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8..c59e2a0 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 57f9115..7ee5d944 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -39,14 +39,14 @@ #else #define DBG(fmt...) #endif -int mbcs_major; +static int mbcs_major; -LIST_HEAD(soft_list); +static LIST_HEAD(soft_list); /* * file operations */ -const struct file_operations mbcs_ops = { +static const struct file_operations mbcs_ops = { .open = mbcs_open, .llseek = mbcs_sram_llseek, .read = mbcs_sram_read, @@ -377,7 +377,7 @@ dmaread_exit: return rv; } -int mbcs_open(struct inode *ip, struct file *fp) +static int mbcs_open(struct inode *ip, struct file *fp) { struct mbcs_soft *soft; int minor; @@ -394,7 +394,7 @@ int mbcs_open(struct inode *ip, struct file *fp) return -ENODEV; } -ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) +static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) { struct cx_dev *cx_dev = fp->private_data; struct mbcs_soft *soft = cx_dev->soft; @@ -418,7 +418,7 @@ ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * return rv; } -ssize_t +static ssize_t mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off) { struct cx_dev *cx_dev = fp->private_data; @@ -443,7 +443,7 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o return rv; } -loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) +static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) { loff_t newpos; @@ -491,7 +491,7 @@ static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); } -int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) +static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) { struct cx_dev *cx_dev = fp->private_data; struct mbcs_soft *soft = cx_dev->soft; @@ -793,7 +793,7 @@ static int mbcs_remove(struct cx_dev *dev) return 0; } -const struct cx_device_id __devinitdata mbcs_id_table[] = { +static const struct cx_device_id __devinitdata mbcs_id_table[] = { { .part_num = MBCS_PART_NUM, .mfg_num = MBCS_MFG_NUM, @@ -807,7 +807,7 @@ const struct cx_device_id __devinitdata mbcs_id_table[] = { MODULE_DEVICE_TABLE(cx, mbcs_id_table); -struct cx_drv mbcs_driver = { +static struct cx_drv mbcs_driver = { .name = DEVICE_NAME, .id_table = mbcs_id_table, .probe = mbcs_probe, @@ -816,12 +816,7 @@ struct cx_drv mbcs_driver = { static void __exit mbcs_exit(void) { - int rv; - - rv = unregister_chrdev(mbcs_major, DEVICE_NAME); - if (rv < 0) - DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv); - + unregister_chrdev(mbcs_major, DEVICE_NAME); cx_driver_unregister(&mbcs_driver); } diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h index e7fd47e..c9905a3 100644 --- a/drivers/char/mbcs.h +++ b/drivers/char/mbcs.h @@ -542,12 +542,12 @@ struct mbcs_soft { struct semaphore algolock; }; -extern int mbcs_open(struct inode *ip, struct file *fp); -extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, +static int mbcs_open(struct inode *ip, struct file *fp); +static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, loff_t * off); -extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, +static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, loff_t * off); -extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); -extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); +static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); +static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); #endif // __MBCS_H__ diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 6e55cfb..e60a74c 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/mm.h> +#include <linux/fs.h> #include <linux/mmtimer.h> #include <linux/miscdevice.h> #include <linux/posix-timers.h> diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index c716ef0..04ac155 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -38,6 +38,7 @@ #include <linux/miscdevice.h> #include <linux/spinlock.h> #include <linux/mm.h> +#include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/string.h> #include <linux/slab.h> @@ -66,7 +67,7 @@ /* * Page types allocated by the device. */ -enum { +enum mspec_page_type { MSPEC_FETCHOP = 1, MSPEC_CACHED, MSPEC_UNCACHED @@ -82,15 +83,25 @@ static int is_sn2; * One of these structures is allocated when an mspec region is mmaped. The * structure is pointed to by the vma->vm_private_data field in the vma struct. * This structure is used to record the addresses of the mspec pages. + * This structure is shared by all vma's that are split off from the + * original vma when split_vma()'s are done. + * + * The refcnt is incremented atomically because mm->mmap_sem does not + * protect in fork case where multiple tasks share the vma_data. */ struct vma_data { atomic_t refcnt; /* Number of vmas sharing the data. */ - spinlock_t lock; /* Serialize access to the vma. */ + spinlock_t lock; /* Serialize access to this structure. */ int count; /* Number of pages allocated. */ - int type; /* Type of pages allocated. */ + enum mspec_page_type type; /* Type of pages allocated. */ + int flags; /* See VMD_xxx below. */ + unsigned long vm_start; /* Original (unsplit) base. */ + unsigned long vm_end; /* Original (unsplit) end. */ unsigned long maddr[0]; /* Array of MSPEC addresses. */ }; +#define VMD_VMALLOCED 0x1 /* vmalloc'd rather than kmalloc'd */ + /* used on shub2 to clear FOP cache in the HUB */ static unsigned long scratch_page[MAX_NUMNODES]; #define SH2_AMO_CACHE_ENTRIES 4 @@ -128,8 +139,8 @@ mspec_zero_block(unsigned long addr, int len) * mspec_open * * Called when a device mapping is created by a means other than mmap - * (via fork, etc.). Increments the reference count on the underlying - * mspec data so it is not freed prematurely. + * (via fork, munmap, etc.). Increments the reference count on the + * underlying mspec data so it is not freed prematurely. */ static void mspec_open(struct vm_area_struct *vma) @@ -144,43 +155,43 @@ mspec_open(struct vm_area_struct *vma) * mspec_close * * Called when unmapping a device mapping. Frees all mspec pages - * belonging to the vma. + * belonging to all the vma's sharing this vma_data structure. */ static void mspec_close(struct vm_area_struct *vma) { struct vma_data *vdata; - int i, pages, result, vdata_size; + int index, last_index; + unsigned long my_page; vdata = vma->vm_private_data; + if (!atomic_dec_and_test(&vdata->refcnt)) return; - pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - vdata_size = sizeof(struct vma_data) + pages * sizeof(long); - for (i = 0; i < pages; i++) { - if (vdata->maddr[i] == 0) + last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT; + for (index = 0; index < last_index; index++) { + if (vdata->maddr[index] == 0) continue; /* * Clear the page before sticking it back * into the pool. */ - result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE); - if (!result) - uncached_free_page(vdata->maddr[i]); + my_page = vdata->maddr[index]; + vdata->maddr[index] = 0; + if (!mspec_zero_block(my_page, PAGE_SIZE)) + uncached_free_page(my_page); else printk(KERN_WARNING "mspec_close(): " - "failed to zero page %i\n", - result); + "failed to zero page %ld\n", my_page); } - if (vdata_size <= PAGE_SIZE) - kfree(vdata); - else + if (vdata->flags & VMD_VMALLOCED) vfree(vdata); + else + kfree(vdata); } - /* * mspec_nopfn * @@ -194,7 +205,8 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) int index; struct vma_data *vdata = vma->vm_private_data; - index = (address - vma->vm_start) >> PAGE_SHIFT; + BUG_ON(address < vdata->vm_start || address >= vdata->vm_end); + index = (address - vdata->vm_start) >> PAGE_SHIFT; maddr = (volatile unsigned long) vdata->maddr[index]; if (maddr == 0) { maddr = uncached_alloc_page(numa_node_id()); @@ -236,10 +248,11 @@ static struct vm_operations_struct mspec_vm_ops = { * underlying pages. */ static int -mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) +mspec_mmap(struct file *file, struct vm_area_struct *vma, + enum mspec_page_type type) { struct vma_data *vdata; - int pages, vdata_size; + int pages, vdata_size, flags = 0; if (vma->vm_pgoff != 0) return -EINVAL; @@ -254,12 +267,17 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) vdata_size = sizeof(struct vma_data) + pages * sizeof(long); if (vdata_size <= PAGE_SIZE) vdata = kmalloc(vdata_size, GFP_KERNEL); - else + else { vdata = vmalloc(vdata_size); + flags = VMD_VMALLOCED; + } if (!vdata) return -ENOMEM; memset(vdata, 0, vdata_size); + vdata->vm_start = vma->vm_start; + vdata->vm_end = vma->vm_end; + vdata->flags = flags; vdata->type = type; spin_lock_init(&vdata->lock); vdata->refcnt = ATOMIC_INIT(1); diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index fee58e0..cc5d777 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1629,7 +1629,7 @@ static int cmm_open(struct inode *inode, struct file *filp) { struct cm4000_dev *dev; struct pcmcia_device *link; - int rc, minor = iminor(inode); + int minor = iminor(inode); if (minor >= CM4000_MAX_DEV) return -ENODEV; @@ -1668,7 +1668,6 @@ static int cmm_open(struct inode *inode, struct file *filp) start_monitor(dev); link->open = 1; /* only one open per device */ - rc = 0; DEBUGP(2, dev, "<- cmm_open\n"); return nonseekable_open(inode, filp); @@ -1824,7 +1823,7 @@ static int cm4000_resume(struct pcmcia_device *link) static void cm4000_release(struct pcmcia_device *link) { - cmm_cm4000_release(link->priv); /* delay release until device closed */ + cmm_cm4000_release(link); /* delay release until device closed */ pcmcia_disable_device(link); } @@ -1864,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1889,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index af88181..a0b9c87 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -599,7 +599,7 @@ cs_release: static void reader_release(struct pcmcia_device *link) { - cm4040_reader_release(link->priv); + cm4040_reader_release(link); pcmcia_disable_device(link); } @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 13808f6..2b88931 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -540,13 +540,12 @@ static int mgslpc_probe(struct pcmcia_device *link) if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_attach\n"); - info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); + info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); if (!info) { printk("Error can't allocate device instance data\n"); return -ENOMEM; } - memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c new file mode 100644 index 0000000..79b6f46 --- /dev/null +++ b/drivers/char/ps3flash.c @@ -0,0 +1,440 @@ +/* + * PS3 FLASH ROM Storage Driver + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corp. + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> + +#include <asm/lv1call.h> +#include <asm/ps3stor.h> + + +#define DEVICE_NAME "ps3flash" + +#define FLASH_BLOCK_SIZE (256*1024) + + +struct ps3flash_private { + struct mutex mutex; /* Bounce buffer mutex */ +}; + +static struct ps3_storage_device *ps3flash_dev; + +static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, + u64 lpar, u64 start_sector, + u64 sectors, int write) +{ + u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, + write); + if (res) { + dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, + __LINE__, write ? "write" : "read", res); + return -EIO; + } + return sectors; +} + +static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, + u64 start_sector, u64 sectors, + unsigned int sector_offset) +{ + u64 max_sectors, lpar; + + max_sectors = dev->bounce_size / dev->blk_size; + if (sectors > max_sectors) { + dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n", + __func__, __LINE__, max_sectors); + sectors = max_sectors; + } + + lpar = dev->bounce_lpar + sector_offset * dev->blk_size; + return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, + 0); +} + +static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, + u64 start_sector) +{ + u64 sectors = dev->bounce_size / dev->blk_size; + return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, + sectors, 1); +} + +static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) +{ + struct ps3_storage_device *dev = ps3flash_dev; + loff_t res; + + mutex_lock(&file->f_mapping->host->i_mutex); + switch (origin) { + case 1: + offset += file->f_pos; + break; + case 2: + offset += dev->regions[dev->region_idx].size*dev->blk_size; + break; + } + if (offset < 0) { + res = -EINVAL; + goto out; + } + + file->f_pos = offset; + res = file->f_pos; + +out: + mutex_unlock(&file->f_mapping->host->i_mutex); + return res; +} + +static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, + loff_t *pos) +{ + struct ps3_storage_device *dev = ps3flash_dev; + struct ps3flash_private *priv = dev->sbd.core.driver_data; + u64 size, start_sector, end_sector, offset; + ssize_t sectors_read; + size_t remaining, n; + + dev_dbg(&dev->sbd.core, + "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", + __func__, __LINE__, count, *pos, buf); + + size = dev->regions[dev->region_idx].size*dev->blk_size; + if (*pos >= size || !count) + return 0; + + if (*pos + count > size) { + dev_dbg(&dev->sbd.core, + "%s:%u Truncating count from %zu to %llu\n", __func__, + __LINE__, count, size - *pos); + count = size - *pos; + } + + start_sector = *pos / dev->blk_size; + offset = *pos % dev->blk_size; + end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); + + remaining = count; + do { + mutex_lock(&priv->mutex); + + sectors_read = ps3flash_read_sectors(dev, start_sector, + end_sector-start_sector, + 0); + if (sectors_read < 0) { + mutex_unlock(&priv->mutex); + goto fail; + } + + n = min(remaining, sectors_read*dev->blk_size-offset); + dev_dbg(&dev->sbd.core, + "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", + __func__, __LINE__, n, dev->bounce_buf+offset, buf); + if (copy_to_user(buf, dev->bounce_buf+offset, n)) { + mutex_unlock(&priv->mutex); + sectors_read = -EFAULT; + goto fail; + } + + mutex_unlock(&priv->mutex); + + *pos += n; + buf += n; + remaining -= n; + start_sector += sectors_read; + offset = 0; + } while (remaining > 0); + + return count; + +fail: + return sectors_read; +} + +static ssize_t ps3flash_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ps3_storage_device *dev = ps3flash_dev; + struct ps3flash_private *priv = dev->sbd.core.driver_data; + u64 size, chunk_sectors, start_write_sector, end_write_sector, + end_read_sector, start_read_sector, head, tail, offset; + ssize_t res; + size_t remaining, n; + unsigned int sec_off; + + dev_dbg(&dev->sbd.core, + "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", + __func__, __LINE__, count, *pos, buf); + + size = dev->regions[dev->region_idx].size*dev->blk_size; + if (*pos >= size || !count) + return 0; + + if (*pos + count > size) { + dev_dbg(&dev->sbd.core, + "%s:%u Truncating count from %zu to %llu\n", __func__, + __LINE__, count, size - *pos); + count = size - *pos; + } + + chunk_sectors = dev->bounce_size / dev->blk_size; + + start_write_sector = *pos / dev->bounce_size * chunk_sectors; + offset = *pos % dev->bounce_size; + end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * + chunk_sectors; + + end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); + start_read_sector = (*pos + count) / dev->blk_size; + + /* + * As we have to write in 256 KiB chunks, while we can read in blk_size + * (usually 512 bytes) chunks, we perform the following steps: + * 1. Read from start_write_sector to end_read_sector ("head") + * 2. Read from start_read_sector to end_write_sector ("tail") + * 3. Copy data to buffer + * 4. Write from start_write_sector to end_write_sector + * All of this is complicated by using only one 256 KiB bounce buffer. + */ + + head = end_read_sector - start_write_sector; + tail = end_write_sector - start_read_sector; + + remaining = count; + do { + mutex_lock(&priv->mutex); + + if (end_read_sector >= start_read_sector) { + /* Merge head and tail */ + dev_dbg(&dev->sbd.core, + "Merged head and tail: %lu sectors at %lu\n", + chunk_sectors, start_write_sector); + res = ps3flash_read_sectors(dev, start_write_sector, + chunk_sectors, 0); + if (res < 0) + goto fail; + } else { + if (head) { + /* Read head */ + dev_dbg(&dev->sbd.core, + "head: %lu sectors at %lu\n", head, + start_write_sector); + res = ps3flash_read_sectors(dev, + start_write_sector, + head, 0); + if (res < 0) + goto fail; + } + if (start_read_sector < + start_write_sector+chunk_sectors) { + /* Read tail */ + dev_dbg(&dev->sbd.core, + "tail: %lu sectors at %lu\n", tail, + start_read_sector); + sec_off = start_read_sector-start_write_sector; + res = ps3flash_read_sectors(dev, + start_read_sector, + tail, sec_off); + if (res < 0) + goto fail; + } + } + + n = min(remaining, dev->bounce_size-offset); + dev_dbg(&dev->sbd.core, + "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", + __func__, __LINE__, n, buf, dev->bounce_buf+offset); + if (copy_from_user(dev->bounce_buf+offset, buf, n)) { + res = -EFAULT; + goto fail; + } + + res = ps3flash_write_chunk(dev, start_write_sector); + if (res < 0) + goto fail; + + mutex_unlock(&priv->mutex); + + *pos += n; + buf += n; + remaining -= n; + start_write_sector += chunk_sectors; + head = 0; + offset = 0; + } while (remaining > 0); + + return count; + +fail: + mutex_unlock(&priv->mutex); + return res; +} + + +static irqreturn_t ps3flash_interrupt(int irq, void *data) +{ + struct ps3_storage_device *dev = data; + int res; + u64 tag, status; + + res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); + + if (tag != dev->tag) + dev_err(&dev->sbd.core, + "%s:%u: tag mismatch, got %lx, expected %lx\n", + __func__, __LINE__, tag, dev->tag); + + if (res) { + dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n", + __func__, __LINE__, res, status); + } else { + dev->lv1_status = status; + complete(&dev->done); + } + return IRQ_HANDLED; +} + + +static const struct file_operations ps3flash_fops = { + .owner = THIS_MODULE, + .llseek = ps3flash_llseek, + .read = ps3flash_read, + .write = ps3flash_write, +}; + +static struct miscdevice ps3flash_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &ps3flash_fops, +}; + +static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) +{ + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); + struct ps3flash_private *priv; + int error; + unsigned long tmp; + + tmp = dev->regions[dev->region_idx].start*dev->blk_size; + if (tmp % FLASH_BLOCK_SIZE) { + dev_err(&dev->sbd.core, + "%s:%u region start %lu is not aligned\n", __func__, + __LINE__, tmp); + return -EINVAL; + } + tmp = dev->regions[dev->region_idx].size*dev->blk_size; + if (tmp % FLASH_BLOCK_SIZE) { + dev_err(&dev->sbd.core, + "%s:%u region size %lu is not aligned\n", __func__, + __LINE__, tmp); + return -EINVAL; + } + + /* use static buffer, kmalloc cannot allocate 256 KiB */ + if (!ps3flash_bounce_buffer.address) + return -ENODEV; + + if (ps3flash_dev) { + dev_err(&dev->sbd.core, + "Only one FLASH device is supported\n"); + return -EBUSY; + } + + ps3flash_dev = dev; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + error = -ENOMEM; + goto fail; + } + + dev->sbd.core.driver_data = priv; + mutex_init(&priv->mutex); + + dev->bounce_size = ps3flash_bounce_buffer.size; + dev->bounce_buf = ps3flash_bounce_buffer.address; + + error = ps3stor_setup(dev, ps3flash_interrupt); + if (error) + goto fail_free_priv; + + ps3flash_misc.parent = &dev->sbd.core; + error = misc_register(&ps3flash_misc); + if (error) { + dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n", + __func__, __LINE__, error); + goto fail_teardown; + } + + dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", + __func__, __LINE__, ps3flash_misc.minor); + return 0; + +fail_teardown: + ps3stor_teardown(dev); +fail_free_priv: + kfree(priv); + dev->sbd.core.driver_data = NULL; +fail: + ps3flash_dev = NULL; + return error; +} + +static int ps3flash_remove(struct ps3_system_bus_device *_dev) +{ + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); + + misc_deregister(&ps3flash_misc); + ps3stor_teardown(dev); + kfree(dev->sbd.core.driver_data); + dev->sbd.core.driver_data = NULL; + ps3flash_dev = NULL; + return 0; +} + + +static struct ps3_system_bus_driver ps3flash = { + .match_id = PS3_MATCH_ID_STOR_FLASH, + .core.name = DEVICE_NAME, + .core.owner = THIS_MODULE, + .probe = ps3flash_probe, + .remove = ps3flash_remove, + .shutdown = ps3flash_remove, +}; + + +static int __init ps3flash_init(void) +{ + return ps3_system_bus_driver_register(&ps3flash); +} + +static void __exit ps3flash_exit(void) +{ + ps3_system_bus_driver_unregister(&ps3flash); +} + +module_init(ps3flash_init); +module_exit(ps3flash_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver"); +MODULE_AUTHOR("Sony Corporation"); +MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH); diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea..73de771 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/drivers/char/random.c b/drivers/char/random.c index 7f52712..af274e5 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -693,9 +693,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) if (r->pull && r->entropy_count < nbytes * 8 && r->entropy_count < r->poolinfo->POOLBITS) { - int bytes = max_t(int, random_read_wakeup_thresh / 8, - min_t(int, nbytes, sizeof(tmp))); + /* If we're limited, always leave two wakeup worth's BITS */ int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int bytes = nbytes; + + /* pull at least as many as BYTES as wakeup BITS */ + bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); + /* but never more than the buffer size */ + bytes = min_t(int, bytes, sizeof(tmp)); DEBUG_ENT("going to reseed %s with %d bits " "(%d of %d requested)\n", @@ -1545,11 +1550,13 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * As close as possible to RFC 793, which * suggests using a 250 kHz clock. * Further reading shows this assumes 2 Mb/s networks. - * For 10 Gb/s Ethernet, a 1 GHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - * (Networks are faster now - should this be increased?) + * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. + * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but + * we also need to limit the resolution so that the u32 seq + * overlaps less than one time per MSL (2 minutes). + * Choosing a clock of 64 ns period is OK. (period of 274 s) */ - seq += ktime_get_real().tv64; + seq += ktime_get_real().tv64 >> 6; #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", saddr, daddr, sport, dport, seq); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c6..bbfa0e2 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 294e9cb..0ce9667 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -803,9 +803,7 @@ static void *ckmalloc(int size) { void *p; - p = kmalloc(size, GFP_KERNEL); - if (p) - memset(p, 0, size); + p = kzalloc(size, GFP_KERNEL); return p; } diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 8cc60b6..7321d00 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -556,9 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void) { struct CmdBlk *CmdBlkP; - CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC); - if (CmdBlkP) - memset(CmdBlkP, 0, sizeof(struct CmdBlk)); + CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC); return CmdBlkP; } diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c index 7e98835..991119c 100644 --- a/drivers/char/rio/riotable.c +++ b/drivers/char/rio/riotable.c @@ -863,8 +863,7 @@ int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP) if (PortP->TxRingBuffer) memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); else if (p->RIOBufferSize) { - PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL); - memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); + PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL); } PortP->TxBufferOut = 0; PortP->TxBufferIn = 0; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0270080..56cbba7 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -635,12 +635,11 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) ctlp = sCtlNumToCtlPtr(board); /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ - info = kmalloc(sizeof (struct r_port), GFP_KERNEL); + info = kzalloc(sizeof (struct r_port), GFP_KERNEL); if (!info) { printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); return; } - memset(info, 0, sizeof (struct r_port)); info->magic = RPORT_MAGIC; info->line = line; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 22cf7aa..ec6b65e 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -82,16 +82,13 @@ #include <asm/uaccess.h> #include <asm/system.h> -#if defined(__i386__) +#ifdef CONFIG_X86 #include <asm/hpet.h> #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 #include <linux/pci.h> #include <asm/ebus.h> -#ifdef __sparc_v9__ -#include <asm/isa.h> -#endif static unsigned long rtc_port; static int rtc_irq = PCI_IRQ_NONE; @@ -930,13 +927,9 @@ static int __init rtc_init(void) unsigned int year, ctrl; char *guess = NULL; #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 struct linux_ebus *ebus; struct linux_ebus_device *edev; -#ifdef __sparc_v9__ - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif #else void *r; #ifdef RTC_IRQ @@ -944,7 +937,7 @@ static int __init rtc_init(void) #endif #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if(strcmp(edev->prom_node->name, "rtc") == 0) { @@ -954,17 +947,6 @@ static int __init rtc_init(void) } } } -#ifdef __sparc_v9__ - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { - rtc_port = isa_dev->resource.start; - rtc_irq = isa_dev->irq; - goto found; - } - } - } -#endif rtc_has_irq = 0; printk(KERN_ERR "rtc_init: no PC rtc found\n"); return -EIO; @@ -1020,7 +1002,7 @@ no_irq: #endif -#endif /* __sparc__ vs. others */ +#endif /* CONFIG_SPARC32 vs. others */ if (misc_register(&rtc_dev)) { #ifdef RTC_IRQ @@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void) remove_proc_entry ("driver/rtc", NULL); misc_deregister(&rtc_dev); -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 if (rtc_has_irq) free_irq (rtc_irq, &rtc_port); #else @@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void) if (rtc_has_irq) free_irq (RTC_IRQ, NULL); #endif -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC32 */ } module_init(rtc_init); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index c585b47..f1497ce 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c, return cy_serial_driver; } -static int __init serial167_console_setup(struct console *co, char *options) -{ - return 0; -} - static struct console sercons = { .name = "ttyS", .write = serial167_console_write, .device = serial167_console_device, - .setup = serial167_console_setup, .flags = CON_PRINTBUFFER, .index = -1, }; diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e7..b9c1dba 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 73037a4..8598585 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -875,7 +875,7 @@ found: #ifdef CONFIG_ACPI if (sonypi_acpi_device) - acpi_bus_generate_event(sonypi_acpi_device, 1, event); + acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); #endif kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); @@ -1147,10 +1147,15 @@ static int sonypi_acpi_remove(struct acpi_device *device, int type) return 0; } +const static struct acpi_device_id sonypi_device_ids[] = { + {"SNY6001", 0}, + {"", 0}, +}; + static struct acpi_driver sonypi_acpi_driver = { .name = "sonypi", .class = "hkey", - .ids = "SNY6001", + .ids = sonypi_device_ids, .ops = { .add = sonypi_acpi_add, .remove = sonypi_acpi_remove, diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 93d0bb8..45758d5 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4795,7 +4794,6 @@ static void __exit stallion_module_exit(void) { struct stlbrd *brdp; unsigned int i, j; - int retval; pr_debug("cleanup_module()\n"); @@ -4817,10 +4815,8 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) - printk("STALLION: failed to un-register serial memory device, " - "errno=%d\n", -retval); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); pci_unregister_driver(&stl_pcidriver); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index f53e51d..fdc256b 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -4324,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void) { struct mgsl_struct *info; - info = kmalloc(sizeof(struct mgsl_struct), + info = kzalloc(sizeof(struct mgsl_struct), GFP_KERNEL); if (!info) { printk("Error can't allocate device instance data\n"); } else { - memset(info, 0, sizeof(struct mgsl_struct)); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 428b514..2f97d2f 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1,5 +1,5 @@ /* - * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $ + * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $ * * Device driver for Microgate SyncLink GT serial adapters. * @@ -93,7 +93,7 @@ * module identification */ static char *driver_name = "SyncLink GT"; -static char *driver_version = "$Revision: 4.36 $"; +static char *driver_version = "$Revision: 4.50 $"; static char *tty_driver_name = "synclink_gt"; static char *tty_dev_prefix = "ttySLG"; MODULE_LICENSE("GPL"); @@ -477,6 +477,7 @@ static void tx_set_idle(struct slgt_info *info); static unsigned int free_tbuf_count(struct slgt_info *info); static void reset_tbufs(struct slgt_info *info); static void tdma_reset(struct slgt_info *info); +static void tdma_start(struct slgt_info *info); static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); static void get_signals(struct slgt_info *info); @@ -904,6 +905,8 @@ start: spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) tx_start(info); + else + tdma_start(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -1562,6 +1565,9 @@ static int hdlcdev_open(struct net_device *dev) int rc; unsigned long flags; + if (!try_module_get(THIS_MODULE)) + return -EBUSY; + DBGINFO(("%s hdlcdev_open\n", dev->name)); /* generic HDLC layer open processing */ @@ -1631,6 +1637,7 @@ static int hdlcdev_close(struct net_device *dev) info->netcount=0; spin_unlock_irqrestore(&info->netlock, flags); + module_put(THIS_MODULE); return 0; } @@ -3414,13 +3421,12 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev { struct slgt_info *info; - info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL); + info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL); if (!info) { DBGERR(("%s device alloc failed adapter=%d port=%d\n", driver_name, adapter_num, port_num)); } else { - memset(info, 0, sizeof(struct slgt_info)); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; @@ -3872,44 +3878,58 @@ static void tx_start(struct slgt_info *info) slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); /* clear tx idle and underrun status bits */ wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); - - if (!(rd_reg32(info, TDCSR) & BIT0)) { - /* tx DMA stopped, restart tx DMA */ - tdma_reset(info); - /* set 1st descriptor address */ - wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); - switch(info->params.mode) { - case MGSL_MODE_RAW: - case MGSL_MODE_MONOSYNC: - case MGSL_MODE_BISYNC: - wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ - break; - default: - wr_reg32(info, TDCSR, BIT0); /* DMA enable */ - } - } - if (info->params.mode == MGSL_MODE_HDLC) mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); } else { - tdma_reset(info); - /* set 1st descriptor address */ - wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); - slgt_irq_off(info, IRQ_TXDATA); slgt_irq_on(info, IRQ_TXIDLE); /* clear tx idle status bit */ wr_reg16(info, SSR, IRQ_TXIDLE); - - /* enable tx DMA */ - wr_reg32(info, TDCSR, BIT0); } - + tdma_start(info); info->tx_active = 1; } } +/* + * start transmit DMA if inactive and there are unsent buffers + */ +static void tdma_start(struct slgt_info *info) +{ + unsigned int i; + + if (rd_reg32(info, TDCSR) & BIT0) + return; + + /* transmit DMA inactive, check for unsent buffers */ + i = info->tbuf_start; + while (!desc_count(info->tbufs[i])) { + if (++i == info->tbuf_count) + i = 0; + if (i == info->tbuf_current) + return; + } + info->tbuf_start = i; + + /* there are unsent buffers, start transmit DMA */ + + /* reset needed if previous error condition */ + tdma_reset(info); + + /* set 1st descriptor address */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + switch(info->params.mode) { + case MGSL_MODE_RAW: + case MGSL_MODE_MONOSYNC: + case MGSL_MODE_BISYNC: + wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ + break; + default: + wr_reg32(info, TDCSR, BIT0); /* DMA enable */ + } +} + static void tx_stop(struct slgt_info *info) { unsigned short val; @@ -4643,8 +4663,8 @@ static unsigned int free_tbuf_count(struct slgt_info *info) i=0; } while (i != info->tbuf_current); - /* last buffer with zero count may be in use, assume it is */ - if (count) + /* if tx DMA active, last zero count buffer is in use */ + if (count && (rd_reg32(info, TDCSR) & BIT0)) --count; return count; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index a65407b..c63013b 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -3786,14 +3786,13 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) { SLMP_INFO *info; - info = kmalloc(sizeof(SLMP_INFO), + info = kzalloc(sizeof(SLMP_INFO), GFP_KERNEL); if (!info) { printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", __FILE__,__LINE__, adapter_num, port_num); } else { - memset(info, 0, sizeof(SLMP_INFO)); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b9..cef55c4 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9bb5429..39564b7 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -7,7 +7,7 @@ * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * Maintained by: <tpmdd_devel@lists.sourceforge.net> + * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index b2e2b00..d15ccdd 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -7,7 +7,7 @@ * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * Maintained by: <tpmdd_devel@lists.sourceforge.net> + * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 1ab0896..d0e7926 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -7,7 +7,7 @@ * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * Maintained by: <tpmdd_devel@lists.sourceforge.net> + * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index 9363bcf..6c831f9 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -4,7 +4,7 @@ * Authors: * Kylene Hall <kjhall@us.ibm.com> * - * Maintained by: <tpmdd_devel@lists.sourceforge.net> + * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 4eba32b..60a2d26 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -7,6 +7,8 @@ * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * + * Maintained by: <tpmdd-devel@lists.sourceforge.net> + * * Access to the eventlog extended by the TCG BIOS of PC platform * * This program is free software; you can redistribute it and/or @@ -427,7 +429,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode, return -ENOMEM; if ((err = read_log(log))) - return err; + goto out_free; /* now register seq file */ err = seq_open(file, &tpm_ascii_b_measurments_seqops); @@ -435,10 +437,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode, seq = file->private_data; seq->private = log; } else { - kfree(log->bios_event_log); - kfree(log); + goto out_free; } + +out: return err; +out_free: + kfree(log->bios_event_log); + kfree(log); + goto out; } const struct file_operations tpm_ascii_bios_measurements_ops = { @@ -460,7 +467,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode, return -ENOMEM; if ((err = read_log(log))) - return err; + goto out_free; /* now register seq file */ err = seq_open(file, &tpm_binary_b_measurments_seqops); @@ -468,10 +475,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode, seq = file->private_data; seq->private = log; } else { - kfree(log->bios_event_log); - kfree(log); + goto out_free; } + +out: return err; +out_free: + kfree(log->bios_event_log); + kfree(log); + goto out; } const struct file_operations tpm_binary_bios_measurements_ops = { diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 608f730..6313326 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -7,7 +7,7 @@ * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * Maintained by: <tpmdd_devel@lists.sourceforge.net> + * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 483f3f6..23fa18a 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -5,6 +5,8 @@ * Leendert van Doorn <leendert@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * + * Maintained by: <tpmdd-devel@lists.sourceforge.net> + * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org * diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index de37ebc..9c867cf 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -369,25 +369,54 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) } /** - * tty_buffer_flush - flush full tty buffers + * __tty_buffer_flush - flush full tty buffers * @tty: tty to flush * - * flush all the buffers containing receive data + * flush all the buffers containing receive data. Caller must + * hold the buffer lock and must have ensured no parallel flush to + * ldisc is running. * - * Locking: none + * Locking: Caller must hold tty->buf.lock */ -static void tty_buffer_flush(struct tty_struct *tty) +static void __tty_buffer_flush(struct tty_struct *tty) { struct tty_buffer *thead; - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); while((thead = tty->buf.head) != NULL) { tty->buf.head = thead->next; tty_buffer_free(tty, thead); } tty->buf.tail = NULL; +} + +/** + * tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data. If the buffer is + * being processed by flush_to_ldisc then we defer the processing + * to that function + * + * Locking: none + */ + +static void tty_buffer_flush(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + + /* If the data is being pushed to the tty layer then we can't + process it here. Instead set a flag and the flush_to_ldisc + path will process the flush request before it exits */ + if (test_bit(TTY_FLUSHING, &tty->flags)) { + set_bit(TTY_FLUSHPENDING, &tty->flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); + wait_event(tty->read_wait, + test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); + return; + } else + __tty_buffer_flush(tty); spin_unlock_irqrestore(&tty->buf.lock, flags); } @@ -2034,8 +2063,7 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*tp_loc) { - tp = (struct ktermios *) kmalloc(sizeof(struct ktermios), - GFP_KERNEL); + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!tp) goto free_mem_out; *tp = driver->init_termios; @@ -2065,8 +2093,7 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*o_tp_loc) { - o_tp = (struct ktermios *) - kmalloc(sizeof(struct ktermios), GFP_KERNEL); + o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!o_tp) goto free_mem_out; *o_tp = driver->other->init_termios; @@ -3594,6 +3621,7 @@ static void flush_to_ldisc(struct work_struct *work) return; spin_lock_irqsave(&tty->buf.lock, flags); + set_bit(TTY_FLUSHING, &tty->flags); /* So we know a flush is running */ head = tty->buf.head; if (head != NULL) { tty->buf.head = NULL; @@ -3607,6 +3635,11 @@ static void flush_to_ldisc(struct work_struct *work) tty_buffer_free(tty, tbuf); continue; } + /* Ldisc or user is trying to flush the buffers + we are feeding to the ldisc, stop feeding the + line discipline as we want to empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) + break; if (!tty->receive_room) { schedule_delayed_work(&tty->buf.work, 1); break; @@ -3620,8 +3653,17 @@ static void flush_to_ldisc(struct work_struct *work) disc->receive_buf(tty, char_buf, flag_buf, count); spin_lock_irqsave(&tty->buf.lock, flags); } + /* Restore the queue head */ tty->buf.head = head; } + /* We may have a deferred request to flush the input buffer, + if so pull the chain under the lock and empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { + __tty_buffer_flush(tty); + clear_bit(TTY_FLUSHPENDING, &tty->flags); + wake_up(&tty->read_wait); + } + clear_bit(TTY_FLUSHING, &tty->flags); spin_unlock_irqrestore(&tty->buf.lock, flags); tty_ldisc_deref(disc); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3423e9ee..3ee73cf 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -795,6 +795,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, if (L_ICANON(tty)) retval = inq_canon(tty); return put_user(retval, (unsigned int __user *) arg); +#ifndef TCGETS2 case TIOCGLCKTRMIOS: if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) return -EFAULT; @@ -806,6 +807,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) return -EFAULT; return 0; +#else + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) + return -EFAULT; + return 0; +#endif case TIOCPKT: { diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index db57277..db7a731 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -92,47 +92,6 @@ struct viot_devinfo_struct { #define VIOTAPOP_SETPART 14 #define VIOTAPOP_UNLOAD 15 -struct viotapelpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_type_result; - u16 tape; - u16 flags; - u32 token; - u64 len; - union { - struct { - u32 tape_op; - u32 count; - } op; - struct { - u32 type; - u32 resid; - u32 dsreg; - u32 gstat; - u32 erreg; - u32 file_no; - u32 block_no; - } get_status; - struct { - u32 block_no; - } get_pos; - } u; -}; - -enum viotapesubtype { - viotapeopen = 0x0001, - viotapeclose = 0x0002, - viotaperead = 0x0003, - viotapewrite = 0x0004, - viotapegetinfo = 0x0005, - viotapeop = 0x0006, - viotapegetpos = 0x0007, - viotapesetpos = 0x0008, - viotapegetstatus = 0x0009 -}; - enum viotaperc { viotape_InvalidRange = 0x0601, viotape_InvalidToken = 0x0602, @@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = { #define VIOT_WRITING 2 /* Our info on the tapes */ -struct tape_descr { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - -static struct tape_descr *viotape_unitinfo; -static dma_addr_t viotape_unitinfo_token; +static struct { + const char *rsrcname; + const char *type; + const char *model; +} viotape_unitinfo[VIOTAPE_MAX_TAPE]; static struct mtget viomtget[VIOTAPE_MAX_TAPE]; @@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno) return -err->errno; } -/* Get info on all tapes from OS/400 */ -static int get_viotape_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE; - struct op_struct *op = get_op_struct(); - - if (op == NULL) - return -ENOMEM; - - viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len, - &viotape_unitinfo_token, GFP_ATOMIC); - if (viotape_unitinfo == NULL) { - free_op_struct(op); - return -ENOMEM; - } - - memset(viotape_unitinfo, 0, len); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_tape | viotapegetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64) (unsigned long) op, VIOVERSION << 16, - viotape_unitinfo_token, len, 0, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOTAPE_KERN_WARN "hv error on op %d\n", - (int)hvrc); - free_op_struct(op); - return -EIO; - } - - wait_for_completion(&op->com); - - free_op_struct(op); - - for (i = 0; - ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0])); - i++) - viotape_numdev++; - return 0; -} - - /* Write */ static ssize_t viotap_write(struct file *file, const char *buf, size_t count, loff_t * ppos) @@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event) tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; op = (struct op_struct *)event->xCorrelationToken; switch (tapeminor) { - case viotapegetinfo: case viotapeopen: case viotapeclose: op->rc = tevent->sub_type_result; @@ -942,19 +850,31 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) { int i = vdev->unit_address; int j; + struct device_node *node = vdev->dev.archdata.of_node; - if (i >= viotape_numdev) + if (i > VIOTAPE_MAX_TAPE) return -ENODEV; + if (!node) + return -ENODEV; + + if (i >= viotape_numdev) + viotape_numdev = i + 1; tape_device[i] = &vdev->dev; + viotape_unitinfo[i].rsrcname = of_get_property(node, + "linux,vio_rsrcname", NULL); + viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type", + NULL); + viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model", + NULL); state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -966,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } @@ -1044,11 +964,6 @@ int __init viotap_init(void) goto unreg_chrdev; } - if ((ret = get_viotape_info()) < 0) { - printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information"); - goto unreg_class; - } - ret = vio_register_driver(&viotape_driver); if (ret) goto unreg_class; @@ -1098,19 +1013,10 @@ static int chg_state(int index, unsigned char new_state, struct file *file) /* Cleanup */ static void __exit viotap_exit(void) { - int ret; - remove_proc_entry("iSeries/viotape", NULL); vio_unregister_driver(&viotape_driver); class_destroy(tape_class); - ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); - if (ret < 0) - printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n", - ret); - if (viotape_unitinfo) - dma_free_coherent(iSeries_vio_dev, - sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, - viotape_unitinfo, viotape_unitinfo_token); + unregister_chrdev(VIOTAPE_MAJOR, "viotape"); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); clear_op_struct_pool(); diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index bef6d88..e122a0e 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index) return scc_driver; } - -static int __init scc_console_setup(struct console *co, char *options) -{ - return 0; -} - - static struct console sercons = { .name = "ttyS", .write = scc_console_write, .device = scc_console_device, - .setup = scc_console_setup, .flags = CON_PRINTBUFFER, .index = -1, }; diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index c6f6f42..7a61a2a 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -770,6 +770,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * Switching-from response */ + acquire_console_sem(); if (vc->vt_newvt >= 0) { if (arg == 0) /* @@ -784,7 +785,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * complete the switch. */ int newvt; - acquire_console_sem(); newvt = vc->vt_newvt; vc->vt_newvt = -1; i = vc_allocate(newvt); @@ -798,7 +798,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * other console switches.. */ complete_change_console(vc_cons[newvt].d); - release_console_sem(); } } @@ -810,9 +809,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * If it's just an ACK, ignore it */ - if (arg != VT_ACKACQ) + if (arg != VT_ACKACQ) { + release_console_sem(); return -EINVAL; + } } + release_console_sem(); return 0; @@ -1030,7 +1032,7 @@ static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); /* * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted. + * 0 if activation, -EINTR if interrupted by a signal handler. */ int vt_waitactive(int vt) { @@ -1055,7 +1057,7 @@ int vt_waitactive(int vt) break; } release_console_sem(); - retval = -EINTR; + retval = -ERESTARTNOHAND; if (signal_pending(current)) break; schedule(); @@ -1208,15 +1210,18 @@ void change_console(struct vc_data *new_vc) /* * Send the signal as privileged - kill_pid() will * tell us if the process has gone or something else - * is awry + * is awry. + * + * We need to set vt_newvt *before* sending the signal or we + * have a race. */ + vc->vt_newvt = new_vc->vc_num; if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a * VT_RELDISP ioctl to complete the switch. */ - vc->vt_newvt = new_vc->vc_num; return; } diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 2f48ba3..37bddc1 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -55,6 +55,8 @@ config SOFT_WATCHDOG To compile this driver as a module, choose M here: the module will be called softdog. +# ALPHA Architecture + # ARM Architecture config AT91RM9200_WATCHDOG @@ -187,15 +189,64 @@ config PNX4008_WATCHDOG Say N if you are unsure. +config IOP_WATCHDOG + tristate "IOP Watchdog" + depends on PLAT_IOP + select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X) + help + Say Y here if to include support for the watchdog timer + in the Intel IOP3XX & IOP13XX I/O Processors. This driver can + be built as a module by choosing M. The module will + be called iop_wdt. + + Note: The IOP13XX watchdog does an Internal Bus Reset which will + affect both cores and the peripherals of the IOP. The ATU-X + and/or ATUe configuration registers will remain intact, but if + operating as an Root Complex and/or Central Resource, the PCI-X + and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER. + +config DAVINCI_WATCHDOG + tristate "DaVinci watchdog" + depends on ARCH_DAVINCI + help + Say Y here if to include support for the watchdog timer + in the DaVinci DM644x/DM646x processors. + To compile this driver as a module, choose M here: the + module will be called davinci_wdt. + + NOTE: once enabled, this timer cannot be disabled. + Say N if you are unsure. + +# ARM26 Architecture + # AVR32 Architecture config AT32AP700X_WDT tristate "AT32AP700x watchdog" - depends on WATCHDOG && CPU_AT32AP7000 + depends on CPU_AT32AP7000 help Watchdog timer embedded into AT32AP700x devices. This will reboot your system when the timeout is reached. +# BLACKFIN Architecture + +config BFIN_WDT + tristate "Blackfin On-Chip Watchdog Timer" + depends on BLACKFIN + ---help--- + If you say yes here you will get support for the Blackfin On-Chip + Watchdog Timer. If you have one of these processors and wish to + have watchdog support enabled, say Y, otherwise say N. + + To compile this driver as a module, choose M here: the + module will be called bfin_wdt. + +# CRIS Architecture + +# FRV Architecture + +# H8300 Architecture + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT @@ -524,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG To compile this driver as a module, choose M here: the module will be called sbc_epx_c3. -# PowerPC Architecture - -config 8xx_WDT - tristate "MPC8xx Watchdog Timer" - depends on 8xx - -config 83xx_WDT - tristate "MPC83xx Watchdog Timer" - depends on PPC_83xx - -config MV64X60_WDT - tristate "MV64X60 (Marvell Discovery) Watchdog Timer" - depends on MV64X60 - -config BOOKE_WDT - bool "PowerPC Book-E Watchdog Timer" - depends on BOOKE || 4xx - ---help--- - Please see Documentation/watchdog/watchdog-api.txt for - more information. - -# PPC64 Architecture +# M32R Architecture -config WATCHDOG_RTAS - tristate "RTAS watchdog" - depends on PPC_RTAS - help - This driver adds watchdog support for the RTAS watchdog. +# M68K Architecture - To compile this driver as a module, choose M here. The module - will be called wdrtas. +# M68KNOMMU Architecture # MIPS Architecture @@ -584,6 +609,44 @@ config WDT_RM9K_GPI To compile this driver as a module, choose M here: the module will be called rm9k_wdt. +# PARISC Architecture + +# POWERPC Architecture + +config MPC5200_WDT + tristate "MPC5200 Watchdog Timer" + depends on PPC_MPC52xx + +config 8xx_WDT + tristate "MPC8xx Watchdog Timer" + depends on 8xx + +config 83xx_WDT + tristate "MPC83xx Watchdog Timer" + depends on PPC_83xx + +config MV64X60_WDT + tristate "MV64X60 (Marvell Discovery) Watchdog Timer" + depends on MV64X60 + +config BOOKE_WDT + bool "PowerPC Book-E Watchdog Timer" + depends on BOOKE || 4xx + ---help--- + Please see Documentation/watchdog/watchdog-api.txt for + more information. + +# PPC64 Architecture + +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on 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. + # S390 Architecture config ZVM_WATCHDOG @@ -598,11 +661,11 @@ config ZVM_WATCHDOG To compile this driver as a module, choose M here. The module will be called vmwatchdog. -# SUPERH Architecture +# SUPERH (sh + sh64) Architecture config SH_WDT tristate "SuperH Watchdog" - depends on SUPERH + depends on SUPERH && (CPU_SH3 || CPU_SH4) help This driver adds watchdog support for the integrated watchdog in the SuperH processors. If you have one of these processors and wish @@ -625,6 +688,8 @@ config SH_WDT_MMAP If you say Y here, user applications will be able to mmap the WDT/CPG registers. +# SPARC Architecture + # SPARC64 Architecture config WATCHDOG_CP1XXX @@ -649,6 +714,10 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +# V850 Architecture + +# XTENSA Architecture + # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 3907ec0..389f8b1 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o # USB-based Watchdog Cards obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o +# ALPHA Architecture + # ARM Architecture obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -35,10 +37,23 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o +obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o +obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o + +# ARM26 Architecture # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o +# BLACKFIN Architecture +obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o + +# CRIS Architecture + +# FRV Architecture + +# H8300 Architecture + # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o @@ -65,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o -# PowerPC Architecture +# M32R Architecture + +# M68K Architecture + +# M68KNOMMU Architecture + +# MIPS Architecture +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o +obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o + +# PARISC Architecture + +# POWERPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o @@ -74,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o -# MIPS Architecture -obj-$(CONFIG_INDYDOG) += indydog.o -obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o -obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o - # S390 Architecture -# SUPERH Architecture +# SUPERH (sh + sh64) Architecture obj-$(CONFIG_SH_WDT) += shwdt.o +# SPARC Architecture + # SPARC64 Architecture +# V850 Architecture + +# XTENSA Architecture + # Architecture Independant obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c index e3f6a7d..c404fc6 100644 --- a/drivers/char/watchdog/alim1535_wdt.c +++ b/drivers/char/watchdog/alim1535_wdt.c @@ -312,6 +312,7 @@ static int ali_notify_sys(struct notifier_block *this, unsigned long code, void */ static struct pci_device_id ali_pci_tbl[] = { + { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, { 0, }, }; @@ -329,9 +330,11 @@ static int __init ali_find_watchdog(void) struct pci_dev *pdev; u32 wdog; - /* Check for a 1535 series bridge */ + /* Check for a 1533/1535 series bridge */ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL); - if(pdev == NULL) + if (pdev == NULL) + pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL); + if (pdev == NULL) return -ENODEV; pci_dev_put(pdev); diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/char/watchdog/bfin_wdt.c new file mode 100644 index 0000000..309d279 --- /dev/null +++ b/drivers/char/watchdog/bfin_wdt.c @@ -0,0 +1,490 @@ +/* + * Blackfin On-Chip Watchdog Driver + * Supports BF53[123]/BF53[467]/BF54[2489]/BF561 + * + * Originally based on softdog.c + * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2007 Michele d'Amico + * Copyright 1996 Alan Cox <alan@redhat.com> + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/timer.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/blackfin.h> +#include <asm/uaccess.h> + +#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) +#define stampit() stamp("here i am") + +#define WATCHDOG_NAME "bfin-wdt" +#define PFX WATCHDOG_NAME ": " + +/* The BF561 has two watchdogs (one per core), but since Linux + * only runs on core A, we'll just work with that one. + */ +#ifdef BF561_FAMILY +# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL() +# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT() +# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT() +# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x) +# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x) +# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x) +#endif + +/* Bit in SWRST that indicates boot caused by watchdog */ +#define SWRST_RESET_WDOG 0x4000 + +/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */ +#define WDOG_EXPIRED 0x8000 + +/* Masks for WDEV field in WDOG_CTL register */ +#define ICTL_RESET 0x0 +#define ICTL_NMI 0x2 +#define ICTL_GPI 0x4 +#define ICTL_NONE 0x6 +#define ICTL_MASK 0x6 + +/* Masks for WDEN field in WDOG_CTL register */ +#define WDEN_MASK 0x0FF0 +#define WDEN_ENABLE 0x0000 +#define WDEN_DISABLE 0x0AD0 + +/* some defaults */ +#define WATCHDOG_TIMEOUT 20 + +static unsigned int timeout = WATCHDOG_TIMEOUT; +static int nowayout = WATCHDOG_NOWAYOUT; +static struct watchdog_info bfin_wdt_info; +static unsigned long open_check; +static char expect_close; +static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED; + +/** + * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive + * + * The Userspace watchdog got a KeepAlive: schedule the next timeout. + */ +static int bfin_wdt_keepalive(void) +{ + stampit(); + bfin_write_WDOG_STAT(0); + return 0; +} + +/** + * bfin_wdt_stop - Stop the Watchdog + * + * Stops the on-chip watchdog. + */ +static int bfin_wdt_stop(void) +{ + stampit(); + bfin_write_WDOG_CTL(WDEN_DISABLE); + return 0; +} + +/** + * bfin_wdt_start - Start the Watchdog + * + * Starts the on-chip watchdog. Automatically loads WDOG_CNT + * into WDOG_STAT for us. + */ +static int bfin_wdt_start(void) +{ + stampit(); + bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET); + return 0; +} + +/** + * bfin_wdt_running - Check Watchdog status + * + * See if the watchdog is running. + */ +static int bfin_wdt_running(void) +{ + stampit(); + return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE); +} + +/** + * bfin_wdt_set_timeout - Set the Userspace Watchdog timeout + * @t: new timeout value (in seconds) + * + * Translate the specified timeout in seconds into System Clock + * terms which is what the on-chip Watchdog requires. + */ +static int bfin_wdt_set_timeout(unsigned long t) +{ + u32 cnt; + unsigned long flags; + + stampit(); + + cnt = t * get_sclk(); + if (cnt < get_sclk()) { + printk(KERN_WARNING PFX "timeout value is too large\n"); + return -EINVAL; + } + + spin_lock_irqsave(&bfin_wdt_spinlock, flags); + { + int run = bfin_wdt_running(); + bfin_wdt_stop(); + bfin_write_WDOG_CNT(cnt); + if (run) bfin_wdt_start(); + } + spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); + + timeout = t; + + return 0; +} + +/** + * bfin_wdt_open - Open the Device + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is opened and started. + */ +static int bfin_wdt_open(struct inode *inode, struct file *file) +{ + stampit(); + + if (test_and_set_bit(0, &open_check)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + bfin_wdt_keepalive(); + bfin_wdt_start(); + + return nonseekable_open(inode, file); +} + +/** + * bfin_wdt_close - Close the Device + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is closed and stopped. + */ +static int bfin_wdt_release(struct inode *inode, struct file *file) +{ + stampit(); + + if (expect_close == 42) { + bfin_wdt_stop(); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + bfin_wdt_keepalive(); + } + + expect_close = 0; + clear_bit(0, &open_check); + + return 0; +} + +/** + * bfin_wdt_write - Write to Device + * @file: file handle of device + * @buf: buffer to write + * @count: length of buffer + * @ppos: offset + * + * Pings the watchdog on write. + */ +static ssize_t bfin_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + stampit(); + + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + bfin_wdt_keepalive(); + } + + return len; +} + +/** + * bfin_wdt_ioctl - Query Device + * @inode: inode of device + * @file: file handle of device + * @cmd: watchdog command + * @arg: argument + * + * Query basic information from the device or ping it, as outlined by the + * watchdog API. + */ +static int bfin_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + + stampit(); + + switch (cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info))) + return -EFAULT; + else + return 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p); + + case WDIOC_KEEPALIVE: + bfin_wdt_keepalive(); + return 0; + + case WDIOC_SETTIMEOUT: { + int new_timeout; + + if (get_user(new_timeout, p)) + return -EFAULT; + + if (bfin_wdt_set_timeout(new_timeout)) + return -EINVAL; + } + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + + case WDIOC_SETOPTIONS: { + unsigned long flags; + int options, ret = -EINVAL; + + if (get_user(options, p)) + return -EFAULT; + + spin_lock_irqsave(&bfin_wdt_spinlock, flags); + + if (options & WDIOS_DISABLECARD) { + bfin_wdt_stop(); + ret = 0; + } + + if (options & WDIOS_ENABLECARD) { + bfin_wdt_start(); + ret = 0; + } + + spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); + + return ret; + } + } +} + +/** + * bfin_wdt_notify_sys - Notifier Handler + * @this: notifier block + * @code: notifier event + * @unused: unused + * + * Handles specific events, such as turning off the watchdog during a + * shutdown event. + */ +static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + stampit(); + + if (code == SYS_DOWN || code == SYS_HALT) + bfin_wdt_stop(); + + return NOTIFY_DONE; +} + +#ifdef CONFIG_PM +static int state_before_suspend; + +/** + * bfin_wdt_suspend - suspend the watchdog + * @pdev: device being suspended + * @state: requested suspend state + * + * Remember if the watchdog was running and stop it. + * TODO: is this even right? Doesn't seem to be any + * standard in the watchdog world ... + */ +static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state) +{ + stampit(); + + state_before_suspend = bfin_wdt_running(); + bfin_wdt_stop(); + + return 0; +} + +/** + * bfin_wdt_resume - resume the watchdog + * @pdev: device being resumed + * + * If the watchdog was running, turn it back on. + */ +static int bfin_wdt_resume(struct platform_device *pdev) +{ + stampit(); + + if (state_before_suspend) { + bfin_wdt_set_timeout(timeout); + bfin_wdt_start(); + } + + return 0; +} +#else +# define bfin_wdt_suspend NULL +# define bfin_wdt_resume NULL +#endif + +static struct platform_device bfin_wdt_device = { + .name = WATCHDOG_NAME, + .id = -1, +}; + +static struct platform_driver bfin_wdt_driver = { + .driver = { + .name = WATCHDOG_NAME, + .owner = THIS_MODULE, + }, + .suspend = bfin_wdt_suspend, + .resume = bfin_wdt_resume, +}; + +static struct file_operations bfin_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = bfin_wdt_write, + .ioctl = bfin_wdt_ioctl, + .open = bfin_wdt_open, + .release = bfin_wdt_release, +}; + +static struct miscdevice bfin_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &bfin_wdt_fops, +}; + +static struct watchdog_info bfin_wdt_info = { + .identity = "Blackfin Watchdog", + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static struct notifier_block bfin_wdt_notifier = { + .notifier_call = bfin_wdt_notify_sys, +}; + +/** + * bfin_wdt_init - Initialize module + * + * Registers the device and notifier handler. Actual device + * initialization is handled by bfin_wdt_open(). + */ +static int __init bfin_wdt_init(void) +{ + int ret; + + stampit(); + + /* Check that the timeout value is within range */ + if (bfin_wdt_set_timeout(timeout)) + return -EINVAL; + + /* Since this is an on-chip device and needs no board-specific + * resources, we'll handle all the platform device stuff here. + */ + ret = platform_device_register(&bfin_wdt_device); + if (ret) + return ret; + + ret = platform_driver_probe(&bfin_wdt_driver, NULL); + if (ret) + return ret; + + ret = register_reboot_notifier(&bfin_wdt_notifier); + if (ret) { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); + return ret; + } + + ret = misc_register(&bfin_wdt_miscdev); + if (ret) { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + unregister_reboot_notifier(&bfin_wdt_notifier); + return ret; + } + + printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); + + return 0; +} + +/** + * bfin_wdt_exit - Deinitialize module + * + * Unregisters the device and notifier handler. Actual device + * deinitialization is handled by bfin_wdt_close(). + */ +static void __exit bfin_wdt_exit(void) +{ + misc_deregister(&bfin_wdt_miscdev); + unregister_reboot_notifier(&bfin_wdt_notifier); +} + +module_init(bfin_wdt_init); +module_exit(bfin_wdt_exit); + +MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>"); +MODULE_DESCRIPTION("Blackfin Watchdog Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c index 0f5c77d..d362f5b 100644 --- a/drivers/char/watchdog/booke_wdt.c +++ b/drivers/char/watchdog/booke_wdt.c @@ -144,7 +144,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file) booke_wdt_period); } - return 0; + return nonseekable_open(inode, file); } static const struct file_operations booke_wdt_fops = { diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index d0d45a8..5941ca6 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -162,6 +162,10 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm if ( copy_to_user(argp, &value, sizeof(int)) ) return -EFAULT; break; + case WDIOC_GETBOOTSTATUS: + if ( copy_to_user(argp, &value, sizeof(int)) ) + return -EFAULT; + break; case WDIOC_GETSUPPORT: if ( copy_to_user(argp, &ident, sizeof(ident)) ) return -EFAULT; diff --git a/drivers/char/watchdog/davinci_wdt.c b/drivers/char/watchdog/davinci_wdt.c new file mode 100644 index 0000000..19db530 --- /dev/null +++ b/drivers/char/watchdog/davinci_wdt.c @@ -0,0 +1,281 @@ +/* + * drivers/char/watchdog/davinci_wdt.c + * + * Watchdog driver for DaVinci DM644x/DM646x processors + * + * Copyright (C) 2006 Texas Instruments. + * + * 2007 (c) MontaVista Software, Inc. 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#include <asm/hardware.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#define MODULE_NAME "DAVINCI-WDT: " + +#define DEFAULT_HEARTBEAT 60 +#define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/ + +/* Timer register set definition */ +#define PID12 (0x0) +#define EMUMGT (0x4) +#define TIM12 (0x10) +#define TIM34 (0x14) +#define PRD12 (0x18) +#define PRD34 (0x1C) +#define TCR (0x20) +#define TGCR (0x24) +#define WDTCR (0x28) + +/* TCR bit definitions */ +#define ENAMODE12_DISABLED (0 << 6) +#define ENAMODE12_ONESHOT (1 << 6) +#define ENAMODE12_PERIODIC (2 << 6) + +/* TGCR bit definitions */ +#define TIM12RS_UNRESET (1 << 0) +#define TIM34RS_UNRESET (1 << 1) +#define TIMMODE_64BIT_WDOG (2 << 2) + +/* WDTCR bit definitions */ +#define WDEN (1 << 14) +#define WDFLAG (1 << 15) +#define WDKEY_SEQ0 (0xa5c6 << 16) +#define WDKEY_SEQ1 (0xda7e << 16) + +static int heartbeat = DEFAULT_HEARTBEAT; + +static spinlock_t io_lock; +static unsigned long wdt_status; +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 +#define WDT_REGION_INITED 2 +#define WDT_DEVICE_INITED 3 + +static struct resource *wdt_mem; +static void __iomem *wdt_base; + +static void wdt_service(void) +{ + spin_lock(&io_lock); + + /* put watchdog in service state */ + davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR); + /* put watchdog in active state */ + davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR); + + spin_unlock(&io_lock); +} + +static void wdt_enable(void) +{ + u32 tgcr; + u32 timer_margin; + + spin_lock(&io_lock); + + /* disable, internal clock source */ + davinci_writel(0, wdt_base + TCR); + /* reset timer, set mode to 64-bit watchdog, and unreset */ + davinci_writel(0, wdt_base + TGCR); + tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET; + davinci_writel(tgcr, wdt_base + TGCR); + /* clear counter regs */ + davinci_writel(0, wdt_base + TIM12); + davinci_writel(0, wdt_base + TIM34); + /* set timeout period */ + timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff); + davinci_writel(timer_margin, wdt_base + PRD12); + timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32); + davinci_writel(timer_margin, wdt_base + PRD34); + /* enable run continuously */ + davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR); + /* Once the WDT is in pre-active state write to + * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are + * write protected (except for the WDKEY field) + */ + /* put watchdog in pre-active state */ + davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR); + /* put watchdog in active state */ + davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR); + + spin_unlock(&io_lock); +} + +static int davinci_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + wdt_enable(); + + return nonseekable_open(inode, file); +} + +static ssize_t +davinci_wdt_write(struct file *file, const char *data, size_t len, + loff_t *ppos) +{ + if (len) + wdt_service(); + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING, + .identity = "DaVinci Watchdog", +}; + +static int +davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -ENOTTY; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETTIMEOUT: + ret = put_user(heartbeat, (int *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_service(); + ret = 0; + break; + } + return ret; +} + +static int davinci_wdt_release(struct inode *inode, struct file *file) +{ + wdt_service(); + clear_bit(WDT_IN_USE, &wdt_status); + + return 0; +} + +static const struct file_operations davinci_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = davinci_wdt_write, + .ioctl = davinci_wdt_ioctl, + .open = davinci_wdt_open, + .release = davinci_wdt_release, +}; + +static struct miscdevice davinci_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &davinci_wdt_fops, +}; + +static int davinci_wdt_probe(struct platform_device *pdev) +{ + int ret = 0, size; + struct resource *res; + + spin_lock_init(&io_lock); + + if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) + heartbeat = DEFAULT_HEARTBEAT; + + printk(KERN_INFO MODULE_NAME + "DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + printk(KERN_INFO MODULE_NAME + "failed to get memory region resource\n"); + return -ENOENT; + } + + size = res->end - res->start + 1; + wdt_mem = request_mem_region(res->start, size, pdev->name); + + if (wdt_mem == NULL) { + printk(KERN_INFO MODULE_NAME "failed to get memory region\n"); + return -ENOENT; + } + wdt_base = (void __iomem *)(res->start); + + ret = misc_register(&davinci_wdt_miscdev); + if (ret < 0) { + printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); + release_resource(wdt_mem); + kfree(wdt_mem); + } else { + set_bit(WDT_DEVICE_INITED, &wdt_status); + } + + return ret; +} + +static int davinci_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&davinci_wdt_miscdev); + if (wdt_mem) { + release_resource(wdt_mem); + kfree(wdt_mem); + wdt_mem = NULL; + } + return 0; +} + +static struct platform_driver platform_wdt_driver = { + .driver = { + .name = "watchdog", + }, + .probe = davinci_wdt_probe, + .remove = davinci_wdt_remove, +}; + +static int __init davinci_wdt_init(void) +{ + return platform_driver_register(&platform_wdt_driver); +} + +static void __exit davinci_wdt_exit(void) +{ + return platform_driver_unregister(&platform_wdt_driver); +} + +module_init(davinci_wdt_init); +module_exit(davinci_wdt_exit); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("DaVinci Watchdog Driver"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, + "Watchdog heartbeat period in seconds from 1 to " + __MODULE_STRING(MAX_HEARTBEAT) ", default " + __MODULE_STRING(DEFAULT_HEARTBEAT)); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index b070324..b14e9d1 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c @@ -1,5 +1,5 @@ /* - * Eurotech CPU-1220/1410 on board WDT driver + * Eurotech CPU-1220/1410/1420 on board WDT driver * * (c) Copyright 2001 Ascensit <support@ascensit.com> * (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com> @@ -25,6 +25,9 @@ /* Changelog: * + * 2001 - Rodolfo Giometti + * Initial release + * * 2002/04/25 - Rob Radez * clean up #includes * clean up locking @@ -33,13 +36,15 @@ * add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls * add expect_close support * - * 2001 - Rodolfo Giometti - * Initial release - * * 2002.05.30 - Joel Becker <joel.becker@oracle.com> * Added Matt Domsch's nowayout module option. */ +/* + * The eurotech CPU-1220/1410/1420's watchdog is a part + * of the on-board SUPER I/O device SMSC FDC 37B782. + */ + #include <linux/interrupt.h> #include <linux/module.h> #include <linux/moduleparam.h> diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index eac4f9b..cd5a565 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -39,7 +39,12 @@ * 82801HR (ICH8R) : document number 313056-002, 313057-004, * 82801HH (ICH8DH) : document number 313056-002, 313057-004, * 82801HO (ICH8DO) : document number 313056-002, 313057-004, - * 6300ESB (6300ESB) : document number 300641-003 + * 82801IB (ICH9) : document number 316972-001, 316973-001, + * 82801IR (ICH9R) : document number 316972-001, 316973-001, + * 82801IH (ICH9DH) : document number 316972-001, 316973-001, + * 6300ESB (6300ESB) : document number 300641-003, 300884-010, + * 631xESB (631xESB) : document number 313082-001, 313075-005, + * 632xESB (632xESB) : document number 313082-001, 313075-005 */ /* @@ -48,8 +53,8 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.01" -#define DRV_RELDATE "21-Jan-2007" +#define DRV_VERSION "1.02" +#define DRV_RELDATE "26-Jul-2007" #define PFX DRV_NAME ": " /* Includes */ @@ -92,6 +97,10 @@ enum iTCO_chipsets { TCO_ICH8, /* ICH8 & ICH8R */ TCO_ICH8DH, /* ICH8DH */ TCO_ICH8DO, /* ICH8DO */ + TCO_ICH9, /* ICH9 */ + TCO_ICH9R, /* ICH9R */ + TCO_ICH9DH, /* ICH9DH */ + TCO_631XESB, /* 631xESB/632xESB */ }; static struct { @@ -118,6 +127,10 @@ static struct { {"ICH8 or ICH8R", 2}, {"ICH8DH", 2}, {"ICH8DO", 2}, + {"ICH9", 2}, + {"ICH9R", 2}, + {"ICH9DH", 2}, + {"631xESB/632xESB", 2}, {NULL,0} }; @@ -148,6 +161,25 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, + { PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 }, + { PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, + { PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c new file mode 100644 index 0000000..bbbd91a --- /dev/null +++ b/drivers/char/watchdog/iop_wdt.c @@ -0,0 +1,262 @@ +/* + * drivers/char/watchdog/iop_wdt.c + * + * WDT driver for Intel I/O Processors + * Copyright (C) 2005, Intel Corporation. + * + * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Curt E Bruns <curt.e.bruns@intel.com> + * Peter Milne <peter.milne@d-tacq.com> + * Dan Williams <dan.j.williams@intel.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/uaccess.h> +#include <asm/hardware.h> + +static int nowayout = WATCHDOG_NOWAYOUT; +static unsigned long wdt_status; +static unsigned long boot_status; + +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 +#define WDT_ENABLED 2 + +static unsigned long iop_watchdog_timeout(void) +{ + return (0xffffffffUL / get_iop_tick_rate()); +} + +/** + * wdt_supports_disable - determine if we are accessing a iop13xx watchdog + * or iop3xx by whether it has a disable command + */ +static int wdt_supports_disable(void) +{ + int can_disable; + + if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM) + can_disable = 1; + else + can_disable = 0; + + return can_disable; +} + +static void wdt_enable(void) +{ + /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF + * Takes approx. 10.7s to timeout + */ + write_wdtcr(IOP_WDTCR_EN_ARM); + write_wdtcr(IOP_WDTCR_EN); +} + +/* returns 0 if the timer was successfully disabled */ +static int wdt_disable(void) +{ + /* Stop Counting */ + if (wdt_supports_disable()) { + write_wdtcr(IOP_WDTCR_DIS_ARM); + write_wdtcr(IOP_WDTCR_DIS); + clear_bit(WDT_ENABLED, &wdt_status); + printk(KERN_INFO "WATCHDOG: Disabled\n"); + return 0; + } else + return 1; +} + +static int iop_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + wdt_enable(); + + set_bit(WDT_ENABLED, &wdt_status); + + return nonseekable_open(inode, file); +} + +static ssize_t +iop_wdt_write(struct file *file, const char *data, size_t len, + loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + wdt_enable(); + } + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, + .identity = "iop watchdog", +}; + +static int +iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int options; + int ret = -ENOTTY; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *)arg, &ident, sizeof ident)) + ret = -EFAULT; + else + ret = 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(boot_status, (int *)arg); + break; + + case WDIOC_GETTIMEOUT: + ret = put_user(iop_watchdog_timeout(), (int *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_enable(); + ret = 0; + break; + + case WDIOC_SETOPTIONS: + if (get_user(options, (int *)arg)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + if (!nowayout) { + if (wdt_disable() == 0) { + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + ret = 0; + } else + ret = -ENXIO; + } else + ret = 0; + } + + if (options & WDIOS_ENABLECARD) { + wdt_enable(); + ret = 0; + } + break; + } + + return ret; +} + +static int iop_wdt_release(struct inode *inode, struct file *file) +{ + int state = 1; + if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) + if (test_bit(WDT_ENABLED, &wdt_status)) + state = wdt_disable(); + + /* if the timer is not disbaled reload and notify that we are still + * going down + */ + if (state != 0) { + wdt_enable(); + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " + "reset in %lu seconds\n", iop_watchdog_timeout()); + } + + clear_bit(WDT_IN_USE, &wdt_status); + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + return 0; +} + +static const struct file_operations iop_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = iop_wdt_write, + .ioctl = iop_wdt_ioctl, + .open = iop_wdt_open, + .release = iop_wdt_release, +}; + +static struct miscdevice iop_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &iop_wdt_fops, +}; + +static int __init iop_wdt_init(void) +{ + int ret; + + ret = misc_register(&iop_wdt_miscdev); + if (ret == 0) + printk("iop watchdog timer: timeout %lu sec\n", + iop_watchdog_timeout()); + + /* check if the reset was caused by the watchdog timer */ + boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; + + /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset + * NOTE: An IB Reset will Reset both cores in the IOP342 + */ + write_wdtsr(IOP13XX_WDTCR_IB_RESET); + + return ret; +} + +static void __exit iop_wdt_exit(void) +{ + misc_deregister(&iop_wdt_miscdev); +} + +module_init(iop_wdt_init); +module_exit(iop_wdt_exit); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>"); +MODULE_DESCRIPTION("iop watchdog timer driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index a0d2716..6d35bb1 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -321,6 +321,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, break; case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index db2ccb8..1adf1d5 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -215,6 +215,11 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, return -EFAULT; } break; + case WDIOC_GETBOOTSTATUS: + if (copy_to_user(p, &status, sizeof(int))) { + return -EFAULT; + } + break; case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) { return -EFAULT; diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c new file mode 100644 index 0000000..564143d --- /dev/null +++ b/drivers/char/watchdog/mpc5200_wdt.c @@ -0,0 +1,286 @@ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <asm/of_platform.h> +#include <asm/uaccess.h> +#include <asm/mpc52xx.h> + + +#define GPT_MODE_WDT (1<<15) +#define GPT_MODE_CE (1<<12) +#define GPT_MODE_MS_TIMER (0x4) + + +struct mpc5200_wdt { + unsigned count; /* timer ticks before watchdog kicks in */ + long ipb_freq; + struct miscdevice miscdev; + struct resource mem; + struct mpc52xx_gpt __iomem *regs; + spinlock_t io_lock; +}; + +/* is_active stores wether or not the /dev/watchdog device is opened */ +static unsigned long is_active; + +/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from + * file operations, which sucks. But there can be max 1 watchdog anyway, so... + */ +static struct mpc5200_wdt *wdt_global; + + +/* helper to calculate timeout in timer counts */ +static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout) +{ + /* use biggest prescaler of 64k */ + wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout; + + if (wdt->count > 0xffff) + wdt->count = 0xffff; +} +/* return timeout in seconds (calculated from timer count) */ +static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt) +{ + return wdt->count * 0x10000 / wdt->ipb_freq; +} + + +/* watchdog operations */ +static int mpc5200_wdt_start(struct mpc5200_wdt *wdt) +{ + spin_lock(&wdt->io_lock); + /* disable */ + out_be32(&wdt->regs->mode, 0); + /* set timeout, with maximum prescaler */ + out_be32(&wdt->regs->count, 0x0 | wdt->count); + /* enable watchdog */ + out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER); + spin_unlock(&wdt->io_lock); + + return 0; +} +static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt) +{ + spin_lock(&wdt->io_lock); + /* writing A5 to OCPW resets the watchdog */ + out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode))); + spin_unlock(&wdt->io_lock); + return 0; +} +static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt) +{ + spin_lock(&wdt->io_lock); + /* disable */ + out_be32(&wdt->regs->mode, 0); + spin_unlock(&wdt->io_lock); + return 0; +} + + +/* file operations */ +static ssize_t mpc5200_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + struct mpc5200_wdt *wdt = file->private_data; + mpc5200_wdt_ping(wdt); + return 0; +} +static struct watchdog_info mpc5200_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "mpc5200 watchdog on GPT0", +}; +static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mpc5200_wdt *wdt = file->private_data; + int __user *data = (int __user *)arg; + int timeout; + int ret = 0; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user(data, &mpc5200_wdt_info, + sizeof(mpc5200_wdt_info)); + if (ret) + ret = -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, data); + break; + + case WDIOC_KEEPALIVE: + mpc5200_wdt_ping(wdt); + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(timeout, data); + if (ret) + break; + mpc5200_wdt_set_timeout(wdt, timeout); + mpc5200_wdt_start(wdt); + /* fall through and return the timeout */ + + case WDIOC_GETTIMEOUT: + timeout = mpc5200_wdt_get_timeout(wdt); + ret = put_user(timeout, data); + break; + + default: + ret = -ENOTTY; + } + return ret; +} +static int mpc5200_wdt_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &is_active)) + return -EBUSY; + + /* Set and activate the watchdog */ + mpc5200_wdt_set_timeout(wdt_global, 30); + mpc5200_wdt_start(wdt_global); + file->private_data = wdt_global; + return nonseekable_open(inode, file); +} +static int mpc5200_wdt_release(struct inode *inode, struct file *file) +{ +#if WATCHDOG_NOWAYOUT == 0 + struct mpc5200_wdt *wdt = file->private_data; + mpc5200_wdt_stop(wdt); + wdt->count = 0; /* == disabled */ +#endif + clear_bit(0, &is_active); + return 0; +} + +static struct file_operations mpc5200_wdt_fops = { + .owner = THIS_MODULE, + .write = mpc5200_wdt_write, + .ioctl = mpc5200_wdt_ioctl, + .open = mpc5200_wdt_open, + .release = mpc5200_wdt_release, +}; + +/* module operations */ +static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match) +{ + struct mpc5200_wdt *wdt; + int err; + const void *has_wdt; + int size; + + has_wdt = of_get_property(op->node, "has-wdt", NULL); + if (!has_wdt) + return -ENODEV; + + wdt = kzalloc(sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node); + + err = of_address_to_resource(op->node, 0, &wdt->mem); + if (err) + goto out_free; + size = wdt->mem.end - wdt->mem.start + 1; + if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) { + err = -ENODEV; + goto out_free; + } + wdt->regs = ioremap(wdt->mem.start, size); + if (!wdt->regs) { + err = -ENODEV; + goto out_release; + } + + dev_set_drvdata(&op->dev, wdt); + spin_lock_init(&wdt->io_lock); + + wdt->miscdev = (struct miscdevice) { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mpc5200_wdt_fops, + .parent = &op->dev, + }; + wdt_global = wdt; + err = misc_register(&wdt->miscdev); + if (!err) + return 0; + + iounmap(wdt->regs); + out_release: + release_mem_region(wdt->mem.start, size); + out_free: + kfree(wdt); + return err; +} + +static int mpc5200_wdt_remove(struct of_device *op) +{ + struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev); + + mpc5200_wdt_stop(wdt); + misc_deregister(&wdt->miscdev); + iounmap(wdt->regs); + release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1); + kfree(wdt); + + return 0; +} +static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state) +{ + struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev); + mpc5200_wdt_stop(wdt); + return 0; +} +static int mpc5200_wdt_resume(struct of_device *op) +{ + struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev); + if (wdt->count) + mpc5200_wdt_start(wdt); + return 0; +} +static int mpc5200_wdt_shutdown(struct of_device *op) +{ + struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev); + mpc5200_wdt_stop(wdt); + return 0; +} + +static struct of_device_id mpc5200_wdt_match[] = { + { .compatible = "mpc5200-gpt", }, + {}, +}; +static struct of_platform_driver mpc5200_wdt_driver = { + .owner = THIS_MODULE, + .name = "mpc5200-gpt-wdt", + .match_table = mpc5200_wdt_match, + .probe = mpc5200_wdt_probe, + .remove = mpc5200_wdt_remove, + .suspend = mpc5200_wdt_suspend, + .resume = mpc5200_wdt_resume, + .shutdown = mpc5200_wdt_shutdown, +}; + + +static int __init mpc5200_wdt_init(void) +{ + return of_register_platform_driver(&mpc5200_wdt_driver); +} + +static void __exit mpc5200_wdt_exit(void) +{ + of_unregister_platform_driver(&mpc5200_wdt_driver); +} + +module_init(mpc5200_wdt_init); +module_exit(mpc5200_wdt_exit); + +MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c index 18ca752..a0bf95f 100644 --- a/drivers/char/watchdog/mpc83xx_wdt.c +++ b/drivers/char/watchdog/mpc83xx_wdt.c @@ -119,6 +119,9 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file, 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: mpc83xx_wdt_keepalive(); return 0; diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c index 8aaed10..85b5734 100644 --- a/drivers/char/watchdog/mpc8xx_wdt.c +++ b/drivers/char/watchdog/mpc8xx_wdt.c @@ -57,7 +57,7 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file) m8xx_wdt_reset(); mpc8xx_wdt_handler_disable(); - return 0; + return nonseekable_open(inode, file); } static int mpc8xx_wdt_release(struct inode *inode, struct file *file) diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index e88947f..0d2b277 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) goto err_out; } - wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL); + wdt = kzalloc(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); diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c index 419ab44..dcfd401 100644 --- a/drivers/char/watchdog/mtx-1_wdt.c +++ b/drivers/char/watchdog/mtx-1_wdt.c @@ -143,6 +143,7 @@ static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int c mtx1_wdt_reset(); break; case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: if ( copy_to_user(argp, &value, sizeof(int)) ) return -EFAULT; break; diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c index b887cdb..0365c31 100644 --- a/drivers/char/watchdog/mv64x60_wdt.c +++ b/drivers/char/watchdog/mv64x60_wdt.c @@ -23,61 +23,101 @@ #include <linux/watchdog.h> #include <linux/platform_device.h> -#include <asm/mv64x60.h> +#include <linux/mv643xx.h> #include <asm/uaccess.h> #include <asm/io.h> -/* 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) +#define MV64x60_WDT_WDC_OFFSET 0 + +/* + * The watchdog configuration register contains a pair of 2-bit fields, + * 1. a reload field, bits 27-26, which triggers a reload of + * the countdown register, and + * 2. an enable field, bits 25-24, which toggles between + * enabling and disabling the watchdog timer. + * Bit 31 is a read-only field which indicates whether the + * watchdog timer is currently enabled. + * + * The low 24 bits contain the timer reload value. + */ +#define MV64x60_WDC_ENABLE_SHIFT 24 +#define MV64x60_WDC_SERVICE_SHIFT 26 +#define MV64x60_WDC_ENABLED_SHIFT 31 + +#define MV64x60_WDC_ENABLED_TRUE 1 +#define MV64x60_WDC_ENABLED_FALSE 0 /* 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 void __iomem *mv64x60_wdt_regs; static int mv64x60_wdt_timeout; +static int mv64x60_wdt_count; +static unsigned int bus_clk; +static char expect_close; +static DEFINE_SPINLOCK(mv64x60_wdt_spinlock); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static void mv64x60_wdt_reg_write(u32 val) +static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) { - /* 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); + u32 data; + u32 enabled; + int ret = 0; + + spin_lock(&mv64x60_wdt_spinlock); + data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); + enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1; + + /* only toggle the requested field if enabled state matches predicate */ + if ((enabled ^ enabled_predicate) == 0) { + /* We write a 1, then a 2 -- to the appropriate field */ + data = (1 << field_shift) | mv64x60_wdt_count; + writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); + + data = (2 << field_shift) | mv64x60_wdt_count; + writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); + ret = 1; + } + spin_unlock(&mv64x60_wdt_spinlock); + + return ret; } 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)); + mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE, + MV64x60_WDC_SERVICE_SHIFT); +} + +static void mv64x60_wdt_handler_enable(void) +{ + if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE, + MV64x60_WDC_ENABLE_SHIFT)) { + mv64x60_wdt_service(); + printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n"); + } } 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)); + if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE, + MV64x60_WDC_ENABLE_SHIFT)) printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n"); - } } -static void mv64x60_wdt_handler_enable(void) +static void mv64x60_wdt_set_timeout(unsigned int timeout) { - 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"); - } + /* maximum bus cycle count is 0xFFFFFFFF */ + if (timeout > 0xFFFFFFFF / bus_clk) + timeout = 0xFFFFFFFF / bus_clk; + + mv64x60_wdt_count = timeout * bus_clk >> 8; + mv64x60_wdt_timeout = timeout; } static int mv64x60_wdt_open(struct inode *inode, struct file *file) @@ -85,21 +125,24 @@ 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(); + if (nowayout) + __module_get(THIS_MODULE); - nonseekable_open(inode, file); + mv64x60_wdt_handler_enable(); - return 0; + return nonseekable_open(inode, file); } static int mv64x60_wdt_release(struct inode *inode, struct file *file) { - mv64x60_wdt_service(); - -#if !defined(CONFIG_WATCHDOG_NOWAYOUT) - mv64x60_wdt_handler_disable(); -#endif + if (expect_close == 42) + mv64x60_wdt_handler_disable(); + else { + printk(KERN_CRIT + "mv64x60_wdt: unexpected close, not stopping timer!\n"); + mv64x60_wdt_service(); + } + expect_close = 0; clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); @@ -109,8 +152,22 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file) static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, size_t len, loff_t * ppos) { - if (len) + if (len) { + if (!nowayout) { + size_t i; + + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + if(get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } mv64x60_wdt_service(); + } return len; } @@ -119,9 +176,12 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int timeout; + int options; void __user *argp = (void __user *)arg; static struct watchdog_info info = { - .options = WDIOF_KEEPALIVEPING, + .options = WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING, .firmware_version = 0, .identity = "MV64x60 watchdog", }; @@ -143,7 +203,15 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, return -EOPNOTSUPP; case WDIOC_SETOPTIONS: - return -EOPNOTSUPP; + if (get_user(options, (int __user *)argp)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) + mv64x60_wdt_handler_disable(); + + if (options & WDIOS_ENABLECARD) + mv64x60_wdt_handler_enable(); + break; case WDIOC_KEEPALIVE: mv64x60_wdt_service(); @@ -151,11 +219,13 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, break; case WDIOC_SETTIMEOUT: - return -EOPNOTSUPP; + if (get_user(timeout, (int __user *)argp)) + return -EFAULT; + mv64x60_wdt_set_timeout(timeout); + /* Fall through */ case WDIOC_GETTIMEOUT: - timeout = mv64x60_wdt_timeout * HZ; - if (put_user(timeout, (int __user *)argp)) + if (put_user(mv64x60_wdt_timeout, (int __user *)argp)) return -EFAULT; break; @@ -184,18 +254,33 @@ static struct miscdevice mv64x60_wdt_miscdev = { static int __devinit mv64x60_wdt_probe(struct platform_device *dev) { struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data; - int bus_clk = 133; + struct resource *r; + int timeout = 10; - mv64x60_wdt_timeout = 10; + bus_clk = 133; /* in MHz */ if (pdata) { - mv64x60_wdt_timeout = pdata->timeout; + timeout = pdata->timeout; bus_clk = pdata->bus_clk; } - mv64x60_regs = mv64x60_get_bridge_vbase(); + /* Since bus_clk is truncated MHz, actual frequency could be + * up to 1MHz higher. Round up, since it's better to time out + * too late than too soon. + */ + bus_clk++; + bus_clk *= 1000000; /* convert to Hz */ + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; - writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, - mv64x60_regs + MV64x60_WDT_WDC); + mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1); + if (mv64x60_wdt_regs == NULL) + return -ENOMEM; + + mv64x60_wdt_set_timeout(timeout); + + mv64x60_wdt_handler_disable(); /* in case timer was already running */ return misc_register(&mv64x60_wdt_miscdev); } @@ -204,9 +289,10 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev) { misc_deregister(&mv64x60_wdt_miscdev); - mv64x60_wdt_service(); mv64x60_wdt_handler_disable(); + iounmap(mv64x60_wdt_regs); + return 0; } @@ -219,40 +305,16 @@ static struct platform_driver mv64x60_wdt_driver = { }, }; -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_alloc(MV64x60_WDT_NAME, -1); - if (!mv64x60_wdt_dev) { - ret = -ENOMEM; - goto out; - } - - ret = platform_device_add(mv64x60_wdt_dev); - if (ret) { - platform_device_put(mv64x60_wdt_dev); - goto out; - } - - ret = platform_driver_register(&mv64x60_wdt_driver); - if (ret) { - platform_device_unregister(mv64x60_wdt_dev); - goto out; - } - - out: - return ret; + return platform_driver_register(&mv64x60_wdt_driver); } static void __exit mv64x60_wdt_exit(void) { platform_driver_unregister(&mv64x60_wdt_driver); - platform_device_unregister(mv64x60_wdt_dev); } module_init(mv64x60_wdt_init); diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c index b36fa8d..719b066 100644 --- a/drivers/char/watchdog/omap_wdt.c +++ b/drivers/char/watchdog/omap_wdt.c @@ -142,7 +142,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file) omap_wdt_set_timeout(); omap_wdt_enable(); - return 0; + return nonseekable_open(inode, file); } static int omap_wdt_release(struct inode *inode, struct file *file) @@ -197,7 +197,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file, switch (cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 1e7a671..0f3fd6c 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); /* allocate memory for our device and initialize it */ - usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); + usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); if (usb_pcwd == NULL) { printk(KERN_ERR PFX "Out of memory\n"); goto error; } - memset (usb_pcwd, 0x00, sizeof (*usb_pcwd)); usb_pcwd_device = usb_pcwd; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 50430bc..5d1c15f 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -52,10 +52,10 @@ #include <asm/arch/map.h> -#undef S3C24XX_VA_WATCHDOG -#define S3C24XX_VA_WATCHDOG (0) +#undef S3C_VA_WATCHDOG +#define S3C_VA_WATCHDOG (0) -#include <asm/arch/regs-watchdog.h> +#include <asm/plat-s3c/regs-watchdog.h> #define PFX "s3c2410-wdt: " diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c index 33c1137..3475f47 100644 --- a/drivers/char/watchdog/sa1100_wdt.c +++ b/drivers/char/watchdog/sa1100_wdt.c @@ -45,7 +45,6 @@ static int boot_status; */ static int sa1100dog_open(struct inode *inode, struct file *file) { - nonseekable_open(inode, file); if (test_and_set_bit(1,&sa1100wdt_users)) return -EBUSY; @@ -54,7 +53,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file) OSSR = OSSR_M3; OWER = OWER_WME; OIER |= OIER_E3; - return 0; + return nonseekable_open(inode, file); } /* diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c index b628203..e4f3cb6 100644 --- a/drivers/char/watchdog/sbc60xxwdt.c +++ b/drivers/char/watchdog/sbc60xxwdt.c @@ -191,8 +191,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou static int fop_open(struct inode * inode, struct file * file) { - nonseekable_open(inode, file); - /* Just in case we're already talking to someone... */ if(test_and_set_bit(0, &wdt_is_open)) return -EBUSY; @@ -202,7 +200,7 @@ static int fop_open(struct inode * inode, struct file * file) /* Good, fire up the show */ wdt_startup(); - return 0; + return nonseekable_open(inode, file); } static int fop_close(struct inode * inode, struct file * file) diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index 2f7ba7a..9670d47 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -150,8 +150,6 @@ static inline int sc1200wdt_status(void) static int sc1200wdt_open(struct inode *inode, struct file *file) { - nonseekable_open(inode, file); - /* allow one at a time */ if (down_trylock(&open_sem)) return -EBUSY; @@ -162,7 +160,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file) sc1200wdt_start(); printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout); - return 0; + return nonseekable_open(inode, file); } diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c index 2676a43..e8594c6 100644 --- a/drivers/char/watchdog/sc520_wdt.c +++ b/drivers/char/watchdog/sc520_wdt.c @@ -248,8 +248,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou static int fop_open(struct inode * inode, struct file * file) { - nonseekable_open(inode, file); - /* Just in case we're already talking to someone... */ if(test_and_set_bit(0, &wdt_is_open)) return -EBUSY; @@ -258,7 +256,7 @@ static int fop_open(struct inode * inode, struct file * file) /* Good, fire up the show */ wdt_startup(); - return 0; + return nonseekable_open(inode, file); } static int fop_close(struct inode * inode, struct file * file) diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b46e7f4..df33b3b 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -4,7 +4,7 @@ * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> * added support for W83627THF. * - * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> + * (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com> * * Based on advantechwdt.c which is based on wdt.c. * Original copyright messages: @@ -42,7 +42,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -#define WATCHDOG_NAME "w83627hf/thf WDT" +#define WATCHDOG_NAME "w83627hf/thf/hg WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -57,7 +57,7 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); @@ -78,9 +78,9 @@ w83627hf_select_wd_register(void) outb_p(0x87, WDT_EFER); /* Enter extended function mode */ outb_p(0x87, WDT_EFER); /* Again according to manual */ - outb(0x20, WDT_EFER); /* check chip version */ + outb(0x20, WDT_EFER); /* check chip version */ c = inb(WDT_EFDR); - if (c == 0x82) { /* W83627THF */ + if (c == 0x82) { /* W83627THF */ outb_p(0x2b, WDT_EFER); /* select GPIO3 */ c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ outb_p(0x2b, WDT_EFER); @@ -114,11 +114,17 @@ w83627hf_init(void) 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 */ outb_p(t, WDT_EFDR); /* Write back to CRF5 */ + outb_p(0xF7, WDT_EFER); /* Select CRF7 */ + t=inb_p(WDT_EFDR); /* read CRF7 */ + t&=~0xC0; /* disable keyboard & mouse turning off watchdog */ + outb_p(t, WDT_EFDR); /* Write back to CRF7 */ + w83627hf_unselect_wd_register(); } @@ -126,7 +132,7 @@ static void wdt_ctrl(int timeout) { spin_lock(&io_lock); - + w83627hf_select_wd_register(); outb_p(0xF6, WDT_EFER); /* Select CRF6 */ @@ -154,7 +160,7 @@ wdt_disable(void) static int wdt_set_heartbeat(int t) { - if ((t < 1) || (t > 63)) + if ((t < 1) || (t > 255)) return -EINVAL; timeout = t; @@ -324,11 +330,11 @@ wdt_init(void) spin_lock_init(&io_lock); - printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n"); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); - printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n", + printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", WATCHDOG_TIMEOUT); } |