1890 lines
57 KiB
Plaintext
1890 lines
57 KiB
Plaintext
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
|
|
index e65736c..63e59b8 100644
|
|
--- a/Documentation/cciss.txt
|
|
+++ b/Documentation/cciss.txt
|
|
@@ -21,6 +21,11 @@ This driver is known to work with the following cards:
|
|
* SA E200
|
|
* SA E200i
|
|
* SA E500
|
|
+ * SA P212
|
|
+ * SA P410
|
|
+ * SA P410i
|
|
+ * SA P411
|
|
+ * SA P812
|
|
|
|
Detecting drive failures:
|
|
-------------------------
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 9d43042..88aac5f 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -1202,6 +1202,7 @@ M: pj@sgi.com
|
|
M: menage@google.com
|
|
L: linux-kernel@vger.kernel.org
|
|
W: http://www.bullopensource.org/cpuset/
|
|
+W: http://oss.sgi.com/projects/cpusets/
|
|
S: Supported
|
|
|
|
CRAMFS FILESYSTEM
|
|
@@ -3329,9 +3330,11 @@ L: video4linux-list@redhat.com
|
|
W: http://www.isely.net/pvrusb2/
|
|
S: Maintained
|
|
|
|
-PXA2xx SUPPORT
|
|
-P: Nicolas Pitre
|
|
-M: nico@cam.org
|
|
+PXA2xx/PXA3xx SUPPORT
|
|
+P: Eric Miao
|
|
+M: eric.miao@marvell.com
|
|
+P: Russell King
|
|
+M: linux@arm.linux.org.uk
|
|
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
|
|
S: Maintained
|
|
|
|
diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c
|
|
index ba5a9f3..454f254 100644
|
|
--- a/arch/m68knommu/platform/coldfire/timers.c
|
|
+++ b/arch/m68knommu/platform/coldfire/timers.c
|
|
@@ -111,7 +111,13 @@ void hw_timer_init(void)
|
|
|
|
__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
|
|
mcftmr_cycles_per_jiffy = FREQ / HZ;
|
|
- __raw_writetrr(mcftmr_cycles_per_jiffy, TA(MCFTIMER_TRR));
|
|
+ /*
|
|
+ * The coldfire timer runs from 0 to TRR included, then 0
|
|
+ * again and so on. It counts thus actually TRR + 1 steps
|
|
+ * for 1 tick, not TRR. So if you want n cycles,
|
|
+ * initialize TRR with n - 1.
|
|
+ */
|
|
+ __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
|
|
__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
|
|
MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
|
|
|
|
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
|
|
index b4b36e0..183db26 100644
|
|
--- a/arch/um/os-Linux/start_up.c
|
|
+++ b/arch/um/os-Linux/start_up.c
|
|
@@ -121,8 +121,10 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit)
|
|
{
|
|
int status, n, ret = 0;
|
|
|
|
- if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
|
|
- fatal_perror("stop_ptraced_child : ptrace failed");
|
|
+ if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
|
|
+ perror("stop_ptraced_child : ptrace failed");
|
|
+ return -1;
|
|
+ }
|
|
CATCH_EINTR(n = waitpid(pid, &status, 0));
|
|
if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
|
|
int exit_with = WEXITSTATUS(status);
|
|
@@ -212,7 +214,7 @@ static void __init check_sysemu(void)
|
|
if (n < 0)
|
|
fatal_perror("check_sysemu : wait failed");
|
|
if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
|
|
- fatal("check_sysemu : expected SIGTRAP, got status = %d",
|
|
+ fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
|
|
status);
|
|
|
|
if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
|
|
@@ -254,9 +256,11 @@ static void __init check_sysemu(void)
|
|
|
|
if (WIFSTOPPED(status) &&
|
|
(WSTOPSIG(status) == (SIGTRAP|0x80))) {
|
|
- if (!count)
|
|
- fatal("check_ptrace : SYSEMU_SINGLESTEP "
|
|
- "doesn't singlestep");
|
|
+ if (!count) {
|
|
+ non_fatal("check_ptrace : SYSEMU_SINGLESTEP "
|
|
+ "doesn't singlestep");
|
|
+ goto fail;
|
|
+ }
|
|
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
|
|
os_getpid());
|
|
if (n < 0)
|
|
@@ -266,9 +270,12 @@ static void __init check_sysemu(void)
|
|
}
|
|
else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
|
|
count++;
|
|
- else
|
|
- fatal("check_ptrace : expected SIGTRAP or "
|
|
- "(SIGTRAP | 0x80), got status = %d", status);
|
|
+ else {
|
|
+ non_fatal("check_ptrace : expected SIGTRAP or "
|
|
+ "(SIGTRAP | 0x80), got status = %d\n",
|
|
+ status);
|
|
+ goto fail;
|
|
+ }
|
|
}
|
|
if (stop_ptraced_child(pid, 0, 0) < 0)
|
|
goto fail_stopped;
|
|
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
|
|
index b487cbe..229f7a5 100644
|
|
--- a/arch/um/os-Linux/sys-i386/registers.c
|
|
+++ b/arch/um/os-Linux/sys-i386/registers.c
|
|
@@ -6,7 +6,7 @@
|
|
|
|
#include <errno.h>
|
|
#include <sys/ptrace.h>
|
|
-#include <asm/user.h>
|
|
+#include <sys/user.h>
|
|
#include "kern_constants.h"
|
|
#include "longjmp.h"
|
|
#include "user.h"
|
|
@@ -76,7 +76,7 @@ int put_fp_registers(int pid, unsigned long *regs)
|
|
|
|
void arch_init_registers(int pid)
|
|
{
|
|
- struct user_fxsr_struct fpx_regs;
|
|
+ struct user_fpxregs_struct fpx_regs;
|
|
int err;
|
|
|
|
err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
|
|
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
|
|
index 9615eee..05191bb 100644
|
|
--- a/arch/x86/kernel/rtc.c
|
|
+++ b/arch/x86/kernel/rtc.c
|
|
@@ -4,6 +4,8 @@
|
|
#include <linux/acpi.h>
|
|
#include <linux/bcd.h>
|
|
#include <linux/mc146818rtc.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pnp.h>
|
|
|
|
#include <asm/time.h>
|
|
#include <asm/vsyscall.h>
|
|
@@ -197,3 +199,35 @@ unsigned long long native_read_tsc(void)
|
|
}
|
|
EXPORT_SYMBOL(native_read_tsc);
|
|
|
|
+
|
|
+static struct resource rtc_resources[] = {
|
|
+ [0] = {
|
|
+ .start = RTC_PORT(0),
|
|
+ .end = RTC_PORT(1),
|
|
+ .flags = IORESOURCE_IO,
|
|
+ },
|
|
+ [1] = {
|
|
+ .start = RTC_IRQ,
|
|
+ .end = RTC_IRQ,
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct platform_device rtc_device = {
|
|
+ .name = "rtc_cmos",
|
|
+ .id = -1,
|
|
+ .resource = rtc_resources,
|
|
+ .num_resources = ARRAY_SIZE(rtc_resources),
|
|
+};
|
|
+
|
|
+static __init int add_rtc_cmos(void)
|
|
+{
|
|
+#ifdef CONFIG_PNP
|
|
+ if (!pnp_platform_devices)
|
|
+ platform_device_register(&rtc_device);
|
|
+#else
|
|
+ platform_device_register(&rtc_device);
|
|
+#endif /* CONFIG_PNP */
|
|
+ return 0;
|
|
+}
|
|
+device_initcall(add_rtc_cmos);
|
|
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
|
|
index e336b05..5f1e1cc 100644
|
|
--- a/drivers/block/cciss.c
|
|
+++ b/drivers/block/cciss.c
|
|
@@ -53,15 +53,16 @@
|
|
#include <linux/scatterlist.h>
|
|
|
|
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
|
|
-#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
|
|
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,14)
|
|
+#define DRIVER_NAME "HP CISS Driver (v 3.6.20)"
|
|
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 20)
|
|
|
|
/* Embedded module documentation macros - see modules.h */
|
|
MODULE_AUTHOR("Hewlett-Packard Company");
|
|
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.14");
|
|
+MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
|
|
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
|
|
- " SA6i P600 P800 P400 P400i E200 E200i E500");
|
|
-MODULE_VERSION("3.6.14");
|
|
+ " SA6i P600 P800 P400 P400i E200 E200i E500 P700m"
|
|
+ " Smart Array G2 Series SAS/SATA Controllers");
|
|
+MODULE_VERSION("3.6.20");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
#include "cciss_cmd.h"
|
|
@@ -90,6 +91,11 @@ static const struct pci_device_id cciss_pci_device_id[] = {
|
|
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215},
|
|
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237},
|
|
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D},
|
|
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
|
|
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
|
|
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
|
|
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247},
|
|
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
|
|
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
|
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
|
|
{0,}
|
|
@@ -123,6 +129,11 @@ static struct board_type products[] = {
|
|
{0x3215103C, "Smart Array E200i", &SA5_access, 120},
|
|
{0x3237103C, "Smart Array E500", &SA5_access, 512},
|
|
{0x323D103C, "Smart Array P700m", &SA5_access, 512},
|
|
+ {0x3241103C, "Smart Array P212", &SA5_access, 384},
|
|
+ {0x3243103C, "Smart Array P410", &SA5_access, 384},
|
|
+ {0x3245103C, "Smart Array P410i", &SA5_access, 384},
|
|
+ {0x3247103C, "Smart Array P411", &SA5_access, 384},
|
|
+ {0x3249103C, "Smart Array P812", &SA5_access, 384},
|
|
{0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
|
|
};
|
|
|
|
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
|
|
index d307bf2..2d854bb 100644
|
|
--- a/drivers/char/Kconfig
|
|
+++ b/drivers/char/Kconfig
|
|
@@ -749,7 +749,7 @@ config NVRAM
|
|
if RTC_LIB=n
|
|
|
|
config RTC
|
|
- tristate "Enhanced Real Time Clock Support"
|
|
+ tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
|
|
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
|
|
&& !ARM && !SUPERH && !S390 && !AVR32
|
|
---help---
|
|
@@ -1036,9 +1036,9 @@ config HPET
|
|
non-periodic and/or periodic.
|
|
|
|
config HPET_RTC_IRQ
|
|
- bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC
|
|
- default n
|
|
- depends on HPET
|
|
+ bool
|
|
+ default HPET_EMULATE_RTC
|
|
+ depends on RTC && HPET
|
|
help
|
|
If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
|
|
is assumed the platform called hpet_alloc with the RTC IRQ values for
|
|
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
|
|
index 55c97f6..07b4d8f 100644
|
|
--- a/drivers/char/agp/ati-agp.c
|
|
+++ b/drivers/char/agp/ati-agp.c
|
|
@@ -458,6 +458,10 @@ static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
|
|
.chipset_name = "IGP9100/M",
|
|
},
|
|
{
|
|
+ .device_id = PCI_DEVICE_ID_ATI_RS350_133,
|
|
+ .chipset_name = "IGP9000/M",
|
|
+ },
|
|
+ {
|
|
.device_id = PCI_DEVICE_ID_ATI_RS350_200,
|
|
.chipset_name = "IGP9100/M",
|
|
},
|
|
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
|
|
index 2398e86..a00869c 100644
|
|
--- a/drivers/char/generic_nvram.c
|
|
+++ b/drivers/char/generic_nvram.c
|
|
@@ -133,7 +133,7 @@ static struct miscdevice nvram_dev = {
|
|
|
|
int __init nvram_init(void)
|
|
{
|
|
- printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
|
|
+ printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
|
|
NVRAM_VERSION);
|
|
return misc_register(&nvram_dev);
|
|
}
|
|
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
|
|
index 5cc651e..27fdc08 100644
|
|
--- a/drivers/char/hw_random/intel-rng.c
|
|
+++ b/drivers/char/hw_random/intel-rng.c
|
|
@@ -273,7 +273,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw)
|
|
if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
|
|
(dvc != INTEL_FWH_DEVICE_CODE_8M &&
|
|
dvc != INTEL_FWH_DEVICE_CODE_4M)) {
|
|
- printk(KERN_ERR PFX "FWH not detected\n");
|
|
+ printk(KERN_NOTICE PFX "FWH not detected\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
|
|
index 7f7e798..d9a0a53 100644
|
|
--- a/drivers/char/keyboard.c
|
|
+++ b/drivers/char/keyboard.c
|
|
@@ -677,12 +677,7 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
|
|
|
|
static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
|
|
{
|
|
- unsigned int uni;
|
|
- if (kbd->kbdmode == VC_UNICODE)
|
|
- uni = value;
|
|
- else
|
|
- uni = conv_8bit_to_uni(value);
|
|
- k_unicode(vc, uni, up_flag);
|
|
+ k_unicode(vc, conv_8bit_to_uni(value), up_flag);
|
|
}
|
|
|
|
static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
|
|
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
|
|
index 7817d22..1081091 100644
|
|
--- a/drivers/isdn/sc/ioctl.c
|
|
+++ b/drivers/isdn/sc/ioctl.c
|
|
@@ -226,6 +226,7 @@ int sc_ioctl(int card, scs_ioctl *data)
|
|
*/
|
|
if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
|
|
kfree(rcvmsg);
|
|
+ kfree(spid);
|
|
return -EFAULT;
|
|
}
|
|
|
|
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
|
|
index be624a0..c303e7f 100644
|
|
--- a/drivers/mmc/host/wbsd.c
|
|
+++ b/drivers/mmc/host/wbsd.c
|
|
@@ -1457,17 +1457,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
|
|
int ret;
|
|
|
|
/*
|
|
- * Allocate interrupt.
|
|
- */
|
|
-
|
|
- ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- host->irq = irq;
|
|
-
|
|
- /*
|
|
- * Set up tasklets.
|
|
+ * Set up tasklets. Must be done before requesting interrupt.
|
|
*/
|
|
tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
|
|
(unsigned long)host);
|
|
@@ -1480,6 +1470,15 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
|
|
tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
|
|
(unsigned long)host);
|
|
|
|
+ /*
|
|
+ * Allocate interrupt.
|
|
+ */
|
|
+ ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->irq = irq;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
|
|
index 60f8afc..4949dc4 100644
|
|
--- a/drivers/rtc/Kconfig
|
|
+++ b/drivers/rtc/Kconfig
|
|
@@ -256,6 +256,17 @@ config RTC_DRV_S35390A
|
|
This driver can also be built as a module. If so the module
|
|
will be called rtc-s35390a.
|
|
|
|
+config RTC_DRV_FM3130
|
|
+ tristate "Ramtron FM3130"
|
|
+ help
|
|
+ If you say Y here you will get support for the
|
|
+ Ramtron FM3130 RTC chips.
|
|
+ Ramtron FM3130 is a chip with two separate devices inside,
|
|
+ RTC clock and FRAM. This driver provides only RTC functionality.
|
|
+
|
|
+ This driver can also be built as a module. If so the module
|
|
+ will be called rtc-fm3130.
|
|
+
|
|
endif # I2C
|
|
|
|
comment "SPI RTC drivers"
|
|
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
|
|
index ebe871c..b6e14d5 100644
|
|
--- a/drivers/rtc/Makefile
|
|
+++ b/drivers/rtc/Makefile
|
|
@@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
|
|
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
|
|
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
|
|
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
|
|
+obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
|
|
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
|
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
|
|
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
|
|
@@ -41,6 +42,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
|
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
|
|
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
|
|
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
|
|
+obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
|
|
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
|
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
|
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
|
|
@@ -54,4 +56,3 @@ obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
|
|
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
|
|
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
|
|
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
|
|
-obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
|
|
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
|
|
index 42244f1..2ef8cdf 100644
|
|
--- a/drivers/rtc/rtc-at32ap700x.c
|
|
+++ b/drivers/rtc/rtc-at32ap700x.c
|
|
@@ -94,8 +94,11 @@ static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|
{
|
|
struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
|
|
|
|
+ spin_lock_irq(&rtc->lock);
|
|
rtc_time_to_tm(rtc->alarm_time, &alrm->time);
|
|
- alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
|
|
+ alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
|
|
+ alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0;
|
|
+ spin_unlock_irq(&rtc->lock);
|
|
|
|
return 0;
|
|
}
|
|
@@ -119,7 +122,7 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|
spin_lock_irq(&rtc->lock);
|
|
rtc->alarm_time = alarm_unix_time;
|
|
rtc_writel(rtc, TOP, rtc->alarm_time);
|
|
- if (alrm->pending)
|
|
+ if (alrm->enabled)
|
|
rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
|
|
| RTC_BIT(CTRL_TOPEN));
|
|
else
|
|
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
|
|
index d060a06..d7bb9ba 100644
|
|
--- a/drivers/rtc/rtc-cmos.c
|
|
+++ b/drivers/rtc/rtc-cmos.c
|
|
@@ -905,19 +905,7 @@ static struct pnp_driver cmos_pnp_driver = {
|
|
.resume = cmos_pnp_resume,
|
|
};
|
|
|
|
-static int __init cmos_init(void)
|
|
-{
|
|
- return pnp_register_driver(&cmos_pnp_driver);
|
|
-}
|
|
-module_init(cmos_init);
|
|
-
|
|
-static void __exit cmos_exit(void)
|
|
-{
|
|
- pnp_unregister_driver(&cmos_pnp_driver);
|
|
-}
|
|
-module_exit(cmos_exit);
|
|
-
|
|
-#else /* no PNP */
|
|
+#endif /* CONFIG_PNP */
|
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
@@ -958,20 +946,33 @@ static struct platform_driver cmos_platform_driver = {
|
|
|
|
static int __init cmos_init(void)
|
|
{
|
|
+#ifdef CONFIG_PNP
|
|
+ if (pnp_platform_devices)
|
|
+ return pnp_register_driver(&cmos_pnp_driver);
|
|
+ else
|
|
+ return platform_driver_probe(&cmos_platform_driver,
|
|
+ cmos_platform_probe);
|
|
+#else
|
|
return platform_driver_probe(&cmos_platform_driver,
|
|
cmos_platform_probe);
|
|
+#endif /* CONFIG_PNP */
|
|
}
|
|
module_init(cmos_init);
|
|
|
|
static void __exit cmos_exit(void)
|
|
{
|
|
+#ifdef CONFIG_PNP
|
|
+ if (pnp_platform_devices)
|
|
+ pnp_unregister_driver(&cmos_pnp_driver);
|
|
+ else
|
|
+ platform_driver_unregister(&cmos_platform_driver);
|
|
+#else
|
|
platform_driver_unregister(&cmos_platform_driver);
|
|
+#endif /* CONFIG_PNP */
|
|
}
|
|
module_exit(cmos_exit);
|
|
|
|
|
|
-#endif /* !PNP */
|
|
-
|
|
MODULE_AUTHOR("David Brownell");
|
|
MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
|
|
MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
|
|
new file mode 100644
|
|
index 0000000..11644c8
|
|
--- /dev/null
|
|
+++ b/drivers/rtc/rtc-fm3130.c
|
|
@@ -0,0 +1,501 @@
|
|
+/*
|
|
+ * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
|
|
+ *
|
|
+ * Copyright (C) 2008 Sergey Lapin
|
|
+ * Based on ds1307 driver by James Chapman and David Brownell
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/rtc.h>
|
|
+#include <linux/bcd.h>
|
|
+
|
|
+#define FM3130_RTC_CONTROL (0x0)
|
|
+#define FM3130_CAL_CONTROL (0x1)
|
|
+#define FM3130_RTC_SECONDS (0x2)
|
|
+#define FM3130_RTC_MINUTES (0x3)
|
|
+#define FM3130_RTC_HOURS (0x4)
|
|
+#define FM3130_RTC_DAY (0x5)
|
|
+#define FM3130_RTC_DATE (0x6)
|
|
+#define FM3130_RTC_MONTHS (0x7)
|
|
+#define FM3130_RTC_YEARS (0x8)
|
|
+
|
|
+#define FM3130_ALARM_SECONDS (0x9)
|
|
+#define FM3130_ALARM_MINUTES (0xa)
|
|
+#define FM3130_ALARM_HOURS (0xb)
|
|
+#define FM3130_ALARM_DATE (0xc)
|
|
+#define FM3130_ALARM_MONTHS (0xd)
|
|
+#define FM3130_ALARM_WP_CONTROL (0xe)
|
|
+
|
|
+#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */
|
|
+#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */
|
|
+#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */
|
|
+#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */
|
|
+#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */
|
|
+#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */
|
|
+#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */
|
|
+#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */
|
|
+#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */
|
|
+
|
|
+#define FM3130_CLOCK_REGS 7
|
|
+#define FM3130_ALARM_REGS 5
|
|
+
|
|
+struct fm3130 {
|
|
+ u8 reg_addr_time;
|
|
+ u8 reg_addr_alarm;
|
|
+ u8 regs[15];
|
|
+ struct i2c_msg msg[4];
|
|
+ struct i2c_client *client;
|
|
+ struct rtc_device *rtc;
|
|
+ int data_valid;
|
|
+ int alarm;
|
|
+};
|
|
+static const struct i2c_device_id fm3130_id[] = {
|
|
+ { "fm3130-rtc", 0 },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(i2c, fm3130_id);
|
|
+
|
|
+#define FM3130_MODE_NORMAL 0
|
|
+#define FM3130_MODE_WRITE 1
|
|
+#define FM3130_MODE_READ 2
|
|
+
|
|
+static void fm3130_rtc_mode(struct device *dev, int mode)
|
|
+{
|
|
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
|
+
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] =
|
|
+ i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
|
|
+ switch (mode) {
|
|
+ case FM3130_MODE_NORMAL:
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &=
|
|
+ ~(FM3130_RTC_CONTROL_BIT_WRITE |
|
|
+ FM3130_RTC_CONTROL_BIT_READ);
|
|
+ break;
|
|
+ case FM3130_MODE_WRITE:
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE;
|
|
+ break;
|
|
+ case FM3130_MODE_READ:
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ;
|
|
+ break;
|
|
+ default:
|
|
+ dev_dbg(dev, "invalid mode %d\n", mode);
|
|
+ break;
|
|
+ }
|
|
+ /* Checking for alarm */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
|
+ fm3130->alarm = 1;
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
|
+ }
|
|
+ i2c_smbus_write_byte_data(fm3130->client,
|
|
+ FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
|
|
+}
|
|
+
|
|
+static int fm3130_get_time(struct device *dev, struct rtc_time *t)
|
|
+{
|
|
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
|
+ int tmp;
|
|
+
|
|
+ if (!fm3130->data_valid) {
|
|
+ /* We have invalid data in RTC, probably due
|
|
+ to battery faults or other problems. Return EIO
|
|
+ for now, it will allow us to set data later insted
|
|
+ of error during probing which disables device */
|
|
+ return -EIO;
|
|
+ }
|
|
+ fm3130_rtc_mode(dev, FM3130_MODE_READ);
|
|
+
|
|
+ /* read the RTC date and time registers all at once */
|
|
+ tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
|
+ fm3130->msg, 2);
|
|
+ if (tmp != 2) {
|
|
+ dev_err(dev, "%s error %d\n", "read", tmp);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
|
|
+
|
|
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
+ "%02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ "read",
|
|
+ fm3130->regs[0], fm3130->regs[1],
|
|
+ fm3130->regs[2], fm3130->regs[3],
|
|
+ fm3130->regs[4], fm3130->regs[5],
|
|
+ fm3130->regs[6], fm3130->regs[7],
|
|
+ fm3130->regs[8], fm3130->regs[9],
|
|
+ fm3130->regs[0xa], fm3130->regs[0xb],
|
|
+ fm3130->regs[0xc], fm3130->regs[0xd],
|
|
+ fm3130->regs[0xe]);
|
|
+
|
|
+ t->tm_sec = BCD2BIN(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
|
|
+ t->tm_min = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
|
|
+ tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
|
|
+ t->tm_hour = BCD2BIN(tmp);
|
|
+ t->tm_wday = BCD2BIN(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
|
|
+ t->tm_mday = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
|
|
+ tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
|
|
+ t->tm_mon = BCD2BIN(tmp) - 1;
|
|
+
|
|
+ /* assume 20YY not 19YY, and ignore CF bit */
|
|
+ t->tm_year = BCD2BIN(fm3130->regs[FM3130_RTC_YEARS]) + 100;
|
|
+
|
|
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
|
|
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
|
+ "read", t->tm_sec, t->tm_min,
|
|
+ t->tm_hour, t->tm_mday,
|
|
+ t->tm_mon, t->tm_year, t->tm_wday);
|
|
+
|
|
+ /* initial clock setting can be undefined */
|
|
+ return rtc_valid_tm(t);
|
|
+}
|
|
+
|
|
+
|
|
+static int fm3130_set_time(struct device *dev, struct rtc_time *t)
|
|
+{
|
|
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
|
+ int tmp, i;
|
|
+ u8 *buf = fm3130->regs;
|
|
+
|
|
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
|
|
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
|
+ "write", t->tm_sec, t->tm_min,
|
|
+ t->tm_hour, t->tm_mday,
|
|
+ t->tm_mon, t->tm_year, t->tm_wday);
|
|
+
|
|
+ /* first register addr */
|
|
+ buf[FM3130_RTC_SECONDS] = BIN2BCD(t->tm_sec);
|
|
+ buf[FM3130_RTC_MINUTES] = BIN2BCD(t->tm_min);
|
|
+ buf[FM3130_RTC_HOURS] = BIN2BCD(t->tm_hour);
|
|
+ buf[FM3130_RTC_DAY] = BIN2BCD(t->tm_wday + 1);
|
|
+ buf[FM3130_RTC_DATE] = BIN2BCD(t->tm_mday);
|
|
+ buf[FM3130_RTC_MONTHS] = BIN2BCD(t->tm_mon + 1);
|
|
+
|
|
+ /* assume 20YY not 19YY */
|
|
+ tmp = t->tm_year - 100;
|
|
+ buf[FM3130_RTC_YEARS] = BIN2BCD(tmp);
|
|
+
|
|
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
|
|
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ "write", buf[0], buf[1], buf[2], buf[3],
|
|
+ buf[4], buf[5], buf[6], buf[7],
|
|
+ buf[8], buf[9], buf[0xa], buf[0xb],
|
|
+ buf[0xc], buf[0xd], buf[0xe]);
|
|
+
|
|
+ fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
|
|
+
|
|
+ /* Writing time registers, we don't support multibyte transfers */
|
|
+ for (i = 0; i < FM3130_CLOCK_REGS; i++) {
|
|
+ i2c_smbus_write_byte_data(fm3130->client,
|
|
+ FM3130_RTC_SECONDS + i,
|
|
+ fm3130->regs[FM3130_RTC_SECONDS + i]);
|
|
+ }
|
|
+
|
|
+ fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
|
|
+
|
|
+ /* We assume here that data are valid once written */
|
|
+ if (!fm3130->data_valid)
|
|
+ fm3130->data_valid = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|
+{
|
|
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
|
+ int tmp;
|
|
+ struct rtc_time *tm = &alrm->time;
|
|
+ /* read the RTC alarm registers all at once */
|
|
+ tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
|
+ &fm3130->msg[2], 2);
|
|
+ if (tmp != 2) {
|
|
+ dev_err(dev, "%s error %d\n", "read", tmp);
|
|
+ return -EIO;
|
|
+ }
|
|
+ dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n",
|
|
+ fm3130->regs[FM3130_ALARM_SECONDS],
|
|
+ fm3130->regs[FM3130_ALARM_MINUTES],
|
|
+ fm3130->regs[FM3130_ALARM_HOURS],
|
|
+ fm3130->regs[FM3130_ALARM_DATE],
|
|
+ fm3130->regs[FM3130_ALARM_MONTHS]);
|
|
+
|
|
+
|
|
+ tm->tm_sec = BCD2BIN(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
|
|
+ tm->tm_min = BCD2BIN(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
|
|
+ tm->tm_hour = BCD2BIN(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
|
|
+ tm->tm_mday = BCD2BIN(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
|
|
+ tm->tm_mon = BCD2BIN(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
|
|
+ if (tm->tm_mon > 0)
|
|
+ tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
|
|
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
|
|
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
|
+ "read alarm", tm->tm_sec, tm->tm_min,
|
|
+ tm->tm_hour, tm->tm_mday,
|
|
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|
+{
|
|
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
|
+ struct rtc_time *tm = &alrm->time;
|
|
+ int i;
|
|
+
|
|
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
|
|
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
|
+ "write alarm", tm->tm_sec, tm->tm_min,
|
|
+ tm->tm_hour, tm->tm_mday,
|
|
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
|
|
+
|
|
+ if (tm->tm_sec != -1)
|
|
+ fm3130->regs[FM3130_ALARM_SECONDS] =
|
|
+ BIN2BCD(tm->tm_sec) | 0x80;
|
|
+
|
|
+ if (tm->tm_min != -1)
|
|
+ fm3130->regs[FM3130_ALARM_MINUTES] =
|
|
+ BIN2BCD(tm->tm_min) | 0x80;
|
|
+
|
|
+ if (tm->tm_hour != -1)
|
|
+ fm3130->regs[FM3130_ALARM_HOURS] =
|
|
+ BIN2BCD(tm->tm_hour) | 0x80;
|
|
+
|
|
+ if (tm->tm_mday != -1)
|
|
+ fm3130->regs[FM3130_ALARM_DATE] =
|
|
+ BIN2BCD(tm->tm_mday) | 0x80;
|
|
+
|
|
+ if (tm->tm_mon != -1)
|
|
+ fm3130->regs[FM3130_ALARM_MONTHS] =
|
|
+ BIN2BCD(tm->tm_mon + 1) | 0x80;
|
|
+
|
|
+ dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
|
|
+ fm3130->regs[FM3130_ALARM_SECONDS],
|
|
+ fm3130->regs[FM3130_ALARM_MINUTES],
|
|
+ fm3130->regs[FM3130_ALARM_HOURS],
|
|
+ fm3130->regs[FM3130_ALARM_DATE],
|
|
+ fm3130->regs[FM3130_ALARM_MONTHS]);
|
|
+ /* Writing time registers, we don't support multibyte transfers */
|
|
+ for (i = 0; i < FM3130_ALARM_REGS; i++) {
|
|
+ i2c_smbus_write_byte_data(fm3130->client,
|
|
+ FM3130_ALARM_SECONDS + i,
|
|
+ fm3130->regs[FM3130_ALARM_SECONDS + i]);
|
|
+ }
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] =
|
|
+ i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
|
|
+ /* Checking for alarm */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
|
+ fm3130->alarm = 1;
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
|
+ }
|
|
+ if (alrm->enabled) {
|
|
+ i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
|
|
+ (fm3130->regs[FM3130_RTC_CONTROL] &
|
|
+ ~(FM3130_RTC_CONTROL_BIT_CAL)) |
|
|
+ FM3130_RTC_CONTROL_BIT_AEN);
|
|
+ } else {
|
|
+ i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &
|
|
+ ~(FM3130_RTC_CONTROL_BIT_AEN));
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct rtc_class_ops fm3130_rtc_ops = {
|
|
+ .read_time = fm3130_get_time,
|
|
+ .set_time = fm3130_set_time,
|
|
+ .read_alarm = fm3130_read_alarm,
|
|
+ .set_alarm = fm3130_set_alarm,
|
|
+};
|
|
+
|
|
+static struct i2c_driver fm3130_driver;
|
|
+
|
|
+static int __devinit fm3130_probe(struct i2c_client *client,
|
|
+ const struct i2c_device_id *id)
|
|
+{
|
|
+ struct fm3130 *fm3130;
|
|
+ int err = -ENODEV;
|
|
+ int tmp;
|
|
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
|
+
|
|
+ if (!i2c_check_functionality(adapter,
|
|
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
|
+ return -EIO;
|
|
+
|
|
+ fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
|
|
+
|
|
+ if (!fm3130)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ fm3130->client = client;
|
|
+ i2c_set_clientdata(client, fm3130);
|
|
+ fm3130->reg_addr_time = FM3130_RTC_SECONDS;
|
|
+ fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS;
|
|
+
|
|
+ /* Messages to read time */
|
|
+ fm3130->msg[0].addr = client->addr;
|
|
+ fm3130->msg[0].flags = 0;
|
|
+ fm3130->msg[0].len = 1;
|
|
+ fm3130->msg[0].buf = &fm3130->reg_addr_time;
|
|
+
|
|
+ fm3130->msg[1].addr = client->addr;
|
|
+ fm3130->msg[1].flags = I2C_M_RD;
|
|
+ fm3130->msg[1].len = FM3130_CLOCK_REGS;
|
|
+ fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS];
|
|
+
|
|
+ /* Messages to read alarm */
|
|
+ fm3130->msg[2].addr = client->addr;
|
|
+ fm3130->msg[2].flags = 0;
|
|
+ fm3130->msg[2].len = 1;
|
|
+ fm3130->msg[2].buf = &fm3130->reg_addr_alarm;
|
|
+
|
|
+ fm3130->msg[3].addr = client->addr;
|
|
+ fm3130->msg[3].flags = I2C_M_RD;
|
|
+ fm3130->msg[3].len = FM3130_ALARM_REGS;
|
|
+ fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
|
|
+
|
|
+ fm3130->data_valid = 0;
|
|
+
|
|
+ tmp = i2c_transfer(adapter, fm3130->msg, 4);
|
|
+ if (tmp != 4) {
|
|
+ pr_debug("read error %d\n", tmp);
|
|
+ err = -EIO;
|
|
+ goto exit_free;
|
|
+ }
|
|
+
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] =
|
|
+ i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL);
|
|
+ fm3130->regs[FM3130_CAL_CONTROL] =
|
|
+ i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
|
|
+
|
|
+ /* Checking for alarm */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
|
+ fm3130->alarm = 1;
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
|
+ }
|
|
+
|
|
+ /* Disabling calibration mode */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)
|
|
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &
|
|
+ ~(FM3130_RTC_CONTROL_BIT_CAL));
|
|
+ dev_warn(&client->dev, "Disabling calibration mode!\n");
|
|
+
|
|
+ /* Disabling read and write modes */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ)
|
|
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &
|
|
+ ~(FM3130_RTC_CONTROL_BIT_READ |
|
|
+ FM3130_RTC_CONTROL_BIT_WRITE));
|
|
+ dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
|
|
+
|
|
+ /* oscillator off? turn it on, so clock can tick. */
|
|
+ if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
|
|
+ i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL,
|
|
+ fm3130->regs[FM3130_CAL_CONTROL] &
|
|
+ ~(FM3130_CAL_CONTROL_BIT_nOSCEN));
|
|
+
|
|
+ /* oscillator fault? clear flag, and warn */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB)
|
|
+ dev_warn(&client->dev, "Low battery!\n");
|
|
+
|
|
+ /* oscillator fault? clear flag, and warn */
|
|
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
|
|
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
|
+ fm3130->regs[FM3130_RTC_CONTROL] &
|
|
+ ~FM3130_RTC_CONTROL_BIT_POR);
|
|
+ dev_warn(&client->dev, "SET TIME!\n");
|
|
+ }
|
|
+ /* ACS is controlled by alarm */
|
|
+ i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
|
|
+
|
|
+ /* TODO */
|
|
+ /* TODO need to sanity check alarm */
|
|
+ tmp = fm3130->regs[FM3130_RTC_SECONDS];
|
|
+ tmp = BCD2BIN(tmp & 0x7f);
|
|
+ if (tmp > 60)
|
|
+ goto exit_bad;
|
|
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
|
|
+ if (tmp > 60)
|
|
+ goto exit_bad;
|
|
+
|
|
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
|
|
+ if (tmp == 0 || tmp > 31)
|
|
+ goto exit_bad;
|
|
+
|
|
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
|
|
+ if (tmp == 0 || tmp > 12)
|
|
+ goto exit_bad;
|
|
+
|
|
+ tmp = fm3130->regs[FM3130_RTC_HOURS];
|
|
+
|
|
+ fm3130->data_valid = 1;
|
|
+
|
|
+exit_bad:
|
|
+ if (!fm3130->data_valid)
|
|
+ dev_dbg(&client->dev,
|
|
+ "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
+ "%02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ "bogus registers",
|
|
+ fm3130->regs[0], fm3130->regs[1],
|
|
+ fm3130->regs[2], fm3130->regs[3],
|
|
+ fm3130->regs[4], fm3130->regs[5],
|
|
+ fm3130->regs[6], fm3130->regs[7],
|
|
+ fm3130->regs[8], fm3130->regs[9],
|
|
+ fm3130->regs[0xa], fm3130->regs[0xb],
|
|
+ fm3130->regs[0xc], fm3130->regs[0xd],
|
|
+ fm3130->regs[0xe]);
|
|
+
|
|
+ /* We won't bail out here because we just got invalid data.
|
|
+ Time setting from u-boot doesn't work anyway */
|
|
+ fm3130->rtc = rtc_device_register(client->name, &client->dev,
|
|
+ &fm3130_rtc_ops, THIS_MODULE);
|
|
+ if (IS_ERR(fm3130->rtc)) {
|
|
+ err = PTR_ERR(fm3130->rtc);
|
|
+ dev_err(&client->dev,
|
|
+ "unable to register the class device\n");
|
|
+ goto exit_free;
|
|
+ }
|
|
+ return 0;
|
|
+exit_free:
|
|
+ kfree(fm3130);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int __devexit fm3130_remove(struct i2c_client *client)
|
|
+{
|
|
+ struct fm3130 *fm3130 = i2c_get_clientdata(client);
|
|
+
|
|
+ rtc_device_unregister(fm3130->rtc);
|
|
+ kfree(fm3130);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct i2c_driver fm3130_driver = {
|
|
+ .driver = {
|
|
+ .name = "rtc-fm3130",
|
|
+ .owner = THIS_MODULE,
|
|
+ },
|
|
+ .probe = fm3130_probe,
|
|
+ .remove = __devexit_p(fm3130_remove),
|
|
+ .id_table = fm3130_id,
|
|
+};
|
|
+
|
|
+static int __init fm3130_init(void)
|
|
+{
|
|
+ return i2c_add_driver(&fm3130_driver);
|
|
+}
|
|
+module_init(fm3130_init);
|
|
+
|
|
+static void __exit fm3130_exit(void)
|
|
+{
|
|
+ i2c_del_driver(&fm3130_driver);
|
|
+}
|
|
+module_exit(fm3130_exit);
|
|
+
|
|
+MODULE_DESCRIPTION("RTC driver for FM3130");
|
|
+MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
|
|
index 35ac9d9..c14b243 100644
|
|
--- a/drivers/video/cirrusfb.c
|
|
+++ b/drivers/video/cirrusfb.c
|
|
@@ -2432,9 +2432,9 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
|
|
info->screen_size = board_size;
|
|
cinfo->unmap = cirrusfb_pci_unmap;
|
|
|
|
- printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
|
|
- info->screen_size >> 10, board_addr);
|
|
- printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
|
|
+ printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus "
|
|
+ "Logic chipset on PCI bus\n",
|
|
+ info->screen_size >> 10, board_addr);
|
|
pci_set_drvdata(pdev, info);
|
|
|
|
ret = cirrusfb_register(info);
|
|
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
|
|
index fb9e672..c18880d 100644
|
|
--- a/drivers/video/hgafb.c
|
|
+++ b/drivers/video/hgafb.c
|
|
@@ -279,7 +279,7 @@ static void hga_blank(int blank_mode)
|
|
|
|
static int __init hga_card_detect(void)
|
|
{
|
|
- int count=0;
|
|
+ int count = 0;
|
|
void __iomem *p, *q;
|
|
unsigned short p_save, q_save;
|
|
|
|
@@ -303,20 +303,18 @@ static int __init hga_card_detect(void)
|
|
writew(0x55aa, p); if (readw(p) == 0x55aa) count++;
|
|
writew(p_save, p);
|
|
|
|
- if (count != 2) {
|
|
- return 0;
|
|
- }
|
|
+ if (count != 2)
|
|
+ goto error;
|
|
|
|
/* Ok, there is definitely a card registering at the correct
|
|
* memory location, so now we do an I/O port test.
|
|
*/
|
|
|
|
- if (!test_hga_b(0x66, 0x0f)) { /* cursor low register */
|
|
- return 0;
|
|
- }
|
|
- if (!test_hga_b(0x99, 0x0f)) { /* cursor low register */
|
|
- return 0;
|
|
- }
|
|
+ if (!test_hga_b(0x66, 0x0f)) /* cursor low register */
|
|
+ goto error;
|
|
+
|
|
+ if (!test_hga_b(0x99, 0x0f)) /* cursor low register */
|
|
+ goto error;
|
|
|
|
/* See if the card is a Hercules, by checking whether the vsync
|
|
* bit of the status register is changing. This test lasts for
|
|
@@ -331,7 +329,7 @@ static int __init hga_card_detect(void)
|
|
}
|
|
|
|
if (p_save == q_save)
|
|
- return 0;
|
|
+ goto error;
|
|
|
|
switch (inb_p(HGA_STATUS_PORT) & 0x70) {
|
|
case 0x10:
|
|
@@ -348,6 +346,12 @@ static int __init hga_card_detect(void)
|
|
break;
|
|
}
|
|
return 1;
|
|
+error:
|
|
+ if (release_io_ports)
|
|
+ release_region(0x3b0, 12);
|
|
+ if (release_io_port)
|
|
+ release_region(0x3bf, 1);
|
|
+ return 0;
|
|
}
|
|
|
|
/**
|
|
diff --git a/fs/fat/file.c b/fs/fat/file.c
|
|
index 27cc116..771326b 100644
|
|
--- a/fs/fat/file.c
|
|
+++ b/fs/fat/file.c
|
|
@@ -257,26 +257,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|
}
|
|
EXPORT_SYMBOL_GPL(fat_getattr);
|
|
|
|
-static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode,
|
|
- mode_t mode)
|
|
+static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
|
|
+ struct inode *inode, umode_t *mode_ptr)
|
|
{
|
|
- mode_t mask, req = mode & ~S_IFMT;
|
|
+ mode_t mask, perm;
|
|
|
|
- if (S_ISREG(mode))
|
|
+ /*
|
|
+ * Note, the basic check is already done by a caller of
|
|
+ * (attr->ia_mode & ~MSDOS_VALID_MODE)
|
|
+ */
|
|
+
|
|
+ if (S_ISREG(inode->i_mode))
|
|
mask = sbi->options.fs_fmask;
|
|
else
|
|
mask = sbi->options.fs_dmask;
|
|
|
|
+ perm = *mode_ptr & ~(S_IFMT | mask);
|
|
+
|
|
/*
|
|
* Of the r and x bits, all (subject to umask) must be present. Of the
|
|
* w bits, either all (subject to umask) or none must be present.
|
|
*/
|
|
- req &= ~mask;
|
|
- if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
|
|
+ if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
|
|
return -EPERM;
|
|
- if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask)))
|
|
+ if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))
|
|
return -EPERM;
|
|
|
|
+ *mode_ptr &= S_IFMT | perm;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -299,7 +307,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
|
|
{
|
|
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
|
|
struct inode *inode = dentry->d_inode;
|
|
- int mask, error = 0;
|
|
+ int error = 0;
|
|
unsigned int ia_valid;
|
|
|
|
lock_kernel();
|
|
@@ -332,12 +340,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
|
|
error = 0;
|
|
goto out;
|
|
}
|
|
+
|
|
if (((attr->ia_valid & ATTR_UID) &&
|
|
(attr->ia_uid != sbi->options.fs_uid)) ||
|
|
((attr->ia_valid & ATTR_GID) &&
|
|
(attr->ia_gid != sbi->options.fs_gid)) ||
|
|
((attr->ia_valid & ATTR_MODE) &&
|
|
- fat_check_mode(sbi, inode, attr->ia_mode) < 0))
|
|
+ (attr->ia_mode & ~MSDOS_VALID_MODE)))
|
|
error = -EPERM;
|
|
|
|
if (error) {
|
|
@@ -346,15 +355,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
|
|
goto out;
|
|
}
|
|
|
|
- error = inode_setattr(inode, attr);
|
|
- if (error)
|
|
- goto out;
|
|
+ /*
|
|
+ * We don't return -EPERM here. Yes, strange, but this is too
|
|
+ * old behavior.
|
|
+ */
|
|
+ if (attr->ia_valid & ATTR_MODE) {
|
|
+ if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
|
|
+ attr->ia_valid &= ~ATTR_MODE;
|
|
+ }
|
|
|
|
- if (S_ISDIR(inode->i_mode))
|
|
- mask = sbi->options.fs_dmask;
|
|
- else
|
|
- mask = sbi->options.fs_fmask;
|
|
- inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
|
|
+ error = inode_setattr(inode, attr);
|
|
out:
|
|
unlock_kernel();
|
|
return error;
|
|
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
|
|
index 1740362..ab8ccc9 100644
|
|
--- a/fs/proc/task_mmu.c
|
|
+++ b/fs/proc/task_mmu.c
|
|
@@ -315,9 +315,9 @@ struct mem_size_stats {
|
|
};
|
|
|
|
static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
|
|
- void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
- struct mem_size_stats *mss = private;
|
|
+ struct mem_size_stats *mss = walk->private;
|
|
struct vm_area_struct *vma = mss->vma;
|
|
pte_t *pte, ptent;
|
|
spinlock_t *ptl;
|
|
@@ -365,19 +365,21 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
|
|
return 0;
|
|
}
|
|
|
|
-static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range };
|
|
-
|
|
static int show_smap(struct seq_file *m, void *v)
|
|
{
|
|
struct vm_area_struct *vma = v;
|
|
struct mem_size_stats mss;
|
|
int ret;
|
|
+ struct mm_walk smaps_walk = {
|
|
+ .pmd_entry = smaps_pte_range,
|
|
+ .mm = vma->vm_mm,
|
|
+ .private = &mss,
|
|
+ };
|
|
|
|
memset(&mss, 0, sizeof mss);
|
|
mss.vma = vma;
|
|
if (vma->vm_mm && !is_vm_hugetlb_page(vma))
|
|
- walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end,
|
|
- &smaps_walk, &mss);
|
|
+ walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk);
|
|
|
|
ret = show_map(m, v);
|
|
if (ret)
|
|
@@ -426,9 +428,9 @@ const struct file_operations proc_smaps_operations = {
|
|
};
|
|
|
|
static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
|
|
- unsigned long end, void *private)
|
|
+ unsigned long end, struct mm_walk *walk)
|
|
{
|
|
- struct vm_area_struct *vma = private;
|
|
+ struct vm_area_struct *vma = walk->private;
|
|
pte_t *pte, ptent;
|
|
spinlock_t *ptl;
|
|
struct page *page;
|
|
@@ -452,8 +454,6 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
|
|
return 0;
|
|
}
|
|
|
|
-static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range };
|
|
-
|
|
static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
@@ -476,11 +476,17 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|
return -ESRCH;
|
|
mm = get_task_mm(task);
|
|
if (mm) {
|
|
+ static struct mm_walk clear_refs_walk;
|
|
+ memset(&clear_refs_walk, 0, sizeof(clear_refs_walk));
|
|
+ clear_refs_walk.pmd_entry = clear_refs_pte_range;
|
|
+ clear_refs_walk.mm = mm;
|
|
down_read(&mm->mmap_sem);
|
|
- for (vma = mm->mmap; vma; vma = vma->vm_next)
|
|
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
|
+ clear_refs_walk.private = vma;
|
|
if (!is_vm_hugetlb_page(vma))
|
|
- walk_page_range(mm, vma->vm_start, vma->vm_end,
|
|
- &clear_refs_walk, vma);
|
|
+ walk_page_range(vma->vm_start, vma->vm_end,
|
|
+ &clear_refs_walk);
|
|
+ }
|
|
flush_tlb_mm(mm);
|
|
up_read(&mm->mmap_sem);
|
|
mmput(mm);
|
|
@@ -528,9 +534,9 @@ static int add_to_pagemap(unsigned long addr, u64 pfn,
|
|
}
|
|
|
|
static int pagemap_pte_hole(unsigned long start, unsigned long end,
|
|
- void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
- struct pagemapread *pm = private;
|
|
+ struct pagemapread *pm = walk->private;
|
|
unsigned long addr;
|
|
int err = 0;
|
|
for (addr = start; addr < end; addr += PAGE_SIZE) {
|
|
@@ -547,24 +553,45 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte)
|
|
return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
|
|
}
|
|
|
|
+static unsigned long pte_to_pagemap_entry(pte_t pte)
|
|
+{
|
|
+ unsigned long pme = 0;
|
|
+ if (is_swap_pte(pte))
|
|
+ pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte))
|
|
+ | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
|
|
+ else if (pte_present(pte))
|
|
+ pme = PM_PFRAME(pte_pfn(pte))
|
|
+ | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
|
|
+ return pme;
|
|
+}
|
|
+
|
|
static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
|
|
- void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
- struct pagemapread *pm = private;
|
|
+ struct vm_area_struct *vma;
|
|
+ struct pagemapread *pm = walk->private;
|
|
pte_t *pte;
|
|
int err = 0;
|
|
|
|
+ /* find the first VMA at or above 'addr' */
|
|
+ vma = find_vma(walk->mm, addr);
|
|
for (; addr != end; addr += PAGE_SIZE) {
|
|
u64 pfn = PM_NOT_PRESENT;
|
|
- pte = pte_offset_map(pmd, addr);
|
|
- if (is_swap_pte(*pte))
|
|
- pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte))
|
|
- | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
|
|
- else if (pte_present(*pte))
|
|
- pfn = PM_PFRAME(pte_pfn(*pte))
|
|
- | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
|
|
- /* unmap so we're not in atomic when we copy to userspace */
|
|
- pte_unmap(pte);
|
|
+
|
|
+ /* check to see if we've left 'vma' behind
|
|
+ * and need a new, higher one */
|
|
+ if (vma && (addr >= vma->vm_end))
|
|
+ vma = find_vma(walk->mm, addr);
|
|
+
|
|
+ /* check that 'vma' actually covers this address,
|
|
+ * and that it isn't a huge page vma */
|
|
+ if (vma && (vma->vm_start <= addr) &&
|
|
+ !is_vm_hugetlb_page(vma)) {
|
|
+ pte = pte_offset_map(pmd, addr);
|
|
+ pfn = pte_to_pagemap_entry(*pte);
|
|
+ /* unmap before userspace copy */
|
|
+ pte_unmap(pte);
|
|
+ }
|
|
err = add_to_pagemap(addr, pfn, pm);
|
|
if (err)
|
|
return err;
|
|
@@ -675,8 +702,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
|
|
* user buffer is tracked in "pm", and the walk
|
|
* will stop when we hit the end of the buffer.
|
|
*/
|
|
- ret = walk_page_range(mm, start_vaddr, end_vaddr,
|
|
- &pagemap_walk, &pm);
|
|
+ ret = walk_page_range(start_vaddr, end_vaddr,
|
|
+ &pagemap_walk);
|
|
if (ret == PM_END_OF_BUFFER)
|
|
ret = 0;
|
|
/* don't need mmap_sem for these, but this looks cleaner */
|
|
diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
|
|
index 83d1f28..3e81064 100644
|
|
--- a/include/asm-m68k/bitops.h
|
|
+++ b/include/asm-m68k/bitops.h
|
|
@@ -410,8 +410,49 @@ static inline int ext2_find_next_zero_bit(const void *vaddr, unsigned size,
|
|
res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
|
|
return (p - addr) * 32 + res;
|
|
}
|
|
-#define ext2_find_next_bit(addr, size, off) \
|
|
- generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
|
|
+
|
|
+static inline int ext2_find_first_bit(const void *vaddr, unsigned size)
|
|
+{
|
|
+ const unsigned long *p = vaddr, *addr = vaddr;
|
|
+ int res;
|
|
+
|
|
+ if (!size)
|
|
+ return 0;
|
|
+
|
|
+ size = (size >> 5) + ((size & 31) > 0);
|
|
+ while (*p++ == 0UL) {
|
|
+ if (--size == 0)
|
|
+ return (p - addr) << 5;
|
|
+ }
|
|
+
|
|
+ --p;
|
|
+ for (res = 0; res < 32; res++)
|
|
+ if (ext2_test_bit(res, p))
|
|
+ break;
|
|
+ return (p - addr) * 32 + res;
|
|
+}
|
|
+
|
|
+static inline int ext2_find_next_bit(const void *vaddr, unsigned size,
|
|
+ unsigned offset)
|
|
+{
|
|
+ const unsigned long *addr = vaddr;
|
|
+ const unsigned long *p = addr + (offset >> 5);
|
|
+ int bit = offset & 31UL, res;
|
|
+
|
|
+ if (offset >= size)
|
|
+ return size;
|
|
+
|
|
+ if (bit) {
|
|
+ /* Look for one in first longword */
|
|
+ for (res = bit; res < 32; res++)
|
|
+ if (ext2_test_bit(res, p))
|
|
+ return (p - addr) * 32 + res;
|
|
+ p++;
|
|
+ }
|
|
+ /* No set bit yet, search remaining full bytes for a set bit */
|
|
+ res = ext2_find_first_bit(p, size - 32 * (p - addr));
|
|
+ return (p - addr) * 32 + res;
|
|
+}
|
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
diff --git a/include/linux/mm.h b/include/linux/mm.h
|
|
index c31a9cd..586a943 100644
|
|
--- a/include/linux/mm.h
|
|
+++ b/include/linux/mm.h
|
|
@@ -760,16 +760,17 @@ unsigned long unmap_vmas(struct mmu_gather **tlb,
|
|
* (see walk_page_range for more details)
|
|
*/
|
|
struct mm_walk {
|
|
- int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, void *);
|
|
- int (*pud_entry)(pud_t *, unsigned long, unsigned long, void *);
|
|
- int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, void *);
|
|
- int (*pte_entry)(pte_t *, unsigned long, unsigned long, void *);
|
|
- int (*pte_hole)(unsigned long, unsigned long, void *);
|
|
+ int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, struct mm_walk *);
|
|
+ int (*pud_entry)(pud_t *, unsigned long, unsigned long, struct mm_walk *);
|
|
+ int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, struct mm_walk *);
|
|
+ int (*pte_entry)(pte_t *, unsigned long, unsigned long, struct mm_walk *);
|
|
+ int (*pte_hole)(unsigned long, unsigned long, struct mm_walk *);
|
|
+ struct mm_struct *mm;
|
|
+ void *private;
|
|
};
|
|
|
|
-int walk_page_range(const struct mm_struct *, unsigned long addr,
|
|
- unsigned long end, const struct mm_walk *walk,
|
|
- void *private);
|
|
+int walk_page_range(unsigned long addr, unsigned long end,
|
|
+ struct mm_walk *walk);
|
|
void free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
|
|
unsigned long end, unsigned long floor, unsigned long ceiling);
|
|
void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma,
|
|
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
|
|
index 9b940e6..eafc9d6 100644
|
|
--- a/include/linux/pci_ids.h
|
|
+++ b/include/linux/pci_ids.h
|
|
@@ -716,6 +716,7 @@
|
|
#define PCI_DEVICE_ID_HP_CISSA 0x3220
|
|
#define PCI_DEVICE_ID_HP_CISSC 0x3230
|
|
#define PCI_DEVICE_ID_HP_CISSD 0x3238
|
|
+#define PCI_DEVICE_ID_HP_CISSE 0x323a
|
|
#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031
|
|
|
|
#define PCI_VENDOR_ID_PCTECH 0x1042
|
|
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
|
|
index 9883bc9..fff1d27 100644
|
|
--- a/include/linux/proc_fs.h
|
|
+++ b/include/linux/proc_fs.h
|
|
@@ -9,6 +9,8 @@
|
|
|
|
struct net;
|
|
struct completion;
|
|
+struct mm_struct;
|
|
+
|
|
/*
|
|
* The proc filesystem constants/structures
|
|
*/
|
|
@@ -101,8 +103,6 @@ extern spinlock_t proc_subdir_lock;
|
|
extern void proc_root_init(void);
|
|
extern void proc_misc_init(void);
|
|
|
|
-struct mm_struct;
|
|
-
|
|
void proc_flush_task(struct task_struct *task);
|
|
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *);
|
|
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
|
|
diff --git a/ipc/shm.c b/ipc/shm.c
|
|
index d05f6b5..790240c 100644
|
|
--- a/ipc/shm.c
|
|
+++ b/ipc/shm.c
|
|
@@ -1058,16 +1058,16 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
|
|
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
|
|
{
|
|
struct shmid_kernel *shp = it;
|
|
- char *format;
|
|
|
|
-#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
|
|
-#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
|
|
+#if BITS_PER_LONG <= 32
|
|
+#define SIZE_SPEC "%10lu"
|
|
+#else
|
|
+#define SIZE_SPEC "%21lu"
|
|
+#endif
|
|
|
|
- if (sizeof(size_t) <= sizeof(int))
|
|
- format = SMALL_STRING;
|
|
- else
|
|
- format = BIG_STRING;
|
|
- return seq_printf(s, format,
|
|
+ return seq_printf(s,
|
|
+ "%10d %10d %4o " SIZE_SPEC " %5u %5u "
|
|
+ "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n",
|
|
shp->shm_perm.key,
|
|
shp->shm_perm.id,
|
|
shp->shm_perm.mode,
|
|
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
|
|
index 1e0250c..d4998f8 100644
|
|
--- a/kernel/kprobes.c
|
|
+++ b/kernel/kprobes.c
|
|
@@ -699,8 +699,9 @@ static int __register_kprobes(struct kprobe **kps, int num,
|
|
return -EINVAL;
|
|
for (i = 0; i < num; i++) {
|
|
ret = __register_kprobe(kps[i], called_from);
|
|
- if (ret < 0 && i > 0) {
|
|
- unregister_kprobes(kps, i);
|
|
+ if (ret < 0) {
|
|
+ if (i > 0)
|
|
+ unregister_kprobes(kps, i);
|
|
break;
|
|
}
|
|
}
|
|
@@ -776,8 +777,9 @@ static int __register_jprobes(struct jprobe **jps, int num,
|
|
jp->kp.break_handler = longjmp_break_handler;
|
|
ret = __register_kprobe(&jp->kp, called_from);
|
|
}
|
|
- if (ret < 0 && i > 0) {
|
|
- unregister_jprobes(jps, i);
|
|
+ if (ret < 0) {
|
|
+ if (i > 0)
|
|
+ unregister_jprobes(jps, i);
|
|
break;
|
|
}
|
|
}
|
|
@@ -920,8 +922,9 @@ static int __register_kretprobes(struct kretprobe **rps, int num,
|
|
return -EINVAL;
|
|
for (i = 0; i < num; i++) {
|
|
ret = __register_kretprobe(rps[i], called_from);
|
|
- if (ret < 0 && i > 0) {
|
|
- unregister_kretprobes(rps, i);
|
|
+ if (ret < 0) {
|
|
+ if (i > 0)
|
|
+ unregister_kretprobes(rps, i);
|
|
break;
|
|
}
|
|
}
|
|
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
|
|
index bd52171..169a2f8 100644
|
|
--- a/lib/radix-tree.c
|
|
+++ b/lib/radix-tree.c
|
|
@@ -88,6 +88,57 @@ static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
|
|
return root->gfp_mask & __GFP_BITS_MASK;
|
|
}
|
|
|
|
+static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
|
|
+ int offset)
|
|
+{
|
|
+ __set_bit(offset, node->tags[tag]);
|
|
+}
|
|
+
|
|
+static inline void tag_clear(struct radix_tree_node *node, unsigned int tag,
|
|
+ int offset)
|
|
+{
|
|
+ __clear_bit(offset, node->tags[tag]);
|
|
+}
|
|
+
|
|
+static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
|
|
+ int offset)
|
|
+{
|
|
+ return test_bit(offset, node->tags[tag]);
|
|
+}
|
|
+
|
|
+static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
|
|
+{
|
|
+ root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
|
|
+}
|
|
+
|
|
+static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
|
|
+{
|
|
+ root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
|
|
+}
|
|
+
|
|
+static inline void root_tag_clear_all(struct radix_tree_root *root)
|
|
+{
|
|
+ root->gfp_mask &= __GFP_BITS_MASK;
|
|
+}
|
|
+
|
|
+static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
|
|
+{
|
|
+ return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Returns 1 if any slot in the node has this tag set.
|
|
+ * Otherwise returns 0.
|
|
+ */
|
|
+static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
|
|
+{
|
|
+ int idx;
|
|
+ for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
+ if (node->tags[tag][idx])
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
/*
|
|
* This assumes that the caller has performed appropriate preallocation, and
|
|
* that the caller has pinned this thread of control to the current CPU.
|
|
@@ -124,6 +175,17 @@ static void radix_tree_node_rcu_free(struct rcu_head *head)
|
|
{
|
|
struct radix_tree_node *node =
|
|
container_of(head, struct radix_tree_node, rcu_head);
|
|
+
|
|
+ /*
|
|
+ * must only free zeroed nodes into the slab. radix_tree_shrink
|
|
+ * can leave us with a non-NULL entry in the first slot, so clear
|
|
+ * that here to make sure.
|
|
+ */
|
|
+ tag_clear(node, 0, 0);
|
|
+ tag_clear(node, 1, 0);
|
|
+ node->slots[0] = NULL;
|
|
+ node->count = 0;
|
|
+
|
|
kmem_cache_free(radix_tree_node_cachep, node);
|
|
}
|
|
|
|
@@ -165,59 +227,6 @@ out:
|
|
}
|
|
EXPORT_SYMBOL(radix_tree_preload);
|
|
|
|
-static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
|
|
- int offset)
|
|
-{
|
|
- __set_bit(offset, node->tags[tag]);
|
|
-}
|
|
-
|
|
-static inline void tag_clear(struct radix_tree_node *node, unsigned int tag,
|
|
- int offset)
|
|
-{
|
|
- __clear_bit(offset, node->tags[tag]);
|
|
-}
|
|
-
|
|
-static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
|
|
- int offset)
|
|
-{
|
|
- return test_bit(offset, node->tags[tag]);
|
|
-}
|
|
-
|
|
-static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
|
|
-{
|
|
- root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
|
|
-}
|
|
-
|
|
-
|
|
-static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
|
|
-{
|
|
- root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
|
|
-}
|
|
-
|
|
-static inline void root_tag_clear_all(struct radix_tree_root *root)
|
|
-{
|
|
- root->gfp_mask &= __GFP_BITS_MASK;
|
|
-}
|
|
-
|
|
-static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
|
|
-{
|
|
- return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
|
|
-}
|
|
-
|
|
-/*
|
|
- * Returns 1 if any slot in the node has this tag set.
|
|
- * Otherwise returns 0.
|
|
- */
|
|
-static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
|
|
-{
|
|
- int idx;
|
|
- for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
- if (node->tags[tag][idx])
|
|
- return 1;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
/*
|
|
* Return the maximum key which can be store into a
|
|
* radix tree with height HEIGHT.
|
|
@@ -930,11 +939,6 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
|
|
newptr = radix_tree_ptr_to_indirect(newptr);
|
|
root->rnode = newptr;
|
|
root->height--;
|
|
- /* must only free zeroed nodes into the slab */
|
|
- tag_clear(to_free, 0, 0);
|
|
- tag_clear(to_free, 1, 0);
|
|
- to_free->slots[0] = NULL;
|
|
- to_free->count = 0;
|
|
radix_tree_node_free(to_free);
|
|
}
|
|
}
|
|
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
|
|
index 0afd238..d5878be 100644
|
|
--- a/mm/pagewalk.c
|
|
+++ b/mm/pagewalk.c
|
|
@@ -3,14 +3,14 @@
|
|
#include <linux/sched.h>
|
|
|
|
static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
|
|
- const struct mm_walk *walk, void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
pte_t *pte;
|
|
int err = 0;
|
|
|
|
pte = pte_offset_map(pmd, addr);
|
|
for (;;) {
|
|
- err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
|
|
+ err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, walk);
|
|
if (err)
|
|
break;
|
|
addr += PAGE_SIZE;
|
|
@@ -24,7 +24,7 @@ static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
|
|
}
|
|
|
|
static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
|
|
- const struct mm_walk *walk, void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
pmd_t *pmd;
|
|
unsigned long next;
|
|
@@ -35,15 +35,15 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
|
|
next = pmd_addr_end(addr, end);
|
|
if (pmd_none_or_clear_bad(pmd)) {
|
|
if (walk->pte_hole)
|
|
- err = walk->pte_hole(addr, next, private);
|
|
+ err = walk->pte_hole(addr, next, walk);
|
|
if (err)
|
|
break;
|
|
continue;
|
|
}
|
|
if (walk->pmd_entry)
|
|
- err = walk->pmd_entry(pmd, addr, next, private);
|
|
+ err = walk->pmd_entry(pmd, addr, next, walk);
|
|
if (!err && walk->pte_entry)
|
|
- err = walk_pte_range(pmd, addr, next, walk, private);
|
|
+ err = walk_pte_range(pmd, addr, next, walk);
|
|
if (err)
|
|
break;
|
|
} while (pmd++, addr = next, addr != end);
|
|
@@ -52,7 +52,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
|
|
}
|
|
|
|
static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
|
|
- const struct mm_walk *walk, void *private)
|
|
+ struct mm_walk *walk)
|
|
{
|
|
pud_t *pud;
|
|
unsigned long next;
|
|
@@ -63,15 +63,15 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
|
|
next = pud_addr_end(addr, end);
|
|
if (pud_none_or_clear_bad(pud)) {
|
|
if (walk->pte_hole)
|
|
- err = walk->pte_hole(addr, next, private);
|
|
+ err = walk->pte_hole(addr, next, walk);
|
|
if (err)
|
|
break;
|
|
continue;
|
|
}
|
|
if (walk->pud_entry)
|
|
- err = walk->pud_entry(pud, addr, next, private);
|
|
+ err = walk->pud_entry(pud, addr, next, walk);
|
|
if (!err && (walk->pmd_entry || walk->pte_entry))
|
|
- err = walk_pmd_range(pud, addr, next, walk, private);
|
|
+ err = walk_pmd_range(pud, addr, next, walk);
|
|
if (err)
|
|
break;
|
|
} while (pud++, addr = next, addr != end);
|
|
@@ -85,15 +85,15 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
|
|
* @addr: starting address
|
|
* @end: ending address
|
|
* @walk: set of callbacks to invoke for each level of the tree
|
|
- * @private: private data passed to the callback function
|
|
*
|
|
* Recursively walk the page table for the memory area in a VMA,
|
|
* calling supplied callbacks. Callbacks are called in-order (first
|
|
* PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
|
|
* etc.). If lower-level callbacks are omitted, walking depth is reduced.
|
|
*
|
|
- * Each callback receives an entry pointer, the start and end of the
|
|
- * associated range, and a caller-supplied private data pointer.
|
|
+ * Each callback receives an entry pointer and the start and end of the
|
|
+ * associated range, and a copy of the original mm_walk for access to
|
|
+ * the ->private or ->mm fields.
|
|
*
|
|
* No locks are taken, but the bottom level iterator will map PTE
|
|
* directories from highmem if necessary.
|
|
@@ -101,9 +101,8 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
|
|
* If any callback returns a non-zero value, the walk is aborted and
|
|
* the return value is propagated back to the caller. Otherwise 0 is returned.
|
|
*/
|
|
-int walk_page_range(const struct mm_struct *mm,
|
|
- unsigned long addr, unsigned long end,
|
|
- const struct mm_walk *walk, void *private)
|
|
+int walk_page_range(unsigned long addr, unsigned long end,
|
|
+ struct mm_walk *walk)
|
|
{
|
|
pgd_t *pgd;
|
|
unsigned long next;
|
|
@@ -112,21 +111,24 @@ int walk_page_range(const struct mm_struct *mm,
|
|
if (addr >= end)
|
|
return err;
|
|
|
|
- pgd = pgd_offset(mm, addr);
|
|
+ if (!walk->mm)
|
|
+ return -EINVAL;
|
|
+
|
|
+ pgd = pgd_offset(walk->mm, addr);
|
|
do {
|
|
next = pgd_addr_end(addr, end);
|
|
if (pgd_none_or_clear_bad(pgd)) {
|
|
if (walk->pte_hole)
|
|
- err = walk->pte_hole(addr, next, private);
|
|
+ err = walk->pte_hole(addr, next, walk);
|
|
if (err)
|
|
break;
|
|
continue;
|
|
}
|
|
if (walk->pgd_entry)
|
|
- err = walk->pgd_entry(pgd, addr, next, private);
|
|
+ err = walk->pgd_entry(pgd, addr, next, walk);
|
|
if (!err &&
|
|
(walk->pud_entry || walk->pmd_entry || walk->pte_entry))
|
|
- err = walk_pud_range(pgd, addr, next, walk, private);
|
|
+ err = walk_pud_range(pgd, addr, next, walk);
|
|
if (err)
|
|
break;
|
|
} while (pgd++, addr = next, addr != end);
|
|
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
|
index 9a29901..967d30c 100644
|
|
--- a/mm/vmscan.c
|
|
+++ b/mm/vmscan.c
|
|
@@ -1307,7 +1307,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
|
|
struct scan_control *sc)
|
|
{
|
|
int priority;
|
|
- int ret = 0;
|
|
+ unsigned long ret = 0;
|
|
unsigned long total_scanned = 0;
|
|
unsigned long nr_reclaimed = 0;
|
|
struct reclaim_state *reclaim_state = current->reclaim_state;
|
|
diff --git a/security/dummy.c b/security/dummy.c
|
|
index f50c6c3..b891688 100644
|
|
--- a/security/dummy.c
|
|
+++ b/security/dummy.c
|
|
@@ -27,6 +27,8 @@
|
|
#include <linux/hugetlb.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/file.h>
|
|
+#include <linux/prctl.h>
|
|
+#include <linux/securebits.h>
|
|
|
|
static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
|
|
{
|
|
@@ -607,7 +609,27 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info,
|
|
static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3,
|
|
unsigned long arg4, unsigned long arg5, long *rc_p)
|
|
{
|
|
- return 0;
|
|
+ switch (option) {
|
|
+ case PR_CAPBSET_READ:
|
|
+ *rc_p = (cap_valid(arg2) ? 1 : -EINVAL);
|
|
+ break;
|
|
+ case PR_GET_KEEPCAPS:
|
|
+ *rc_p = issecure(SECURE_KEEP_CAPS);
|
|
+ break;
|
|
+ case PR_SET_KEEPCAPS:
|
|
+ if (arg2 > 1)
|
|
+ *rc_p = -EINVAL;
|
|
+ else if (arg2)
|
|
+ current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
|
|
+ else
|
|
+ current->securebits &=
|
|
+ ~issecure_mask(SECURE_KEEP_CAPS);
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
}
|
|
|
|
static void dummy_task_reparent_to_init (struct task_struct *p)
|